Подтвердить что ты не робот

Как правильно использовать параметры -verbose и -debug в пользовательском командлете

По умолчанию любая именованная функция, имеющая атрибут [CmdletBinding()], принимает параметры -debug и -verbose (и несколько других) и имеет предопределенные переменные $debug и $verbose. Я пытаюсь выяснить, как передать их другому командлету, который вызывается внутри функции.

Допустим, у меня есть такой командлет:

function DoStuff() {
   [CmdletBinding()]

   PROCESS {
      new-item Test -type Directory
   }
}

Если в мою функцию были переданы -debug или -verbose, я хочу передать этот флаг в командлет new-item. Какой правильный шаблон для этого?

4b9b3361

Ответ 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