Вы не можете действительно ссылаться на $ WhatIf или $ Verbose, поскольку они синтезированы для вас, то есть эти переменные не существуют в вашей функции. Если пользователь указывает их, вы можете получить их через $ PSBoundParameters, но если пользователь не указал, то, очевидно, они не будут в этой хеш-таблице.
Когда вы передаете значение в коммутатор, PowerShell выполнит типичный принудительный процесс, чтобы попытаться преобразовать указанное значение в логическое значение. Так как $ whatif не определено, это приводит к значению $ null, в результате чего значение переключателя устанавливается равным $ true. Предположительно это происходит потому, что он видит, что переключатель явно указан без значения, что эквивалентно указанию -Whatif без значения. Вы можете увидеть это, когда проследите привязку параметра:
function Foo
{
[CmdletBinding(SupportsShouldProcess=1)]
param()
Process
{
$PSBoundParameters
}
}
Trace-Command -name ParameterBinding -expr {Foo -whatif:$xyzzy} -PSHost
DEBUG: BIND NAMED cmd line args [Foo]
DEBUG: BIND arg [] to parameter [WhatIf]
DEBUG: COERCE arg to [System.Management.Automation.SwitchParameter]
DEBUG: Arg is null or not present, type is SWITCHPARAMTER, value is true.
DEBUG: BIND arg [True] to param [WhatIf] SUCCESSFUL
DEBUG: BIND POSITIONAL cmd line args [Foo]
DEBUG: MANDATORY PARAMETER CHECK on cmdlet [Foo]
DEBUG: CALLING BeginProcessing
DEBUG: CALLING EndProcessing
$ WhatIfPreference и $ VerbosePreference устанавливаются соответствующим образом в external в зависимости от того, был ли external вызван с -verbose или -whatif. Я вижу, что эти значения распространяются на внутреннюю сторону просто отлично. Казалось бы, есть ошибка PowerShell с $ pscmdlet.ShouldProcess. Похоже, что в этом случае он не учитывает значение $ VerbosePreference. Вы можете попробовать пройти через -Verbose к внутреннему так:
inner VerbosePassthru -Verbose:($VerbosePreference -eq 'Continue')
Другой вариант - использовать Get-Variable -Scope примерно так:
function Outer
{
[CmdletBinding(SupportsShouldProcess=1)]
param()
Process
{
$pscmdlet.ShouldProcess("Outer process", '') > $null
inner
#inner -Verbose:($VerbosePreference -eq 'Continue')
}
}
function Inner
{
[CmdletBinding(SupportsShouldProcess=1)]
param()
Process
{
$pscmdlet = (Get-Variable -Scope 1 -Name PSCmdlet).Value
$pscmdlet.ShouldProcess("Inner process", '') > $null
"Inner $VerbosePreference"
}
}
Outer -Verbose
Я не уверен, что мне это нравится, потому что это означает, что вы знаете, что внешний на 1 уровень выше внутреннего. Вы могли бы «пройтись» по стеку в поисках следующей переменной PSCmdlet вверх по стеку. Это эффективно избавляет от необходимости передавать в PSCmdlet (что является грубым), но это все еще хак. Вы должны рассмотреть вопрос об ошибке в MS Connect по этому поводу.