Public/Move-VMReliably.ps1
function Move-VMReliably { [CmdletBinding()] Param ( [Parameter(ParameterSetName = 'ByHost', Mandatory)] [Microsoft.HyperV.PowerShell.VMHost]$SourceVMHost, [Parameter(ParameterSetName = 'ByVM', Mandatory)] [Microsoft.HyperV.PowerShell.VirtualMachine[]]$VM, [Parameter(ParameterSetName = 'ByHost', Mandatory)] [Parameter(ParameterSetName = 'ByVM', Mandatory)] [Microsoft.HyperV.PowerShell.VMHost]$DestinationVMHost, [Parameter(ParameterSetName = 'ByHost', Mandatory)] [Parameter(ParameterSetName = 'ByVM', Mandatory)] [string]$Path, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [ValidateRange(0, [int]::MaxValue)] [int]$Timeout = $ModuleWideMigrationTimeout, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [ValidateRange(0, [int]::MaxValue)] [int]$MaxAttempts = $ModuleWideMigrationMaxAttempts, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [ValidateRange(0, [int]::MaxValue)] [int]$MaxParallelMigrations, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [ValidateRange(0, [int]::MaxValue)] [int]$MigrationJobGetTimeout = $ModuleWideMigrationJobGetTimeout, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [ValidateRange(0, [int]::MaxValue)] [int]$MigrationJobGetMaxAttempts = $ModuleWideMigrationJobGetMaxAttempts, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [System.TimeSpan]$BackupThreshold = $ModuleWideBackupThreshold, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [switch]$Bulletproof, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [switch]$CrashOnUnmigratable, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [switch]$ReturnSourceVMs, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [switch]$PutInASubfolder, [Parameter(ParameterSetName = 'ByHost')] [Parameter(ParameterSetName = 'ByVM')] [string]$SessionID = [guid]::NewGuid().ToString() # Because .Guid property is twice slower ) $ErrorActionPreference = [System.Management.Automation.ActionPreference]::Stop Write-Debug -Message ('ENTER {0}' -f $MyInvocation.MyCommand.Name) try { Write-Debug -Message ('ENTER TRY {0}' -f $MyInvocation.MyCommand.Name) Write-Debug -Message ('$SourceVMHost: ''{0}''' -f [string]$SourceVMHost) Write-Debug -Message ('$VM: ''{0}''' -f [string]$VM.Name) Write-Debug -Message ('$DestinationVMHost: ''{0}''' -f [string]$DestinationVMHost) Write-Debug -Message ('$Path = ''{0}''' -f $Path) Write-Debug -Message ('$Timeout = {0}' -f $Timeout) Write-Debug -Message ('$MaxAttempts = {0}' -f $MaxAttempts) Write-Debug -Message ('$MaxParallelMigrations = {0}' -f $MaxParallelMigrations) Write-Debug -Message ('$MigrationJobGetTimeout = {0}' -f $MigrationJobGetTimeout) Write-Debug -Message ('$MigrationJobGetMaxAttempts = {0}' -f $MigrationJobGetMaxAttempts) Write-Debug -Message ('$BackupThreshold: ''{0}''' -f [string]$BackupThreshold) Write-Debug -Message ('$Bulletproof: ''{0}''' -f [string]$Bulletproof) Write-Debug -Message ('$CrashOnUnmigratable: ''{0}''' -f [string]$CrashOnUnmigratable) Write-Debug -Message ('$ReturnSourceVMs = ${0}' -f $ReturnSourceVMs) Write-Debug -Message ('$PutInASubfolder = ${0}' -f $PutInASubfolder) Write-Debug -Message ('$SessionID = ''{0}''' -f $SessionID) Write-Debug -Message 'if ($VM)' if ($VM) { Write-Debug -Message '$UniqueVMHosts = $VM.ComputerName | Select-Object -Unique' $UniqueVMHosts = $VM.ComputerName | Select-Object -Unique Write-Debug -Message ('$UniqueVMHosts: ''{0}''' -f [string]$UniqueVMHosts) Write-Debug -Message ('$UniqueVMHosts.Count: {0}' -f $UniqueVMHosts.Count) Write-Debug -Message 'if ($UniqueVMHosts.Count -eq 1)' if ($UniqueVMHosts.Count -eq 1) { # Right now the function supports moving VMs between two hosts only Write-Debug -Message ('$SourceVMHost = Get-VMHost -ComputerName ''{0}''' -f $UniqueVMHosts) $SourceVMHost = Get-VMHost -ComputerName $UniqueVMHosts Write-Debug -Message ('$SourceVMHost: ''{0}''' -f [string]$SourceVMHost) } elseif ($UniqueVMHosts.Count -lt 1) { $Message = ('Somehow there are no unique VMHosts: {0}' -f [string]$UniqueVMHosts.Name) $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.Management.Automation.PSNotSupportedException' -ArgumentList $Message), 'PSNotSupportedException', [System.Management.Automation.ErrorCategory]::InvalidData, $UniqueVMHosts))) } else { $Message = ('Input VMs are from several VMHosts: {0}' -f [string]$UniqueVMHosts.Name) $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.Management.Automation.PSNotSupportedException' -ArgumentList $Message), 'PSNotSupportedException', [System.Management.Automation.ErrorCategory]::InvalidData, $UniqueVMHosts))) } } Write-Debug -Message '$SourceHostName = $SourceVMHost.Name' $SourceHostName = $SourceVMHost.Name Write-Debug -Message ('$SourceHostName = ''{0}''' -f $SourceHostName) Write-Debug -Message '$DestinationHostName = $DestinationVMHost.Name' $DestinationHostName = $DestinationVMHost.Name Write-Debug -Message ('$DestinationHostName = ''{0}''' -f $DestinationHostName) Write-Debug -Message 'if ($SourceVMHost -ne $DestinationVMHost)' if ($SourceVMHost -ne $DestinationVMHost) { Write-Debug -Message 'if (-not $VM)' if (-not $VM) { Write-Debug -Message ('$VM = Get-VM -ComputerName ''{0}''' -f $SourceHostName) $VM = Get-VM -ComputerName $SourceHostName } Write-Debug -Message ('$VM: ''{0}''' -f [string]$VM.Name) Write-Debug -Message 'if ($VM)' if ($VM) { Write-Debug -Message '[System.Collections.ArrayList]$UnmigratableVMs = @()' [System.Collections.ArrayList]$UnmigratableVMs = @() Write-Debug -Message '[System.Collections.ArrayList]$BackingUpVMs = @()' [System.Collections.ArrayList]$BackingUpVMs = @() Write-Debug -Message '[System.Collections.ArrayList]$VMMigrationRetryInfo = @()' [System.Collections.ArrayList]$VMMigrationRetryInfo = @() Write-Debug -Message '$SourceVMHostLiveMigrationMaximum = $SourceVMHost.MaximumVirtualMachineMigrations' $SourceVMHostLiveMigrationMaximum = $SourceVMHost.MaximumVirtualMachineMigrations Write-Debug -Message ('$SourceVMHostLiveMigrationMaximum = {0}' -f $SourceVMHostLiveMigrationMaximum) Write-Debug -Message '$DestinationVMHostLiveMigrationMaximum = $DestinationVMHost.MaximumVirtualMachineMigrations' $DestinationVMHostLiveMigrationMaximum = $DestinationVMHost.MaximumVirtualMachineMigrations Write-Debug -Message ('$DestinationVMHostLiveMigrationMaximum = {0}' -f $DestinationVMHostLiveMigrationMaximum) Write-Debug -Message ('$LiveMigrationMaximum = (({0}, {1}) | Measure-Object -Minimum).Minimum' -f $SourceVMHostLiveMigrationMaximum, $DestinationVMHostLiveMigrationMaximum) $LiveMigrationMaximum = (($SourceVMHostLiveMigrationMaximum, $DestinationVMHostLiveMigrationMaximum) | Measure-Object -Minimum).Minimum Write-Debug -Message ('$LiveMigrationMaximum = {0}' -f $LiveMigrationMaximum) Write-Debug -Message ('$MaxParallelMigrations = {0}' -f $MaxParallelMigrations) Write-Debug -Message 'if ($MaxParallelMigrations)' if ($MaxParallelMigrations) { Write-Debug -Message ('$LiveMigrationMaximum = (({0}, {1}) | Measure-Object -Minimum).Minimum' -f $LiveMigrationMaximum, $MaxParallelMigrations) $LiveMigrationMaximum = (($LiveMigrationMaximum, $MaxParallelMigrations) | Measure-Object -Minimum).Minimum } Write-Debug -Message ('$LiveMigrationMaximum = {0}' -f $LiveMigrationMaximum) Write-Debug -Message ('$ReturnSourceVMs = ${0}' -f $ReturnSourceVMs) Write-Debug -Message ('if ($ReturnSourceVMs)') if ($ReturnSourceVMs) { Write-Debug -Message '$FirstRun = $true' $FirstRun = $true Write-Debug -Message ('$FirstRun = ${0}' -f $FirstRun) } do { Write-Debug -Message ('$PsCmdlet.ParameterSetName: ''{0}''' -f $PsCmdlet.ParameterSetName) switch ($PsCmdlet.ParameterSetName) { 'ByHost' { Write-Debug -Message '$Filter = {$_.Id -notin $UnmigratableVMs}' $Filter = {$_.Id -notin $UnmigratableVMs} } 'ByVM' { Write-Debug -Message '$Filter = {$_.Id -in $VM.Id -and $_.Id -notin $UnmigratableVMs}' $Filter = {$_.Id -in $VM.Id -and $_.Id -notin $UnmigratableVMs} } } Write-Debug -Message ('$Filter = {{{0}}}' -f $Filter) Write-Debug -Message ('$SourceVMs = Get-VM -ComputerName ''{0}'' | Where-Object -FilterScript {{{1}}}' -f $SourceHostName, $Filter) $SourceVMs = Get-VM -ComputerName $SourceHostName | Where-Object -FilterScript $Filter # Getting those VMs of which we care about Write-Debug -Message ('$SourceVMs: ''{0}''' -f [string]$SourceVMs.Name) Write-Debug -Message ('$SourceVMs.Id: ''{0}''' -f [string]$SourceVMs.Id) Write-Debug -Message 'if ($SourceVMs)' if ($SourceVMs) { Write-Debug -Message ('$ReturnSourceVMs = ${0}' -f $ReturnSourceVMs) Write-Debug -Message ('if ($ReturnSourceVMs)') if ($ReturnSourceVMs) { Write-Debug -Message ('$FirstRun = ${0}' -f $FirstRun) Write-Debug -Message 'if ($FirstRun)' if ($FirstRun) { Write-Debug -Message '$SourceVMsOriginal = $SourceSCVMs.Clone()' $SourceVMsOriginal = $SourceVMs.Clone() Write-Debug -Message ('$SourceVMsOriginal: ''{0}''' -f [string]$SourceVMsOriginal.Name) Write-Debug -Message '$FirstRun = $false' $FirstRun = $false Write-Debug -Message ('$FirstRun = ${0}' -f $FirstRun) } } Write-Debug -Message ('$SourceVMsMigrating = $SourceVMs | Select-VM -Migrating -Force:${0}' -f $Bulletproof) $SourceVMsMigrating = $SourceVMs | Select-VM -Migrating -Force:$Bulletproof Write-Debug -Message ('$SourceVMsMigrating: ''{0}''' -f [string]$SourceVMsMigrating.Name) Write-Debug -Message '$SourceVMsNotMigrating = $SourceVMs | Where-Object -FilterScript {$_.Id -notin $SourceVMsMigrating.Id}' $SourceVMsNotMigrating = $SourceVMs | Where-Object -FilterScript {$_.Id -notin $SourceVMsMigrating.Id} Write-Debug -Message ('$SourceVMsNotMigrating: ''{0}''' -f [string]$SourceVMsNotMigrating.Name) Write-Debug -Message ('$SourceVMsNotMigratingRunning = $SourceVMsNotMigrating | Select-VM -Running -Force:${0}' -f $Bulletproof) $SourceVMsNotMigratingRunning = $SourceVMsNotMigrating | Select-VM -Running -Force:$Bulletproof Write-Debug -Message ('$SourceVMsNotMigratingRunning: ''{0}''' -f [string]$SourceVMsNotMigratingRunning.Name) Write-Verbose -Message ('VMs left to migrate: {0}' -f [string]$SourceVMs.Name) Write-Debug -Message 'if ($SourceVMsNotMigratingRunning)' if ($SourceVMsNotMigratingRunning) { Write-Debug -Message '$SourceVMsToMigrate = $SourceVMsNotMigratingRunning' $SourceVMsToMigrate = $SourceVMsNotMigratingRunning # We TRY to migrate VMs which have just been running } else { Write-Debug -Message '$SourceVMsToMigrate = $SourceVMsNotMigrating' $SourceVMsToMigrate = $SourceVMsNotMigrating } Write-Debug -Message ('$SourceVMsToMigrate: ''{0}''' -f [string]$SourceVMsToMigrate.Name) foreach ($VMItem in $SourceVMsToMigrate) { # If a VM is migrating already - we don't care about it Write-Debug -Message ('$VMItem.Name: ''{0}''' -f $VMItem.Name) Write-Debug -Message ('$VMItem.Id: ''{0}''' -f $VMItem.Id) Write-Debug -Message ('$SourceVMHostVMs = Get-VM -ComputerName ''{0}''' -f $SourceHostName) $SourceVMHostVMs = Get-VM -ComputerName $SourceHostName Write-Debug -Message ('$SourceVMHostVMs: ''{0}''' -f [string]$SourceVMsNotMigratingRunning.Name) Write-Debug -Message ('$DestinationVMHostVMs = Get-VM -ComputerName ''{0}''' -f $DestinationHostName) $DestinationVMHostVMs = Get-VM -ComputerName $DestinationHostName Write-Debug -Message ('$DestinationVMHostVMs: ''{0}''' -f [string]$DestinationVMHostVMs.Name) Write-Debug -Message ('$SourceVMHostMigratingVMs = $SourceVMHostVMs | Select-VM -Migrating -Force:${0}' -f $Bulletproof) $SourceVMHostMigratingVMs = $SourceVMHostVMs | Select-VM -Migrating -Force:$Bulletproof Write-Debug -Message ('$SourceVMHostMigratingVMs: ''{0}''' -f [string]$SourceVMHostMigratingVMs.Name) Write-Debug -Message ('$DestinationVMHostMigratingVMs = $DestinationVMHostVMs | Select-VM -Migrating -Force:${0}' -f $Bulletproof) $DestinationVMHostMigratingVMs = $DestinationVMHostVMs | Select-VM -Migrating -Force:$Bulletproof Write-Debug -Message ('$DestinationVMHostMigratingVMs: ''{0}''' -f [string]$DestinationVMHostMigratingVMs.Name) Write-Debug -Message ('$VMHostMigratingVMs = {0} + {1}' -f $SourceVMHostMigratingVMs.Count, $DestinationVMHostMigratingVMs.Count) $VMHostMigratingVMsCount = $SourceVMHostMigratingVMs.Count + $DestinationVMHostMigratingVMs.Count Write-Debug -Message ('$VMHostMigratingVMsCount = {0}' -f $VMHostMigratingVMsCount) Write-Debug -Message '$CurrentLiveMigrationCount = $VMHostMigratingVMsCount' $CurrentLiveMigrationCount = $VMHostMigratingVMsCount Write-Debug -Message ('$CurrentLiveMigrationCount = {0}' -f $CurrentLiveMigrationCount) Write-Debug -Message ('$LiveMigrationMaximum = {0}' -f $LiveMigrationMaximum) Write-Debug -Message 'if ($CurrentLiveMigrationCount -lt $LiveMigrationMaximum)' if ($CurrentLiveMigrationCount -lt $LiveMigrationMaximum) { # If the migration queue is not full (if it is full, we do no care who filled it up) Write-Debug -Message '$VirtualMachineLiveMigrationEligibility = Test-VMLiveMigrationEligibility -VM $VMItem -DestinationHost $DestinationVMHost' $VirtualMachineLiveMigrationEligibility = Test-VMLiveMigrationEligibility -VM $VMItem -DestinationHost $DestinationVMHost Write-Debug -Message ('$VirtualMachineLiveMigrationEligibility.Result: ''{0}''' -f $VirtualMachineLiveMigrationEligibility.Result) Write-Debug -Message ('$VirtualMachineLiveMigrationEligibility.Reason: ''{0}''' -f $VirtualMachineLiveMigrationEligibility.Reason) Write-Debug -Message 'if ($VirtualMachineLiveMigrationEligibility.Result -or $VirtualMachineLiveMigrationEligibility.Reason -eq ''NotRunning'')' if ($VirtualMachineLiveMigrationEligibility.Result -or $VirtualMachineLiveMigrationEligibility.Reason -eq 'NotRunning') { Write-Debug -Message ('$VMMigrationRetryInfo: ''{0}''' -f [string]$VMMigrationRetryInfo) Write-Debug -Message ('$VMMigrationRetryInfoCount = ($VMMigrationRetryInfo | Where-Object -FilterScript {{$_ -eq ''{0}''}}).Count' -f $VMItem.Id) $VMMigrationRetryInfoCount = ($VMMigrationRetryInfo | Where-Object -FilterScript {$_ -eq $VMItem.Id}).Count Write-Debug -Message ('$VMMigrationRetryInfoCount = {0}' -f $VMMigrationRetryInfoCount) Write-Debug -Message ('$MaxAttempts = {0}' -f $MaxAttempts) Write-Debug -Message 'if ($VMMigrationRetryInfoCount -ge $MaxAttempts)' if ($VMMigrationRetryInfoCount -ge $MaxAttempts) { Write-Verbose -Message ('VM {0} is unmigratable' -f $VMItem.Id) Write-Debug -Message ('$CrashOnUnmigratable: ''{0}''' -f $CrashOnUnmigratable) Write-Debug -Message 'if ($CrashOnUnmigratable)' if ($CrashOnUnmigratable) { $Message = ('Tried to migrate VM {0} {1} times - did not succeed' -f $VMItem.Id, $VMMigrationRetryInfoCount) $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.ServiceModel.Channels.RetryException' -ArgumentList $Message), 'RetryException', [System.Management.Automation.ErrorCategory]::OperationTimeout, $VMItem))) } else { Write-Debug -Message ('$null = $UnmigratableVMs.Add(''{0}'')' -f $VMItem.Id) $null = $UnmigratableVMs.Add($VMItem.Id) } } } Write-Debug -Message ('$UnmigratableVMs: ''{0}''' -f [string]$UnmigratableVMs) Write-Debug -Message ('$VMItem.Id: ''{0}''' -f $VMItem.Id) Write-Debug -Message 'if ($VMItem.Id -notin $UnmigratableVMs)' if ($VMItem.Id -notin $UnmigratableVMs) { Write-Debug -Message 'if ($VirtualMachineLiveMigrationEligibility.Result)' if ($VirtualMachineLiveMigrationEligibility.Result) { Write-Debug -Message ('$VMItem.ComputerName: ''{0}''' -f $VMItem.ComputerName) Write-Debug -Message ('$DestinationHostName = ''{0}''' -f $DestinationHostName) Write-Debug -Message 'if ($VMItem.ComputerName -ne $DestinationHostName)' if ($VMItem.ComputerName -ne $DestinationHostName) { # Better safe than sorry Write-Debug -Message ('$null = $VMMigrationRetryInfo.Add(''{0}'')' -f $VMItem.Id) $null = $VMMigrationRetryInfo.Add($VMItem.Id) Write-Debug -Message ('$VMMigrationRetryInfo: ''{0}''' -f [string]$VMMigrationRetryInfo) Write-Debug -Message ('$VMMigrationRetryInfoCount = ($VMMigrationRetryInfo | Where-Object -FilterScript {{$_ -eq ''{0}''}}).Count' -f $VMItem.Id) $VMMigrationRetryInfoCount = ($VMMigrationRetryInfo | Where-Object -FilterScript {$_ -eq $VMItem.Id}).Count Write-Debug -Message ('$VMMigrationRetryInfoCount = {0}' -f $VMMigrationRetryInfoCount) Write-Debug -Message ('$JobName = ''HVMIG/{{0}}/{{1}}/{{2}}'' -f ''{0}'', ''{1}'', ''{2}''' -f $SessionID, $VMItem.Id, $VMMigrationRetryInfoCount) $JobName = 'HVMIG/{0}/{1}/{2}' -f $SessionID, $VMItem.Id, $VMMigrationRetryInfoCount Write-Debug -Message ('$JobName = ''{0}''' -f $JobName) $ScriptBlock = { Param ( $VM, $HostName, $Path, $PutInASubfolder, $Definition, $DebugPreference, $ErrorActionPreference ) Set-Item -Path 'Function:\Move-HVVM' -Value $Definition Move-HVVM -VM $VM -HostName $HostName -Path $Path -PutInASubfolder:$PutInASubfolder } Write-Debug -Message ('$ScriptBlock = ''{{{0}}}''' -f $ScriptBlock) Write-Debug -Message '$MoveFunction = Get-Item -Path ''Function:\Move-HVVM''' $MoveFunction = Get-Item -Path 'Function:\Move-HVVM' Write-Debug -Message ('$MoveFunction: ''{0}''' -f $MoveFunction) $MoveFunctionDefinition = $MoveFunction.Definition Write-Debug -Message ('$MoveFunctionDefinition: ''{0}''' -f $MoveFunctionDefinition) Write-Verbose -Message ('Trying to live-migrate a VM {0} from {1} to {2}' -f $VMItem.Id, $VMItem.ComputerName, $DestinationHostName) try { Write-Debug -Message ('$null = Start-ThreadJob -Name ''{0}'' -ScriptBlock $ScriptBlock -ArgumentList ($VMItem, ''{1}'', ''{2}'', ${3}, $MoveFunctionDefinition, ''{4}'', ''5'')' -f $JobName, $DestinationHostName, $Path, $PutInASubfolder, $DebugPreference, $ErrorActionPreference) $null = Start-ThreadJob -Name $JobName -ScriptBlock $ScriptBlock -ArgumentList ($VMItem, $DestinationHostName, $Path, $PutInASubfolder, $MoveFunctionDefinition, $DebugPreference, $ErrorActionPreference) } catch { Write-Debug -Message ($_) Write-Debug -Message ('Exception.HResult: {0}' -f $_.Exception.HResult) Write-Debug -Message 'Continue' Continue } Write-Debug -Message ('$MigrationJobGetMaxAttempts = {0}' -f $MigrationJobGetMaxAttempts) Write-Debug -Message 'for ($MigrationJobGetCounter = 0; $MigrationJobGetCounter -lt $MigrationJobGetMaxAttempts; $MigrationJobGetCounter++)' for ($MigrationJobGetCounter = 0; $MigrationJobGetCounter -lt $MigrationJobGetMaxAttempts; $MigrationJobGetCounter++) { Write-Debug -Message ('$MigrationJobGetCounter = {0}' -f $MigrationJobGetCounter) Write-Debug -Message '$VMMigratingStatus = Test-VMMigratingStatus -VM $VMItem -Force' $VMMigratingStatus = Test-VMMigratingStatus -VM $VMItem -Force Write-Debug -Message ('$VMMigratingStatus = ${0}' -f $VMMigratingStatus) Write-Debug -Message 'if (-not $VMMigratingStatus)' if (-not $VMMigratingStatus) { Write-Debug -Message ('Start-Sleep -Seconds {0}' -f $MigrationJobGetTimeout) Start-Sleep -Seconds $MigrationJobGetTimeout } else { Write-Debug -Message 'break' break } } Write-Debug -Message '$LastVMWasPoweredDown = $false' $LastVMWasPoweredDown = $false Write-Debug -Message ('$LastVMWasPoweredDown = ${0}' -f $LastVMWasPoweredDown) Write-Debug -Message ('$BackingUpVMs: ''{0}''' -f [string]$BackingUpVMs) Write-Debug -Message ('$VMItem.Id: ''{0}''' -f $VMItem.Id) Write-Debug -Message 'if ($BackingUpVMs.VM -contains $VMItem.Id)' if ($BackingUpVMs.VM -contains $VMItem.Id) { Write-Debug -Message ('$BackingUpVMDescription = $BackingUpVMs | Where-Object -FilterScript {{$_.VM -eq ''{0}''}}' -f $VMItem.Id) $BackingUpVMDescription = $BackingUpVMs | Where-Object -FilterScript {$_.VM -eq $VMItem.Id} Write-Debug -Message ('$BackingUpVMDescription: ''{0}''' -f [string]$BackingUpVMDescription) Write-Debug -Message '$null = $BackingUpVMs.Remove($BackingUpVMDescription)' $null = $BackingUpVMs.Remove($BackingUpVMDescription) Write-Debug -Message ('$BackingUpVMs.VM: ''{0}''' -f [string]$BackingUpVMs.VM) } } } else { Write-Verbose -Message ('Skipping VM {0} this time because: {1}' -f $VMItem.Id, $VirtualMachineLiveMigrationEligibility.Reason) switch ($VirtualMachineLiveMigrationEligibility.Reason) { 'BackingUp' { Write-Debug -Message ('$BackingUpVMs.VM: ''{0}''' -f [string]$BackingUpVMs.VM) Write-Debug -Message ('$VMItem.Id: ''{0}''' -f $VMItem.Id) Write-Debug -Message 'if ($BackingUpVMs.VM -contains $VMItem.Id)' if ($BackingUpVMs.VM -contains $VMItem.Id) { Write-Debug -Message ('$BackingUpVMDescription = $BackingUpVMs | Where-Object -FilterScript {{$_.VM -eq ''{0}''}}' -f $VMItem.Id) $BackingUpVMDescription = $BackingUpVMs | Where-Object -FilterScript {$_.VM -eq $VMItem.Id} Write-Debug -Message '$BackupAddDateTime = $BackingUpVMDescription.DateTime' $BackupAddDateTime = $BackingUpVMDescription.DateTime Write-Debug -Message ('$BackupAddDateTime: ''{0}''' -f [string]$BackupAddDateTime) Write-Debug -Message '$CurrentDateTime = Get-Date' $CurrentDateTime = Get-Date Write-Debug -Message ('$CurrentDateTime: ''{0}''' -f [string]$CurrentDateTime) Write-Debug -Message '$BackupDateTimeThreshold = $BackupAddDateTime + $BackupThreshold' $BackupDateTimeThreshold = $BackupAddDateTime + $BackupThreshold Write-Debug -Message ('$BackupDateTimeThreshold: ''{0}''' -f [string]$BackupDateTimeThreshold) Write-Debug -Message 'if ($CurrentDateTime -gt $BackupDateTimeThreshold)' if ($CurrentDateTime -gt $BackupDateTimeThreshold) { Write-Verbose -Message ('VM {0} is unmigratable' -f $VMItem.Id) if ($CrashOnUnmigratable) { $Message = ('VM {0} is in backing up state for more than {1} already' -f $VMItem.Id, [string]$BackupThreshold) $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.TimeoutException' -ArgumentList $Message), 'TimeoutException', [System.Management.Automation.ErrorCategory]::OperationTimeout, $VMItem))) } else { Write-Debug -Message ('$null = $UnmigratableVMs.Add(''{0}'')' -f $VMItem.Id) $null = $UnmigratableVMs.Add($VMItem.Id) Write-Debug -Message ('$UnmigratableVMs: ''{0}''' -f [string]$UnmigratableVMs) Write-Debug -Message '$null = $BackingUpVMs.Remove($BackingUpVMDescription)' $null = $BackingUpVMs.Remove($BackingUpVMDescription) Write-Debug -Message ('$BackingUpVMs.VM: ''{0}''' -f [string]$BackingUpVMs.VM) } } } else { Write-Debug -Message '$CurrentDateTime = Get-Date' $CurrentDateTime = Get-Date Write-Debug -Message ('$CurrentDateTime: ''{0}''' -f [string]$CurrentDateTime) Write-Debug -Message ('$null = $BackingUpVMs.Add(@{{VM = ''{0}''; DateTime = $CurrentDateTime}})' -f $VMItem.Id) $null = $BackingUpVMs.Add( @{ VM = $VMItem.Id DateTime = $CurrentDateTime } ) Write-Debug -Message ('$BackingUpVMs.VM: ''{0}''' -f [string]$BackingUpVMs.VM) } } 'NotRunning' { Write-Debug -Message ('$SourceVMs.Status: ''{0}''' -f [string]$SourceVMs.Status) Write-Debug -Message ('$SourceVMsRunning = $SourceVMs | Select-VM -Running -Force:${0}' -f $Bulletproof) $SourceVMsRunning = $SourceVMs | Select-VM -Running -Force:$Bulletproof Write-Debug -Message ('$SourceVMsRunning: ''{0}''' -f [string]$SourceVMsRunning.Name) Write-Debug -Message ('$SourceVMsMigrating = $SourceVMs | Select-VM -Migrating -Force:${0}' -f $Bulletproof) $SourceVMsMigrating = $SourceVMs | Select-VM -Migrating -Force:$Bulletproof Write-Debug -Message ('$SourceVMsMigrating: ''{0}''' -f [string]$SourceVMsMigrating.Name) Write-Debug -Message 'if (-not ($SourceVMsRunning -or $SourceVMsMigrating))' if (-not ($SourceVMsRunning -or $SourceVMsMigrating)) { # We do not want to move PoweredDown VMs while there's anything in the queue. We also want to migrate them as last as possible. Write-Debug -Message ('$null = $VMMigrationRetryInfo.Add(''{0}'')' -f $VMItem.Id) $null = $VMMigrationRetryInfo.Add($VMItem.Id) Write-Debug -Message ('$VMMigrationRetryInfo: ''{0}''' -f [string]$VMMigrationRetryInfo) Write-Verbose -Message ('Trying to migrate a powered-down VM {0} from {1} to {2}' -f $VMItem.Id, $VMItem.ComputerName, $DestinationHostName) Write-Debug -Message ('Move-HVVM -VM $VMItem -HostName ''{0}'' -Path ''{1}'' -PutInASubfolder:${2}' -f $DestinationHostName, $Path, $PutInASubfolder) Move-HVVM -VM $VMItem -HostName $DestinationHostName -Path $Path -PutInASubfolder:$PutInASubfolder Write-Debug -Message '$LastVMWasPoweredDown = $true' $LastVMWasPoweredDown = $true Write-Debug -Message ('$LastVMWasPoweredDown = ${0}' -f $LastVMWasPoweredDown) } } 'OK' { Write-Debug -Message ('$null = $UnmigratableVMs.Add(''{0}'')' -f $VMItem.Id) $null = $UnmigratableVMs.Add($VMItem.Id) Write-Debug -Message ('$UnmigratableVMs: ''{0}''' -f [string]$UnmigratableVMs) Write-Debug -Message ('$BackingUpVMs.VM: ''{0}''' -f [string]$BackingUpVMs.VM) Write-Debug -Message ('$VMItem.Id: ''{0}''' -f $VMItem.Id) Write-Debug -Message 'if ($BackingUpVMs.VM -contains $VMItem.Id)' if ($BackingUpVMs.VM -contains $VMItem.Id) { Write-Debug -Message ('$BackingUpVMDescription = $BackingUpVMs | Where-Object -FilterScript {{$_.VM -eq ''{0}''}}' -f $VMItem.Id) $BackingUpVMDescription = $BackingUpVMs | Where-Object -FilterScript {$_.VM -eq $VMItem.Id} Write-Debug -Message ('$BackingUpVMDescription: ''{0}''' -f [string]$BackingUpVMDescription) Write-Debug -Message '$null = $BackingUpVMs.Remove($BackingUpVMDescription)' $null = $BackingUpVMs.Remove($BackingUpVMDescription) Write-Debug -Message ('$BackingUpVMs.VM: ''{0}''' -f [string]$BackingUpVMs.VM) } Write-Verbose -Message ('VM {0} is unmigratable because of an unsupported status: {1}' -f $VMItem.Id, $VirtualMachineLiveMigrationEligibility.Status) } } } } } } Write-Debug -Message ('$LastVMWasPoweredDown = ${0}' -f $LastVMWasPoweredDown) Write-Debug -Message 'if (-not $LastVMWasPoweredDown)' # No need to wait if the last job was synchronous if (-not $LastVMWasPoweredDown) { Write-Debug -Message ('Start-Sleep -Seconds {0}' -f $Timeout) Start-Sleep -Seconds $Timeout } } Write-Debug -Message ('$SourceVMs: ''{0}''' -f [string]$SourceVMs.Name) Write-Debug -Message ('$SourceVMs.Id: ''{0}''' -f [string]$SourceVMs.Id) Write-Debug -Message 'while ($SourceVMs)' } while ($SourceVMs) Write-Debug -Message '$ReturnUnmigratableVMs = $false' $ReturnUnmigratableVMs = $false Write-Debug -Message ('$ReturnUnmigratableVMs = ${0}' -f $ReturnUnmigratableVMs) Write-Debug -Message ('$UnmigratableVMs: ''{0}''' -f [string]$UnmigratableVMs) Write-Debug -Message 'if ($UnmigratableVMs)' if ($UnmigratableVMs) { Write-Debug -Message ('$UnmigratableVMs.Count: {0}' -f $UnmigratableVMs.Count) Write-Debug -Message 'if ($UnmigratableVMs.Count -gt 0)' if ($UnmigratableVMs.Count -gt 0) { Write-Debug -Message ('$UnmigratableVMs: ''{0}''' -f [string]$UnmigratableVMs.Name) Write-Debug -Message '$ReturnUnmigratableVMs = $true' $ReturnUnmigratableVMs = $true Write-Debug -Message ('$ReturnUnmigratableVMs = ${0}' -f $ReturnUnmigratableVMs) } } Write-Debug -Message ('$ReturnUnmigratableVMs = ${0}' -f $ReturnUnmigratableVMs) Write-Debug -Message ('$UnmigratableVMs: ''{0}''' -f [string]$UnmigratableVMs.Name) Write-Debug -Message ('$ReturnSourceVMs = ${0}' -f $ReturnSourceVMs) Write-Debug -Message ('if ($ReturnSourceVMs)') if ($ReturnSourceVMs) { Write-Debug -Message ('$SourceVMsOriginal: ''{0}''' -f [string]$SourceVMsOriginal.Name) Write-Debug -Message 'if ($ReturnUnmigratableVMs)' if ($ReturnUnmigratableVMs) { Write-Debug -Message '@{SourceVMs = $SourceVMsOriginal, UnmigratableVMs = $UnmigratableVMs}' @{ SourceVMs = $SourceVMsOriginal UnmigratableVMs = $UnmigratableVMs } } else { Write-Debug -Message '@{SourceVMs = $SourceVMsOriginal}' @{ SourceVMs = $SourceVMsOriginal } } } else { Write-Debug -Message 'if ($ReturnUnmigratableVMs)' if ($ReturnUnmigratableVMs) { Write-Debug -Message '$UnmigratableVMs' $UnmigratableVMs } } } } else { $Message = 'Source ({0}) and destination ({1}) servers are the same' -f $SourceHostName, $DestinationHostName $PSCmdlet.ThrowTerminatingError((New-Object -TypeName 'System.Management.Automation.ErrorRecord' -ArgumentList ((New-Object -TypeName 'System.ArgumentException' -ArgumentList $Message), 'ArgumentException', [System.Management.Automation.ErrorCategory]::InvalidArgument, $null))) } Write-Debug -Message ('EXIT TRY {0}' -f $MyInvocation.MyCommand.Name) } catch { Write-Debug -Message ('ENTER CATCH {0}' -f $MyInvocation.MyCommand.Name) Write-Debug -Message ('{0}: $PSCmdlet.ThrowTerminatingError($_)' -f $MyInvocation.MyCommand.Name) $PSCmdlet.ThrowTerminatingError($_) Write-Debug -Message ('EXIT CATCH {0}' -f $MyInvocation.MyCommand.Name) } Write-Debug -Message ('EXIT {0}' -f $MyInvocation.MyCommand.Name) } |