With PowerCLI’s ConnectCI-Server CmdLet it is pretty easy to login to a vCD host. And for most of the time the supplied CmdLets are sufficient enough to solve the problems we deal with it daily. However, sometimes we would like to make specific REST calls to vCD directly (for example when the Searc-Cloud CmdLet is not doing what we want). In this case you would normally make another connection to vCD. This commonly involves saving a cookie or session state, but moreover requries you to know how to make the login call. This seems an unneccessary burden, because you already logged in successfully earlier on via Connect-CiServer.
But there is help. When you save the session of your PowerCLI logon you will see it contains several properties with SessionSecret and SessionId looking quite promising:
PS > $SessionVcd | fl * -force IsConnected : True ServiceUri : https://vcloud.sharedop.com/api/ SessionId : rawCookieText User : edgar RefCount : 1 Org : System Port : 443 Version : 1.5.1.622844 ExtensionData : VMware.VimAutomation.Cloud.Views.VCloud Id : /CIServer=edgar:system@vcloud.sharedop.com:443/ Name : vcloud.sharedop.com Client : /CIServer=edgar:system@vcloud.sharedop.com:443/ Uid : /CIServer=edgar:system@vcloud.sharedop.com:443/CIServer=&slash;CIServer&eq;edgar:system@vcloud.sharedop.com:443&slash;/ Description : Represents a vCloud server session. Href : https://vcloud.sharedop.com:443/api/ SessionSecret : rawCookieText
With that you can perform an actual query to vCD without an extra login:
# create WebClient $wc = New-Object System.Net.WebClient; # extract version number from logged in PowerCLI session $SessionVcd.Version -match '^(\d\.\d)\..+$' $HeaderAcceptValue = [string]::Format("application/*+xml;version={0}", $Matches[1]); $HeaderCookieValue = [string]::Format("vcloud-token={0}; Secure; Path=/", $SessionVcd.SessionSecret); # add headers for request $wc.Headers.Add("Accept", $HeaderAcceptValue); $wc.Headers.Add("Cookie", $HeaderCookieValue); # perform request $aBytes = $wc.DownloadData($SessionVcd.ServiceUri.AbsoluteUri); # transform to xml document $xmlResult = [xml] [System.Text.Encoding]::ASCII.GetString($aBytes); # extract org link (or whatever) $xmlResult.Session.link[0].href https://vcloud.sharedop.com/api/org/
When using the Invoke-RestMethod (available from PS v3) you have to fill the Session object first. Adding headers will not be enough. Note: The WebClient used in the example above is also available on PS v2.
As a side note for the WebClient object: You have to add the “Accept”-Header again for every call you make. The “Cookie” is persistent on the object, though.
As you can see it is pretty easy to re-use the log in from PowerCLI without having to worry about the version and login details of the vCD REST API. As an additional benefit for long running tasks. In case you timeout on a session all you need to do is refresh one connection and take the properties from the returned session object instead of doing two re-logins.
Below you find an example of a Cmdlet function that takes a VCD session and generates a REST call against vCD:
function Invoke-VcdRestCall { <# .SYNOPSIS Performs a REST call against a vCD host and returns the XML result set. .DESCRIPTION Performs a REST call against a vCD host and returns the XML result set. .OUTPUTS This Cmdlet returns an XML document on success. On failure it returns $null. .INPUTS See PARAMETER section for a description of input parameters. .PARAMETER CIServer The vCD host to execute the REST call against. Default is '$global:DefaultCIServers[0]'. .PARAMETER Method The HTTP method of the REST call. Default is 'GET'. Possible values: 'GET', 'POST', 'DELETE'. 'PUT'. Alias: m .PARAMETER Api The command part of the REST call. Default is 'query'. For possible values see the vCD REST reference. Alias: a .PARAMETER QueryParameters The QueryString part of the REST call. For possible values see the vCD REST reference. Alias: q .PARAMETER Body Optional body of the REST call when using a POST or PUT operation/method. Default is '$null'. For possible values see the vCD REST reference. Alias: b .EXAMPLE Gets all possible 'query' operations of the vCD REST query service. $xmlResponse = Invoke-VcdRestCall; $xmlResponse.QueryList.Link; .EXAMPLE Gets all vCD Cells. $xmlResponse = Invoke-VcdRestCall -Api "query" -QueryParameters "type=cell"; $xmlResponse.QueryResultRecords.CellRecord; .LINK Online Version: http://dfch.biz/PS/vCD/Utilities .NOTES Requires Powershell v3. Requires module 'biz.dfch.PS.System.Logging'. Requires a PowerCLI session to VCD. #> [CmdletBinding( HelpURI='http://dfch.biz/PS/vCD/Utilities/Invoke-VcdRestCall' )] [OutputType([xml])] Param ( [Parameter(Mandatory = $false, Position = 2)] [alias("s")] $CIServer = $global:DefaultCIServers[0] , [ValidateSet('GET', 'POST', 'PUT', 'DELETE')] [Parameter(Mandatory = $false, Position = 1)] [alias("m")] [string] $Method = 'GET' , [Parameter(Mandatory = $false, Position = 0)] [alias("a")] [string] $Api = 'query' , [Parameter(Mandatory = $false, Position = 3)] [alias("q")] [string] $QueryParameters = $null , [Parameter(Mandatory = $false, Position = 4)] [alias("b")] [string] $Body = $null ) # Param BEGIN { $datBegin = [datetime]::Now; [string] $fn = $MyInvocation.MyCommand.Name; Log-Debug -fn $fn -msg "CALL. Api: '$Api'." -fac 1; } PROCESS { [boolean] $fReturn = $false; $retNull = $null; try { # Parameter validation if( !$CIServer -or ($CIServer.GetType().FullName -ne "VMware.VimAutomation.Cloud.Impl.V1.CIServerImpl") ) { Log-Error $fn "Invalid input parameter type specified: CIServer [$($CIServer.GetType().FullName)]. Aborting ..."; throw($gotoFailure); } # if if( !$CIServer.IsConnected ) { Log-Error $fn "CIServer '$($CIServer.Name)' is not connected. Reconnect session before trying again. Aborting ..."; throw($gotoFailure); } # if if(!$Api) { Log-Error $fn "Invalid or empty input parameter specified: Api. Aborting ..."; throw($gotoFailure); } # if # create WebClient $SessionVcd = $CIServer; $wc = New-Object System.Net.WebClient; # extract version number from logged in PowerCLI session $fReturn = $SessionVcd.Version -match '^(\d\.\d)\..+$'; if(!$fReturn) { Log-Error $fn "CIServer version could not be matched: '$($SessionVcd.Version)'. Aborting ..."; } # if $HeaderAcceptValue = [string]::Format("application/*+xml;version={0}", $Matches[1]); $HeaderCookieValue = [string]::Format("vcloud-token={0}; Secure; Path=/", $SessionVcd.SessionSecret); # add headers for request $null = $wc.Headers.Add("Accept", $HeaderAcceptValue); $null = $wc.Headers.Add("Cookie", $HeaderCookieValue); [string] $Uri = [string]::Format("{0}{1}?{2}", $SessionVcd.ServiceUri.AbsoluteUri, $Api, $QueryParameters); Log-Debug $fn "Invoking '$Method' '$Uri' ..."; [string] $response = ''; if('GET'.Equals($Method.ToUpper()) ) { $response = $wc.DownloadString($Uri); } else { $response = $wc.UploadString($Uri, $Method.ToUpper(), $Body); } # if $null = $wc.Dispose(); # transform to xml document $xmlResult = [xml] $response; $OutputParameter = $xmlResult.Clone(); } # try catch { if($gotoSuccess -eq $_.Exception.Message) { $fReturn = $true; } else { [string] $ErrorText = "catch [$($_.FullyQualifiedErrorId)]"; $ErrorText += (($_ | fl * -Force) | Out-String); $ErrorText += (($_.Exception | fl * -Force) | Out-String); $ErrorText += (Get-PSCallStack | Out-String); if( ($_.Exception.InnerException) -and ([System.Net.WebException] -eq ($_.Exception.InnerException.GetType())) ) { Log-Critical $fn "Operation '$Method' '$Api' with CIServer '$($CiServer.Name)' FAILED [$_]."; Log-Debug $fn $ErrorText -fac 3; } # [System.Net.WebException] else { Log-Error $fn $ErrorText -fac 3; if($gotoFailure -ne $_.Exception.Message) { Write-Verbose ("$fn`n$ErrorText"); } } # other exceptions $fReturn = $false; $OutputParameter = $null; } # !$gotoSuccess } # catch finally { # Clean up } # finally return $OutputParameter; } # PROCESS END { $datEnd = [datetime]::Now; Log-Debug -fn $fn -msg "RET. fReturn: [$fReturn]. Execution time: [$(($datEnd - $datBegin).TotalMilliseconds)]ms. Started: [$($datBegin.ToString('yyyy-MM-dd HH:mm:ss.fffzzz'))]." -fac 2; } # END } # function Set-Alias -Name Invoke-VcdCommand -Value Invoke-VcdRestCall; Export-ModuleMember -Function Invoke-VcdRestCall -Alias Invoke-VcdCommand;
As a side note: you might want to use the same cookie value for access to vCD Administration GUI (via vcloud_session_id) as well. For further information see Login to vCloud Director 1.5 with a generated Cookie.