Как правильно использовать параметры -verbose и -debug в пользовательском командлете
По умолчанию любая именованная функция, имеющая атрибут [CmdletBinding()], принимает параметры -debug
и -verbose
(и несколько других) и имеет предопределенные переменные $debug
и $verbose
. Я пытаюсь выяснить, как передать их другому командлету, который вызывается внутри функции.
Допустим, у меня есть такой командлет:
function DoStuff() {
[CmdletBinding()]
PROCESS {
new-item Test -type Directory
}
}
Если в мою функцию были переданы -debug
или -verbose
, я хочу передать этот флаг в командлет new-item
. Какой правильный шаблон для этого?
Ответы
Ответ 1
Возможно, это звучит странно, но для командлета не существует простого способа узнать его подробный режим или режим отладки. Посмотрите на связанный вопрос:
Как командлет узнает, когда он действительно должен вызывать WriteVerbose()?
Один не идеальный, но практически разумный вариант - ввести собственные параметры командлета (например, $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
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
Всё равно не идеально. Если есть лучшие решения, то я бы очень хотел узнать их сам.
Ответ 2
$PSBoundParameters
- это не то, что вы ищете. Использование атрибута [CmdletBinding()]
позволяет использовать $PSCmdlet
в вашем script, помимо предоставления флага Verbose. На самом деле это то же самое, что вы должны использовать.
Через [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
Нет необходимости. 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 для следующего командлета. Это делается через переменные $DebugPreference и $VerbrosePreference. Write-Debug и Write-Verbose действуют так, как вы ожидали, но если вы хотите сделать что-то другое с помощью отладки или подробного описания, вы можете прочитать здесь, как проверить себя.
Ответ 4
Вот мое решение:
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, только если вы используете следующее:
DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
Ответ 5
Вы можете создать новую хеш-таблицу на основе связанных параметров debug или verbose, а затем поместить ее во внутреннюю команду. Если вы просто указываете ключи (и не передаете ложный переключатель, например $debug: $false), вы можете просто проверить наличие отладки или подробного:
function DoStuff() {
[CmdletBinding()]
PROCESS {
[email protected]{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}
[email protected]{Verbose=$v;Debug=$d}
new-item Test -type Directory @HT
}
}
Ответ 6
Лучший способ сделать это - установить $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
Вы можете установить VerbosePreference в качестве глобальной переменной при запуске script, а затем проверить глобальную переменную в своем настраиваемом командлете.
Script:
$global:VerbosePreference = $VerbosePreference
Your-CmdLet
Ваш командлетов:
if ($global:VerbosePreference -eq 'Continue') {
# verbose code
}
Проверка явно для "Продолжить" позволяет script быть равно -verbose:$false
при вызове CmdLet из script, который не устанавливает глобальную переменную (в этом случае она $null
)
Ответ 8
Я думаю, что это самый простой способ:
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