How to properly use the -verbose and -debug parameters in a custom cmdlet
默认情况下,具有[CmdletBinding()]属性的任何命名函数都接受
假设我有一个这样的cmdlet:
1 2 3 4 5 6 7 | function DoStuff() { [CmdletBinding()] PROCESS { new-item Test -type Directory } } |
如果将
通过
1 2 3 4 5 6 7 8 9 10 11 | 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 |
因此在您的示例中,您需要以下内容:
1 2 3 4 5 6 7 8 9 10 | function DoStuff ` { [CmdletBinding()] param () process { new-item Test -type Directory ` -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true) } } |
这包括-Verbose,-Verbose:$ false,-Verbose:$ true,以及根本不存在该开关的情况。
也许这听起来很奇怪,但是对于cmdlet而言,没有任何简单的方法来了解其详细或调试模式。看看相关的问题:
cmdlet如何知道何时应真正调用WriteVerbose()?
一个不完美但实际上合理的选择是引入您自己的cmdlet参数(例如
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |
更新
当我们只需要一个开关(而不是冗长级别值)时,使用
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | function DoStuff { [CmdletBinding()] param() process { if ($PSBoundParameters['Verbose']) { # Do verbose stuff } New-Item Test -Type Directory -Verbose:($PSBoundParameters['Verbose'] -eq $true) } } DoStuff -Verbose |
这还不是完美的。如果有更好的解决方案,那么我真的很想认识他们。
没有必要。如下面的代码所示,PowerShell已执行此操作。
1 2 3 4 5 6 7 8 9 10 | function f { [cmdletbinding()]Param() "f is called" Write-Debug Debug Write-Verbose Verbose } function g { [cmdletbinding()]Param() "g is called" f } g -Debug -Verbose |
输出为
1 2 3 4 | g is called f is called DEBUG: Debug VERBOSE: Verbose |
虽然这样做不像将-Debug传递给下一个cmdlet那样直接。这是通过$ DebugPreference和$ VerbrosePreference变量完成的。 Write-Debug和Write-Verbose的行为与您期望的一样,但是如果您想对debug或冗长的内容进行其他操作,可以在此处阅读如何进行自我检查。
这是我的解决方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | 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:
1 2 3 4 | DoStuff -Verbose DoStuff -Verbose:$true DoStuff -Debug DoStuff -Debug:$true |
最好的方法是设置
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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> } |
您可以基于绑定的调试或详细参数构建一个新的哈希表,然后将其放到内部命令中。如果您只是指定开关(并且没有传递错误的开关,例如$ debug:$ false),则可以检查是否存在debug或verbose:
1 2 3 4 5 6 7 8 | function DoStuff() { [CmdletBinding()] PROCESS { $HT=@{Verbose=$PSBoundParameters.ContainsKey'Verbose');Debug=$PSBoundParameters.ContainsKey('Debug')} new-item Test -type Directory @HT } } |
如果要传递参数值,则更为复杂,但可以使用以下方法完成:
1 2 3 4 5 6 7 8 9 10 11 | 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设置为全局变量,然后在自定义cmdlet中检查全局变量。
脚本:
1 2 |
您的CmdLet:
1 2 3 | if ($global:VerbosePreference -eq 'Continue') { # verbose code } |
通过从未设置全局变量的脚本(在这种情况下为
我认为这是最简单的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | 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 |