I do not mean to sound too cute with the question, but that really is the question at hand. Consider the following two functions defined in a PowerShell module Test.psm1 installed under $env:PSModulePath:
function Start-TestAsync
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
Start-Job { Start-Test -Name $using:Name -Block $using:Block }
}
function Start-Test
{
[CmdletBinding()]
param([ScriptBlock]$Block, [string]$Name = '')
# do some work here, including this:
Invoke-Command -ScriptBlock $Block
}
After importing the module, I can then run the synchronous function...
PS> Start-Test -Name "My Test" -Block { ps | select -first 9 }
...and it displays appropriate output from Get-Process.
However, when I attempt to run the asynchronous version...
PS> $testJob=Start-TestAsync -Name "My Test" -Block { ps | select -first 9 }
...and then review its output...
PS> Receive-Job $testJob
... it fails at just bringing in the parameter to the Start-Test function, reporting it cannot convert a String to a ScriptBlock. Thus, -Block $using:Block
is passing a String rather than a ScriptBlock!
After some experimentation, I did find a workaround. If I modify Start-Test so that the type of the $Block parameter is [string] instead of [ScriptBlock] -- and then convert that string back to a block to feed to Invoke-Command...
function Start-Test
{
[CmdletBinding()]
param([string]$Block, [string]$Name = '')
$myBlock = [ScriptBlock]::Create($Block)
Invoke-Command -ScriptBlock $myBlock
}
I then obtain the correct result when I run the same commands from above:
PS> $testJob=Start-TestAsync -Name "My Test" -Block { ps | select -first 9 }
PS> Receive-Job $testJob
Is the using
scope working correctly in my initial example (converting a ScriptBlock to a string)? The limited documentation on it (about_Remote_Variables, about_Scopes) offers little guidance.
Ultimately, is there a way to make Start-Test work when its $Block parameter is typed as a [ScriptBlock]?