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

StackOverflow https://stackoverflow.com/questions/4301562

Вопрос

По умолчанию любая именованная функция, которая имеет атрибут [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
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top