Reputation: 447
I'm trying to get the Invoke-Command
cmdlet working with a CredSsp session by passing a locally defined function.
I have two local functions:
MyCopy
which just invokes Copy-Item cmdlet on passed params with additional switchesMyCopyReturn
which is the same as above, but in addition has return
statement at the endNow when I pass those functions to Invoke-Command
without -Session
parameter, they both succeed.
However, when specifying -Session
for Invoke-Command
, MyCopy
fails with following exception (2. case):
Cannot bind argument to parameter 'Path' because it is null.
+ CategoryInfo : InvalidData: (:) [Copy-Item], ParameterBindingValidationException
+ FullyQualifiedErrorId : ParameterArgumentValidationErrorNullNotAllowed,Microsoft.PowerShell.Commands.CopyItemCommand
+ PSComputerName : localhost
Could someone please explain why result of passing MyCopyReturn
is different from passing MyCopy
?
function MyCopy ($from, $to) {
Copy-Item $from $to -Force -Recurse -Verbose
}
function MyCopyReturn ($from, $to) {
Copy-Item $from $to -Force -Recurse -Verbose
return
}
$credential = Get-Credential
$computerName = 'localhost'
$session = New-PSSession -ComputerName $computerName -Credential $credential -Authentication Credssp
# src is a file
$src = "c:\sandbox\a\test"
# dest is a directory
$dest = "c:\sandbox\b"
# 1.
# MyCopy works fine without giving session
Invoke-Command -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
# 2.
# MyCopy DOESN'T WORK when session is given
Invoke-Command -Session $session -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
# 4.
# MyCopyReturn works fine without the session
Invoke-Command -ScriptBlock ${function:MyCopyReturn} -ArgumentList $src,$dest
# 3.
# MyCopyReturn works fine with session too
Invoke-Command -Session $session -ScriptBlock ${function:MyCopyReturn} -ArgumentList $src,$dest
Remove-PSSession $session
Upvotes: 2
Views: 3368
Reputation: 22132
I make some digging with ILSpy and can say, that the problem in the bug in ScriptBlock.GetPowerShell
method. It does not bind parameters properly, if them come not from param
block:
function f($Arg){write "`$Arg=`"$Arg`";`$Args=`"$Args`""}
function g{param($Arg) write "`$Arg=`"$Arg`";`$Args=`"$Args`""}
$Function:f.GetPowerShell('Test1','Test2').Invoke()
# $Arg="";$Args="Test1 Test2"
$Function:g.GetPowerShell('Test1','Test2').Invoke()
# $Arg="Test1";$Args="Test2"
As you can see, $Function:f.GetPowerShell('Test1','Test2')
bind both arguments to $Args
automatic variable and nothing get bound to $Arg
. So when you invoke this command
Invoke-Command -Session $session -ScriptBlock ${function:MyCopy} -ArgumentList $src,$dest
$from
and $to
does not get bound properly and cause error.
Why error does not happens when you not use -Session
parameter?
Looks like Invoke-Command
have to convert ScriptBlock
to PowerShell
to invoke command in remote session and that does not required when ScriptBlock
invoked locally.
Why MyCopyReturn
does not cause same error?
Not all ScripBlock
s can be converted to PowerShell by GetPowerShell
method (in particular, it is required that ScriptBlock
must have a single statement, having another statement return
violate this). If that is the case (GetPowerShell
throws ScriptBlockToPowerShellNotSupportedException
), than Invoke-Command
use some backup scenario to convert ScriptBlock
to PowerShell
and that scenario does not suffer from bug of GetPowerShell
method.
Upvotes: 1