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

我有两个 PowerShell 脚本,它们有开关参数:

Compile-tool1. 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脚本的高级包装器。

36913 次浏览

试试看

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

您可以使用 冒号语法在交换机上指定 $true$false:

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

所以只要传递实际值:

compile-tool1.ps1 -VHDL2008:$VHDL2008

另一种解决方案。如果使用默认值 $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.

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

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

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

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

根据一个 power shell 团队的博客(下面的链接) ,自从 V2以来,有一种技术叫做 Splatting。基本上,您可以使用自动变量@psbound Parameter 来转发所有参数。关于飞溅的详细信息以及@和 $之间的区别在 Microsoft Docs 文章中有解释(链接如下)

例如:

家长1

#Begin of parent.ps1
param(
[Switch] $MySwitch
)


Import-Module .\child.psm1


Call-Child @psBoundParameters
#End of parent.ps1

小朋友1

# 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

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

关于 Splatting (MicrosoftDocs)

如何和为什么使用 Splatting (传递[开关]参数)