public/Invoke-WorkdayRequest.ps1
function Invoke-WorkdayRequest { <# .SYNOPSIS Sends XML requests to Workday API, with proper authentication and receives XML response. .DESCRIPTION Sends XML requests to Workday API, with proper authentication and receives XML response. Used for all communication to Workday in this module and may be used to send custom XML requests. .PARAMETER Request The Workday request XML to be sent to Workday. See https://community.workday.com/custom/developer/API/index.html for more information. .PARAMETER Uri Endpoint Uri for the request. .PARAMETER Username Username used to authenticate with Workday. If empty, the value stored using Set-WorkdayCredential will be used. .PARAMETER Password Password used to authenticate with Workday. If empty, the value stored using Set-WorkdayCredential will be used. .EXAMPLE $response = Invoke-WorkdayRequest -Request '<bsvc:Server_Timestamp_Get xmlns:bsvc="urn:com.workday/bsvc" />' -Uri https://SERVICE.workday.com/ccx/service/TENANT/Human_Resources/v25.1 $response.Server_Timestamp wd version Server_Timestamp_Data -- ------- --------------------- urn:com.workday/bsvc v25.1 2015-12-02T12:18:30.841-08:00 .INPUTS Workday XML .OUTPUTS Workday XML .NOTES TODO: Wrap the password and possibly other values in CDATA tags, if the XML setter is not already handling special characters. TODO: Better error handling. Right not, when Workday returns an error in the XML, it also sets the HTTP status as 500. The following exception was thrown, when an invalid username was sent to Workday: You cannot call a method on a null-valued expression. At C:\Program Files\WindowsPowerShell\Modules\WorkdayApi\scripts\Invoke-WorkdayRequest.ps1:104 char:3 + $reader = New-Object System.IO.StreamReader -ArgumentList $_. ... + ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + CategoryInfo : InvalidOperation: (:) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull #> [CmdletBinding()] [OutputType([XML])] param ( [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [xml]$Request, [Parameter(Mandatory = $true)] [ValidateNotNullOrEmpty()] [string]$Uri, [string]$Username, [string]$Password ) if ($WorkdayConfiguration.Credential -is [PSCredential]) { if ([string]::IsNullOrWhiteSpace($Username)) { $Username = $WorkdayConfiguration.Credential.Username } if ([string]::IsNullOrWhiteSpace($Password)) { $Password = $WorkdayConfiguration.Credential.GetNetworkCredential().Password } } $WorkdaySoapEnvelope = [xml] @' <soapenv:Envelope xmlns:bsvc="urn:com.workday/bsvc" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"> <soapenv:Header> <wsse:Security soapenv:mustUnderstand="1" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"> <wsse:UsernameToken> <wsse:Username>IntegrationUser@Tenant</wsse:Username> <wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">Password</wsse:Password> </wsse:UsernameToken> </wsse:Security> </soapenv:Header> <soapenv:Body> <bsvc:RequestNode xmlns:bsvc="urn:com.workday/bsvc" /> </soapenv:Body> </soapenv:Envelope> '@ $WorkdaySoapEnvelope.Envelope.Header.Security.UsernameToken.Username = $Username $WorkdaySoapEnvelope.Envelope.Header.Security.UsernameToken.Password.InnerText = $Password $WorkdaySoapEnvelope.Envelope.Body.InnerXml = $Request.OuterXml Write-Debug "Request: $($WorkdaySoapEnvelope.OuterXml)" $headers= @{ 'Content-Type' = 'text/xml;charset=UTF-8' } $o = [pscustomobject]@{ Success = $false Message = 'Unknown Error' Xml = $null } $o.psobject.TypeNames.Insert(0, "WorkdayResponse") $response = $null try { $response = Invoke-RestMethod -Method Post -Uri $Uri -Headers $headers -Body $WorkdaySoapEnvelope -ErrorAction Stop $o.Xml = [xml]$response.Envelope.Body.InnerXml $o.Message = '' $o.Success = $true } catch [System.Net.WebException] { Write-Debug $_ $o.Success = $false $o.Message = $_.ToString() try { $reader = New-Object System.IO.StreamReader -ArgumentList $_.Exception.Response.GetResponseStream() $response = $reader.ReadToEnd() $reader.Close() $o.Message = $response $xml = [xml]$response $o.Xml = [xml]$xml.Envelope.Body.InnerXml # Put the first Workday Exception into the Message property. if ($o.Xml.InnerXml.StartsWith('<SOAP-ENV:Fault ')) { $o.Success = $false $o.Message = "$($o.Xml.Fault.faultcode): $($o.Xml.Fault.faultstring)" } } catch {} } catch { Write-Debug $_ $o.Success = $false } finally { Write-Output $o } } |