Invoke-Command で名前付きパラメータを渡すにはどうすればよいですか?
-
26-09-2019 - |
質問
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 を試しましたが、エラーが発生するため、構文が間違っているか何かがあると思われます。ご協力をよろしくお願いいたします。
解決
-ArgumentList
との使用に基づいています スクリプトブロック 次のようなコマンド:
Invoke-Command -Cn (gc Servers.txt) {param($Debug=$False, $Clear=$False) C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 } -ArgumentList $False,$True
で呼び出すと、 -File
それでも、パラメータは愚かな分割された配列のように渡されます。を提出しました 機能リクエスト それをコマンドに追加します (賛成票を投じてください)。
したがって、次の 2 つのオプションがあります。
リモート マシンからアクセスできるネットワーク上の場所に次のようなスクリプトがある場合 (注意してください) -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
, 必要なものだけを渡すことができます。以下の 2 番目の例では、スイッチ パラメーターを渡す方法を示すために $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)
&$Script "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, $(Test-Path $Profile)
他のヒント
これに対する私のソリューションは、[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コマンド」呪文とは本当の問題はありません。
(それは難しいことではありません。:))
私はその新機能を疑う - 使用$を使用してスクリプトブロックにパスパラメータ:VAR。次いで、パラメータを渡すために、その簡単な母校は、スクリプトがマシンまたはマシンの既知のネットワークロケーション相対
に既に提供されます主な例に取るとすると、それは次のようになります:
icm -cn $Env:ComputerName {
C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
私は、名前付きパラメータを使用してスクリプトを呼び出すために何かを必要としていました。私たちは、パラメータの序数位置を使用して、パラメータ名を必要としないという方針を持っています。
私のアプローチは、上記のものと似ていますが、呼び出したいというスクリプトファイルの内容を取得し、パラメータと値を含むパラメータブロックを送信します。
このの利点の一つは、あなたが、必要に応じてデフォルト値を持つ非必須パラメータを可能にするスクリプトファイルに送信するためにどのパラメータを選択することができるということです。
以下のパラメータブロックを持っている一時的なパスに「する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
私はシナリオの多くでこれを使用している、それは本当によく働きます。 あなたが時折行う必要があるということの一つは、パラメータ値割当ブロックの前後に引用符を入れています。これは、常に値にスペースが含まれている場合です。
例えば。このPARAMブロックは、空白文字が含まれているPowerShellのC:\Program Files\WindowsPowerShell\Modules
で使用される標準的な場所にコピーし、様々なモジュールをそのスクリプトを呼び出すために使用されます。
$params = @{
SourcePath = "$WorkingDirectory\Modules"
DestinationPath = "'$(Join-Path -Path $([System.Environment]::GetFolderPath('ProgramFiles')) -ChildPath 'WindowsPowershell\Modules')'"
}
希望このことができます!