我有一个可以通过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但是我遇到了错误所以我必须要有语法错误或者其他东西。非常感谢任何帮助。
答案 0 :(得分:90)
-ArgumentList
基于与 scriptblock 命令一起使用,例如:
Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True
当你使用-File
调用它时,它仍然传递参数,如愚蠢的splatted数组。我已经提交了feature request来添加命令(请将其投票)。
所以,你有两个选择:
如果您的脚本看起来像这样,则可以从远程计算机访问的网络位置(请注意,-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
在那个,我正在复制 scriptblock 中我关心的所有参数,所以我可以传递值。如果我可以对它们进行硬编码(这是我实际做的那样),就没有必要这样做并使用PSBoundParameters
,我可以通过我需要的那些。在下面的第二个例子中,我将传递$ Clear,只是为了演示如何传递开关参数:
icm -cn $Env:ComputerName {
param([bool]$Clear)
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $(Test-Path $Profile)
如果脚本在您的本地计算机上,并且您不想将参数更改为位置,或者您想要指定常用参数的参数(因此您无法控制它们),您将需要获取该脚本的内容并将其嵌入 scriptblock :
$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
或{{ 1}}
如果它是已经在远程计算机上定义的环境变量,那就是它的全部内容。如果它是 local 变量,那么你必须将它传递给远程脚本块:
&$Env:Script
答案 1 :(得分:5)
我的解决方案是使用[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”咒语没有真正的问题。
(应该不那么难。:))
答案 2 :(得分:4)
我怀疑自创建这篇文章以来它是一个新功能 - 使用$ Using:var将参数传递给脚本块。如果脚本已经在机器上或相对于机器的已知网络位置
,那么它就是一个简单的传递参数的物质以主要例子为例:
icm -cn $Env:ComputerName {
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
答案 3 :(得分: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
我在很多场景中都使用了它,它的效果非常好。 您偶尔需要做的一件事是在参数值赋值块周围加上引号。当值中有空格时,情况总是如此。
e.g。此param块用于调用脚本,该脚本将各种模块复制到PowerShell C:\Program Files\WindowsPowerShell\Modules
使用的包含空格字符的标准位置。
$params = @{
SourcePath = "$WorkingDirectory\Modules"
DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
}
希望这有帮助!