Comment passer une variable par référence en PowerShell ? Telle est la question qui m’a assailli alors que je venais de finir la réécrire une application C++ en PowerShell. Pour schématiser, le script contient des fonctions qui traitent des données issu d’un pipe, et un compteur s’incrémente dans le niveau le plus bas.

Function f{
   param([parameter(ValueFromPipeline=$True)] $objects)
   Process {
      Foreach($object in $objects){
         #conditions
         manyRes $objet | f2
         #utiliser compteur
      }
   }
}

Function f2{
   param([parameter(ValueFromPipeline=$True)] $objects)
   Process {
      Foreach($object in $objects){
         #conditions et compteur
      }
   }
}

AlotOfRes | f

Deux possibilités pour passer des variables par référence

  • La référence classique avec [ref] qui fonctionne comme le out en C#.
  • Utiliser les scopes de variable avec les commandlets *-Variable

L’exemple suivant illustre les 2 mécanismes.

New-Variable -Name 'varValueType' -Scope 'Script' -Value 'newValue'

# not working
function ChangeFail(){
   "MaFonction avant : $varValueType"
   $varValueType = 'ChangeFail'
   "MaFonction apres : $varValueType"
}

# working by reference
# note : Reference Type do not need [ref]
function ChangeRef{
   param(
      [ref]$varRef
   )
   "ChangeRef avant : $($varRef.Value)"
   $varRef.Value= 'ChangeRef'
   "ChangeRef apres : $($varRef.Value)"
}

#working by Set-Variable
function ChangeSetVariable(){
   "ChangeSetVariable avant : $varValueType"
   Set-Variable -Name 'varValueType' -Value 'ChangeSetVariable' -Scope 'Script'
   "ChangeSetVariable apres : $varValueType"
}

function main(){
   "Main: $varValueType"
   ChangeFail
   "Main: $varValueType"
   ChangeRef -varRef ([ref]$varValueType)
   "Main: $varValueType"
   #$varValueType2.key
   ChangeSetVariable
   "Main: $varValueType"
}

main
Main: ChangeSetVariable
MaFonction avant : ChangeSetVariable
MaFonction apres : ChangeFail
Main: ChangeSetVariable
ChangeRef avant : ChangeSetVariable
ChangeRef apres : ChangeRef
Main: ChangeRef
ChangeSetVariable avant : ChangeRef
ChangeSetVariable apres : ChangeSetVariable
Main: ChangeSetVariable

Les cmdlets associées aux variables et les scopes

Pour manipuler les variables, les commandlets *-Variable sont intuitives:

  • Clear-Variable : supprimer la valeur d’une variable
  • Get-Variable : obtenir une variable
  • New-Variable : créer une nouvelle variable
  • Remove-Variable : supprimer une variable et sa valeur
  • Set-Variable: définir une variable

Par contre, tester l’existence d’une variable est moins trivial. 2 possibilités s’offrent à vous :

  • Test-Path Variable::
  • Get-Variable en cachant les erreurs et vérifier le code de retour $?
Test-Path Variable:script:VarExist
> True
Get-Variable -Name VarExist -Scope 'Script' -ErrorAction SilentlyContinue
$?
> True

Test-Path Variable:script:VarNotExist
> False
Get-Variable -Name VarNotExist -Scope 'Script' -ErrorAction SilentlyContinue
$?
> False

J’ai apprécié [ref] pour son côté rassurant en tant que développeur. Pourtant j’ai choisi Set-Variable pour la propreté du code.

Qu’aurez vous choisi dans cette situation?

Références :

About_Scopes sur la technet