Get-VHD works localy but not remotely

Sorry, I was doing all my testing locally on a single Hyper-V host. I forgot that you’re doing it remotely to Hyper-V hosts. I edited my original shared code to include the -ComputerName parameter for Get-VHD, and I rewrote it with comments, and an outer loop for going through multiple Hyper-V hosts

# create an array of all the Hyper-V hosts
$Servers = @(
    "SalamCOGRETOUR",
    "Server2",
    "Server3"
)

# create an array of the properties, and calculated properties, to pull from a VM
$Properties = @(
    "ComputerName",
    "Name",
    "ProcessorCount",
    "VMID",
    @{Name='MemoryStartup';Expression={[math]::Round($_.MemoryStartup/1GB,0).tostring() + ' GB'}},
    @{Name='MemoryAssigned';Expression={[math]::Round($_.MemoryAssigned/1GB,0).tostring() + ' GB'}},
    @{Name='Uptime';Expression={(Get-Date) - $_.Uptime}},
    "State",
    "Version" 
)

# first loop through all of the Hyper-V hosts. Any output from within will be captured by $VMDetails
$VMDetails = foreach ($Server in $Servers) {
    # Get all of the VMs for the host and retrieve the properties from Get-VM we want
    $VMResources = Get-VM -ComputerName $Server | Select-Object -Property $Properties

    # now loop through each VM for this Hyper-V host, get the VHDs for it and for each VHD
    # return a PSCustomObject with all the properties in total we want
    Foreach ($VM in $VMResources) {
        Get-VHD -ComputerName $Server -VMid $VM.VMid | Foreach-Object {
            # for each VHD return a custom object containing all our properties
            [PSCustomObject]@{
                ComputerName = $VM.ComputerName
                Name = $VM.Name
                ProcessorCount = $VM.ProcessorCount
                VMID = $VM.VMId
                MemoryStartup = $VM.MemoryStartup
                MemoryAssigned = $VM.MemoryAssigned
                Uptime = $VM.Uptime
                State = $VM.State
                Version = $VM.Version
                Path = $_.Path
                'Size(GB)' = $_.FileSize/1GB -as [int]
                VHDType = $_.VhdType
            }
        }
    }

}

# we're done looping, let's export our array of objects to a CSV
$VMDetails | Export-Csv -Path "outputMerge.csv" -NoTypeInformation
1 Like

This is what I did and it works fine, thanks for the link. However, there is something making a little bit confused on the 1st line

$Properties = @(
    "ComputerName",
    "Name",
    "ProcessorCount",
    "VMID",
    @{Name='MemoryStartup';Expression={[math]::Round($_.MemoryStartup/1GB,0).tostring() + ' GB'}},
    @{Name='MemoryAssigned';Expression={[math]::Round($_.MemoryAssigned/1GB,0).tostring() + ' GB'}},
    @{Name='Uptime';Expression={(Get-Date) - $_.Uptime}},
    "State",
    "Version" 
)

If I am not mistaken, you declare an array, in this array yo make reference to variables that does not exist like $.MemoryStartup and $.MemoryAssigned which you populate later inside the loop. How this can work without erroring? Thanks for your help

OK got it, I went through the url, it talks a lot about commandlets but no mention for array object. Also, all examples on this url start by something piped to something else.

:man_shrugging:

Calculated properties create additional properties. You give it a name and you give it an expression. In this expression you can use existing properties and transform them or even do additional queries or other things.

The array created beforehand is just to make it easier readable. It is then used in the pipeline later on.

OK, got it and so many thanks again

I didn’t find proposal that you can used invoke-command
Invoke-Command -ComputerName XXX {get-vm * |Select-Object vmid |Get-VHD}
I already saw, that guys explain how Pipe works :slight_smile: and whuy get-vhd didn’t work for you :slight_smile: