Как правильно использовать параметры -вербоз и -debug в пользовательском командлете
-
29-09-2019 - |
Вопрос
По умолчанию любая именованная функция, которая имеет атрибут [cmdletbinding ()], принимает параметры -debug и -вербоз (и несколько других) и имеют предопределенные $ Debug и $ Verbose переменные. То, что я пытаюсь выяснить, это как передать их другим командам, которые вызываются в рамках функции.
Допустим, у меня есть командлет, как это:
function DoStuff() {
[CmdletBinding()]
PROCESS {
new-item Test -type Directory
}
}
если -debug
или -verbose
был передан в мою функцию, я хочу передать этот флаг в new-item
командлет. Что правильный шаблон для этого?
Решение
Возможно, это звучит странно, но для командлета нет простого способа узнать его Verbose или Debug Mode. Посмотрите на связанный вопрос:
Как командлет знает, когда он действительно должен позвонить в WhickverBOSE ()?
Один не идеальный, но практически обоснованный вариант - ввести свои собственные параметры командлета (например, $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
В любом случае все это не идеально. Если есть лучшие решения, я бы очень хотел узнать их сам.
Другие советы
$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)
}
}
Это охватывает -Вербоза, -Вербозу: $ false, -verbose: $ true, и случай, когда переключатель вообще отсутствует.
Нет нужды. 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. Написать-дебу и писать веру вступайте так, как вы ожидаете, но если вы хотите сделать что-то другое с отладкой или словесами, вы можете прочитать здесь Как проверить сами.
С риском возрождения и старой ветки. Вот мое решение.
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
}
Что это отличается от других примеров, так это то, что он будет повторение «-вербозе: $ false" или "-debug: $ false". Он установит только -Вербоз/-дебуг на $ true, если вы используете следующее:
DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
Вы можете построить новый хэш-таблица на основе связанных параметров отладки или многослойных параметров, а затем Splat его к внутренней команде. Если вы просто указываете коммутаторы (и не передавайте ложный выключатель, например, $ debug: $ false) Вы можете просто проверить наличие отладки или 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
}
}
Лучший способ сделать это, установив $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>>
}
Вы можете установить VerbOsePreference в качестве глобальной переменной при запуске скрипта, а затем проверьте глобальную переменную в вашем пользовательском командлете.
Сценарий:
$global:VerbosePreference = $VerbosePreference
Your-CmdLet
Ваш командлет:
if ($global:VerbosePreference -eq 'Continue') {
# verbose code
}
Проверка явно для «продолжения» позволяет сценарию равным -verbose:$false
Когда вы называете командлет из сценария, который не устанавливает глобальную переменную (в этом случае это $null
)
Я думаю, что это самый простой способ:
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