如何将开关参数传递给另一个 PowerShell 脚本?
Posted
技术标签:
【中文标题】如何将开关参数传递给另一个 PowerShell 脚本?【英文标题】:How to pass a switch parameter to another PowerShell script? 【发布时间】: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..else
或 case
语句的情况下将 switch 参数传递给另一个 PowerShell 脚本?
我不想将compile-tool1.ps1
的参数$VHDL2008
转换成bool
类型,因为这两个脚本都是前端脚本(用户使用)。后者是多个compile-tool*.ps1
脚本的高级包装器。
【问题讨论】:
【参考方案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 $true
和script.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 或类似的东西),但在这种情况下似乎完全是多余的 :)以上是关于如何将开关参数传递给另一个 PowerShell 脚本?的主要内容,如果未能解决你的问题,请参考以下文章
如何将空参数传递给 msdeploy powershell deploy 命令
如何使用 Terraform local-exec 将命名参数传递给 powershell 脚本?
PowerShell 将命名参数传递给 ArgumentList