In a development team, I would like to have the same test scripts to be executed locally by a developper or remotely by our test platform.
Here is what I would like to use as premises for each script
# Test local/remote execution by reading C:\ directory
param(
[switch] $verbose,
[switch] $remote,
[string] $ip,
[string] $user,
[string] $password
#Add here script specific parameters
)
Write-Host "Command invokation incoming parameter count : " $psboundparameters.count
if ($remote) {
$Params = @{}
$RemoteParams = @{}
$pass = ConvertTo-SecureString -String $password -AsPlainText -Force
$Params.Credential = new-object -TypeName System.management.automation.PSCredential -argumentlist $user, $pass
$Params.ComputerName = $ip
$Params.FilePath = $MyInvocation.MyCommand.Name
$null = $psboundparameters.Remove('remote')
$null = $psboundparameters.Remove('ip')
$null = $psboundparameters.Remove('user')
$null = $psboundparameters.Remove('password')
foreach($psbp in $PSBoundParameters.GetEnumerator())
{
$RemoteParams.$($psbp.Key)=$psbp.Value
}
Write-Host $RemoteParams
Invoke-Command @Params @Using:RemoteParams
Exit
}
Write-Host "Command execution incoming parameters count : " $psboundparameters.count
# Here goes the test
Get-ChildItem C:\
However, when I execute this, I got the following error:
Invoke-Command : A positional parameter cannot be found that accepts argument '$null'.
It seems that @Using:RemoteParams is not the correct way of doing this, but I'm quite lost here. Thanks in advance
Here's my take on the problem of being able to do both local and remote execution using named parameters:
$IP = '192.168.0.1'
$User = 'Test User'
$Password = 'P@ssW0rd!'
$params = @{
IP = $IP
User = $User
Password = $Password
}
$command = 'new-something'
$ScriptBlock = [Scriptblock]::Create("$command $(&{$args} @Params)")
Start with a hash table of parameters, using local varibles, then use this:
[Scriptblock]::Create("$command $(&{$args} @Params)")
to create a script block of the command, with the parameters inline and the values already expanded. Now that script block is ready to be run locally (either by invocation with &
or dot-sourcing), or remotely using Invoke-Command
.
$ScriptBlock
new-something -IP: 192.168.0.1 -User: Test User -Password: P@ssW0rd!
No scoping with $Using:
or -argumentlist
required.
Edit: Here's an example using a script rather than a single command:
$path = 'c:\windows'
$filter = '*.xml'
$Params =
@{
Path = $path
Filter = $filter
}
$command = @'
{
Param (
[String]$path,
[String]$Filter
)
Get-childitem -Path $path -Filter $filter
}
'@
$ScriptBlock = [Scriptblock]::Create(".$command $(&{$args} @Params)")
To run it locally:
Invoke-Command $ScriptBlock
or just:
.$ScriptBlock
To run it remotely:
Invoke-Command -Scriptblock $ScriptBlock -ComputerName Server1