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

Mic*_*cah 41 parameters powershell cmdlets cmdlet

默认情况下,任何具有[CmdletBinding()]属性的命名函数都接受-debug和-verbose(以及其他一些)参数,并具有预定义的$ debug和$ verbose变量.我想弄清楚的是如何将它们传递给在函数内调用的其他cmdlet.

假设我有一个像这样的cmdlet:

function DoStuff() {
   [CmdletBinding()]

   PROCESS {
      new-item Test -type Directory
   }
}
Run Code Online (Sandbox Code Playgroud)

if -debug或者-verbose传入我的函数我想将该标志传递给$debugcmdlet.这样做的正确模式是什么?

bwe*_*rks 35

$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                                                                                       
Run Code Online (Sandbox Code Playgroud)

因此,在您的示例中,您需要以下内容:

function DoStuff `
{
    [CmdletBinding()]
    param ()
    process
    {
      new-item Test -type Directory `
        -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true)
    }
}
Run Code Online (Sandbox Code Playgroud)

这包括-Verbose,-Verbose:$ false,-Verbose:$ true,以及交换机根本不存在的情况.


Rom*_*min 33

也许这听起来很奇怪但是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
Run Code Online (Sandbox Code Playgroud)

UPDATE

当我们只需要一个开关(不是,比如详细级别值)时,方法$PSBoundParameters可能比上面提出的额外参数更好:

function DoStuff {
    [CmdletBinding()]
    param()

    process {
        if ($PSBoundParameters['Verbose']) {
            # Do verbose stuff
        }

        New-Item Test -Type Directory -Verbose:($PSBoundParameters['Verbose'] -eq $true)
    }
}

DoStuff -Verbose
Run Code Online (Sandbox Code Playgroud)

无论如何,这一切都不完美.如果有更好的解决方案,那么我真的想自己了解它们.

  • 这就是诀窍"-Vebose:(xxx)"我不知道你可以用这种方式设置开关.我以为它总是包含或排除.我不知道你可以直接设置这样的开关值. (2认同)
  • @RomanKuzmin:有一个更好的解决方案.由于PowerShell已经开始处理它,因此更好的解决方案是什么都不做.请参见http://stackoverflow.com/a/20830886/1242.有关检测部分,请参阅http://stackoverflow.com/a/20828118/1242 (2认同)

Lar*_*ens 26

没有必要.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
Run Code Online (Sandbox Code Playgroud)

输出是

g is called
f is called
DEBUG: Debug
VERBOSE: Verbose
Run Code Online (Sandbox Code Playgroud)

它不是像将-Debug传递给下一个cmdlet一样直接.它是通过$ DebugPreference和$ VerbrosePreference变量完成的.Write-Debug和Write-Verbose就像你期望的那样,但是如果你想用debug或verbose做一些不同的事情,你可以在这里阅读如何自己检查.

  • 正如你所说,这适用于Write-Verbose,但OP询问是否导致New-Item写入详细输出,而这并没有实现. (4认同)
  • 当您使用 -Verbose 调用函数时,在函数内部,$VerbosePrefence 变量将设置为 Continue(默认情况下为 SilentlyContinue)。这将依次传递给函数内调用的任何函数。如果这些函数调用 Write-Verbose,它将检查 $VerbosePreference 并打印详细信息。New-Item(以及许多 MS cmdlet)的问题在于它会忽略这个变量。因此,您必须使用 $PSBoundParameters 或查看 $VerbosePreference 的当前设置来确定是否应手动将 -Verbose 指定为 New-Item。 (4认同)
  • 在这里回答这个问题:/sf/ask/3143039791/ (3认同)
  • 虽然这个例子本身就像宣传的那样,但当 f 被移动到一个模块中时,它似乎不再这样做了。知道这是什么原因,以及如何解决? (2认同)

小智 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
}
Run Code Online (Sandbox Code Playgroud)

这与其他示例的不同之处在于它将重新选择"-Verbose:$ false"或"-Debug:$ false".如果您使用以下内容,它只会将-Verbose/-Debug设置为$ true:

DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
Run Code Online (Sandbox Code Playgroud)