代码之家  ›  专栏  ›  技术社区  ›  Micah

如何在自定义cmdlet中正确使用-verbose和-debug参数

  •  38
  • Micah  · 技术社区  · 14 年前

    默认情况下,任何具有[CmdletBinding()]属性的命名函数都接受 -debug -verbose (以及其他一些)参数,并具有预定义的 $debug $verbose 变量。我试图找出如何将它们传递给函数中调用的其他cmdlet。

    假设我有一个这样的命令:

    function DoStuff() {
       [CmdletBinding()]
    
       PROCESS {
          new-item Test -type Directory
       }
    }
    

    如果 -调试 -冗长的 被传递到我的函数中,我想将该标志传递到 new-item 指挥官。这样做的正确模式是什么?

    8 回复  |  直到 5 年前
        1
  •  33
  •   Peter Mortensen TravisEz13    5 年前

    也许这听起来很奇怪,但是对于一个cmdlet来说,没有任何简单的方法可以知道它的详细模式或调试模式。看看相关的问题:

    How does a cmdlet know when it really should call 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
    

    反正也不完美。如果有更好的解决方案,我真的很想知道他们自己。

        2
  •  35
  •   bwerks    10 年前

    $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以及根本不存在开关的情况。

        3
  •  26
  •   Community Michael Schmitz    7 年前

    没有必要。正如下面的代码所证明的那样,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和$VerbrosePreference变量完成的。Write Debug和Write Verbose的行为与您预期的一样,但是如果您想对Debug或Verbose做一些不同的事情,可以读取 here 如何检查自己。

        4
  •  5
  •   Peter Mortensen TravisEz13    5 年前

    我的解决方案是:

    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
    }
    

    与其他示例不同的是,它将repsect“-Verbose:$false”或“-Debug:$false”。如果使用以下命令,它将只将-Verbose/-Debug设置为$true:

    DoStuff -Verbose
    DoStuff -Verbose:$true
    DoStuff -Debug
    DoStuff -Debug:$true
    
        5
  •  2
  •   craika    14 年前

    您可以基于绑定的调试或详细参数构建一个新的哈希表,然后将其splat到内部命令。如果您只指定开关(并且没有传递假开关,比如$Debug:$false),您可以检查是否存在调试或冗长:

    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 
       }  
    }  
    
        6
  •  2
  •   Peter Mortensen TravisEz13    5 年前

    最好的方法是设置 $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>
    
    }
    
        7
  •  1
  •   svandragt    9 年前

    可以在启动脚本时将verboseproference设置为全局变量,然后在自定义cmdlet中检查全局变量。

    脚本:

    $global:VerbosePreference = $VerbosePreference
    Your-CmdLet
    

    您的CmdLet:

    if ($global:VerbosePreference -eq 'Continue') {
       # verbose code
    }
    

    显式检查“Continue”允许脚本等于 -verbose:$false 从未设置全局变量的脚本调用CmdLet时(在这种情况下 $null )

        8
  •  0
  •   emekm    11 年前

    我认为这是最简单的方法:

    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
    
    推荐文章