powershellpowershell-5.1

How to recreate a ScriptBlock serialized to a String when passed into Start-Job via -ArgumentList?


I want to pass a ScriptBlock as an argument into a Start-Job ScriptBlock. I understand that [ScriptBlock] is serialized to a string for safety when passed into a job. So, I need to deserialize it. I've tried using [ScriptBlock]::Create() but it doesn't seem to process the $($args[0].cheese) correctly.

This is a simplied version of what I'm doing.

function Format-Text {
    [CmdletBinding()]
    param([Parameter(Mandatory, ValueFromPipeline)][Object]$InputObject,
          [Parameter(Mandatory)][ScriptBlock]$Formatter)
    Write-Host ($Formatter.Invoke($InputObject))
}

$formatter = {"My favourite cheese is: $($args[0].cheese)"}
$testObject = [PSCustomObject]@{cheese = 'cheddar'}

Format-Text -InputObject $testObject -Formatter $formatter


# stuff before this is just to demonstrate that it works outside of Start-Job 


$job = Start-Job -ArgumentList $testObject,$formatter.ToString() -ScriptBlock {
    param ([String]$Obj,
           [String]$Fmtr)

    function Format-Text {
        [CmdletBinding()]
        param([Parameter(Mandatory, ValueFromPipeline)][Object]$InputObject,
              [Parameter(Mandatory)][ScriptBlock]$Formatter)
        Write-Host ($Formatter.Invoke($InputObject))
    }

    $sb = [ScriptBlock]::Create($Fmtr)

    Format-Text -InputObject $Obj -Formatter $sb
}

# clean up

do { Start-Sleep -Milliseconds 500 } until ($job.State -ne 'Running')
Receive-Job $job; Remove-Job $job

The output is:

My favourite cheese is: cheddar
My favourite cheese is: 

How can I deserialize the string such that the $($args[0].cheese) works?

The example above is pared down to the bone, the real script is 00s of lines and many functions. I don't want to rewrite the function if I can avoid it because it's used in many other locations.

I'm running the built-in PowerShell 5.1.


Solution