I've been trying to make use of a vendor supplied Web Service system via Powershell (I'm running 4.0). The following is the code I've used to set up the proxy to use the service :
$uri = http://somehost.employer.net:9999/AdministrationService?wsdl
$webSvc = New-WebServiceProxy -Uri $uri -namespace WebServiceProxy -Credential $TestCreds_NonPriv
Currently, I'm interested in two methods that the service exposes, "SaveAttributes" and "GetAllAttributes", wsdl definitions as here:
<xsd:element name="SaveAttributes">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" name="Id" nillable="true" type="xsd:string"/>
<xsd:element minOccurs="0" name="attributes" nillable="true" type="q5:ArrayOfKeyValueOfstringstring"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GetAllAttributes">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" name="Id" nillable="true" type="xsd:string"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
<xsd:element name="GetAllAttributesResponse">
<xsd:complexType>
<xsd:sequence>
<xsd:element minOccurs="0" name="GetAllAttributesResult" nillable="true" type="q2:ArrayOfKeyValueOfstringstring"/>
</xsd:sequence>
</xsd:complexType>
</xsd:element>
I've successfully used the GetAllAttributes function via :
$websvc.GetAllAttributes('someid')
and this returns me an object which is an array of key value pairs like this :
Key Value
--- -----
ID 01
PERSONA [email protected]
NAME GodEater's real name
If I wish to create a new object on the Web Service, I have to call the "SaveAttributes" function with two parameters, a new "ID" as a string and an Array of Key/Value pairs for the rest of the attributes, and this is where I'm stumped. I'm unable to create a powershell object which gets successfully serialized to the service. What I tried was this:
[WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring[]]$newentity = @(
@{Key='PERSONA';Value='[email protected]'},
@{Key='NAME';Value='Someone Elses Real Name'}
)
$WebSvc.SaveAttributes('02',$newentity)
But what I get this is this rather perplexing error:
Cannot convert argument "attributes", with value: "WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring[]", for "SaveAttributes" to type
"WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring[]": "Cannot convert the "WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring" value of type
"WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring" to type "WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring"."
At line:1 char:1
+ $WebSvc.SaveAttributes('02',$newentity)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument
Now, looking at what the GetAllAttributes returned to me, which should be the same sort of object as I try to feed into the 'attributes' argument of the SaveAttributes method, it seems to serialize slightly differently to the object I've constructed myself.
Result from GetAllAttributes when serialized:
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring[]</T>
<T>System.Array</T>
<T>System.Object</T>
</TN>
<LST>
<Obj RefId="1">
<TN RefId="1">
<T>WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring</T>
<T>System.Object</T>
</TN>
<ToString>WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring</ToString>
<Props>
<S N="Key">ID</S>
<S N="Value">01</S>
</Props>
</Obj>
<Obj RefId="2">
<TNRef RefId="1" />
<ToString>WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring</ToString>
<Props>
<S N="Key">PERSONA</S>
<S N="Value">[email protected]</S>
</Props>
</Obj>
<Obj RefId="3">
<TNRef RefId="1" />
<ToString>WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring</ToString>
<Props>
<S N="Key">NAME</S>
<S N="Value">GodEater's real name</S>
</Props>
</Obj>
</LST>
</Obj>
</Objs>
Whilst the object I've created serializes to this:
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Collections.Hashtable</T>
<T>System.Object</T>
</TN>
<DCT>
<En>
<S N="Key">PERSONA</S>
<S N="Value"></S>
</En>
</DCT>
</Obj>
</Objs>
<Objs Version="1.1.0.1" xmlns="http://schemas.microsoft.com/powershell/2004/04">
<Obj RefId="0">
<TN RefId="0">
<T>System.Collections.Hashtable</T>
<T>System.Object</T>
</TN>
<DCT>
<En>
<S N="Key">NAME</S>
<S N="Value">Someone Elses Real Name</S>
</En>
</DCT>
</Obj>
</Objs>
Which seems to lack the wrapping around the members of the array, and seems instead to have each item in the array as a standalone object.
Anyone have any ideas?
It seems to be a common problem of passing complex custom types to web service methods in Powershell. Here they recommend to add '-Class' parameter to New-WebServiceProxy: https://groups.google.com/forum/#!msg/microsoft.public.windows.powershell/JWB5yueLtrg/k0zeUUxAkTMJ
In my case it did not help - seems this solution is unstable too. I finally had to use autogenerated namespace to avoid this problem.
Web service proxy should be created without namespace:
$webSvc = New-WebServiceProxy -Uri $uri
Then you create your array in the autogenerated namespace:
$newentity = New-Object -TypeName ($webSvc.GetType().Namespace + '.ArrayOfKeyValueOfstringstringKeyValueOfstringstring[]') -ArgumentList 2
$newentity[0] = New-Object -TypeName ($webSvc.GetType().Namespace + '.ArrayOfKeyValueOfstringstringKeyValueOfstringstring')
$newentity[0].Key = 'key0'
$newentity[0].Value = 'value0'
$newentity[1] = New-Object -TypeName ($webSvc.GetType().Namespace + '.ArrayOfKeyValueOfstringstringKeyValueOfstringstring')
$newentity[1].Key = 'key1'
$newentity[1].Value = 'value1'
$WebSvc.SaveAttributes('02',$newentity)
Looks clumsy, but at least it worked for me.
Try forcing Key/Value pairs to be of the WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring type:
$Properties = @(
@{Key='PERSONA';Value='[email protected]'},
@{Key='NAME';Value='Someone Elses Real Name'}
)
[WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring[]]$newentity = $Properties | ForEach-Object {
New-Object -TypeName 'WebServiceProxy.ArrayOfKeyValueOfstringstringKeyValueOfstringstring' -Property $_
}
$WebSvc.SaveAttributes('02',$newentity)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With