Saturday 11 November 2017

Hyper-V Auditing With PowerShell

Wanted to share some handy PowerShell constructions for extracting information from Hyper-V servers - particularly useful if you have multiple hosts and are trying to work out how all the VMs are configured across them all and different storage devices

Bring up an administrative PowerShell prompt (note run on Windows 10 or Server 2016, some of this doesn't work on 2012 R2), and first set up some credentials and a list of the hosts you want to query:


$cred = Get-Credential domain\adminaccount
$hosts = ('host001','host002','host003','host004')


Then grab the relevant command from below:


# get all vmswitches
$hosts | % { invoke-command -computername $_ -credential $cred -ScriptBlock {get-vmswitch}}

#show location of all hard disks
$hosts | % { invoke-command -computername $_ -credential $cred -scriptblock {(Get-VM).HardDrives }} | select VMName, ComputerName, Path | ft -autosize

# show location of all other (non-vhd) files
$hosts | % { invoke-command -computername $_ -credential $cred -scriptblock {Get-VM}} | select VMName, ComputerName, Path, CheckpointFileLocation, ConfigurationLocation, SmartPagingFilePath, SnapshotFileLocation | ft -autosize

# show all network adpaters
$hosts | % { invoke-command -computername $_ -credential $cred -scriptblock {( Get-VM).NetworkAdapters }} | select VMName, ComputerName, SwitchName, Status, IPAddresses | ft -autosize

# show all VM cpu and RAM
$hosts | % { invoke-command -computername $_ -credential $cred -scriptblock {(Get-VM) }} | ft VMName, ComputerName, @{Expression={$_.ProcessorCount};Label="Cores"}, @{Expression={[math]::Round($_.MemoryStartup/1024/1024/1024)};Label="RAM"}, @{Expression={$_.DynamicMemoryEnabled};Label="DynamicRAM"}

# show all dynamic disks
$hosts | % { invoke-command -computername $_ -credential $cred -scriptblock {(Get-VM).HardDrives } | % {get-vhd -Path $_.path}} | ft Path, VhdType, @{Expression={[math]::Round($_.FileSize/1024/1024/1024,2)};Label="FileSize (GB)"}, @{Expression={$_.Size/1024/1024/1024};Label="Size (GB)"}

If you have a lot of host servers that you are querying then this will all take some time - you can speed this up by using a workflow to query each host in parallel rather than seqeuntially:


# using a workflow to query each host in parallel
workflow getVHDLocations {
  param([string[]]$computers)
  ForEach -parallel ($vmhost in $computers) {
    InlineScript {invoke-command -computername $using:vmhost -scriptblock {(Get-VM).HardDrives } }
  }
}

getVHDLocations $hosts | select VMName, ComputerName, Path | ft -autosize