How to Assign Active Network Location with PowerShell.
Step 1: Identify networks and associated NICs.
Get-NetConnectionProfile
Name : domain.com
InterfaceAlias : Ethernet (Domain)
InterfaceIndex : 1
NetworkCategory : DomainAuthenticated
IPv4Connectivity : Internet
IPv6Connectivity : NoTraffic
Name : Unidentified network
InterfaceAlias : RDMA
InterfaceIndex : 2
NetworkCategory : Public
IPv4Connectivity : NoTraffic
IPv6Connectivity : NoTraffic
The above examples shows two NICs that belong to two different networks.
Step 2. Change the NetworkCategory:
Set-NetConnectionProfile -InterfaceIndex 13 -NetworkCategory Private
This example changes the active network for the NIC named RDMA. The network location changed from Public to Private. Confirm with Get-NetConnectionProfile.
That't It!
References:
https://docs.microsoft.com/en-us/powershell/module/netconnection/get-netconnectionprofile?view=win10-ps
Problem:
How to use PowerShell commands to transfer FISMO roles?
Solution:
Active Directory PowerShell module.
Assumptions:
FISMO PowerShell management requires Active Directory PowerShell module.
Import-Module ActiveDirectory
Example 1. Show forest FSMO roles (forest):
PS> Get-ADForest contoso.com| ft DomainNamingMaster, SchemaMaster
Example 2. Show domain FSMO roles (domain):
PS> Get-ADDomain contoso.com | ft InfrastructureMaster, PDCEmulator, RIDMaster
Example 3. Transfer single role to a domain controller.
PS>; Move-ADDirectoryServerOperationMasterRole -Identity "DCX" PDCEmulator
#N.B., PowerShell FISMO role names:
0= PDCEmulator
1= RIDMaster
2= InfrastructureMaster
3= SchemaMaster
4= DomainNamingMaster
Example 4. Transfer multiple roles.
Move-ADDirectoryServerOperationMasterRole -Identity “DCX” –OperationMasterRole DomainNamingMaster,PDCEmulator,RIDMaster,SchemaMaster,InfrastructureMaster
Example 5: Transfer all roles with numbers:
Move-ADDirectoryServerOperationMasterRole “DCX” –OperationMasterRole 0,1,2,3,4
Example 6. Transfer FSMO roles between domain controllers:
Move-ADDirectoryServerOperationMasterRole
That's It!
References:
https://docs.microsoft.com/en-us/powershell/module/addsadministration/move-addirectoryserveroperationmasterrole?view=win10-ps
https://blogs.technet.microsoft.com/canitpro/2017/05/24/step-by-step-migrating-active-directory-fsmo-roles-from-windows-server-2012-r2-to-2016/
Problem:
Import VMWare virtual machine (VM) into Hyper-V hypervisor. Convert VMDK virtual disk into VHDX disk.
Solution:
Use Microsoft Virtual Machine Converter (MVMC) 3.1 to import and convert the VMWare ESXi VM into Hyper-V.
Background:
The MVMC GUI provides a simple import wizard. Please note, the GUI only imports VMWare hypervisors (including ESXi) connected to VMSphere. MVMC PowerShell commands can convert stand-alone ESX and ESXi VMs.
Convert:
- Download MVMC. The Microsoft download sites lists MVMC as 3.0. N.B., the file installs version 3.1.
- Install MVMC on Hyper-V host.
- Uninstall VMTools from VMDK VM.
- Copy VMDK to Hyper-V host.
- Open PowerShell. Import MVMC PowerShell library.
Import-Module "C:\Program Files\Microsoft Virtual Machine Converter\MvmcCmdlet.psd1"
- Use PowerShell to convert VMDK to VHD. N.B., Do not use VMDK_Flat file!
PS D:\TMP> ConvertTo-MvmcVirtualHardDisk -SourceLiteralPath "D:\VMS\DEV.vmdk" -DestinationLiteralPath "S:\VMS" -VhdType DynamicHardDisk
- Create new VM in Hyper-V. Add newly created (i.e., system) disk to IDE adapter. Additional disks can use the SCSI adapter. This is the time to configure dynamic memory or add additional CPUs.
N.B., Do not resize the disk until after the VM starts at least once in Hyper-V!
- Start-up VM. Install Hyper-V tools. Restart.
- Optional: New NIC "hardware" causes problems with retaining preexisting static IPs. Resolve problem by deleting the network adapter and restating. Windows creates a new network adapter upon start-up. Manually add IP addresses into new adapter.
That's It!
Error:
The trust relationship between this workstation and the primary domain failed.
Problem:
Domain computers use internal passwords to authenticate with Active Directory (AD). Servers and workstations automatically reset their passwords every 30 days. Suspended virtual machines or server backups may not logon domain users if the computer has a new password in AD.
Solution:
Fix domain trust issues: (1) in AD, and (2) on the computer.
- Reset the computer account in Active Directory Users and Computers (ADUC).
Open ADUC → Computers OU → Right-Click on the computer → Reset Accout
-
Reset the computer with PowerShell. N.B., This step requires local Administrative rights. We can't reset the computer, or even re-join the domain, with out the ability to log on locally.
From PowerShell: Reset-ComputerMachinePassword
That's It!
References: http://technet.microsoft.com/en-us/library/hh849751.aspx
By Steven Jordan on 4/17/2014
Takeaway: Steps on how to apply Windows updates to the Exchange Data Availability Group (DAG) servers. Take care when applying Exchange service pack rollups on Patch Tuesday.
- Prevent the server from activating databases. N.B., Exchange continues to keep databases current; however it will not activate if other DAG members become unavailable.
Get-MailboxDatabaseCopyStatus –Server (hostname) | Suspend-MailboxDatabaseCopy –ActivationOnly –Confirm:$false
- Migrate all active databases to another DAG member
Move-ActiveMailboxDatabse -Server (hostname)
-ActivateOnServer (Other DAG Member)
- Check activation status with PowerShell:
Get-MailboxDatabaseCopyStatus –Server (hostname) | Select Name, ActivationSuspended, MailboxServer
Get-MailboxDatabase | Select Name, ActivationPreference, Server
- It's safe to install the Exchange roll-ups when activation is suspended. Proceed with patching.
- Re-enable the database after patching is complete. N.B., This server only becomes active if the other DAG member becomes unavailable.
Get-MailboxDatabaseCopyStatus –Server (hostname) | Resume-MailboxDatabaseCopy
- Repeat the process for the remaining DAG servers: (a) prevent activation, (b) migrate active database to another DAG member, (c) install the roll-ups, (d) resume activation.
That's It!
References: http://www.ehloworld.com/167
By Steven Jordan on 4/17/2014.
Takeaway: Sign PowerShell scripts with a code signing certificate.
Assumptions: We'll assume a code-signing
certificate is already installed the Windows certificate root store. If you don't already have a code-signing certificate, obtain one:
- Enroll with the Windows Certificate Authority (CA) server.
- Enroll with a public CA. Best option if you plan to publicly distribute your scripts.
- Generate a self-signed certificate.
Use the code-signing certificate located in the the Windows Certificate Store to sign PowerShell scripts. First,
export the certificate from the Certificate Store. Export the certificate as follows:
Start → MMC → Add/Remove Snap-In → Certificates → Personal → Right click on the certificate → Export.
Save the certificate as a PFX file in a directory of your choice (e.g., c:\scripts).
Lastly, use the following PowerShell script to sign the code:
PS C:\scripts> $cert = Get-PfxCertificate C:\scripts\codesigncert.pfx C:\scripts> Set-AuthenticodeSignature -Filepath pruneVSS.ps1 -Cert $cert
Directory: C:\scripts
SignerCertificate Status Path
----------------- ------ ---- 2603FCAA10343AE1DD78AB41D984728D657499D3 Valid pruneVSS.ps1
That's it -the PowerShell script is signed. Time to change the
set-execution policy throughout the domain!
By Steven Jordan on 4/15/2014.
There are times when the DPM console GUI cannot remove its inactive data sources. This PowerShell script removes all inactive data from DPM. Choose between inactive disk or tape based data sources.
Removeinactivedatasource.ps1:
param([string] $DPMServerName, [string] $RemoveOption)
function Usage()
{
write-host
write-host "Usage::"
write-host "Remove-InactiveDatasource.ps1 -DPMServerName [DPMServername] -RemoveOption [Remove Options]"
write-host
write-host "Run 'Remove-InactiveDatasource.ps1 -detailed' for detailed help"
write-host
write-host
}
if(("-?","-help") -contains $args[0])
{
Usage
exit 0
}
if(("-detailed") -contains $args[0])
{
write-host
write-host "Detailed Help : Use this script to remove inactive datasources on disk or tape or both"
write-host "Valid inputs of RemoveOption"
write-host "OnDisk : Removes all inactive datasources on Disk only"
write-host "OnTape : Removes all inactive datasources on Tape only"
write-host "OnBoth : Removes all inactive datasources on both Disk and Tape"
write-host
write-host
exit 0
}
if(!$DPMServerName)
{
$DPMServerName = read-host "DPMServerName:"
}
$dpmServer = Connect-DPMServer $DPMServerName
if (!$dpmServer)
{
write-Error "Failed To Connect To DPM Server::$DPMServerName"
exit 1
}
$dsList = get-datasource $dpmservername
if (!$dsList -or ($dsList.Count -eq 0) )
{
write-verbose "No Datasources found"
disconnect-dpmserver $dpmservername
exit 2
}
if(!$RemoveOption)
{
$RemoveOption = read-host "RemoveOption:"
}
if($RemoveOption)
{
if ("ONDISK" -eq $RemoveOption)
{
$RemoveOption = "OnDisk"
}
elseIf ("ONTAPE" -eq $RemoveOption)
{
$RemoveOption = "OnTape"
}
elseIf("ONBOTH" -eq $RemoveOption)
{
$RemoveOption = "OnBoth"
}
else
{
write-Error "Invalid Value::$RemoveOption For Parameter -RemoveOption[OnDisk/OnTape/OnBoth]"
Disconnect-dpmserver
exit 1
}
}
else
{
Usage
Disconnect-dpmserver
exit 1
}
foreach($ds in $dsList)
{
if($RemoveOption -eq "OnDisk" -and
($ds.InactiveProtectionStatus -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::Disk -or
$ds.InactiveProtectionStatus -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::DiskAndTape)
)
{
write-host "Removing inactive Disk protection of " $ds.Name
$confirm = read-host "Confirm(y/n):"
if($confirm -eq "y")
{
Remove-DatasourceReplica -Datasource $ds -Disk
write-host "Inactive disk protection for " $ds.Name " removed"
}
}
if($RemoveOption -eq "OnTape" -and
($ds.InactiveProtectionStatus -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::Tape -or
$ds.InactiveProtectionStatus -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::DiskAndTape)
)
{
write-host "Removing inactive Tape protection of " $ds.Name
$confirm = read-host "Confirm(y/n):"
if($confirm -eq "y")
{
Remove-DatasourceReplica -Datasource $ds -Tape
write-host "Inactive tape protection for " $ds.Name " removed"
}
}
if($RemoveOption -eq "OnBoth" -and
$ds.InactiveProtectionStatus -ne [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::None)
{
write-host "Removing inactive Disk and Tape protection of " $ds.Name
$confirm = read-host "Confirm(y/n):"
if($confirm -eq "y")
{
if($ds.InactiveProtectionStatus -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::Disk)
{
Remove-DatasourceReplica -Datasource $ds -Disk
}
elseif($ds.InactiveProtectionStatus -eq [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.OMCommon.InactiveProtection]::Tape)
{
Remove-DatasourceReplica -Datasource $ds -Tape
}
else
{
Remove-DatasourceReplica -Datasource $ds -Disk
Remove-DatasourceReplica -Datasource $ds -Tape
}
write-host "Inactive protection for " $ds.Name " removed"
}
}
}
Disconnect-dpmserver
By Steven Jordan on April 15th, 2014.
There are times when DPM fails to remove expired recovery points. PruneVSS.ps1 can remove excessive disk (i.e., not tape) based recovery points.
#Author : Ruud Baars
#Date : 11/09/2008
#Edited : 11/15/2012 By: Wilson S.
#edited : 11:27:2012 By: Mike J.
#Edited : 3/25/2014 By: Steven J.
# $VerbosePreference = "Continue"
# NOTE: Update script to only remove recovery points on Disk. Recovery points removed will be from the oldest one up to the date
# entered by the user while the script is running
#deletes all recovery points before 'now' on selected data source.
$version="V4.7"
$ErrorActionPreference = "silentlycontinue"
add-pssnapin sqlservercmdletsnapin100
Add-PSSnapin -Name Microsoft.DataProtectionManager.PowerShell
#display RP's to delete and ask to continue.
#Check & wait data source to be idle else removal may fail (in Mojito filter on 'intent' to see the error)
#Fixed prune default and logfile name and some logging lines (concatenate question + answer)
#Check dependent recovery points do not pass BEFORE date and adjust selection to not select those ($reselect)
#--- Fixed reselect logic to keep adjusting reselect for as long as older than BEFORE date
#--- Fixed post removal rechecking logic to match what is done so far (was still geared to old logic)
#--- Modified to remove making RP and ask for pruning, fixed logic for removal rechecking logic
$MB=1024*1024
$logfile="DPMdeleteRP.LOG"
$wait=10
#seconds
$confirmpreference = "None"
function Show_help
{
cls
$l="=" * 79
write-host $l -foregroundcolor magenta
write-host -nonewline "`t<<<" -foregroundcolor white
write-host -nonewline " DANGEROUS :: MAY DELETE MANY RECOVERY POINTS " -foregroundcolor red
write-host ">>>" -foregroundcolor white
write-host $l -foregroundcolor magenta
write-host "Version: $version" -foregroundcolor cyan
write-host "A: User Selects data source to remove recovery points for" -foregroundcolor green
write-host "B: User enters date / time (using 24hr clock) to Delete recovery points" -foregroundcolor green
write-host "C: User Confirms deletion after list of recovery points to be deleted is displayed." -foregroundcolor green
write-host "Appending to log file $logfile`n" -foregroundcolor white
write-host "User Accepts all responsibilities by entering a data source or just pressing [Enter] " -foregroundcolor white -backgroundcolor blue
}
"**********************************" >> $logfile
"Version $version" >> $logfile
get-date >> $logfile
show_help
$DPMservername=&"hostname"
"Selected DPM server = $DPMservername" >> $logfile
write-host "`nConnnecting to DPM server retrieving data source list...`n" -foregroundcolor green
$pglist = @(Get-ProtectionGroup $DPMservername) # WILSON - Created PGlist as array in case we have a single protection group.
$ds=@()
$tapes=$null
$count = 0
$dscount = 0
foreach ($count in 0..($pglist.count - 1))
{
# write-host $pglist[$count].friendlyname
$ds += @(get-datasource $pglist[$count]) # WILSON - Created DS as array in case we have a single protection group.
# write-host $ds
# write-host $count -foreground yellow
}
if ( Get-Datasource $DPMservername -inactive) {$ds += Get-Datasource $DPMservername -inactive}
$i=0
write-host "Index Protection Group Computer Path"
write-host "---------------------------------------------------------------------------------"
foreach ($l in $ds)
{
"[{0,3}] {1,-20} {2,-20} {3}" -f $i, $l.ProtectionGroupName, $l.psinfo.netbiosname, $l.logicalpath
$i++
}
$DSname=read-host "`nEnter a data source index from list above - Note co-located datasources on same replica will be effected"
if (!$DSname)
{
write-host "No datasource selected `n" -foregroundcolor yellow
"Aborted on Datasource name" >> $logfile
exit 0
}
$DSselected=$ds[$DSname]
if (!$DSselected)
{
write-host "No datasource selected `n" -foregroundcolor yellow
"Aborted on Datasource name" >> $logfile
exit 0
}
$rp=get-recoverypoint $DS[$dsname]
$rp
# $DoTape=read-host "`nDo you want to remove when recovery points are on tape ? [y/N]"
# "Remove tape recovery point = $DoTape" >> $logfile
write-host "`nCollecting recoverypoint information for datasource $DSselected.name" -foregroundcolor green
if ($DSselected.ShadowCopyUsedspace -gt 0)
{
while ($DSSelected.TotalRecoveryPoints -eq 0)
{ # "still 0"
}
#this is on disk
$oldShadowUsage=[math]::round($DSselected.ShadowCopyUsedspace/$MB,1)
$line=("Total recoverypoint usage {0} MB on DISK in {1} recovery points" -f $oldShadowUsage ,$DSselected.TotalRecoveryPoints )
$line >> $logfile
write-host $line`n -foregroundcolor white
}
#this is on tape
#$trptot=0
#$tp= Get-RecoveryPoint($dsselected) | where {($_.Datalocation -eq "Media")}
#foreach ($trp in $tp) {$trptot += $trp.size }
#if ($trptot -gt 0 )
#{
# $line=("Total recoverypoint usage {0} MB on TAPE in {1} recovery points" -f ($trptot/$MB) ,$DSselected.TotalRecoveryPoints )
# $line >> $logfile
# write-host $line`n -foregroundcolor white
#}
[datetime]$afterdate="1/1/1980"
#$answer=read-host "`nDo you want to delete recovery points from the beginning [Y/n]"
#if ($answer -eq "n" )
#{
# [datetime]$afterdate=read-host "Delete recovery points AFTER date [MM/DD/YYYY hh:mm]"
#}
[datetime]$enddate=read-host "Delete ALL Disk based recovery points BEFORE and Including date/time entered [MM/DD/YYYY hh:mm]"
"Deleting recovery points until $enddate" >>$logfile
write-host "Deleting recovery points until and $enddate" -foregroundcolor yellow
$rp=get-recoverypoint $DSselected
if ($DoTape -ne "y" )
{
$RPselected=$rp | where {($_.representedpointintime -le $enddate) -and ($_.Isincremental -eq $FALSE)-and ($_.DataLocation -eq "Disk")}
}
else
{
$RPselected=$rp | where {($_.representedpointintime -le $enddate) -and ($_.Isincremental -eq $FALSE)}
}
if (!$RPselected)
{
write-host "No recovery points found!" -foregroundcolor yellow
"No recovery points found, aborting...!" >> $logfile
exit 0
}
$reselect = $enddate
$adjustflag = $false
foreach ($onerp in $RPselected)
{
$rtime=[string]$onerp.representedpointintime
$rsize=[math]::round(($onerp.size/$MB),1)
$line= "Found {0}, RP size= {1} MB (If 0 MB, co-located datasource cannot be computed), Incremental={2} "-f $rtime, $rsize,$onerp.Isincremental
$line >> $logfile
write-host "$line" -foregroundcolor yellow
#
#Get dependent rp's for data source
#
$allRPtbd=$DSselected.GetAllRecoveryPointsToBeDeleted($onerp)
foreach ($oneDrp in $allRPtbd)
{
if ($oneDrp.IsIncremental -eq $FALSE) {continue}
$rtime=[string]$oneDrp.representedpointintime
$rsize=[math]::round(($oneDrp.size/$MB),1)
$line= ("`t...is dependancy for {0} size {1} `tIncremental={2}" -f $rtime, $rsize, $oneDrp.Isincremental)
$line >> $logfile
if ($oneDrp.representedpointintime -ge $enddate)
{
#stick to latest full ($oneDrp = dependents, $onerp = full)
$adjustflag = $true
$reselect = $onerp.representedpointintime
"<< Dependents newer than BEFORE date >>>" >> $logfile
Write-Host -nonewline "`t <<< later than BEFORE date >>>" -foregroundcolor white -backgroundcolor red
write-host "$line" -foregroundcolor yellow
}
else
{
#Ok, include current latest incremental
$reselect = $oneDrp.representedpointintime
write-host "$line" -foregroundcolor yellow
}
}
}
if ($reselect -lt $oneDrp.representedpointintime)
{
#we adjusted further backward than latest incremental within selection
$reselect = $rtime
$line = "Adjusted BEFORE date to be $reselect to include dependents to $enddate"
$line >> $logfile
Write-Host $line -foregroundcolor white -backgroundcolor blue
}
$line="`n<<< SECOND TO LAST CHANCE TO ABORT - ONE MORE PROMPT TO CONFIRM. >>>"
write-host $line -foregroundcolor white -backgroundcolor blue
$line >> $logfile
$line="Above recovery points within adjusted range will be permanently deleted !!!"
write-host $line -foregroundcolor red
$line >> $logfile
$line="These RP's include dependent recovery points and may contain co-located datasource(s)"
write-host $line -foregroundcolor red
$line >> $logfile
$line="Data source activity = " + $DSselected.Activity
$line >> $logfile
write-host $line -foregroundcolor white
$DoDelete=""
while (($DoDelete -ne "N" ) -and ($DoDelete -ne "Y"))
{
$line="Continue with deletion (must answer) Y/N? "
write-host $line -foregroundcolor white
$DoDelete=read-host
$line = $line + $DoDelete
$line >> $logfile
}
if (!$DSselected.Activity -eq "Idle")
{
$line="Data source not idle, do you want to wait Y/N ? "
write-host $line -foregroundcolor yellow
$Y=read-host
$line = $line + $Y
$line >> $logfile
if ($Y -ieq "Y")
{
Write-Host "Waiting for data source to become idle..." -foregroundcolor green
while ($DSselected.Activity -ne "Idle")
{
("Waiting {0} seconds" -f $wait) >>$logfile
Write-Host -NoNewline "..." -ForegroundColor blue
start-sleep -s $wait
}
}
}
if ($DoDelete -eq "Y")
{
foreach ($onerp in $RPselected)
{
#reselect is adjusted to safe range relative to what was requested
#--- if adjustflag not set then all up to including else only older because we must keep the full
if ((($onerp.representedpointintime -le $reselect) -and ($adjustflag -eq $false)) -or ($onerp.representedpointintime -lt $reselect))
{
$rtime=[string]$onerp.representedpointintime
write-host `n$line -foregroundcolor red
$line >>$logfile
if (($onerp ) -and ($onerp.IsIncremental -eq $FALSE)) { remove-recoverypoint -RecoveryPoint $onerp -recurse -force -confirm:$False} # >> $logfile}
$line =("---`nDeleting recoverypoint -> " + $rtime)
$line >>$logfile
}
}
}
"All Done!" >> $logfile
write-host "`nAll Done!`n`n" -foregroundcolor white
$line="Do you want to View DPMdeleteRP.LOG file Y/N ? "
write-host $line -foregroundcolor white
$Y=read-host
$line = $line + $Y
$line >> $logfile
if ($Y -ieq "Y")
{
Notepad DPMdeleteRP.LOG}
Problem: Incorporate code signing scripts in PowerShell.
PowerShell script execution policy set to unrestricted is poor practice; don't do it! A compromised computer is especially dangerous with unrestricted PowerShell scripts. Exceptions may include one time use but don't forget to change the execution policy back to to restricted.
Solution:
- Generate a free code signing certificate using Windows SDK (free download from Microsoft).
Global PKI code signing certificates are expensive. Unless you plan to distribute your PowerShell script outside your organization use of a code signing certificate from a public CA is not necessary.
- Incorporate the self generated code signing certificate for all PowerShell scripts.
- Change PowerShell execution policy to AllSigned.
- Import the self generated code signing certificate to the Trusted Root Certification Authorities using the Certificate manager or distribute to domain resources with group policy.
All PowerShell scripts must include a code signing certificate to maintain server integrity. All self generated code signing certificates must be considered a Trusted Root to maintain functionality.
Please visit the
Kreelbits Blog for detailed instructions on how to implement the above steps. Great work
+Scott Kreel!
Script to export the Exchange 2010 SMTP logs into an easy to "read and work with" Excel file:
1. Load Exchange Management Shell:
add-pssnapin Microsoft.Exchange.Management.PowerShell.E2010
2. Export message tracking results to CSV:
get-messagetrackinglog -resultsize unlimited -Sender "user@sender.com" -MessageSubject "This is where the subject goes" | Select Sender,{$_.Recipients},{$_.RecipientStatus},MessageSubject,TimeStamp, EventId, Source, SourceContext,MessageId,InternalMessageId,ClientIP,ClientHostName,ServerIP,ServerHostName,ConnectorId,TotalBytes,RecipientCount,RelatedRecipientAddress,Reference,ReturnPath,MessageInfo | Export-Csv .\MessageTrackingLog.csv
Last updated June 13th, 2013 by Steven Jordan.
This is an update to a previous post on how to mark a tape as "free". Because of limitations with the DPM GUI a Power Shell script must be run to free the tapes associated with protection groups.
I ran into a problem specifying the location of the tape when using the previous script. The PS script below sidesteps the location problem.
N. B. Here is the correct format to run the script:
PS C:\scripts> .\free2.ps1 -dpmservername dpserver01 -LibraryName "Hewlett Packard DAT72 drive"
Here is the script:
param ([string] $DPMServerName, [string] $LibraryName)
if(("-?","-help") -contains $args[0])
{
Write-Host "Usage: ForceFree-Tape.ps1 [[-DPMServerName] ] [-LibraryName]
Write-Host "Example: Force-FreeTape.ps1 -Dpmservername SDPM01 -LibraryName My library
exit 0
}
if (!$DPMServerName)
{
$DPMServerName = Read-Host "DPM server name: "
if (!$DPMServerName)
{
Write-Error "Dpm server name not specified."
exit 1
}
}
if (!$LibraryName)
{
$LibraryName = Read-Host "Library name: "
if (!$LibraryName)
{
Write-Error "Library name not specified."
exit 1
}
}
if (!(Connect-DPMServer $DPMServerName))
{
Write-Error "Failed to connect To DPM server $DPMServerName"
exit 1
}
$library = Get-DPMLibrary $DPMServerName | where {$_.UserFriendlyName -eq $LibraryName}
write-host "Getting library..."
if (!$library)
{
Write-Error "Failed to find library with user friendly name $LibraryName"
exit 1
}
foreach ($media in @(Get-Tape -DPMLibrary $library))
{
write-host "Getting media..."
if ($media -is [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.LibraryManagement.ArchiveMedia])
{
foreach ($rp in @(Get-RecoveryPoint -Tape $media))
{
write-host "Getting recovery point..."
Get-RecoveryPoint -Datasource $rp.Datasource | Out-Null
Write-Verbose "Removing recovery point created at $($rp.RepresentedPointInTime) for tape in $($media.Location)."
write-host "Force removing recovery point..."
Remove-RecoveryPoint -RecoveryPoint $rp -ForceDeletion -Confirm:$false
}
Write-Verbose "Setting tape in $($media.Location) as free."
write-host "Setting tape as free..."
Set-Tape -Tape $media -Free
}
else
{
Write-Error "The tape in $($media.Location) is a cleaner tape."
}
}
*I posted an update to this script
here.
Problem: I wanted to use a DAT 72 tape that previously had data written to it. When trying to free the tape I received the following error:
The selected tapes cannot be erased because they belong to protection groups
Solution: The tape cannot be released via DPM 2010 GUI. I found the following PowerShell script that allowed me to use the tape:
----------------------------- Start of Script --------------------------------
param ([string] $DPMServerName, [string] $LibraryName, [string[]] $TapeLocationList)
if(("-?","-help") -contains $Args[0])
{Write-Host "Usage: ForceFree-Tape.ps1 [[-DPMServerName] ] [-LibraryName] [-TapeLocationList] "Write-Host "Example: Force-FreeTape.ps1 -LibraryName "My library" -TapeLocationList Slot-1, Slot-7"exit 0
}
if (!$DPMServerName)
{$DPMServerName = Read-Host "DPM server name: "if (!$DPMServerName)
{Write-Error "Dpm server name not specified."exit 1
}
}if (!(Connect-DPMServer $DPMServerName))
{Write-Error "Failed to connect To DPM server $DPMServerName"exit 1
}
$library = @(Get-DPMLibrary $DPMServerName )if ($library.count -eq 0)
{Write-Error "Failed to find library with user friendly name $LibraryName"exit 1
}
if (!$LibraryName)
{$library | foreach {$_.userfriendlyname}$LibraryName = Read-Host "Library name (cut & paste from above): "if (!$LibraryName)
{
Write-Error "Library name not specified."exit 1
}
}
if (!$TapeLocationList)
{$tmp = Read-Host "Tape location: "$TapeLocationList=$tmp.split(",")write-host "Processing this slot list..."$TapeLocationListif (!$TapeLocationList)
{Write-Error "Tape location not specified."exit 1
}
}
foreach ($media in @(Get-Tape -DPMLibrary $library))
{if ($TapeLocationList -contains $media.Location)
{if ($media -is [Microsoft.Internal.EnterpriseStorage.Dls.UI.ObjectModel.LibraryManagement.ArchiveMedia])
{foreach ($rp in @(Get-RecoveryPoint -Tape $media))
{Get-RecoveryPoint -Datasource $rp.Datasource | Out-NullWrite-Verbose "Removing recovery point created at $($rp.RepresentedPointInTime) for tape in $($media.Location)."Remove-RecoveryPoint -RecoveryPoint $rp -ForceDeletion -Confirm:$false}
Write-Verbose "Setting tape in $($media.Location) as free."Set-Tape -Tape $media -Free}else{Write-Error "The tape in $($media.Location) is a cleaner tape."}
}
}
----------------------------- End of Script ---------------------------------