如何在自定义cmdlet中正确使用-verbose和-debug参数
-
29-09-2019 - |
题
默认情况下,任何具有[cmdletBinding()]属性的任何命名函数接受-debug和-verbose(以及其他一些)参数,并且具有预定义的$ debug和$ debug和$ verbose变量。我要弄清楚的是如何将它们传递到在功能中被调用的其他CMDLET。
假设我有这样的cmdlet:
function DoStuff() {
[CmdletBinding()]
PROCESS {
new-item Test -type Directory
}
}
如果 -debug
或者 -verbose
被传递到我的功能中,我想传递该标志 new-item
cmdlet。正确执行此操作的模式是什么?
解决方案
也许听起来很奇怪,但是CMDLET没有简单的方法知道其冗长或调试模式。看一个相关的问题:
cmdlet如何知道何时应该调用writeverbose()?
一个不是完美的,但实际上合理的选择是引入您自己的CMDLET参数(例如 $MyVerbose
, $MyDebug
)并明确使用它们。
function DoStuff {
[CmdletBinding()]
param
(
# unfortunately, we cannot use Verbose name with CmdletBinding
[switch]$MyVerbose
)
process {
if ($MyVerbose) {
# do verbose stuff
}
# pass $MyVerbose in the cmdlet explicitly
New-Item Test -Type Directory -Verbose:$MyVerbose
}
}
DoStuff -MyVerbose
更新
当我们只需要一个开关(不像词曲级值)时, $PSBoundParameters
也许比提议的额外参数更好:
function DoStuff {
[CmdletBinding()]
param()
process {
if ($PSBoundParameters['Verbose']) {
# do verbose stuff
}
New-Item Test -Type Directory -Verbose:($PSBoundParameters['Verbose'] -eq $true)
}
}
DoStuff -Verbose
无论如何,一切都不是完美的。如果有更好的解决方案,那么我真的很想自己认识他们。
其他提示
$PSBoundParameters
不是您想要的。使用 [CmdletBinding()]
属性允许使用 $PSCmdlet
在您的脚本中,除了提供详细标志。实际上,您应该使用的是相同的详细信息。
通过 [CmdletBinding()]
, ,您可以通过 $PSCmdlet.MyInvocation.BoundParameters
. 。这是一个使用cmdletbinding的函数,并简单地立即输入嵌套的提示符,以便检查功能范围内的可用变量。
PS D:\> function hi { [CmdletBinding()]param([string] $Salutation) $host.EnterNestedPrompt() }; hi -Salutation Yo -Verbose
PS D:\>>> $PSBoundParameters
____________________________________________________________________________________________________
PS D:\>>> $PSCmdlet.MyInvocation.BoundParameters
Key Value
--- -----
Salutation Yo
Verbose True
因此,在您的示例中,您需要以下内容:
function DoStuff `
{
[CmdletBinding()]
param ()
process
{
new-item Test -type Directory `
-Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true)
}
}
这涵盖了-verbose,-verbose:$ false,-verbose:$ true,以及完全不存在开关的情况。
没有必要。 PowerShell已经这样做,如下所示。
function f { [cmdletbinding()]Param()
"f is called"
Write-Debug Debug
Write-Verbose Verbose
}
function g { [cmdletbinding()]Param()
"g is called"
f
}
g -Debug -Verbose
输出是
g is called
f is called
DEBUG: Debug
VERBOSE: Verbose
它并不像传递-Debug到下一个CMDLET那样直接。它是通过$ debugpreference和$ derbrosepreference变量完成的。写入和写作的动作就像您期望的那样,但是如果您想对调试或冗长做一些不同的事情,您可以阅读 这里 如何检查自己。
有恢复和旧线程的风险。这是我的解决方案。
function DoStuff {
[CmdletBinding()]
param ()
BEGIN
{
$CMDOUT=@{
Verbose=If ($PSBoundParameters.Verbose -eq $true) { $true } else { $false };
Debug=If ($PSBoundParameters.Debug -eq $true) { $true } else { $false }
}
} # BEGIN ENDS
PROCESS
{
New-Item Example -ItemType Directory @CMDOUT
} # PROCESS ENDS
END
{
} #END ENDS
}
与其他示例不同的是,它将重复“ -verbose:$ false”或“ -debug:$ false”。如果您使用以下内容,它将仅将-verbose/-debug设置为$ true:
DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
您可以根据界限或详细参数构建新的哈希表,然后将其插入内部命令。如果您只是指定开关(并且不传递错误的开关,例如$ debug:$ false),您只需检查debug或冗长的存在:
function DoStuff() {
[CmdletBinding()]
PROCESS {
$HT=@{Verbose=$PSBoundParameters.ContainsKey'Verbose');Debug=$PSBoundParameters.ContainsKey('Debug')}
new-item Test -type Directory @HT
}
}
如果要传递参数值,则更复杂,但可以完成:
function DoStuff {
[CmdletBinding()]
param()
PROCESS {
$v,$d = $null
if(!$PSBoundParameters.TryGetValue('Verbose',[ref]$v)){$v=$false}
if(!$PSBoundParameters.TryGetValue('Debug',[ref]$d)){$d=$false}
$HT=@{Verbose=$v;Debug=$d}
new-item Test -type Directory @HT
}
}
最好的方法是设置 $VerbosePreference
. 。这将使整个脚本启用详细级别。不要忘记在脚本末尾禁用它。
Function test
{
[CmdletBinding()]
param( $param1)
if($psBoundParameters['verbose'])
{
$VerbosePreference = "Continue"
Write-verbose " Verbose mode is on"
}
else
{
$VerbosePreference = "SilentlyContinue"
Write-verbose " Verbose mode is Off"
}
<<your code>>
}
您可以在启动脚本时将VerbosePreference设置为全局变量,然后检查自定义CMDLET中的全局变量。
脚本:
$global:VerbosePreference = $VerbosePreference
Your-CmdLet
您的CMDLET:
if ($global:VerbosePreference -eq 'Continue') {
# verbose code
}
明确检查“继续”允许脚本等于 -verbose:$false
当您从未设置全局变量的脚本调用cmdlet时(在这种情况下是 $null
)
我认为这是最简单的方法:
Function Test {
[CmdletBinding()]
Param (
[parameter(Mandatory=$False)]
[String]$Message
)
Write-Host "This is INFO message"
if ($PSBoundParameters.debug) {
Write-Host -fore cyan "This is DEBUG message"
}
if ($PSBoundParameters.verbose) {
Write-Host -fore green "This is VERBOSE message"
}
""
}
Test -Verbose -Debug