In this continuation from part 1, I turn this script into a function that is much more usable day-to-day.
What improvements have been made? It’s a function now, so that makes it reusable without hardcoding each value. The function will save most values, like TokenUser and TokenSecret so you don’t have to re-enter them each time you run it. Note that importantly, that since TokenSecret is a SecureString, it is encrypted when saved to XML. Also, with the function, you can specify an individual VM ID, or don’t specify an ID to return all VMs on that node.
How does it work?
The first time you run it, you will need to specify parameters TokenUser, TokenSecret, Node, PveServer. This example will securely save those parameters. The parameters are using splatting to make them easier to read, and the example prompts for the TokenSecret so it won’t be listed in plaintext.
if (-not $Secret) { $Secret = Read-Host "Enter the TokenSecret" -AsSecureString }
# Example use:
$PveVmParams = @{
TokenUser = "username@pam!prov" # example: "username@pam!tokenname"
TokenSecret = $Secret # example: "11111111-2222-3333-4444-555555555555"
VmId = "100" # ID of VM
Node = "pve" # PVE node name
PveServer = "192.168.0.123" # PVE node IP Address or if using SSL certificate, then use name as in certificate
}
Get-PveVM @PveVmParams
This is the output of the above example:
Name : highcastle--debian
VmId : 100
Status : running
CPUs : 4
MaxDiskGB : 20
MaxMemGB : 8
Tags : env-dev;os-debian
UpDays : 0
UpHours : 7
UpMinutes : 43
UpSeconds : 57
Following is another example. The Get-PveVM command is run without any parameters. Since the connection parameters were set and saved in the prior run, they are not needed again, unless they will change. Without “VmID” parameter, it returns all VMs on the node. We filter so we only show those VMs where the status is “running”, and then we format it as a table.
Get-PveVM | Where-Object Status -EQ "running" | Format-Table
This is the output:
Name VmId Status CPUs MaxDiskGB MaxMemGB Tags UpDays UpHours UpMinutes
---- ---- ------ ---- --------- -------- ---- ------ ------- ---------
highcastle--debian 100 running 4 20 8 env-dev;os-debian 0 7 47
electricsheep--windows2022 101 running 2 60 4 env-dev;os-windows 0 7 47
active-directory1 102 running 2 60 4 env-prod;os-windows 0 7 47
The function
function Get-PveVM {
[CmdletBinding()]
param (
[string]$TokenUser,
[SecureString]$TokenSecret,
[string]$VmId, # Optional
[string]$Node,
[string]$PveServer,
[int]$PvePort = 8006,
[string]$PveConnectSetingsPath = $env:LOCALAPPDATA + "\PveConnectSettings.XML"
)
begin {
#region SETUP
# import settings
if (Test-Path -Path $PveConnectSetingsPath) {
Write-Verbose -Message "Loading settings"
$settings = Import-Clixml -Path $PveConnectSetingsPath
}
# apply imported settings if not specified in parameters
if (-not $TokenUser) { $TokenUser = $settings.TokenUser }
if (-not $TokenSecret) { $TokenSecret = $settings.TokenSecret }
if (-not $Node) { $Node = $settings.Node }
if (-not $PveServer) { $PveServer = $settings.PveServer }
if (-not $PvePort) { $PvePort = $settings.PvePort }
# Save settings
$settings = @{
TokenUser = $TokenUser
TokenSecret = $TokenSecret
Node = $Node
PveServer = $PveServer
PvePort = $PvePort
}
Export-Clixml -Path $PveConnectSetingsPath -InputObject $settings -Force -ErrorAction Continue -Depth 2
# form URL
if ($VmId) { $url = "https://${pveserver}:$pveport/api2/json/nodes/$node/qemu/$vmid/status/current" }
else { $url = "https://${pveserver}:$pveport/api2/json/nodes/$node/qemu" }
# set up authorization header to use token values
$pveheader = @{Authorization = "PVEAPIToken=$tokenUser=$((New-Object PSCredential 0, $TokenSecret).GetNetworkCredential().Password)" }
#endregion
}
process {
#region EXCUTE
# send the API request to PVE
$result = Invoke-RestMethod -Headers $pveheader -Method Get -Uri $url -ErrorAction Stop
#endregion
#region OUTPUT
# format the result
$result.data | ForEach-Object {
$uptimeSeconds = New-TimeSpan -Seconds $_.uptime
[pscustomobject]@{
Name = $_.name
VmId = $_.vmid
Status = $_.status
CPUs = $_.cpus
MaxDiskGB = $_.maxdisk / 1GB
MaxMemGB = $_.maxmem / 1GB
Tags = $_.tags
UpDays = $uptimeSeconds.Days
UpHours = $uptimeSeconds.Hours
UpMinutes = $uptimeSeconds.Minutes
UpSeconds = $uptimeSeconds.Seconds
}
}
#endregion
}
end {
}
}