web-dev-qa-db-ja.com

Invoke-Commandで名前付きパラメーターを渡すにはどうすればよいですか?

Invoke-Commandを介してリモートで実行できるスクリプトがあります

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

デフォルトのパラメータを使用している限り、問題なく機能します。ただし、スクリプトには2つの名前付き[スイッチ]パラメーターがあります(-Debugおよび-Clear)

Invoke-Commandを介して切り替えられたパラメーターを渡すにはどうすればよいですか? -ArgumentListを試しましたが、エラーが発生しているので、構文が間違っているか何かが必要です。どんな助けも大歓迎です。

71
Sean

-ArgumentListは、次のようなscriptblockコマンドでの使用に基づいています。

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

-Fileを指定して呼び出した場合、それはまだダムのスプラット配列のようなパラメーターを渡します。コマンドに追加するために 機能要求 を送信しました(投票してください)。

したがって、2つのオプションがあります。

リモートマシンからアクセスできるネットワーク上の場所にこのようなスクリプトがある場合(Parameter属性を使用すると、スクリプトが暗黙的にCmdletBindingを取得するため、-Debugが暗示されることに注意してください。すべての共通パラメーター):

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

その1つでは、値を渡すことができるように、scriptblockで重要なパラメーターをすべて複製しています。それらをハードコーディングできる場合(実際に行ったことです)、それを実行して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)

他のオプション

スクリプトがローカルマシン上にあり、パラメーターを定位置に変更したくない場合、または共通パラメーターであるパラメーターを指定したい場合(制御できない場合)、次の内容を取得します。そのスクリプトを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

PostScript:

スクリプト名に変数を渡す必要がある場合は、変数がローカルで定義されているかリモートで定義されているかによって異なります。一般に、スクリプト名を持つ変数$Scriptまたは環境変数$Env:Scriptがある場合、呼び出し演算子(&)で実行できます:&$Scriptまたは&$Env:Script

リモートコンピューターで既に定義されている環境変数の場合は、それだけです。 local変数の場合、リモートスクリプトブロックに渡す必要があります。

Invoke-Command -cn $Env:ComputerName { 
    param([String]$Script, [bool]$Clear)
    &$Script "uno" "dos" -Debug -Clear:$Clear
} -ArgumentList $ScriptPath, $(Test-Path $Profile)
92
Jaykul

これに対する私の解決策は、[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"呪文には実際の問題はありません。

(それほど難しくないはずです。:))

5
HerbM

この投稿が作成されて以来、私はその新機能を疑っています-$ Using:varを使用してスクリプトブロックにパラメーターを渡します。次に、スクリプトが既にマシン上にあるか、マシンに関連する既知のネットワークの場所にある場合、パラメーターを渡す簡単な方法

主な例を挙げると:

icm -cn $Env:ComputerName { 
    C:\Scripts\ArchiveEventLogs\ver5\ArchiveEventLogs.ps1 -one "uno" -two "dos" -Debug -Clear $Using:Clear
}
4
RobG

名前付きパラメーターでスクリプトを呼び出すために何かが必要でした。パラメータの順序付けを使用せず、パラメータ名を要求するというポリシーがあります。

私のアプローチは上記のものと似ていますが、呼び出すスクリプトファイルのコンテンツを取得し、パラメーターと値を含むパラメーターブロックを送信します。

この利点の1つは、スクリプトファイルに送信するパラメーターをオプションで選択できることです。これにより、既定では必須ではないパラメーターを使用できます。

次のパラメータブロックを持つ一時パスに「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

私はこれを多くのシナリオで使用しましたが、本当にうまく機能します。ときどき必要になることの1つは、パラメーター値割り当てブロックを引用符で囲むことです。これは、値にスペースが含まれる場合に常に当てはまります。

例えばこのparamブロックは、スペース文字を含むPowerShell C:\Program Files\WindowsPowerShell\Modulesが使用する標準の場所にさまざまなモジュールをコピーするスクリプトを呼び出すために使用されます。

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

お役に立てれば!

3
CarlR