I am trying to retrieve data from a SOAP web service using PowerShell. I am having issues retrieving values from the inner XML. The code is listed below.
In the [XML]$body2 variable if I pass the $queryid variable then the values in the else condition of the Response function does not print. I debugged the code and $queryid is getting the correct value. If I remove $queryid and replace it with a number then the values print fine.
Edit: The $queryid should be set to a number which I then want to use in $body2.
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
$id1 = "1"
$id2 = "2"
$global:queryid = ""
$array = #()
function Main() {
$uri = "https://mywebsite/CatalogTasks.asmx?WSDL"
[XML]$body = #"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">
<soap:Body>
<Request xmlns="http://mywebsite.com">
<user>user_id</user>
<pwd>password</pwd>
<fields>[Number],Tech name],[Description],[State]</fields>
<condition>[State]='Open'</condition>
<orderBy>[Number]</orderBy>
</Request>
</soap:Body>
</soap:Envelope>
"#
Response $uri $body $id1
Write-Host "Id: $global:queryid"
$queryid = $global:queryid
[XML]$body2 = #"
<?xml version="1.0" encoding="utf-8"?>
<soap:Envelope xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/soap/envelope">
<soap:Body>
<RetrieveXML xmlns="http://mywebsite.com">
<user>user_id</user>
<pwd>password</pwd>
<queryId>$queryid</queryId>
</RetrieveXML>
</soap:Body>
</soap:Envelope>
"#
Response $uri $body2 $id2
}
function Response ($url, $bodyy, $id) {
$resp = (Invoke-WebRequest -Uri $url -Body $bodyy -ContentType "text/xml" -Proxy "http://proxy" -ProxyUseDefaultCredentials -Method POST)
if ($id -eq 1) {
$soap = $resp.Content
$xpathfilter = "//*[local-name()='QueryId']"
$Element = Select-Xml -Content $soap -XPath $xpathfilter
$global:queryid = $Element.Node.'#text'
} else {
$soap2 = $resp.Content
$filter = "//*[local-name()='Number']"
$Element2 = Select-Xml -Content $soap2 -XPath $filter
$number = $Element2.Node.'#text'
[array]$array = ($number)
foreach ($i in $array){
Write-Host $i
}
}
}
Main
Related
I am trying to POST an associative array to a web-service.
I create the array and I use Invoke-RestMethod to POST it:
$LogData = #{
"MyProperty" = "bla bla";
"LogText" = "This is my Text."
}
Invoke-RestMethod -Method Post -Uri $URL -Body ( $LogData | ConvertTo-JSON -Compress ) -ContentType "application/json"
This is working fine.
Now I want the property LogText to be dynamical and not static like in the example above.
I want to take the content of a text-file and therefore I use the code as above, but with Get-Content:
$LogData = #{
"MyProperty" = "bla bla";
"LogText" = Get-Content -Path $LogFile
}
This does not work. The text does not seem to be a String. It seems to be an object. If I have a closer look using the command $LogData.LogText | ConvertTo-JSON, I get an output like:
I did try to use the following, but this did not change the situation:
Get-Content -Path $LogFile -Raw
( Get-Content -Path $LogFile -Raw ).ToString()
How can I solve this?
Thank you
Get-Content attaches some metadata to it's output, and ConvertTo-Json (in Windows PowerShell at least) serializes the attached metadata instead of treating the underlying string as just a string.
You can force ConvertTo-Json to treat them as strings by explicitly typing the containing array:
$LogData = #{
"MyProperty" = "bla bla";
"LogText" = [string[]]#( Get-Content -Path $LogFile )
}
For scalar string values, you can create a new string using "":
$LogData = #{
"MyProperty" = "bla bla";
"LogText" = "$( Get-Content -Path $LogFile -Raw )"
}
Using the following lines of code did the trick:
$LogData = #{
"MyProperty" = "bla bla";
"LogText" = "$( Get-Content -Path $LogFile -Raw )"
}
Invoke-RestMethod -Method Post -Uri $URL -Body ( $LogData | ConvertTo-JSON -Compress ) -ContentType "application/json; charset=utf-8"
Most important thing was adding charset=utf-8 to the ContentType. Without it the webservice did "sometimes" respond with "405 Method Not Allowed".
I'm attempting to test this section of a PowerShell function:
# post
$Response = Invoke-WebRequest -Method POST -Uri $Uri -Body $Body -ContentType 'application/xml'
# parse Response.Content; return as System.Xml.XmlDocument
[xml]$Response.Content
by mocking the BasicHtmlWebResponseObject that is returned by Invoke-WebRequest:
Mock Invoke-WebRequest {
$WebResponse = [System.Net.HttpWebResponse]::new()
[System.Net.HttpWebResponse].GetField('m_StatusCode', 'NonPublic, Instance').SetValue(
$WebResponse,
200,
'NonPublic,SetField',
$null,
(Get-Culture)
)
$Content = '<?xml version="1.0" encoding="UTF-8"?><response><control>failure<status></status></control><operation><result><status>failure</status></result></operation></response>'
$Response = [Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject]::new($WebResponse,$Content)
return $Response
}
This assertion fails because I'm not creating the HttpWebResponse or BasicHtmlWebResponseObject correctly:
It "returns the response's Content object" {
# act
$Content = Send-Request -Session $Session
# assert
Assert-MockCalled Invoke-WebRequest
$Content | Should -BeOfType [xml]
$Content.response.control.status | Should -Be 'success'
$Content.response.operation.result.status | Should -Be 'success'
}
** edit **
I thought about using New-MockObject:
Mock Invoke-WebRequest {
$Response = New‐MockObject -Type Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject
$Response.Content = '<?xml version="1.0" encoding="...'
}
but, the Content property is read-only.
** /edit **
What am I missing?
A slightly simpler alternative might be to wrap your invoke-webrequest in a function and just mock that instead. E.g.
function Get-XmlFromUri
{
param( $Uri, $Method, $Body )
$Response = Invoke-WebRequest -Method $Method -Uri $Uri -Body $Body -ContentType 'application/xml’
[xml]$Response.Content
}
Now you can mock Get-XmlFromUri and just return a System.Xml.XmlDocument object from hard-coded xml, which is much easier to create than a BasicHtmlWebResponseObject that needs reflection calls spin up.
Mock Get-XmlFromUri {
[xml] '<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>'
}
Or, depending on how much like BasicHtmlWebResponseObject your code needs it to be, you can just return a hashtable from your invoke-webrequest mock that has the properties you need:
Mock Invoke-WebRequest {
new-object pscustomobject -property #{
Content = '<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>’
}
}
(apologies for code formatting - currently typing one handed on an iPhone at 4 AM holding a not-very-sleepy baby :-S)
On PowerShell Core this doesn't work for me:
[System.Net.HttpWebResponse].GetField('m_StatusCode', 'NonPublic, Instance')
And thats why your Mock isn't returning what you expect. That line does work on Windows PowerShell however. Not sure what the right equivalent is on PSCore, needs research but thought i'd get you this far in the meantime.
This works:
Mock Invoke-WebRequest {
$Response = New-MockObject -Type Microsoft.PowerShell.Commands.BasicHtmlWebResponseObject
$Content = `
'<?xml version="1.0" encoding="UTF-8"?>
<response>
<control><status>success</status></control>
<operation><result><status>success</status></result></operation>
</response>'
$Response | Add-Member -NotePropertyName Content -NotePropertyValue $Content -Force
$Response
}
I need to make a Soap Request from Powershell, I am on Powershell 2.0, I can find lots of examples but I also need to include a username and password to get through the api.
I get a response of
Exception calling "GetResponse" with "0" argument(s): "The underlying connectio
n was closed: An unexpected error occurred on a send."
My Powershell code (I have redacted some sensitive stuff) is
function Execute-SOAPRequest
(
[Xml] $SOAPRequest,
[String] $URL
)
{
write-host "Sending SOAP Request To Server: $URL"
$soapWebRequest = [System.Net.WebRequest]::Create($URL)
$soapWebRequest.Headers.Add("SOAPAction","`"`"")
$soapWebRequest.ContentType = "text/xml;charset=`"utf-8`""
$soapWebRequest.Accept = "text/xml"
$soapWebRequest.Method = "POST"
$username = "USERNAME"
$password = "Password" | ConvertTo-SecureString -asPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential($username,$password)
$soapWebRequest.Credentials = $cred
#$soapWebRequest.Proxy.Credentials = [System.Net.CredentialCache]::DefaultNetworkCredentials
#$soapWebRequest.UseDefaultCredentials = $true
write-host $soapWebRequest
write-host "Initiating Send."
$requestStream = $soapWebRequest.GetRequestStream()
write-host $requestStream
$SOAPRequest.Save($requestStream)
$requestStream.Close()
write-host "Send Complete, Waiting For Response."
$resp = $soapWebRequest.GetResponse()
$responseStream = $resp.GetResponseStream()
$soapReader = [System.IO.StreamReader]($responseStream)
$ReturnXml = [Xml] $soapReader.ReadToEnd()
$responseStream.Close()
write-host "Response Received."
return $ReturnXml
}
$url = 'https://zkncsavia049.via.novonet:7180/ws/activeservices/pmspapi_nomination'
$soap = [xml]#'
<?xml version="1.0" encoding="utf-8"?>
<soapenv:Envelope xmlns:pms="http://www.mydomain.co.uk/pmsapi_nomination" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/"
xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wssu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soapenv:Header><wsse:Security><wsse:UsernameToken wssu:Id="UsernameToken-4B81F4838BB6D8A60715299310629901"><wsse:Username>igyadmin</wsse:Username>
<wsse:Password Type="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">V3rm0nt</wsse:Password>
<wsse:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">x9DSipKzGHLbvyCOXKIY6A==</wsse:Nonce>
<wssu:Created>2018-06-25T12:51:02.986Z</wssu:Created></wsse:UsernameToken></wsse:Security>
</soapenv:Header>
<soapenv:Body>
<pms:pmsapi_nomination.getlist.ApiRequest xmlns:ns2="http://www.mydomain.co.uk/pmsapi_nomination">
<ApiRequest>
<LogonInfo>
<BusinessGroup>GMP</BusinessGroup>
<AdminGroup>ADMN</AdminGroup>
</LogonInfo>
<BUSINESS_GROUP>
<value>GMP</value>
</BUSINESS_GROUP>
<CONTEXT>
<value>F</value>
</CONTEXT>
<REFNO>
<value>0039760</value>
</REFNO>
</ApiRequest>
</pms:pmsapi_nomination.getlist.ApiRequest>
</soapenv:Body>
</soapenv:Envelope>
'#
$ret = Execute-SOAPRequest $soap $url
I can get the call to work through SOAPUI the raw XML is
POST http://zkncsavia049.via.novonet:7180/ws/activeservices/pmsapi_nomination/HTTP/1.1
Accept-Encoding: gzip,deflate
Content-Type: text/xml;charset=UTF-8
SOAPAction: ""
Content-Length: 1541
Host: zkncsavia049.via.novonet:7180
Connection: Keep-Alive
User-Agent: Apache-HttpClient/4.1.1 (java 1.5)
<soapenv:Envelope xmlns:pms="http://www.mydomain.co.uk/pmsapi_nomination" xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" xmlns:wssu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd">
<soapenv:Header><wsse:Security><wsse:UsernameToken wssu:Id="UsernameToken-78C15367B2B1287BB3153000735070610"><wsse:Username>USERNAME</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:Nonce EncodingType="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-soap-message-security-1.0#Base64Binary">q5B6XRmHsecmHouCqH03qA==</wsse:Nonce><wssu:Created>2018-06-26T10:02:30.696Z</wssu:Created></wsse:UsernameToken></wsse:Security>
</soapenv:Header>
<soapenv:Body>
<pms:pmsapi_nomination.getlist.ApiRequest xmlns:ns2="http://www.aquilauk.co.uk/pmsapi_nomination">
<ApiRequest>
<LogonInfo>
<BusinessGroup>GMP</BusinessGroup>
<AdminGroup>ADMN</AdminGroup>
</LogonInfo>
<BUSINESS_GROUP>
<value>GMP</value>
</BUSINESS_GROUP>
<CONTEXT>
<value>F</value>
</CONTEXT>
<REFNO>
<value>0039761</value>
</REFNO>
</ApiRequest>
</pms:pmsapi_nomination.getlist.ApiRequest>
</soapenv:Body>
</soapenv:Envelope>
There is an SSL certificate on the system but not for port 7180.
I'm also very much a powershell novice, I only write it a couple of times a year.
So the fail is on
$resp = $soapWebRequest.GetResponse()
but I guess that the setting up of $soapWebRequest may be the problem
Hi i need a help with proper soap request. I tried few ways do it but no luck.
Need to generate such soap request:
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope"><soap:Header><Action xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:env="http://www.w3.org/2003/05/soap-envelope" env:mustUnderstand="true"/><MessageID xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing">uuid:..............</MessageID><ReplyTo xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing"><Address>http://www.w3.org/2004/08/addressing/anonymous</Address></ReplyTo><To xmlns="http://schemas.xmlsoap.org/ws/2004/08/addressing" xmlns:env="http://www.w3.org/2003/05/soap-envelope" env:mustUnderstand="true">host_url</To><wsse:Security xmlns:env="http://www.w3.org/2003/05/soap-envelope" xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" env:mustUnderstand="true"><wsse:UsernameToken><wsse:Username xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">$login</wsse:Username><wsse:Password xmlns:wsse="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd" wsse:Type="http://docs.oas
is-open.org/wss/2004/01/oasis-200401-wss-username-token-profile-1.0#PasswordText">$password</wsse:Password></wsse:UsernameToken></wsse:Security></soap:Header>
<soap:Body>
................
</soap:Body>
</soap:Envelope>
i stucked on this getting iis internal error 500:
(...)
write-host "Sending SOAP Request To Server: $URL"
$soapWebRequest = [System.Net.WebRequest]::Create($URL)
$soapWebRequest.Headers.Add("SOAPAction","`"MethodName`"")
$soapWebRequest.ContentType = "application/soap+xml;charset=`"utf-8`";action=`"host/MethodName`""
$soapWebRequest.Method = "POST"
write-host "Initiating Send."
$requestStream = $soapWebRequest.GetRequestStream()
$SOAPRequest.Save($requestStream)
$requestStream.Close()
write-host "Send Complete, Waiting For Response."
$resp = $soapWebRequest.GetResponse()
$responseStream = $resp.GetResponseStream()
$soapReader = [System.IO.StreamReader]($responseStream)
$ReturnXml = [Xml] $soapReader.ReadToEnd()
$responseStream.Close()
write-host "Response Received."
return $ReturnXml
}
$url = 'host.asmx'
$soap = [xml]#"
<soap:Envelope xmlns:soap="http://www.w3.org/2003/05/soap-envelope" xmlns:flow="host">
<soap:Header/>
<soap:Body>
.....
</soap:Body>
</soap:Envelope>
"#
$ret = Execute-SOAPRequest $soap $url; $ret | Export-Clixml "test-$(Get-date -f yyyy-MM-dd-mm-ss).xml";
Your headers seem odd mixing up escaped quotes you actually don't need.
Try replacing
$soapWebRequest.Headers.Add("SOAPAction","`"MethodName`"")
by
$soapWebRequest.Headers.Add("SOAPAction","MethodName")
as well as
$soapWebRequest.ContentType = "application/soap+xml;charset=`"utf-8`";action=`"host/MethodName`""
by
$soapWebRequest.ContentType = "application/soap+xml; charset=utf-8";
I try to utilise the code example. But I am unsuscessful. Can any one pick up an error? (I know about New-WebServiceProxy cmdlet.)
function Execute-SOAPRequest
(
[Xml] $SOAPRequest,
[String] $URL
)
{
write-host “Sending SOAP Request To Server: $URL”
$soapWebRequest = [System.Net.WebRequest]::Create($URL)
$soapWebRequest.Headers.Add("SOAPAction" ,"http://www.webservicex.net/globalweather.asmx?WSDL/GetWeather")
$soapWebRequest.ContentType = 'text/xml;charset="utf-8"'
$soapWebRequest.Accept = “text/xml”
$soapWebRequest.Method = “POST”
write-host “Initiating Send.”
$requestStream = $soapWebRequest.GetRequestStream()
$SOAPRequest.Save($requestStream)
$requestStream.Close()
write-host “Send Complete, Waiting For Response.”
$resp = $soapWebRequest.GetResponse()
$responseStream = $resp.GetResponseStream()
$soapReader = [System.IO.StreamReader]($responseStream)
$ReturnXml = [Xml] $soapReader.ReadToEnd()
$responseStream.Close()
write-host “Response Received.”
return $ReturnXml
}
function Execute-SOAPRequestFromFile
(
[String] $SOAPRequestFile,
[String] $URL
)
{
write-host “Reading and converting file to XmlDocument: $SOAPRequestFile”
$SOAPRequest = [Xml](Get-Content $SOAPRequestFile)
return $(Execute-SOAPRequest $SOAPRequest $URL)
}
$x = Execute-SOAPRequestFromFile -SOAPRequestFile soap-W.txt -URL "http://www.webservicex.net/globalweather.asmx?WSDL"
The file soap-W.txt:
<?xml version="1.0" encoding="UTF-8"?>
<SOAP-ENV:Envelope xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/" xmlns:http="http://schemas.xmlsoap.org/wsdl/http/" xmlns:soap12="http://schemas.xmlsoap.org/wsdl/soap12/" xmlns:s="http://www.w3.org/2001/XMLSchema" xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/" xmlns:tns="http://www.webserviceX.NET" xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/" xmlns:soapenc="http://schemas.xmlsoap.org/soap/encoding/" xmlns:tm="http://microsoft.com/wsdl/mime/textMatching/" xmlns:SOAP-ENV="http://www.w3.org/2003/05/soap-envelope">
<SOAP-ENV:Body>
<tns:GetWeather xmlns:tns="http://www.webserviceX.NET">
<tns:CityName>Tampa</tns:CityName>
<tns:CountryName>United States</tns:CountryName>
</tns:GetWeather>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>
Server return error 500. Query via New-WebServiceProxy is successfull.
You should try New-WebServiceProxy CmdLet.
$svc = New-WebServiceProxy -Uri "http://www.webservicex.net/globalweather.asmx?WSDL"
$svc.GetWeather("Aurillac", "France")