web-dev-qa-db-ja.com

PowerShell名前付きパラメーターをArgumentListに渡す

3つの名前付きパラメーターを受け入れるPowerShellスクリプトがあります。コマンドラインから同じものを渡す方法を教えてください。以下のコードを試しましたが、同じことが機能しません。値全体をP3のみに割り当てます。私の要件は、P1に1が含まれ、P2に2が含まれ、P3に3が割り当てられる必要があることです。

Invoke-Command -ComputerName server -FilePath "D:\test.ps1" -ArgumentList  {-P1 1 -P2 2 -P3 3}

以下はスクリプトファイルコードです。

Param (
    [string]$P3,
    [string]$P2,
    [string]$P1
)
Write-Output "P1 Value :" $P1
Write-Output "P2 Value:" $P2
Write-Output "P3 Value :" $P3
11
Parveen Kumar

1つのオプション:

$params = @{
P1 = 1
P2 = 2 
P3 = 3
}

$ScriptPath = 'D:\Test.ps1'

$sb = [scriptblock]::create(".{$(get-content $ScriptPath -Raw)} $(&{$args} @params)")

Invoke-Command -ComputerName server -ScriptBlock $sb
16
mjolinor

mjolinorによるコードはうまく機能しますが、理解するのに数分かかりました。

コードは単純なものになります-組み込みパラメーターを使用してスクリプトブロックのコンテンツを生成します。

&{
    Param (
        [string]$P3,
        [string]$P2,
        [string]$P1
    )
    Write-Output "P1 Value:" $P1
    Write-Output "P2 Value:" $P2
    Write-Output "P3 Value:" $P3
} -P1 1 -P2 2 -P3 3

次に、このスクリプトブロックがInvoke-Commandに渡されます。

コードを単純化するには:

".{$(get-content $ScriptPath -Raw)} $(&{$args} @params)"

$scriptContent = Get-Content $ScriptPath -Raw
$formattedParams = &{ $args } @params
# The `.{}` statement could be replaced with `&{}` here, because we don't need to persist variables after script call.
$scriptBlockContent = ".{ $scriptContent } $formattedParams"
$sb = [scriptblock]::create($scriptBlockContent)

基本的なC#実装を作成しましょう:

void Run()
{
    var parameters = new Dictionary<string, string>
    {
        ["P1"] = "1",
        ["P2"] = "2",
        ["P3"] = "3"
    };

    var scriptResult = InvokeScript("Test.ps1", "server", parameters)
    Console.WriteLine(scriptResult);
}

string InvokeScript(string filePath, string computerName, Dictionary<string, string> parameters)
{
    var innerScriptContent = File.ReadAllText(filePath);
    var formattedParams = string.Join(" ", parameters.Select(p => $"-{p.Key} {p.Value}"));
    var scriptContent = "$sb = { &{ " + innerScriptContent + " } " + formattedParams + " }\n" +
        $"Invoke-Command -ComputerName {computerName} -ScriptBlock $sb";

    var tempFile = Path.Combine(Path.GetTempPath(), Guid.NewGuid() + ".ps1");
    File.WriteAllText(tempFile, scriptContent);

    var psi = new ProcessStartInfo
        {
            FileName = "powershell",
            Arguments = $@"-ExecutionPolicy Bypass -File ""{tempFile}""",
            RedirectStandardOutput = true,
            UseShellExecute = false
        };

    var process = Process.Start(psi);
    var responseText = process.StandardOutput.ReadToEnd();

    File.Delete(tempFile);

    return responseText;
}

コードは一時的なスクリプトを生成し、それを実行します。

スクリプトの例:

$sb = {
    &{
        Param (
            [string]$P3,
            [string]$P2,
            [string]$P1
        )
        Write-Output "P1 Value:" $P1
        Write-Output "P2 Value:" $P2
        Write-Output "P3 Value:" $P3
     } -P1 1 -P2 2 -P3 3
}
Invoke-Command -ComputerName server -ScriptBlock $sb
5
Der_Meister

ハッシュテーブルを使用する:

icm -ComputerName test -ScriptBlock{$args} -ArgumentList @{"p1"=1;"p2"=2;"p3"=3} 
3
Loïc MICHEL

簡単な解決策は次のとおりです。

[PowerShell]::Create().AddCommand('D:\test.ps1').AddParameters(@{ P1 = 1; P2 = 2; P3 = 3 }).Invoke()

出力は次のとおりです。

PS C:\Windows\system32> [PowerShell]::Create().AddCommand('D:\test.ps1').AddParameters(@{ P1 = 1; P2 = 2; P3 = 3 }).Invoke()
P1 Value :
1
P2 Value:
2
P3 Value :
3
0
Haoshu

確かに、ハッシュテーブルを使用してください!

#TestPs1.ps1
Param (
    [string]$P3,
    [string]$P2,
    [string]$P1
)
Write-Output "P1 Value :" $P1
Write-Output "P2 Value:" $P2
Write-Output "P3 Value :" $P3
$params = @{
    P3 = 3
    P2 = 2
}
#(just to prove it doesn't matter which order you put them in)
$params["P1"] = 1;
#Trhough the use of the "Splat" operator, we can add parameters directly onto the module
& ".\TestPs1.ps1" @params

出力:

P1 Value :
1
P2 Value:
2
P3 Value :
3
0
Max Hay