PowerShell在Invoke-Command上发送Argumentlist

时间:2015-01-30 11:04:31

标签: powershell argument-passing invoke-command

如何使用哈希表中收集的参数与ArgumentList上的Invoke-Command一起使用?

$CopyParams = @{
    Source      = 'E:\DEPARTMENTS\CBR\SHARE\Target'
    Destination = 'E:\DEPARTMENTS\CBR\SHARE\Target 2'
    Structure   = 'yyyy-MM-dd'
}
Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock ${Function:Copy-FilesHC} -ArgumentList @CopyParams

无论我尝试什么,它总是抱怨来源':

Cannot validate argument on parameter 'Source'. The "Test-Path $_" validation script for the argument with
 value "System.Collections.Hashtable" did not return true. Determine why the validation script failed

这个blog谈到了类似的问题,但我无法让它发挥作用。

Copy-Item内的简单Invoke-Command也是如此,例如:

Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock {Copy-Item} -ArgumentList @CopyParams

Invoke-Command : Missing an argument for parameter 'ArgumentList'. Specify a parameter of type 'System.Obj
ect[]' and try again.
At line:11 char:89
+ ... ck {Copy-Item} -ArgumentList @CopyParams

感谢您的帮助。

6 个答案:

答案 0 :(得分:5)

One-liner,用于转换远程脚本以接受来自散列的命名参数。

给出一个你想要调用的脚本块:

$Options = @{
    Parameter1 = "foo"
    Parameter2 = "bar"
}

Invoke-Command -ComputerName REMOTESERVER -ArgumentList $Options -ScriptBlock {
    param(
        $Parameter1,
        $Parameter2
    )
    #Script goes here, this is just a sample
    "ComputerName: $ENV:COMPUTERNAME"
    "Parameter1: $Parameter1"
    "Parameter2: $Parameter2"
} 

您可以像这样进行转换

Invoke-Command -Computername REMOTESERVER -ArgumentList $Options -ScriptBlock {param($Options)&{
    param(
        $Parameter1,
        $Parameter2
    )
    #Script goes here, this is just a sample
    "ComputerName: $ENV:COMPUTERNAME"
    "Parameter1: $Parameter1"
    "Parameter2: $Parameter2"
} @Options}

发生了什么事?基本上我们像这样包装原始脚本块:

{param($Options)& <# Original script block (including {} braces)#> @options }

这使得原始脚本阻止了一个匿名函数,并创建了一个带有参数$Options的外部脚本块,除了调用内部脚本块之外什么都不做,传递@options来散列哈希值。

答案 1 :(得分:2)

这是接近传递命名参数的一种方法:

function Copy-FilesHC 
{
  param ($Source,$Destination,$Structure)
  "Source is $Source"
  "Desintation is $Destination"
  "Structure is $Structure"
  }


$CopyParams = @{
    Source      = 'E:\DEPARTMENTS\CBR\SHARE\Target'
    Destination = "'E:\DEPARTMENTS\CBR\SHARE\Target 2'" #Nested quotes required due to embedded space in value.
    Structure   = 'yyyy-MM-dd'
}

$SB = [scriptblock]::Create(".{${Function:Copy-FilesHC}} $(&{$args}@CopyParams)")

Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock $SB

基本上,您从调用的脚本中创建一个新的脚本块,参数从哈希表中映射到该脚本块。所有内容都已经在脚本块中,并且值已展开,因此没有参数列表可以传递。

答案 2 :(得分:0)

我找到了解决方法,但您必须确保位于模块文件中的Advanced function在本地会话中预先加载。所以它可以用在远程会话中。我为此写了一个小帮手函数。

Function Add-FunctionHC {
    [CmdletBinding(SupportsShouldProcess=$True)]
    Param(
        [String]$Name
    )
    Process {
        Try {
            $Module = (Get-Command $Name -EA Stop).ModuleName
        }
        Catch {
            Write-Error "Add-FunctionHC: Function '$Name' doesn't exist in any module"
            $Global:Error.RemoveAt('1')
            Break
        }
        if (-not (Get-Module -Name $Module)) {
            Import-Module -Name $Module
        }
    }
}

# Load funtion for remoting
Add-FunctionHC -Name 'Copy-FilesHC'

$CopyParams = @{
    Source      = 'E:\DEPARTMENTS\CBR\SHARE\Target\De file.txt'
    Destination = 'E:\DEPARTMENTS\CBR\SHARE\Target 2'
}

$RemoteFunctions = "function Copy-FilesHC {${function:Copy-FilesHC}}" #';' seperated to add more

Invoke-Command -ArgumentList $RemoteFunctions -ComputerName 'SERVER' -Credential $Cred -ScriptBlock {
    Param (
        $RemoteFunctions
    )
    . ([ScriptBlock]::Create($RemoteFunctions))
    $CopyParams = $using:CopyParams
    Copy-FilesHC @CopyParams
}

最大的好处是您不需要在脚本中复制完整的功能,它可以保留在模块中。因此,当您将模块中的某些内容更改为该功能时,它也将在远程会话中可用,而无需更新您的脚本。

答案 3 :(得分:0)

我最近遇到了类似的问题,并通过利用$ using变量范围(更多关于here)来构建调用内部的散列(或重建散列)来解决它。

它看起来像这样:

$Source      = 'E:\DEPARTMENTS\CBR\SHARE\Target'
$Destination = 'E:\DEPARTMENTS\CBR\SHARE\Target 2'
$Structure   = 'yyyy-MM-dd'

Invoke-Command -Credential $Cred -ComputerName 'SERVER' -ScriptBlock {
    $CopyParms= @{ 
        'Source'=$Using:Source
        'Destination'=$Using:Destination
        'Structure'=$Using:Structure
    }
    Function:Copy-FilesHC @CopyParms
}

答案 4 :(得分:0)

这对我有用:

$hash = @{
    PARAM1="meaning of life"
    PARAM2=42
    PARAM3=$true
}
$params = foreach($x in $hash.GetEnumerator()) {"$($x.Name)=""$($x.Value)"""}

答案 5 :(得分:-1)

我知道这已经很晚了,但我遇到了同样的问题并找到了适合我的解决方案。将它分配给scriptblock中的变量然后使用该变量进行splat并没有显示任何问题。

以下是一个例子:

$param=@{"parameter","value"}
invoke-command -asjob -session $session -ScriptBlock {$a=$args[0];cmdlet @a } -ArgumentList $param