Search code examples
powershellhashtablestart-job

Use hashtable as parameter when splatting?


I am trying to use Start-Job to launch a new Powershell script. The new script has several parameters (some optional, some not), so I want to make a hashtable and splat them. However, one of these parameters is itself a hash table. I am trying to start the job like this:

$MyStringParam = "string1"
$MyHashParam = @{}
$MyHashParam.Add("Key1", "hashvalue1")

$arguments = @{MyStringParam=$MyStringParam;MyHashParam=$MyHashParam}

Start-Job -Name "MyJob" -ScriptBlock ([scriptblock]::create("C:\myscript.ps1 $(&{$args} @arguments)"))

Whereupon I get this error in the new job:

Cannot process argument transformation on parameter 'arguments'. 
Cannot convert the "System.Collections.Hashtable" value of 
type "System.String" to type "System.Collections.Hashtable".

Looks like it's treating the value I want to pass in as a hash table as a string. For the life of me I can't figure out how to get around this. Can anyone help?


Solution

  • You will need to pass the variable into the scriptblock as a parameter of the scriptblock, and then splat that parameter to your second script. Something like this should work for you:

    Start-Job -Name "MyJob" -ScriptBlock {Param($PassedArgs);& "C:\myscript.ps1" @PassedArgs} -ArgumentList $Arguments
    

    I created the following script and saved it to C:\Temp\TestScript.ps1

    Param(
        [String]$InString,
        [HashTable]$InHash
    )
    ForEach($Key in $InHash.keys){
        [pscustomobject]@{'String'=$InString;'HashKey'=$Key;'HashValue'=$InHash[$Key]}
    }
    

    I then ran the following:

    $MyString = "Hello World"
    $MyHash = @{}
    $MyHash.Add("Green","Apple")
    $MyHash.Add("Yellow","Banana")
    $MyHash.Add("Purple","Grapes")
    
    $Arguments = @{'InString'=$MyString;'InHash'=$MyHash}
    
    $MyJob = Start-Job -scriptblock {Param($MyArgs);& "C:\Temp\testscript.ps1" @MyArgs} -Name "MyJob" -ArgumentList $Arguments | Wait-Job | Receive-Job
    Remove-Job -Name 'MyJob'
    $MyJob | Select * -ExcludeProperty RunspaceId | Format-Table
    

    It produced the expected results:

    String                               HashKey                              HashValue                          
    ------                               -------                              ---------                          
    Hello World                          Yellow                               Banana                             
    Hello World                          Green                                Apple                              
    Hello World                          Purple                               Grapes 
    

    The process of running the job will add a RunspaceId property to any objects returned, that is why I had to exclude that.