80

我有一个可以通过 Invoke-Command 远程运行的脚本

Invoke-Command -ComputerName (Get-Content C:\Scripts\Servers.txt) `
               -FilePath C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1

只要我使用默认参数,它就可以正常工作。但是,该脚本有 2 个名为 [switch] 的参数(-Debug 和 -Clear)

如何通过 Invoke-Command 传递切换的参数?我已经尝试过 -ArgumentList 但我遇到了错误,所以我必须有语法错误或其他东西。任何帮助是极大的赞赏。

4

5 回答 5

100

-ArgumentList基于与scriptblock命令一起使用,例如:

Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True

当你用 a 调用它时,-File它仍然像一个哑弹数组一样传递参数。我已经提交了一个功能请求,将其添加到命令中(请投票)。

所以,你有两个选择:

如果您有一个看起来像这样的脚本,位于可从远程计算机访问的网络位置(请注意,这-Debug是隐含的,因为当我使用该Parameter属性时,脚本会隐式获取 CmdletBinding,因此,所有公共参数):

param(
   [Parameter(Position=0)]
   $one
,
   [Parameter(Position=1)]
   $two
,
   [Parameter()]
   [Switch]$Clear
)

"The test is for '$one' and '$two' ... and we $(if($DebugPreference -ne 'SilentlyContinue'){"will"}else{"won't"}) run in debug mode, and we $(if($Clear){"will"}else{"won't"}) clear the logs after."

如果$Clear你想调用它,你可以使用以下任一Invoke-Command语法:

icm -cn (gc Servers.txt) { 
    param($one,$two,$Debug=$False,$Clear=$False)
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 @PSBoundParameters
} -ArgumentList "uno", "dos", $false, $true

在那一个中​​,我在脚本块中复制了我关心的所有参数,以便我可以传递值。如果我可以对它们进行硬编码(这是我实际所做的),则无需这样做并使用PSBoundParameters,我可以传递我需要的那些。在下面的第二个示例中,我将传递 $Clear 一个,只是为了演示如何传递开关参数:

icm -cn $Env:ComputerName { 
    param([bool]$Clear)
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $(Test-Path $Profile)

另一种选择

如果脚本在您的本地机器上,并且您不想将参数更改为位置参数,或者您想指定公共参数的参数(因此您无法控制它们),您将希望获取的内容该脚本并将其嵌入到您的脚本中:

$script = [scriptblock]::create( @"
param(`$one,`$two,`$Debug=`$False,`$Clear=`$False)
&{ $(Get-Content C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -delimiter ([char]0)) } @PSBoundParameters
"@ )

Invoke-Command -Script $script -Args "uno", "dos", $false, $true

后记:

如果您确实需要为脚本名称传递一个变量,您将做什么取决于该变量是在本地还是远程定义的。一般来说,如果你有一个变量$Script或环境变量$Env:Script与一个脚本的名称,你可以用调用运算符(&)执行它:&$Script&$Env:Script

如果它是已经在远程计算机上定义的环境变量,那就是它的全部内容。如果它是一个局部变量,那么您必须将它传递给远程脚本块:

Invoke-Command -cn $Env:ComputerName { 
    param([String]$Script, [bool]$Clear)
    & $ScriptPath "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, (Test-Path $Profile)
于 2010-11-19T14:39:38.907 回答
7

我对此的解决方案是动态编写脚本块[scriptblock]:Create

# Or build a complex local script with MARKERS here, and do substitutions
# I was sending install scripts to the remote along with MSI packages
# ...for things like Backup and AV protection etc.

$p1 = "good stuff"; $p2 = "better stuff"; $p3 = "best stuff"; $etc = "!"
$script = [scriptblock]::Create("MyScriptOnRemoteServer.ps1 $p1 $p2 $etc")
#strings get interpolated/expanded while a direct scriptblock does not

# the $parms are now expanded in the script block itself
# ...so just call it:
$result = invoke-command $computer -script $script

传递参数非常令人沮丧,尝试了各种方法,例如 、
-arguments$using:p1,这只是按预期工作,没有任何问题。

由于我以这种方式控制创建(或脚本文件)的字符串的内容和变量扩展,[scriptblock]因此“invoke-command”咒语没有真正的问题。

(这不应该那么难。:))

于 2016-05-23T20:01:54.457 回答
6

我怀疑它是自创建此帖子以来的一项新功能 - 使用 $Using:var 将参数传递给脚本块。如果脚本已经在机器上或相对于机器的已知网络位置,那么它是一个简单的传递参数的方法

以主要示例为例:

icm -cn $Env:ComputerName { 
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
于 2017-04-20T09:02:16.950 回答
3

我需要一些东西来调用带有命名参数的脚本。我们的政策是不使用参数的顺序定位并要求参数名称。

我的方法与上面的方法类似,但获取您要调用的脚本文件的内容并发送包含参数和值的参数块。

这样做的优点之一是您可以选择将哪些参数发送到脚本文件,从而允许使用默认值的非强制性参数。

假设在具有以下参数块的临时路径中有一个名为“MyScript.ps1”的脚本:

[CmdletBinding(PositionalBinding = $False)]
param
(
    [Parameter(Mandatory = $True)] [String] $MyNamedParameter1,
    [Parameter(Mandatory = $True)] [String] $MyNamedParameter2,
    [Parameter(Mandatory = $False)] [String] $MyNamedParameter3 = "some default value"
)

这就是我从另一个脚本调用这个脚本的方式:

$params = @{
    MyNamedParameter1 = $SomeValue
    MyNamedParameter2 = $SomeOtherValue
}

If ($SomeCondition)
{
    $params['MyNamedParameter3'] = $YetAnotherValue
}

$pathToScript = Join-Path -Path $env:Temp -ChildPath MyScript.ps1

$sb = [scriptblock]::create(".{$(Get-Content -Path $pathToScript -Raw)} $(&{
        $args
} @params)")
Invoke-Command -ScriptBlock $sb

我在很多场景中都使用过它,而且效果非常好。您偶尔需要做的一件事是在参数值分配块周围加上引号。当值中有空格时,总是会出现这种情况。

例如,此参数块用于调用将各种模块复制到 PowerShell 使用的C:\Program Files\WindowsPowerShell\Modules包含空格字符的标准位置的脚本。

$params = @{
        SourcePath      = "$WorkingDirectory\Modules"
        DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
    }

希望这可以帮助!

于 2016-10-27T14:19:31.383 回答
0

这是一个不幸的情况。位置参数起作用。

# test.ps1
param($myarg1, $myarg2, $myarg3)

"myarg1 $myarg1"
"myarg2 $myarg2"
"myarg3 $myarg3"
# elevated prompt
invoke-command localhost test.ps1 -args 1,$null,3

myarg1 1
myarg2
myarg3 3

或者您可以硬编码默认值。

# test2.ps1
param($myarg='foo2')

dir $myarg
invoke-command localhost test2.ps1

Cannot find path 'C:\Users\js\Documents\foo2' because it does not exist.

或者在那里复制脚本:

$s = New-PSSession localhost
copy-item test2.ps1 $home\documents -ToSession $s
icm $s { .\test2.ps1 -myarg foo3 }

Cannot find path 'C:\Users\js\Documents\foo3' because it does not exist.
于 2021-09-22T17:49:27.733 回答