1

I have a PowerShell (v2) script, that I want to be able to call itself, but have that second invocation run on a remote computer. I need to be able to pass several (~10) named parameters to the second invocation.

In the past, when working with jobs, I've used "splatting" to create a hashmap of values and pass them along to the job. I've tried something similar with Invoke-Command, but it isn't working as expected. I created a simple script to illustrate my point, save this as test.ps1. If not the remote machine, print the variables, and call the remote invocation, the remote invocation just prints what it received.

param([string]$paramA, [string]$paramB, [bool]$remote = $false)

if(!$remote)
{
    Write-Host "LOCAL: paramA is $paramA"
    Write-Host "LOCAL: paramB is $paramB"
    Write-Host "LOCAL: remote is $remote"
}
else
{
    Write-Host "REMOTE: paramA is $paramA"
    Write-Host "REMOTE: paramB is $paramB"
    Write-Host "REMOTE: remote is $remote"  
}

if(!$remote)
{
    $sess = New-PSSession -computername MACHINENAME -credential CREDENTIALS
    #w/o hashmap
    $responseObject = Invoke-Command -session $sess -FilePath .\test.ps1 -ArgumentList($paramA,$paramB,$true) -AsJob 

    #with hashmap (this doesn't work)
    #$arguments = @{paramA = $paramA; paramB = $paramB; remote = $true}
    #$responseObject = Invoke-Command -session $sess -FilePath .\test.ps1 -ArgumentList $arguments -AsJob 

    while($responseObject.State -ne "Completed")
    {
    }

    $result = Receive-Job -Id $responseObject.Id
    Write-Host  $result

    Remove-PSSession -Session $sess
}

Running the script I would see this, but uncommenting the hashmap part fails (never returns).

.\test.ps1  -paramA "First" -paramB "Second"
LOCAL: paramA is First
LOCAL: paramB is Second
LOCAL: remote is False
REMOTE: paramA is First
REMOTE: paramB is Second
REMOTE: remote is True

I've tried variations of this with scriptblocks, etc, but I'm missing something.

2 Answers 2

2

Unfortunately the ArgumentList parameter expects an array (of object) and not a hashtable (or hashmap as you say). So the hashtable gets assigned to the first parameter instead of being splatted across all the parameters. It would be nice if this worked. Consider submitting a suggestion on http://connect.microsoft.com.

Sign up to request clarification or add additional context in comments.

2 Comments

Is it acceptable to have a first parameter explicitly for this purpose? And replace the value of script variables if their name matches a key found in the hashtable?
You could do that but I think I would leave the parameters as-is except that I would not specify a type for the first param. And then if the object passed to the first param was a hashtable, I would enum the hashtable to set all the parameters - including the string value of the first parameter.
0

I added an additional parameter to the script (at position 0) and if that parameter is a HashTable, update the local variables with those found in the hashtable. It works now. Thanks all.

param($paramMap, [string]$paramA, [string]$paramB, [bool]$remote = $false)

...

Function configureVariables()
{
    if($paramMap.GetType().FullName -eq "System.Collections.HashTable")
    {
        $variables = get-variable -Scope "Script"

        foreach($param in $paramMap.GetEnumerator())
        {
            foreach($variable in $variables)
            {
                if($param.key -eq $variable.Name)
                {
                    $variable.Value = $param.value
                }
            }
        }
    }
}

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.