Public/Get-PVEVMGuest.ps1
|
function Get-PVEVMGuest { <# .SYNOPSIS Gets what the QEMU guest agent reports from inside VMs: OS, host name and IP addresses. .DESCRIPTION For each VM, writes one PVEPS.VMGuest object. State is: - Running: the agent answered (POST .../agent/ping), and the other properties come from it. - AgentNotRunning: the VM runs but the agent did not answer (not installed, not started, or the agent option is off in the VM's configuration). - VMNotRunning: the VM is not running. The details come from the agent's get-osinfo, get-host-name, network-get-interfaces and info calls. An older agent that lacks one of them leaves those properties empty. IPAddress lists every address except loopback ones; Interfaces has the per-interface detail. .PARAMETER VMId VM ID(s). Binds from piped PVEPS.VM objects. .PARAMETER VMName VM name(s). Wildcards allowed. .PARAMETER Server Connection(s) to use. Defaults to the default connection; binds from piped objects. .EXAMPLE Get-PVEVM web01 | Get-PVEVMGuest .EXAMPLE Get-PVEVMGuest -VMName '*' | Where-Object State -EQ 'Running' | Select-Object VMName, HostName, OSName, IPAddress #> [CmdletBinding(DefaultParameterSetName = 'Id')] [OutputType('PVEPS.VMGuest')] param( [Parameter(Mandatory, ParameterSetName = 'Id', ValueFromPipelineByPropertyName)] [ValidateRange(100, 999999999)] [int[]]$VMId, [Parameter(Mandatory, ParameterSetName = 'Name', Position = 0)] [SupportsWildcards()] [ValidateNotNullOrEmpty()] [string[]]$VMName, [Parameter(ValueFromPipelineByPropertyName)] [Alias('Connection')] [object[]]$Server ) begin { $targets = [System.Collections.Generic.List[psobject]]::new() } process { Add-PVEGuestTarget -Cmdlet $PSCmdlet -Target $targets -Server $Server -VMId $VMId -Name $VMName } end { foreach ($guest in @(Resolve-PVEGuestTarget -Cmdlet $PSCmdlet -Type qemu -Target $targets)) { $info = [ordered]@{ PSTypeName = 'PVEPS.VMGuest' VMId = $guest.VMId VMName = $guest.Name Node = $guest.Node State = 'VMNotRunning' HostName = $null OSName = $null OSVersion = $null KernelRelease = $null IPAddress = [string[]]@() Interfaces = @() AgentVersion = $null Connection = $guest.Connection } try { $null = Update-PVEGuestStatus -Guest $guest } catch { $PSCmdlet.WriteError($_) continue } if ($guest.Status -eq 'running') { try { $null = Invoke-PVEAgentRequest -Guest $guest -Command ping -Method POST $info.State = 'Running' } catch { Write-Verbose "$(Get-PVEGuestLabel -Guest $guest): the guest agent did not answer: $($_.Exception.Message)" $info.State = 'AgentNotRunning' } } if ($info.State -eq 'Running') { $calls = @{} foreach ($command in 'get-osinfo', 'get-host-name', 'network-get-interfaces', 'info') { try { $calls[$command] = Invoke-PVEAgentRequest -Guest $guest -Command $command } catch { Write-Verbose "$(Get-PVEGuestLabel -Guest $guest): agent call $command failed: $($_.Exception.Message)" } } $os = $calls['get-osinfo'] $info.OSName = Get-PVEValue $os 'pretty-name' if (-not $info.OSName) { $info.OSName = Get-PVEValue $os 'name' } $info.OSVersion = Get-PVEValue $os 'version' $info.KernelRelease = Get-PVEValue $os 'kernel-release' $info.HostName = Get-PVEValue $calls['get-host-name'] 'host-name' $info.AgentVersion = Get-PVEValue $calls['info'] 'version' $interfaces = @( foreach ($interface in @($calls['network-get-interfaces'] | Where-Object { $_ })) { $addresses = Get-PVEValue $interface 'ip-addresses' [pscustomobject]@{ PSTypeName = 'PVEPS.VMGuestInterface' Name = Get-PVEValue $interface 'name' MacAddress = Get-PVEValue $interface 'hardware-address' IPAddress = [string[]]@( @($addresses | Where-Object { $_ }) | ForEach-Object { '{0}/{1}' -f (Get-PVEValue $_ 'ip-address'), (Get-PVEValue $_ 'prefix') } ) } } ) $info.Interfaces = $interfaces $info.IPAddress = [string[]]@( $interfaces | ForEach-Object { $_.IPAddress } | ForEach-Object { ($_ -split '/')[0] } | Where-Object { $_ -and $_ -notmatch '^127\.' -and $_ -ne '::1' } ) } [pscustomobject]$info } } } |