默认情况下,任何具有[CmdletBinding()]属性的命名函数都接受-debug和-verbose(以及其他一些)参数,并具有预定义的$ debug和$ verbose变量。我想弄清楚的是如何将它们传递给在函数中调用的其他cmdlet。
假设我有一个这样的cmdlet:
function DoStuff() {
[CmdletBinding()]
PROCESS {
new-item Test -type Directory
}
}
如果将-debug
或-verbose
传递给我的函数,我想将该标记传递到new-item
cmdlet。这样做的正确模式是什么?
答案 0 :(得分:33)
$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,以及根本不存在开关的情况。
答案 1 :(得分:31)
也许这听起来很奇怪但是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 :(得分: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
输出
g is called
f is called
DEBUG: Debug
VERBOSE: Verbose
虽然将-Debug传递给下一个cmdlet并不是直接完成的。它是通过$ DebugPreference和$ VerbrosePreference变量完成的。 Write-Debug和Write-Verbose就像你期望的那样,但如果你想做一些与debug或verbose不同的事情,你可以阅读here如何自己检查。
答案 3 :(得分: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
}
这与其他示例的不同之处在于它将重新选择“-Verbose:$ false”或“-Debug:$ false”。如果您使用以下内容,它只会将-Verbose / -Debug设置为$:
DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
答案 4 :(得分:2)
您可以根据绑定的debug或verbose参数构建新的哈希表,然后将其splat到内部命令。如果你只是指定开关(并且没有传递假开关,比如$ debug:$ false),你可以检查是否存在debug或verbose:
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
}
}
答案 5 :(得分:2)
最好的方法是设置$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>>
}
答案 6 :(得分:1)
您可以在启动脚本时将VerbosePreference设置为全局变量,然后在自定义cmdlet中检查全局变量。
脚本:
$global:VerbosePreference = $VerbosePreference
Your-CmdLet
您-小命令:
if ($global:VerbosePreference -eq 'Continue') {
# verbose code
}
明确检查&#39;继续&#39;当您从没有设置全局变量的脚本调用CmdLet时,脚本等于-verbose:$false
(在这种情况下,它是$null
)
答案 7 :(得分:0)
我认为这是最简单的方法:
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