【问题标题】:How to pass a switch parameter to another PowerShell script?如何将开关参数传递给另一个 PowerShell 脚本?
【发布时间】:2016-10-26 19:40:48
【问题描述】:

我有两个带有开关参数的 PowerShell 脚本:

编译工具1.ps1:

[CmdletBinding()]
param(
  [switch]$VHDL2008
)

Write-Host "VHDL-2008 is enabled: $VHDL2008"

编译.ps1:

[CmdletBinding()]
param(
  [switch]$VHDL2008
)

if (-not $VHDL2008)
{ compile-tool1.ps1            }
else
{ compile-tool1.ps1 -VHDL2008  }

如何在不编写大的 if..then..elsecase 语句的情况下将 switch 参数传递给另一个 PowerShell 脚本?

我不想将compile-tool1.ps1的参数$VHDL2008转换成bool类型,因为这两个脚本都是前端脚本(用户使用)。后者是多个compile-tool*.ps1 脚本的高级包装器。

【问题讨论】:

    标签: powershell parameter-passing


    【解决方案1】:

    根据 power shell 团队的博客(下面的链接),从 V2 开始就有一种称为 splatting 的技术。基本上,您使用自动变量@PsBoundParameters 来转发所有参数。 Microsoft Docs 文章(下面的链接)中解释了有关喷溅的详细信息以及 @ 和 $ 之间的区别。

    例子:

    父.ps1

    #Begin of parent.ps1     
    param(
        [Switch] $MySwitch
        )
    
     Import-Module .\child.psm1     
    
    Call-Child @psBoundParameters
    #End of parent.ps1
    

    child.psm1

    # Begin of child.psm1
    function Call-Child {
        param(
            [switch] $MySwitch
        )
    
        if ($MySwitch){
            Write-Output "`$MySwitch was specified"
        } else {
            Write-Output "`$MySwitch is missing"
        }
    }
    #End of child.psm1
    

    现在我们可以使用或不使用开关来调用父脚本

    PS V:\sof\splatting> .\parent.ps1 
    $MySwitch is missing
    
    PS V:\sof\splatting> .\parent.ps1 -MySwitch
    $MySwitch was specified
    
    PS V:\sof\splatting> 
    

    更新

    在我最初的答案中,我采购了孩子而不是将其作为模块导入。似乎将另一个脚本采购到原始脚本中只会使父级的变量对所有子级可见,因此这也将起作用:

    # Begin of child.ps1
    function Call-Child {
        if ($MySwitch){
            Write-Output "`$MySwitch was specified"
        } else {
            Write-Output "`$MySwitch is missing"
        }
    
    }
    #End of child.ps1
    

    #Begin of parent.ps1     
    param(
        [Switch] $MySwitch
        )
    
    . .\child.ps1    
    
     Call-Child # Not even specifying @psBoundParameters   
    #End of parent.ps1
    

    也许,这不是制作程序的最佳方式,但是,这就是它的工作方式。

    About Splatting(Microsoft Docs)

    How and Why to Use Splatting (passing [switch] parameters)

    【讨论】:

    • 感谢您添加此解决方案。如果父母比孩子有更多的选择,或者如果父母和孩子之间的某些参数不同,在哪里添加/覆盖?
    • 如果函数作为模块导入,则变量是相互独立的(即如果在子函数中更改传递的参数,则不会影响父函数中对应的变量。)在采购的情况下呈现了一种不同的场景,您可以将所有变量视为全局变量,因此更改子变量中的变量将更改父变量中相同变量的值。
    【解决方案2】:

    您可以使用冒号语法在开关上指定$true$false

    compile-tool1.ps1 -VHDL2008:$true
    compile-tool1.ps1 -VHDL2008:$false
    

    所以只需传递实际值:

    compile-tool1.ps1 -VHDL2008:$VHDL2008
    

    【讨论】:

    • 参数-冒号-值语法是自 PS 版本 xx 以来的新语法,还是多年来我错过了此语法?
    • 你错过了很多年 :-)。我用 2.0 测试了它
    • 是需要下面提到的ispresent。否则参数始终存在(开关没有值?)
    • 只是偶然发现了这个,因为我遇到了同样的问题。我测试了一下:如果你通过-VHDL2008:$false,那么$VHDL2008.IsPresent会返回$false。
    • 这也可以在命令行上完成,但是您必须安排字符串$true/$false 以字面形式出现在命令行上,并带有美元符号。
    【解决方案3】:

    假设您正在迭代开发,很有可能在某些时候您将向主脚本添加其他开关和参数,这些开关和参数将被传递到下一个调用的脚本。使用之前的响应,您必须在每次添加参数时查找每个调用并重写该行。在这种情况下,您可以通过执行以下操作来避免开销,

    .\compile-tool1.ps1 $($PSBoundParameters.GetEnumerator() | ForEach-Object {"-$($_.Key) $($_.Value)"})

    自动变量$PSBoundParameters 是一个哈希表,其中包含显式传递给脚本的参数。

    请注意script.ps1 -SomeSwitch 等价于script.ps1 -SomeSwitch $truescript.ps1 等价于script.ps1 -SomeSwitch $false。因此,包含设置为 false 的开关相当于不包含它。

    【讨论】:

      【解决方案4】:

      另一种解决方案。如果您使用默认值 $false 声明参数:

      [switch] $VHDL2008 = $false
      

      那么下面的(没有值的-VHDL2008选项)会将$VHDL2008设置为$true:

      compile-tool1.ps1 -VHDL2008
      

      如果您省略 -VHDL2008 选项,则这会强制 $VHDL2008 使用默认的 $false 值:

      compile-tool1.ps1
      

      这些示例在从 bat 脚本调用 Powershell 脚本时很有用,因为将 $true/$false bool 从 bat 传递到 Powershell 很棘手,因为 bat 会尝试将 bool 转换为字符串,从而导致错误:

      Cannot process argument transformation on parameter 'VHDL2008'. 
      Cannot convert value "System.String" to type "System.Management.Automation.SwitchParameter". 
      Boolean parameters accept only Boolean values and numbers, such as $True, $False, 1 or 0.
      

      【讨论】:

      • 这个答案没有回答我的问题,即在另一个 powershell 脚本中调用一个 powershell 脚本。默认参数不起作用。我没有使用过时的 Windows 批处理 shell...
      【解决方案5】:

      试试

      compile-tool1.ps1 -VHDL2008:$VHDL2008.IsPresent 
      

      【讨论】:

      • 我为什么要使用额外的.IsPresent
      • 欢迎进行一些解释,但它“获取一个指示参数是否在命令行上指定的值。”(来自msdn.microsoft.com/en-us/library/…
      • ... 但它是一个开关参数。据我所知,它总是被定义的。如果没有定义$VHDL2008,你会得到一个NullReference 异常,因为$null 没有方法IsPresent。我说的对吗?
      • 我已经对此进行了测试,-VHDL2008:$false 或根本没有 -VHDL2008 开关,$VHDL2008.IsPresent$false :)(当然还有 $true-VHDL2008 或 @987654332 @)
      • 在某些情况下您必须使用 .isPresent (它可能已经通过 -verbose 或类似的东西),但在这种情况下似乎完全是多余的 :)
      猜你喜欢
      • 2012-04-13
      • 1970-01-01
      • 2011-08-01
      • 1970-01-01
      • 2017-05-08
      • 1970-01-01
      • 2014-04-08
      相关资源
      最近更新 更多