PowerShell 将命名参数传递给 ArgumentList

Posted

技术标签:

【中文标题】PowerShell 将命名参数传递给 ArgumentList【英文标题】:PowerShell Pass Named parameters to ArgumentList 【发布时间】:2015-03-03 21:33:08 【问题描述】:

我有一个接受 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

【问题讨论】:

How do I pass named parameters with Invoke-Command? 的可能重复项 【参考方案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

【讨论】:

是的,我可以使用上面的代码实现结果。 您能否告诉我如何使用 C# 代码实现相同的目标,因为我的要求是从 C# 运行此 PowerShell 脚本。 抱歉,对 C# 不太了解,无法为您转换。 此代码运行良好,直到您将数组作为参数。发生这种情况时,您只需将“System.String[]”作为值,因为参数块在展开时有效地应用了 .ToString()。我还没有找到避免这种情况的可靠方法,如果有人有解决方案,我很乐意看到它! @CarlR - 试试 P3 = "@('a','b','c')"【参考方案2】:

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

【讨论】:

您能解释一下$(&amp;args) 的作用吗?我试图了解它如何与@params 结合为您提供类似“-P1 1 -P2 2 -P3 3”的字符串。 从内到外工作,$args 是一个脚本块,它简单地返回它给出的任何参数。 &args 执行脚本块。将其包装在 $() - $(&$args) 中使其成为子表达式,以便它在字符串中展开。因为给定的参数是一个哈希表,所以输出是一系列键/值对——当它被传递到脚本块时,喷溅操作的结果。【参考方案3】:

这是一个简单的解决方案:

[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

【讨论】:

只有这段代码返回了另一个外部函数的结果 Invoke-Command 由于执行而无法将获胜表单返回给我 我的表单在线程上,但您的代码运行良好。 是的,还有更多。您的解决方案不会破坏空格,不像 $sb = [scriptblock]::create(".$(get-content $ScriptPath -Raw) $(&$args @params)")【参考方案4】:

如果您尝试将 -FilePath 与命名参数 (-P1 1 -P2 2) 一起使用,那么我发现这会起作用。使用脚本块来运行文件,而不是使用 -FilePath。

Invoke-Command -ComputerName server -ScriptBlock & "D:\test.ps1" -P1 1 -P2 2 -P3 3

【讨论】:

【参考方案5】:

使用哈希表:

icm -ComputerName test -ScriptBlock$args -ArgumentList @"p1"=1;"p2"=2;"p3"=3 

【讨论】:

能否提供更多详细信息。 这不起作用——整个哈希表作为第一个参数传递。文档说参数需要是逗号分隔的列表(非关联数组)(source)。【参考方案6】:

确实使用哈希表!

#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

【讨论】:

【参考方案7】:

如果您愿意完全跳过 Invoke-Command...

您的脚本可能如下所示:

([string]$args).split('-') | % 
    if ($_.Split(' ')[0].ToUpper() -eq "P1")  $P1 = $_.Split(' ')[1]  
    elseif ($_.Split(' ')[0].ToUpper() -eq "P2")  $P2 = $_.Split(' ')[1] 
    elseif ($_.Split(' ')[0].ToUpper() -eq "P3")  $P3 = $_.Split(' ')[1]  


Write-Output "P1 Value :" $P1
Write-Output "P2 Value :" $P2
Write-Output "P3 Value :" $P3

你会这样称呼它:

D:\test.ps1 -P1 1 -P2 2 -P3 3

【讨论】:

以上是关于PowerShell 将命名参数传递给 ArgumentList的主要内容,如果未能解决你的问题,请参考以下文章

将 PowerShell 参数传递给 Process.Start

如何将开关参数传递给另一个 PowerShell 脚本?

如何将多个字符串参数传递给 PowerShell 脚本?

从 powershell.exe 将参数传递给脚本

将多个参数传递给Powershell中的函数变量[重复]

如何将命令行参数传递给 PowerShell ps1 文件