HVTools.psm1
|
<#
.SYNOPSIS PowerShell module for managing Hyper-V virtual machines across multiple hosts. .DESCRIPTION Posh-HVTools provides a comprehensive set of functions for creating, managing, and monitoring Hyper-V virtual machines across multiple Hyper-V hosts. The module simplifies common Hyper-V administration tasks such as: - Creating new virtual machines - Retrieving detailed VM information - Managing VM state (start, stop, restart) - Configuring boot devices - Managing virtual disks - Cleaning up VMs and disks .NOTES File Name : HVTools.psm1 Prerequisite : PowerShell 5.1 or later Hyper-V PowerShell module installed Administrative rights on Hyper-V hosts Configuration : Requires HVparam.json file in the same directory .EXAMPLE # List all VMs matching a pattern across all Hyper-V hosts Get-HVMachineInfo -MachineName "Web*" .EXAMPLE # Create a new virtual machine New-HVMachine -MachineName "WebServer01" -HVServer "HyperVHost1" -MemoryStartup 8 -CPUCount 4 .LINK https://github.com/yourusername/Posh-HVTools #> Function New-HVMachine { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string]$MachineName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string]$HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [int64]$MemoryStartup = 4, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string[]]$Switchname = @(), [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [int]$CPUCount = 2, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$NotDynamicRam, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [int64]$MemoryMinimum = 1468006400, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [int64[]]$HardDiskSize = @(48), [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string]$HDPath, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch]$AutomaticCheckPoints, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [int[]]$Vlan = @(), [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string]$jsonFilePath ) begin {} process { if ($jsonFilePath) { if (Test-Path -Path $jsonFilePath) { Get-HVConfigFromJson -jsonFilePath $jsonFilePath } else { Write-Error "Configuration file $jsonFilePath not found" return } } else { $config = Get-Config if ($Switchname.Length -eq 0) { $Switchname += $config.config.Switchname } if (!($HDPath)) { $HDPath = $config.config.diskpaths.diskpath[0] } $HDSizeGB = ConvertTo-Bytes $HardDiskSize[0] $VlanId = $Vlan[0] $Switchname = $Switchname[0] $MemoryStartupBytes = ConvertTo-Bytes -RAM $MemoryStartup $ProgressValue = 20 Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue New-VM -Name $MachineName -Generation 2 -MemoryStartupBytes ([system.int64]$MemoryStartupBytes) -SwitchName $Switchname[0] -ComputerName $HVServer | Out-Null $ProgressValue = 40 Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue Set-VMProcessor -VMName $MachineName -Count $CPUCount -ComputerName $HVServer if ($NotDynamicRam) { Set-VM -VMName $MachineName -DynamicMemory -ComputerName $HVServer } $ProgressValue = 60 Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue set-vm -VMName $MachineName -MemoryMinimumBytes $MemoryMinimum -ComputerName $HVServer $VHD = Join-Path -Path $HDPath -ChildPath "$MachineName.vhdx" New-VHD -Path $VHD -SizeBytes $HDSizeGB -Dynamic -ComputerName $HVServer | Out-Null $ProgressValue = 80 Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue Add-VMHardDiskDrive -Path $VHD -VMName $MachineName -ComputerName $HVServer $ProgressValue = 95 Write-Progress -Activity "Creating" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue if (!($AutomaticCheckPoints)) { set-vm -VMName $MachineName -AutomaticCheckpointsEnabled:$false -ComputerName $HVServer } if ($VlanId) { get-vmnetworkAdapter -VMname $MachineName -ComputerName $HVServer | set-VMNetworkAdapterVlan -Access -VlanId $VlanId } Start-VM -VMName $MachineName -ComputerName $hvserver Start-Sleep -Seconds 2 stop-VM -VMName $MachineName -ComputerName $hvserver -Force Get-HVMachineInfo -MachineName $MachineName -HVServer $HVServer } } end {} } function Get-HVConfigFromJson { param( [Parameter(Mandatory = $true)] [string]$jsonFilePath ) $jsonData = Get-Content -Path $jsonFilePath -Raw | ConvertFrom-Json if ($jsonData -is [Array]) { $machines = $jsonData } else { $machines = @($jsonData) } foreach ($machine in $machines) { try { $params = @{ MachineName = $machine.MachineName HVServer = $machine.HVServer MemoryStartup = $machine.MemoryStartup CPUCount = $machine.CPUCount Switchname = $machine.SwitchName Vlan = $machine.Vlan HardDiskSize = $machine.HardDiskSize[0] } New-HVMachine @params } catch { Write-Error "Failed to create VM $($machine.MachineName): $_" } } } function ConvertTo-Bytes { param( [Parameter(Mandatory=$true)] $RAM ) if ($RAM -is [string] -and $RAM -match '^(\d+)(GB|MB|KB)?$') { $value = [int64]$matches[1] $unit = $matches[2] switch ($unit) { 'GB' { return $value * 1GB } 'MB' { return $value * 1MB } 'KB' { return $value * 1KB } default { return $value * 1GB } # Default to GB if no unit } } elseif ($RAM -is [int64] -or $RAM -is [int]) { # Numeric input: small = GB, large = bytes if ($RAM -lt 1024) { return $RAM * 1GB } else { return $RAM } } } function Get-HVMachineInfo { Param( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $MachineName = '', [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $ExportAsJsonFilePath ) begin{} process { if (!($HVServers)) { $config = Get-Config $HVServers = $config.config.servers.server } [int]$HVServerCount = $HVServers.count [int]$HVServerProgressCount = 0 $MachineInfo = New-Object 'System.Collections.Generic.List[HVMachineInformation]' foreach ($HVServer in $HVServers) { $AllHV = get-vm -ComputerName $HVServer | Where-Object {$_.VMName -match $MachineName} [int]$HVCount = $AllHV.count if ($HVCount -ne 0) { [int]$Progresscount = 1 foreach ($HVName in ($AllHV).Name) { $ProgressValue = [math]::round($Progresscount * 100 / $HVCount / $HVServerCount + $HVServerProgressCount * 100 / $HVServerCount,1) Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue $Progresscount++ $NIC = get-vmnetworkAdapter -VMname $HVName -ComputerName $HVServer $HVMachineInfo = get-vm -Name $HVName -ComputerName $HVServer | Select-Object Name, State, CPUUsage, ProcessorCount, MemoryStartup ,MemoryAssigned, Uptime, Status, Version, Generation $HVHostInfo = get-vmhost -ComputerName $HVServer | Select-Object ComputerName, LogicalProcessorCount, MemoryCapacity $Gen = $HVMachineInfo.Generation switch ($Gen) { "1" { $BootOrder = (Get-VMBios -VMName $HVName -ComputerName $HVServer).StartupOrder } "2" { $BootOrder = (get-vmfirmware -VMName $HVName -ComputerName $HVServer).bootorder.BootType } } $HardDisk = (get-vmhardDiskDrive -VMName $HVName -ComputerName $HVServer).Path [bool]$HasCheckPoint = $false [int64[]]$HardDiskSize = @() foreach ($EachHardDisk in $HardDisk) { $VHD = Get-VHD -Path $EachHardDisk -ComputerName $HVServer if ($VHD.ParentPath) { $HasCheckPoint = $true } $HardDiskSize += $VHD.Size } $Machine = [HVMachineInformation]::new( $HVMachineInfo.Name, $HVMachineInfo.State, $HVMachineInfo.CPUUsage, $HVMachineInfo.ProcessorCount, $HVMachineInfo.MemoryStartup, $HVMachineInfo.MemoryAssigned, $NIC.SwitchName, $NIC.VlanSetting.AccessVlanId, $NIC.IPaddresses, (Get-MACFormatted -Mac $NIC.macaddress), $HardDisk, $HardDiskSize, $HasCheckPoint, $BootOrder, $HVMachineInfo.Uptime, $HVMachineInfo.Status, $HVMachineInfo.Version, $Gen, $HVHostInfo.ComputerName, $HVHostInfo.LogicalProcessorCount, $HVHostInfo.MemoryCapacity ) $MachineInfo.Add($Machine) } $HVServerProgressCount++ } } if ($ExportAsJsonFilePath) { $MachineInfo | ConvertTo-Json -Depth 10 | Out-File -FilePath $ExportAsJsonFilePath -Encoding utf8 Write-Host "Machine information exported to: $ExportAsJsonFilePath" -ForegroundColor Green } return $MachineInfo } end {} } function Get-HVMachineNetworkInfo { Param( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $MachineName = '', [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) begin{} process { if (!($HVServers)) { $config = Get-Config $HVServers = $config.config.servers.server } [int]$HVServerCount = $HVServers.count [int]$HVServerProgressCount = 0 $NetworkInfo = New-Object 'System.Collections.Generic.List[HVNetworkInfo]' foreach ($HVServer in $HVServers) { $AllHV = get-vm -ComputerName $HVServer | Where-Object {$_.VMName -match $MachineName} [int]$HVCount = $AllHV.count if ($HVCount -ne 0) { [int]$Progresscount = 1 foreach ($HVName in ($AllHV).Name) { $ProgressValue = [math]::round($Progresscount * 100 / $HVCount / $HVServerCount + $HVServerProgressCount * 100 / $HVServerCount,1) Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue $Progresscount++ $AllNics = get-vmnetworkAdapter -VMname $HVName -ComputerName $HVServer foreach ($Nic in $AllNics) { $Network = [HVNetworkInfo]::new( $HVName, $NIC.SwitchName, $NIC.IPaddresses, (Get-MACFormatted -Mac $NIC.macaddress), $NIC.VlanSetting.OperationMode, $NIC.VlanSetting.AccessVlanId ) $NetworkInfo.Add($Network) } $ProgressValue += $ProgressPerHV } } $HVServerProgressCount++ } return $NetworkInfo } end {} } function Set-HVMachineBootDevice { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'NIC')] [switch] $nic, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'DVD')] [switch] $dvd, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'File')] [switch] $File, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Floppy')] [switch] $Floppy, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true, ParameterSetName = 'Drive')] [switch] $Drive ) begin{} process{ $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers foreach ($HVServer in $HVServers) { foreach ($Machine in (get-vm -ComputerName $HVServer | Where-Object {$_.Name -eq $MachineName})) { $FoundMachineName = $Machine.VMName switch ($machine.generation) { "1" { $StartupOrder = '' if ($nic) { $StartupOrder = @("LegacyNetworkAdapter", "Floppy", "CD", "IDE") } if ($dvd) { $StartupOrder = @("CD", "LegacyNetworkAdapter", "Floppy", "IDE") } if ($File) { $StartupOrder = @("IDE","LegacyNetworkAdapter", "Floppy", "CD") } if ($Floppy) { $StartupOrder = @("Floppy", "LegacyNetworkAdapter", "CD", "IDE") } Set-VMBios -VMName $FoundMachineName -ComputerName $HVServer -StartupOrder $StartupOrder Get-VMBios -VMName $FoundMachineName -ComputerName $HVServer } "2"{ if ($nic) { $BootDevice = Get-VMNetworkAdapter -VMName $FoundMachineName -ComputerName $HVServer } if ($dvd) { $BootDevice = Get-VMDvdDrive -VMName $FoundMachineName -ComputerName $HVServer } if ($File) { $BootDevice = (get-vmfirmware -VMName $FoundMachineName -ComputerName $HVServer).BootOrder | Where-Object {$_.BootType -eq 'File'} } if ($Drive) { $BootDevice = (get-vmfirmware -VMName $FoundMachineName -ComputerName $HVServer).BootOrder | Where-Object {$_.BootType -eq 'Drive'} } Set-VMFirmware -VMName $FoundMachineName -FirstBootDevice ($BootDevice) -ComputerName $HVServer get-vmfirmware -VMName $FoundMachineName -ComputerName $HVServer | Select-Object -ExpandProperty BootOrder } } } } } end {} } function Remove-HVMachine { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) begin{} process { $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers [int]$ProgressValue = 0 Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue foreach ($HVServer in $HVServers) { [int]$ProgressValue = 25 Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue Stop-VM -Name $MachineName -ComputerName $HVServer -ErrorAction Ignore -WarningAction SilentlyContinue -Force | Out-Null $Disks = Get-VMHardDiskDrive -VMName $MachineName -ComputerName $HVServer $DisksToRemove = @() [int]$ProgressValue = 50 Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue foreach ($disk in $disks.path) { $DisksToRemove += $disk $vhd = (Get-VHD -Path $disk -ComputerName $HVServer).ParentPath if ($vhd) { $DisksToRemove += $vhd do { $vhd = (Get-VHD -Path $vhd -ComputerName $HVServer).ParentPath if ($vhd) { $DisksToRemove += $vhd } } while ($vhd) } } [int]$ProgressValue = 60 Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue foreach ($disk in $DisksToRemove) { $DiskSplit = $disk.split(':') $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])" Remove-Item -Path $UNCPath -Force } [int]$ProgressValue = 80 Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue remove-vm -Name $MachineName -ComputerName $HVServer -Force } } end {} } function Get-HVUnassignedDiskDrive { Param( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $DiskDrivePath, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) begin{} process { $config = Get-Config if (!($HVServers)) { $HVServers = $config.config.servers.server } if (!($DiskDrivePath)) { $DiskDrivePaths = $config.config.diskpaths.diskpath } [int]$ProgressValue = 0 [int]$ProgressPerHVServer = 100 / $HVServers.Count $DiskInfo = New-Object 'System.Collections.Generic.List[HVDiskInfo]' foreach ($HVServer in $HVServers) { [int]$DiskDriveCount = 0 foreach ($DiskDrivePath in $DiskDrivePaths) { $DiskSplit = $DiskDrivePath.split(':') $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])" if (Test-Path -Path $UNCPath) { $DiskDriveCount += 1 } } if ($DiskDriveCount -gt 0) { foreach ($DiskDrivePath in $DiskDrivePaths) { $DiskSplit = $DiskDrivePath.split(':') $UNCPath = "\\$HVServer\$($DiskSplit[0])`$$($DiskSplit[1])" if (Test-Path -Path $UNCPath) { $HardDrives = (get-childitem -Path $UNCPath).FullName $AllHV = get-vm -ComputerName $HVServer [int]$AllDiskCount = $HardDrives.count if ($AllDiskCount -ne 0) { [int]$ProgressPerDisk = $ProgressPerHVServer / $AllDiskCount / $DiskDriveCount } else { [int]$ProgressPerDisk = $ProgressPerHVServer / $DiskDriveCount $ProgressValue += $ProgressPerDisk Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue # redundant but needed when vhd = 0 LA 250822 } foreach ($HardDrive in $HardDrives) { <# "AllDiskCount: $AllDiskCount" "diskDiskDriveCount: $DiskDriveCount" "ProgressPerHVServer: $ProgressPerHVServer" "progressperdisk: $ProgressPerDisk" "progressvalue: $ProgressValue" #> Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue $UNCDiskSplit = $HardDrive.split('$') $LocalDiskPath = "$($UNCDiskSplit[0][-1]):$($UNCDiskSplit[1])" $Outcome = "Not Assigned" [bool]$Match = $false foreach ($vm in $AllHV) { foreach ($VMDisk in (Get-VMHardDiskDrive -VMName $vm.name -ComputerName $HVServer).Path) { if ($VMDisk -eq $LocalDiskPath -and !($Match)) { $Outcome = $vm.Name $Match = $true } } } $ProgressValue += $ProgressPerDisk $Disk = [HVDiskInfo]::new( $HVServer, $LocalDiskPath, $Outcome ) $DiskInfo.add($Disk) } } } } } Return $DiskInfo } end {} } function Get-Config { $jsonFilePath = Join-Path -Path $PSScriptRoot -ChildPath "HVparam.json" Return (Get-Content -Path $jsonFilePath | ConvertFrom-Json) } function Get-HVServers { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) if ($HVServer) { $HVServers = $HVServer } if (!($HVServers)) { $HVServers = Find-HVServer -MachineName $MachineName -ExactMatch } return $HVServers } Function Find-HVServer { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [switch] $ExactMatch ) $config = Get-Config $HVServers = $config.config.servers.server $ReturnHVServers = @() [int]$ProgressCount = 0 [bool]$FoundMachine = $false foreach ($HVServer in $HVServers) { $progressvalue = $ProgressCount * 100 / $HVServers.count Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue $ProgressCount++ if ($ExactMatch) { $FoundMachine = get-vm -ComputerName $HVServer | Where-Object {$_.Name -eq $MachineName} } else { $FoundMachine = get-vm -ComputerName $HVServer | Where-Object {$_.Name -match $MachineName} } if ($FoundMachine) { $ReturnHVServers += $HVServer } } return $ReturnHVServers } Function Get-MACFormatted { Param( [Parameter(Mandatory = $true)] [array] $Mac ) return $Mac -replace '(.{2})(?!$)', '$1:' } Function Set-HVMachineState { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [ValidateSet ("Stop", "Restart", "Start")] [string] $Action ) begin{} process { switch ($Action) { "Stop" { Stop-VM -ComputerName $HVServer -Name $MachineName -Force } "Restart" { Restart-VM -ComputerName $HVServer -Name $MachineName -Force } "Start" { Start-VM -ComputerName $HVServer -Name $MachineName } } } end {} } function Stop-HVMachine { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) begin{} process { $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers foreach ($HVServer in $HVServers) { Set-HVMachineState -MachineName $MachineName -HVServer $HVServer -Action Stop } } end {} } function Restart-HVMachine { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true, ValueFromPipeline = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) begin{} process { $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers foreach ($HVServer in $HVServers) { Set-HVMachineState -MachineName $MachineName -HVServer $HVServer -Action Restart } } end {} } function Start-HVMachine { Param( [Parameter(Mandatory = $true, ValueFromPipelineByPropertyName = $true)] [string] $MachineName, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer, [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [array] $HVServers ) begin {} process { $HVServers = Get-HVServers -MachineName $MachineName -HVServer $HVServer -HVServers $HVServers foreach ($HVServer in $HVServers) { Set-HVMachineState -MachineName $MachineName -HVServer $HVServer -Action Start } } end {} } function Get-HVServerInfo { Param( [Parameter(Mandatory = $false, ValueFromPipelineByPropertyName = $true)] [string] $HVServer ) begin{} process { if (!($HVServer)) { $config = Get-Config $HVServers = $config.config.servers.server } else { $HVServers = $HVServer } $HVServerInfo = New-Object 'System.Collections.Generic.List[HVServerInformation]' [int]$progresscount = 0 foreach ($HVServer in $HVServers) { $progressvalue = [math]::round($progresscount * 100 / $HVServers.count,1) Write-Progress -Activity "Processing" -Status "$ProgressValue% complete" -PercentComplete $ProgressValue $progresscount ++ $SrvInfo1 = get-vmhost -ComputerName $HVServer $SrvInfo2 = Get-CimInstance -ClassName Win32_OperatingSystem -ComputerName $HVServer | Select-Object PSComputerName, LastBootUpTime, @{Name='Uptime'; Expression={(Get-Date) - $_.LastBootUpTime}}, FreePhysicalMemory $SrvInfo3 = Get-CimInstance -ClassName Win32_LogicalDisk -ComputerName $HVServer -Filter "DriveType=3" | Select-Object DeviceID, @{Name='Size'; Expression={[math]::Round($_.Size/1GB, 2)}}, @{Name='FreeSpace'; Expression={[math]::Round($_.FreeSpace/1GB, 2)}} $Machine = [HVServerInformation]::new( $SrvInfo1.ComputerName, $SrvInfo3.DeviceID, $SrvInfo3.Size, $SrvInfo3.FreeSpace, $SrvInfo1.LogicalProcessorCount, $SrvInfo1.MemoryCapacity, $SrvInfo2.FreePhysicalMemory * 1KB, $SrvInfo2.LastBootUpTime, $SrvInfo2.Uptime ) $HVServerInfo.Add($Machine) } return $HVServerInfo } end {} } # Class Definitions <# .SYNOPSIS Class for storing detailed Hyper-V virtual machine information. .DESCRIPTION Represents comprehensive information about a Hyper-V virtual machine, including its configuration, state, network settings, and host information. .NOTES Used by Get-HVMachineInfo to return structured information about virtual machines. #> Class HVMachineInformation { [string]$MachineName [string]$State [int]$CPUUsage [int]$CPUCount [int64]$MemoryStartup [int64]$MemoryAssigned [array]$SwitchName [array]$Vlan [array]$IPaddresses [array]$MACAddress [array]$HardDisk [array]$HardDiskSize [bool]$Checkpoint [array]$BootInfo [timespan]$Uptime [string]$Status [string]$Version [string]$Generation [string]$HVServer [int]$LogicalProcessorCount [int64]$MemoryCapacity HVMachineInformation ( [string]$MachineName, [string]$State, [int]$CPUUsage, [int]$CPUCount, [int64]$MemoryStartup, [int64]$MemoryAssigned, [array]$SwitchName, [array]$VLan, [array]$IPaddresses, [array]$MACAddress, [array]$HardDisk, [array]$HardDiskSize, [bool]$Checkpoint, [array]$BootInfo, [timespan]$Uptime, [string]$Status, [string]$Version, [string]$Generation, [string]$HVServer, [int]$LogicalProcessorCount, [int64]$MemoryCapacity ) { $this.MachineName = $MachineName $this.State = $State $this.CPUUsage = $CPUUsage $this.CPUCount = $CPUCount $this.MemoryStartup = $MemoryStartup $this.MemoryAssigned = $MemoryAssigned $this.SwitchName = $SwitchName $this.Vlan = $VLan $this.IPaddresses = $IPaddresses $this.MacAddress = $MACAddress $this.HardDisk = $HardDisk $this.HardDiskSize = $HardDiskSize $this.Checkpoint = $Checkpoint $this.BootInfo = $BootInfo $this.Uptime = $Uptime $this.Status = $Status $this.Version = $Version $this.Generation = $Generation $this.HVServer = $HVServer $this.LogicalProcessorCount = $LogicalProcessorCount $this.MemoryCapacity = $MemoryCapacity } } Class HVServerInformation { [string]$HVServer [array]$HardDisk [array]$HardDiskSize [array]$HardDiskFree [int]$LogicalProcessorCount [int64]$MemoryCapacity [int64]$FreePhysicalMemory [datetime]$LastBootUpTime [timespan]$Uptime HVServerInformation ( [string]$HVServer, [array]$HardDisk, [array]$HardDiskSize, [array]$HardDiskFree, [int]$LogicalProcessorCount, [int64]$MemoryCapacity, [int64]$FreePhysicalMemory, [datetime]$LastBootUpTime, [timespan]$Uptime ) { $this.HVServer = $HVServer $this.HardDisk = $HardDisk $this.HardDiskSize = $HardDiskSize $this.HardDiskFree = $HardDiskFree $this.LogicalProcessorCount = $LogicalProcessorCount $this.MemoryCapacity = $MemoryCapacity $this.FreePhysicalMemory = $FreePhysicalMemory $this.LastBootUpTime = $LastBootUpTime $this.Uptime = $Uptime } } <# .SYNOPSIS Class for storing Hyper-V disk information. .DESCRIPTION Represents information about a virtual hard disk file, including its location and associated virtual machine (if any). .NOTES Used by Get-HVUnassignedDiskDrive to return structured information about virtual disks. #> Class HVDiskInfo { [string]$HVServer [string]$Diskname [string]$MachineName HVDiskInfo ( [string]$HVServer, [string]$Diskname, [string]$MachineName ) { $this.HVServer = $HVServer $this.Diskname = $Diskname $this.MachineName = $MachineName } } <# .SYNOPSIS Class for storing Hyper-V network adapter information. .DESCRIPTION Represents detailed network configuration information for a virtual machine network adapter, including IP, MAC, and VLAN settings. .NOTES Used by Get-HVMachineNetworkInfo to return structured information about network adapters. #> Class HVNetworkInfo { [string]$MachineName [string]$SwitchName [array]$IPaddresses [string]$MacAddress [string]$OperationMode [int]$Vlan HVNetworkInfo ( [string]$MachineName, [string]$SwitchName, [array]$IPaddresses, [string]$MacAddress, [string]$OperationMode, [int]$Vlan ) { $this.MachineName = $MachineName $this.SwitchName = $SwitchName $this.IPaddresses = $IPaddresses $this.MacAddress = $MacAddress $this.OperationMode = $OperationMode $this.Vlan = $Vlan } } |