web-dev-qa-db-fra.com

Comment utiliser correctement les paramètres -verbose et -debug dans une applet de commande personnalisée

Par défaut, toute fonction nommée ayant l'attribut [CmdletBinding ()] accepte les paramètres -debug et -verbose (et quelques autres) et comporte des variables prédéfinies $ debug et $ verbose. Ce que j'essaie de comprendre, c'est comment les transmettre à d'autres applets de commande qui sont appelées dans la fonction.

Disons que j'ai une applet de commande comme ceci:

function DoStuff() {
   [CmdletBinding()]

   PROCESS {
      new-item Test -type Directory 
   }
}

si -debug ou -verbose a été passé dans ma fonction, je souhaite passer cet indicateur dans la cmdlet new-item. Quel est le bon modèle pour faire cela?

38
Micah

Cela peut sembler étrange, mais il n’existe pas de moyen facile pour une applet de commande de connaître son mode verbose ou de débogage. Jetez un oeil à la question connexe:

Comment une applet de commande sait-elle à quel moment elle doit appeler WriteVerbose ()?

Une option non parfaite mais pratiquement raisonnable consiste à introduire vos propres paramètres d'applet de commande (par exemple, $MyVerbose, $MyDebug) et à les utiliser explicitement dans le code.

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 

METTRE À JOUR

Lorsque nous n'avons besoin que d'un commutateur (pas, par exemple, de valeur de niveau de verbosité), l'approche avec $PSBoundParameters est peut-être préférable aux paramètres supplémentaires proposés ci-dessus:

function DoStuff {
    [CmdletBinding()]
    param()

    process {
        if ($PSBoundParameters['Verbose']) {
            # do verbose stuff
        }

        New-Item Test -Type Directory -Verbose:($PSBoundParameters['Verbose'] -eq $true)
    }
}

DoStuff -Verbose

Ce n'est pas parfait de toute façon. S'il existe de meilleures solutions, j'aimerais vraiment les connaître moi-même.

31
Roman Kuzmin

$PSBoundParameters n'est pas ce que vous cherchez. L'utilisation de l'attribut [CmdletBinding()] permet d'utiliser $PSCmdlet dans votre script, en plus de fournir un indicateur Verbose. C'est en fait ce même Verbose que vous êtes censé utiliser. 

Grâce à [CmdletBinding()], vous pouvez accéder aux paramètres liés via $PSCmdlet.MyInvocation.BoundParameters. Voici une fonction qui utilise CmdletBinding et entre simplement une invite imbriquée immédiatement pour examiner les variables disponibles dans la portée de la fonction.

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                                                                                       

Donc, dans votre exemple, vous voudriez ce qui suit:

function DoStuff `
{
    [CmdletBinding()]
    param ()
    process
    {
      new-item Test -type Directory `
        -Verbose:($PSCmdlet.MyInvocation.BoundParameters["Verbose"].IsPresent -eq $true)
    }
}

Cela couvre -Verbose, -Verbose: $ false, -Verbose: $ true et le cas où le commutateur n'est pas présent du tout.

33
bwerks

Il n'y a pas besoin. PowerShell le fait déjà comme le prouve le code ci-dessous.

function f { [cmdletbinding()]Param()    
    "f is called"
    Write-Debug Debug
    Write-Verbose Verbose
}
function g { [cmdletbinding()]Param() 
    "g is called"
    f 
}
g -Debug -Verbose

La sortie est

g is called
f is called
DEBUG: Debug
VERBOSE: Verbose

Cela ne se fait pas aussi directement que de passer -Debug à la cmdlet suivante. Cela se fait via les variables $ DebugPreference et $ VerbrosePreference. Write-Debug et Write-Verbose agissent comme vous le souhaitez, mais si vous voulez faire quelque chose de différent avec debug ou verbose, vous pouvez lire ici comment vérifier par vous-même.

24
Lars Truijens

Avec un risque de renaissance et de vieux fils. Voici ma solution.

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
}

Ce qui diffère des autres exemples est qu’il va représenter "-Verbose: $ false" ou "-Debug: $ false". Il ne définira -Verbose/-Debug sur $ true que si vous utilisez les éléments suivants:

DoStuff -Verbose
DoStuff -Verbose:$true
DoStuff -Debug
DoStuff -Debug:$true
5
desek

La meilleure façon de le faire est de définir le $VerbosePreference. Cela activera le niveau de commentaires pour l’ensemble du script. N'oubliez pas de le désactiver avant la fin du script.

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>>
   }
2
MilindK

Vous pouvez créer une nouvelle table de hachage basée sur les paramètres liés de débogage ou détaillé, puis la scinder à la commande interne. Si vous ne spécifiez que des commutateurs (et ne passez pas un commutateur faux, comme $ debug: $ false), vous pouvez simplement vérifier l'existence de débogage ou de commentaires:

function DoStuff() { 
   [CmdletBinding()] 

   PROCESS { 
        $HT=@{Verbose=$PSBoundParameters.ContainsKey'Verbose');Debug=$PSBoundParameters.ContainsKey('Debug')}
      new-item Test -type Directory @HT
   } 
} 

Si vous voulez passer la valeur du paramètre, c'est plus compliqué, mais vous pouvez le faire avec:

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 
   }  
}  
2
craika

Vous pouvez définir VerbosePreference en tant que variable globale au démarrage de votre script, puis rechercher la variable globale dans votre cmdlet personnalisée. 

Scénario:

$global:VerbosePreference = $VerbosePreference
Your-CmdLet

Votre-CmdLet:

if ($global:VerbosePreference -eq 'Continue') {
   # verbose code
}

La recherche explicite de 'Continuer' permet au script d'être égal à -verbose:$false lorsque vous appelez le CmdLet à partir d'un script qui ne définit pas la variable globale (auquel cas c'est $null)

1
svandragt

Je pense que c'est le moyen le plus simple:

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
0
emekm