Private/vm-helpers.ps1
|
# Shared VM helpers used by the public VM functions. function Resolve-CSVMTagId { <# .SYNOPSIS Resolves a VM name, VM object, or VM ID down to a VM ID string. .DESCRIPTION Used internally by the public VM functions so they can all accept -VM (name or pipeline object) or -VirtualMachineId interchangeably. #> param( [string]$VirtualMachineId, [object]$VM ) if ($null -ne $VM) { if ($VM -is [string]) { $resolved = @(Get-CSVM -Name $VM) if ($resolved.Count -eq 0) { throw "No virtual machine found with name '$VM'." } if ($resolved.Count -gt 1) { throw "More than one virtual machine matched name '$VM'." } return [string]$resolved[0].id } if ($null -ne $VM.id) { return [string]$VM.id } if ($null -ne $VM.name) { $resolved = @(Get-CSVM -Name ([string]$VM.name)) if ($resolved.Count -eq 0) { throw "No virtual machine found with name '$($VM.name)'." } if ($resolved.Count -gt 1) { throw "More than one virtual machine matched name '$($VM.name)'." } return [string]$resolved[0].id } throw 'The VM pipeline object must contain an id or name property.' } if ([string]::IsNullOrWhiteSpace($VirtualMachineId)) { throw 'A VM name, VM object, or VirtualMachineId is required.' } return $VirtualMachineId } function Resolve-CSObjectId { <# .SYNOPSIS Resolves a matching -<Thing>Id / -<Thing>Name parameter pair to a single ID. .DESCRIPTION Lets the public functions accept either the ID or the name of a CloudStack object. Rejects the ambiguous cases up front (both supplied, neither supplied when required, a name that matches more than one object) so the caller gets a clear error instead of a confusing server-side failure. .PARAMETER Lookup Script block that takes the name and returns candidate objects. Each object is expected to expose 'id' and 'name' properties. .PARAMETER Required Throw when neither the ID nor the name was supplied. Without it, an omitted pair resolves to $null so the caller can skip the API parameter. #> [CmdletBinding()] param( [string]$Id, [string]$Name, [Parameter(Mandatory = $true)] [scriptblock]$Lookup, [Parameter(Mandatory = $true)] [string]$TypeName, [Parameter(Mandatory = $true)] [string]$IdParameter, [Parameter(Mandatory = $true)] [string]$NameParameter, [switch]$Required ) $hasId = -not [string]::IsNullOrWhiteSpace($Id) $hasName = -not [string]::IsNullOrWhiteSpace($Name) if ($hasId -and $hasName) { throw "Specify either -$IdParameter or -$NameParameter for the $TypeName, not both." } if (-not $hasId -and -not $hasName) { if ($Required) { throw "A -$IdParameter or -$NameParameter is required." } return $null } if ($hasId) { return $Id } # The Get-CS* functions return $null (not an empty array) when nothing # matches, and @($null) has a Count of 1, so strip nulls before counting. $found = @(& $Lookup $Name | Where-Object { $null -ne $_ }) if ($found.Count -eq 0) { throw "No $TypeName found with name '$Name'." } # Several CloudStack list endpoints treat 'name' as a substring filter, so # narrow to an exact (case-insensitive) hit before deciding. $exact = @($found | Where-Object { $_.name -eq $Name }) if ($exact.Count -eq 0) { $candidates = ($found | ForEach-Object { $_.name } | Sort-Object -Unique) -join ', ' throw "No $TypeName is named exactly '$Name'. Partial matches: $candidates." } # A template or ISO seeded into several zones is listed once per zone, so # collapse to distinct IDs before calling it ambiguous. $ids = @($exact | ForEach-Object { [string]$_.id } | Where-Object { $_ } | Sort-Object -Unique) if ($ids.Count -eq 0) { throw "The $TypeName '$Name' did not return an ID." } if ($ids.Count -gt 1) { throw "More than one $TypeName is named '$Name' (IDs: $($ids -join ', ')). Use -$IdParameter instead." } return $ids[0] } function Resolve-CSVolumeId { <# .SYNOPSIS Resolves a volume name or volume object down to a volume ID string. .DESCRIPTION The volume counterpart of Resolve-CSVMTagId, used by functions that accept -Volume (a name or a piped volume object) alongside -VolumeId. A string is treated as an exact volume name. #> param( [Parameter(Mandatory = $true)] [object]$Volume ) if ($Volume -is [string]) { return Resolve-CSObjectId -Name $Volume -Required ` -TypeName 'volume' -IdParameter 'VolumeId' -NameParameter 'Volume' ` -Lookup { param($lookupName) Get-CSVolume -Name $lookupName } } if ($null -ne $Volume.id) { return [string]$Volume.id } throw 'The volume pipeline object must contain an id property.' } |