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

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

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

function DoStuff() {
   [CmdletBinding()]

   PROCESS {
      new-item Test -type Directory 
   }
}

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

8 ответов


возможно, это звучит странно, но для командлета нет простого способа узнать его подробный или отладочный режим. Взгляните на связанный с этим вопрос:

как командлет знает, когда он действительно должен вызывать 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 

обновление

когда мы нужен только переключатель (не, скажем, значение уровня многословия), тогда подход с $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)
    }
}

это охватывает-Verbose, - Verbose:$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 следующему командлету. Это делается с помощью переменной $а $переменные VerbrosePreference. Write-Debug и Write-Verbose действуют так, как вы ожидали, но если вы хотите сделать что-то другое с debug или verbose, вы можете прочитать здесь как проверить на себе.


С риском оживления и старой нити. Вот мое решение.

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

вы можете создать новую хэш-таблицу на основе связанных параметров debug или verbose, а затем splat ее внутренней команде. Если вы просто указываете переключатели (и не передаете ложный переключатель, например $debug:$false), вы можете просто проверить наличие debug или 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