Invoke-vCloud.psm1
## Invoke-vCloud.psm1 - Wrapper for Invoke-RestMethod for consuming VMware vCloud Director API # Main function to interact with the vCloud Director REST API from within PowerShell # Note: Does not require PowerCLI, but without it you'll need to specify a valid x-vcloud-authorization # or JWT token to authenticate against the vCloud API. Function Invoke-vCloud( [Parameter(Mandatory=$true)][uri]$URI, # We must specify the API endpoint [string]$ContentType, # Optional ContentType for returned XML [string]$Method = 'GET', # HTTP verb to use (default 'GET') [Parameter(Mandatory=$true)][string]$ApiVersion, # vCloud Director API version (e.g. '34.0') [string]$Body, # Any body document to be submitted to the API [int]$APITimeout = 30, # Timeout in seconds to wait for API response (by default) [int]$TaskTimeout = 300, # Timeout in seconds to wait for a VCD task to complete [switch]$WaitForTask, # Should we wait for task completion if reponse includes a task href? [string]$vCloudToken, # If not already authenticated using Connect-CIServer (PowerCLI) allow us to specify a token [string]$vCloudJWT, # Allow use of JWT token instead of x-vcloud-authorization token [string]$Accept = 'application/*+xml', # Override the 'Accept' HTML header sumbitted with the API request [switch]$skipCertificateCheck # Ignore the SSL certificate presented by the endpoint - Requires PS 7.0+ ) { <# .SYNOPSIS Provides a wrapper for Invoke-RestMethod for vCloud Director API calls .DESCRIPTION Invoke-vCloud provides an easy to use interface to the vCloud Director API and provides sensible defaults for many parameters. It wraps the native PowerShell Invoke-RestMethod cmdlet. .PARAMETER URI A mandatory parameter which provides the API URI to be accessed. .PARAMETER ContentType An optional parameter which provides the ContentType of any submitted data. .PARAMETER Method An optional parameter to specify the HTML verb to be used (GET, PUT, POST or DELETE). Defaults to 'GET' if not specified. .PARAMETER ApiVersion An required parameter to specify the API version to be used for the call. If API version is not known use Get-vCloudAPIVersion to determine this for the endpoint first. .PARAMETER Body An optional parameter which specifies XML body to be submitted to the API (usually for a PUT or POST action). .PARAMETER APITimeout An optional parameter which specifies the time (in seconds) to wait for an API call to complete. Defaults to 40 seconds if not specified. Note that this is the time for the API to respond and NOT for a task to complete (see the TaskTimeout parameter for that). .PARAMETER TaskTimeout An optional parameter which specifies the time (in seconds) to wait for a Cloud Director task to finish. Tasks can be long-running, especially when deploying new VMs/vApps so set this value appropriately if the task is expected to take a long time. .PARAMETER WaitForTask If the API call we submit results in a Task object indicating an asynchronous vCloud task, should we wait for this to complete before returning? Defaults to $false. .PARAMETER vCloudToken An alternative method of passing a session token to Invoke-vCloud if there is no current PowerCLI session established to a vCloud endpoint. The session must have already been established and be still valid (not timed-out). The value supplied is copied to the 'x-vcloud-authorization' header value in API calls. .PARAMETER vCloudJWT Another alternative method of passing a session token to Invoke-vCloud using a Java Web Token (JWT) from an existing session. The session must have already been established and be still valid (not timed-out). The value supplied is copied to the 'X-VMWARE-VCLOUD-ACCESS-TOKEN' header value in API calls. .PARAMETER Accept This parameter provides a way to override the default 'Accept' header sent to all Cloud Director API calls. The default of 'application/*+xml' should be suitable in most cases. .PARAMETER skipCertificateCheck A switch that allows ignoring invalid SSL certificates from the API endpoint. Should not be used in production environments. Note that the -SkipCertificateCheck option for Invoke-RestMethod is only supported in PowerShell versions 6.0 and higher, attempting to use this flag in lower versions of PowerShell will result in an error. .OUTPUTS An XML document returned from the vCloud API (if not waiting for task), or a success/failure indication if waiting for a task to complete. .EXAMPLE Returns list of Organizations to which my current vCloud Session has access > $orgs = Invoke-vCloud -URI https://my.cloud.com/api/org > $orgs.InnerXML <?xml version="1.0" encoding="UTF-8"?> <OrgList xmlns="http://www.vmware.com/vcloud/v1.5" href="https://my.cloud.com/api/org/" type="application/vnd.vmware.vcloud.orgList+xml" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.vmware.com/vcloud/v1.5 http://my.cloud.com/api/v1.5/schema/master.xsd"> <Org href="https://my.cloud.com/api/org/6f14c081-3728-4918-a5cc-bb756452f485" name="MyDemoOrg" type="application/vnd.vmware.vcloud.org+xml" /> </OrgList> .NOTES You must either have an existing PowerCLI connection to vCloud Director (Connect-CIServer) in your current PowerShell session, or provide a valid token (using the -vCloudToken parameter) in order to authenticate against the API for calls to suceed. #> # Build authentication header based on current session or supplied token: $mySessionId = ($Global:DefaultCIServers | Where-Object { $_.Name -eq $URI.Host }).SessionId if ($mySessionId) { # Found a matching session - Connect-CIServer has been used: $Headers = @{'x-vcloud-authorization'=$mySessionId} } else { # No connected session found, see if we have a token: if ($vCloudToken) { $Headers = @{'x-vcloud-authorization'=$vCloudToken} } elseif ($vCloudJWT) { $Headers = @{'Authorization'="Bearer $($vCloudJWT)"} } else { Write-Error ("No existing Connect-CIServer session found and no vCloudToken or vCloudJWT token specified.") Write-Error ("Cannot authenticate to the vCloud API, exiting.") Return } } # Configure HTTP headers for this request: $Headers.Add("Accept","$($Accept);version=$($ApiVersion)") # Build parameters hash to be passed to Invoke-RestMethod $InvokeParams = @{ Method = $Method Uri = $URI Headers = $Headers TimeoutSec = $APITimeout } # Handle optional parameters and add to hash where defined: if ($ContentType) { $InvokeParams.ContentType = $ContentType } if ($Body) { $InvokeParams.Body = $Body } if ($skipCertificateCheck) { $InvokeParams.SkipCertificateCheck = $true } # Submit API request: Try { [xml]$response = Invoke-RestMethod @InvokeParams } Catch { # Something went wrong, so return error information and exit: Write-Warning ("Invoke-vCloud Exception: $($_.Exception.Message)") if ( $_.Exception.ItemName ) { Write-Warning ("Failed Item: $($_.Exception.ItemName)") } Return } if ($WaitForTask) { # If we've requested to wait for the task to complete if ($response.Task.href) { # and we have a task href in the document returned Write-Host ("Task submitted successfully, waiting for result") Write-Host ("q=queued, P=pre-running, .=Task Running:") while($TaskTimeout -gt 0) { $taskxml = Invoke-RestMethod -Uri $response.Task.href -Method 'Get' -Headers $Headers -TimeoutSec $APITimeout # Get/refresh our task status switch ($taskxml.Task.status) { "success" { Write-Host " "; Write-Host "Task completed successfully"; return $true; break } "running" { Write-Host -NoNewline "." } "error" { Write-Host " "; Write-Warning "Error running task"; return $false; break } "canceled" { Write-Host " "; Write-Warning "Task was cancelled"; return $false; break } "aborted" { Write-Host " "; Write-Warning "Task was aborted"; return $false; break } "queued" { Write-Host -NoNewline "q" } "preRunning" { Write-Host -NoNewline "P" } } # switch on current task status $TaskTimeout -= 5 # Decrease our Task timeout Start-Sleep -s 5 # Pause 5 seconds } # Timeout expired Write-Warning "Task timeout reached (task may still be in progress)" return $false } else { Write-Warning 'Wait for task requested, but no task returned by vCloud API' } } # WaitForTask # Return API response to caller Return $response } # Invoke-vCloud Function end Function Get-vCloudAPIVersion( [Parameter(Mandatory=$true)][uri]$URI, # API Endpoint to check the version for [int]$APITimeout = 30, # Optional timeout in seconds to wait for API response [switch]$skipCertificateCheck # Ignore SSL errors (defaults to False) ) { <# .SYNOPSIS Gets the highest supported API version for the specified vCloud endpoint .DESCRIPTION Get-vCloudAPIVersion provides an easy method to determine the highest non-deprecated API version for the URI specified. The format of API versions in vCloud Director is a string value (e.g. '33.0') even though all currently valid values appear to be floats. .PARAMETER URI A mandatory parameter which provides the API URI to be accessed. .PARAMETER APITimeout An optional parameter which specifies the time in seconds to wait for a response from the API version call. If this time is exceeded a timeout error is returned. Defaults to 30 seconds. .PARAMETER skipCertificateCheck A switch that allows ignoring invalid SSL certificates from the API endpoint. Should not be used in production environments. Note that the -SkipCertificateCheck switch for Invoke-RestMethod is only supported in PowerShell versions 6.0 and higher, attempting to use this flag in lower versions of PowerShell will result in an error. .OUTPUTS A string containing the highest supported API version for the specified URI. .EXAMPLE Returns the highest supported API version for the specified URI: PS /> Get-vCloudAPIVersion -URI https://my.cloud.com/ 33.0 .NOTES No existing session is required to the specified URI as the request for API versions supported by the endpoint does not require authentication. #> $InvokeParams = @{ Method = 'Get' Uri = "https://$($URI.Host)/api/versions" Headers = @{'Accept'='application/*+xml'} TimeoutSec = $APITimeout } if ($skipCertificateCheck) { $InvokeParams.SkipCertificateCheck = $true } Try { [xml]$r = Invoke-RestMethod @InvokeParams } Catch { Write-Warning ("Invoke-vCloud Exception finding API versions: $($_.Exception.Message)") if ( $_.Exception.ItemName ) { Write-Warning ("Failed Item: $($_.Exception.ItemName)") } Return "Error determining highest supported API version." } Return (($r.SupportedVersions.VersionInfo | Where-Object { $_.deprecated -eq $False }) | Measure-Object -Property Version -Maximum).Maximum.ToString() + ".0" } # Export function from module Export-ModuleMember -Function Invoke-vCloud Export-ModuleMember -Function Get-vCloudAPIVersion |