Search code examples
.netpowershellparallel-processingf#jobs

Receive-Job not returning same type as calling the script block without a Job


I am loading an F# dll that defines certain types in a powershell script, in order to create a web request with a body to send it to a web service made in F#. One of those types is the following:

type Resource =
| VM of VMResource
| Unit of UnitResource 

With

type VMResource = {
    ComputerName: string
    Ip: string
    Attributes: string[]
}

type UnitResource = {
    UnitName: string
    Ip: string
    Username: string
    Password: string
    Attributes: string[]
}

When I run the following small powershell snippet, the request's response is actually of type GetResourcesResponse (which is a record type containing an Array of Resource), which is what I want:

Add-Type -Path "pathtomydll.dll"

$fullRequestUrl = "http://localhost:2121/Resources/Get"
$body = "{`"Id`":`"Test`",`"RequestedResources`":[{`"ResourceType`":{`"Case`":`"VM`"},`"Attributes`":[`"A1`",`"A2`"]},{`"ResourceType`":{`"Case`":`"Unit`"},`"Attributes`":[]}]}"

$resp = Invoke-WebRequest $fullRequestUrl -Method Post -Body $body -ContentType "application/json"
$obj = [ServerProtocolTypes+GetResourcesResponse]::FromJson($resp)
$obj.GetType() # GetResourcesResponse

Unfortunately, when I try to run the same code in a Job, I get a PSObject type with a property which is an Array of string representation of my Resource type (for example: ResourceTypes+Resource+VM), which doesn't contain any information about the VMResource or UnitResource:

Add-Type -Path "pathtomydll.dll"

$fullRequestUrl = "http://localhost:2121/Resources/Get"
$body = "{`"Id`":`"Test`",`"RequestedResources`":[{`"ResourceType`":{`"Case`":`"VM`"},`"Attributes`":[`"A1`",`"A2`"]},{`"ResourceType`":{`"Case`":`"Unit`"},`"Attributes`":[]}]}"

$job = Start-Job -ScriptBlock { param($url, $reqBody) Add-Type -Path "pathtomydll.dll"; $resp = Invoke-WebRequest $url -Method Post -Body $reqBody -ContentType "application/json"; return [ServerProtocolTypes+GetResourcesResponse]::FromJson($resp) } -ArgumentList ($fullRequestUrl, $body)
Wait-Job $job
$obj = Receive-Job $job
$obj.GetType() # PSObject

In this case, $obj is an array of string, with one entry being ResourceTypes+Resource+VM and the other being ResourceTypes+Resource+Unit.

Is there any way for me to get back my GetResourcesResponse object back from the Job instead of a PSObject that contains an array of string?


Solution

  • Per the comments:

    I think the problem is that output from Jobs is serialized when it's returned. You can run parallel processes and retain the native object types by using runspaces instead of jobs.