Second Life of a Hungarian SharePoint Geek

April 20, 2016

Reusing PSI Proxy Objects from PowerShell

Filed under: PowerShell, PS 2013, PSI — Tags: , , — Peter Holpar @ 22:06

Assume you create a PowerShell script that invokes PSI to perform some actions on Project Server. For example, creating a custom field as described in my former post. You save the script as a .ps1 file and invoke it from the PowerShell shell. Assume it has some parameters and your goal is to invoke it multiple times with various parameter sets. On of the first step in the script is of course the creation in the PSI proxy object, as shown in the original version:

$pwaUrl = "http://YourProjectServer/pwa"
$svcPath = "/_vti_bin/psi/CustomFields.asmx?wsdl"

$svcPSProxy = New-WebServiceProxy -Namespace PSIProxy -Uri ($pwaUrl + $svcPath) -UseDefaultCredential

later in your code you invoke a method on the proxy object:

$svcPSProxy.CreateCustomFields($customFieldDataSet, $false, $true)

On the first run of the script it performs the actions without error, however on the next (and on each later) run it gives you an exception like this:

Cannot convert argument "cfds", with value: "PSIProxy.CustomFieldDataSet", for
"CreateCustomFields" to type "PSIProxy.CustomFieldDataSet": "Cannot convert
the "PSIProxy.CustomFieldDataSet" value of type "PSIProxy.CustomFieldDataSet"
to type "PSIProxy.CustomFieldDataSet"."
At line:1 char:1
+ $svcPSProxy.CreateCustomFields($customFieldDataSet, $false, $true)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : NotSpecified: (:) [], MethodException
    + FullyQualifiedErrorId : MethodArgumentConversionInvalidCastArgument

Do you see the strange error message?

Cannot convert the "PSIProxy.CustomFieldDataSet" value of type "PSIProxy.CustomFieldDataSet" to type "PSIProxy.CustomFieldDataSet".

An object having a specific type cannot be converted to a type having the same type name. Very weird. PowerShell seems to cache the object types created dynamically by the New-WebServiceProxy cmdlet on the first run, and these types seem to be not compatible (at least, in the .NET-sense) with the ones created on the next runs. The single (or at least the most simple) solution seems to be to restart the shell after each run, but it is not very nice, to say the least.

Fortunately, I’ve found a better way in this thread for the “recycling” of the proxy object created on the first execution. Note, that the solution I find there is not the accepted answer as I wrote this post. See the answer from existenz7 on February 07, 2013 1:08 PM.

So I’ve changed the proxy creation part in my script to the form:

If ($global:svcPSProxy -eq $null)
{
  Write-Host "Connecting PSI proxy at $pwaUrl …"
  $global:svcPSProxy = New-WebServiceProxy -Namespace PSIProxy -Uri ($pwaUrl + $svcPath) -UseDefaultCredential
}
Else
{
  Write-Host "Reusing existing PSI proxy"
}

You can invoke the proxy method just like earlier:

$svcPSProxy.CreateCustomFields($customFieldDataSet, $false, $true)

Note: I typically omit this kind of proxy creation from my code posted here on the blog just not to disturb you with details that are not relevant to the problem discussed actually in the post. However, I suggest you to apply the same technique to avoid the type incompatibility issue mentioned above.

Leave a Comment »

No comments yet.

RSS feed for comments on this post. TrackBack URI

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Blog at WordPress.com.

%d bloggers like this: