I am trying to robocopy a set of VHDs, while skipping over those that are in use.
To that end, I am trying to create a list of all VHDs which are not in use. If the VHD is not in use, I will be able to run Get-VHD
and check that the .Attached
property is false. If the VHD is in use, I get the following error:
Get-VHD Getting the mounted storage instance for the path <VHD-Path> failed.
The operation cannot be performed while the object is in use.
CategoryInfo: ResourceBusy: (:) [Get-VHD], VirtualizationException
FullyQualifiedErrorID: ObjectInUse,Microsoft.Vhd.PowerShell.Cmdlets.GetVHD
My plan is to use a try-catch to identify which VHDs are in use, create a list of their file names, then pass it to the robocopy /xf
option. To that end, the following code should output the names of all in-use VHDs to console:
$VHDLocation = "\\server\share"
$VHDs = Get-Children -Path $VHDLocation -Include "*.vhd" -Recurse
$VHDs | ForEach-Object {
try { Get-VHD ($VHDLocation + "\" + $_)).Attached }
catch { Write-Output $_ }}
However, when I run it, Powershell outputs "False" for VHDs that are not in use, and the "object in use" error for VHDs that are in use. It seems like the try-catch is being ignored in favour of just running the Get-VHD
command.
Is there something wrong with the above code, or am I off the mark with how to accomplish this task altogether?
Untested, but I think your code is missing -ErrorAction Stop
in the try block. Without that, Get-VHD
calls that succeed will output the value of the Attached
property, which is either $true
or $false
.
Also, once inside a catch block, the $_
automatic variable no longer represents the item from the ForEach-Object loop, but rather the exception being thrown.
Try:
$VHDLocation = "\\server\share"
$VHDs = Get-Children -Path $VHDLocation -Include "*.vhd" -Recurse
# try and get an array of unattached VHD full file names
$unAttached = foreach($vhd in $VHDs) {
try {
# ErrorAction Stop ensures exceptions are being handled in the catch block
$disk = $vhd | Get-VHD -ErrorAction Stop
# if you get here, the Get-VHD succeeded, output if Attached is False
if (!($disk.Attached)) { $vhd.FullName }
}
catch {
# exception is thrown, so VHD must be in use; output this VHD object
# inside a catch block, the '$_' automatic variable represents the exception
$vhd.FullName
}
}
Hope that helps