Question Exécution de code dans une portée protégée

Plus d'informations
il y a 11 ans 11 mois #11783 par Laurent Dardenne
Voici une fonction permettant d'exécuter du code dans une portée où $ErrorActionPreference est égale à 'Stop'.

En production, on présuppose les prérequis à l'exécution du code, droits, accès disque, etc comme étant toujours valides.
Ainsi,en appelant le code dans ce contexte 'protégé', on se prémunit de leur hypothétique changement.
Et sur ce type d'erreur on aimerait également mémoriser l'erreur déclenchée, cette fonction enregistre la collection $Erreur dans un fichier XML.

Il est donc possible de retrouver, le plus souvent, le contexte de l'erreur.

Si vous utilisez cette approche, il reste possible de modifier localement (un script,une fonction ou un bloc d'instructions) la valeur de la variable $ErrorActionPreference.

[code:1]
function New-Exception($Exception,$Message=$null) {
#Crée et renvoi un objet exception pour l'utiliser avec $PSCmdlet.WriteError()

#Le constructeur de la classe de l'exception trappée est inaccessible
if ($Exception.GetType().IsNotPublic)
{
$ExceptionClassName=\"System.Exception\"
#On mémorise l'exception courante.
$InnerException=$Exception
}
else
{
$ExceptionClassName=$Exception.GetType().FullName
$InnerException=$Null
}
if ($Message -eq $null)
{$Message=$Exception.Message}

#Recrée l'exception trappée avec un message personnalisé
New-Object $ExceptionClassName($Message,$InnerException)
} #New-Exception

Function Invoke-CommandStopOnAllErrors {
#Exécute par défaut du code Powershell en configurant $ErrorActionPreference à STOP.
#En cas de changement du contexte, directory, module, droits toutes erreur provoquera un arrêt du traitement.
#La collection $Error est sérialisée dans un fichier XML.

param (
[Parameter(Position=0, Mandatory=$true)]
[ValidateNotNullOrEmpty()]
#Nom de l'activité ou du script
[String] $ActivityName,

[Parameter(Position=1, Mandatory=$true)]
[ValidateNotNullOrEmpty()]
#Chemin du fichier de log.
[String] $Path,

[Parameter(Position=2, Mandatory=$true)]
[ValidateNotNull()]
[ValidateScript( {$_.ToString().Trim() -ne [string]::Empty} )]
#Code Powershell à exécuter
[ScriptBlock]$Command
)

$isStopException=$False
$ErrorActionPreference = 'Stop'

#Dans un bloc catch la variable $_ est tjr une instance de ErrorRecord hébergeant une instance d'exception.
#Alors que dans $Error celle-ci peut contenir :
# soit une erreur non bloquante du type ErrorRecord (PowerShell)
# $error[0].ErrorRecord.Exception
# soit une erreur bloquante d'un type dérivé de la classe Exception (dotnet)
# $error[0].Exception
#
#On obtient le contexte de l'erreur avec : $Error[0].errorrecord.invocationInfo |select *

try {
#Exécute le code dans le portée courante
. $command
} catch [System.Management.Automation.ActionPreferenceStopException]
{
# Déclenchée, si $ErrorActionPreference='Stop', lors
# d'un appel à Write-Error ou à $PSCmdlet.WriteError
$isStopException=$true

#Redéclenche l'exception encapsulée dans l'exception ActionPreferenceStopException
#cf. msdn.microsoft.com/en-us/library/ms714465(v=vs.85).aspx

#L'exception qui nous intéresse est imbriquée dans ActionPreferenceStopException
Throw (New-Exception $_.Exception)
#Le bloc Catch suivant ne traitera pas l'exception que l'on créé ici
# Pour ce faire il faut une nouvelle imbrication try/catch :
# try { Invoke-CommandStopOnAllErrors { myFunction } } catch {...}

}#catch ActionPreferenceStopException

catch #Trappe les autres erreurs
{
#Pour une exception de type System.Management.Automation.RuntimeException,
#le champ InnerException est tjr renseigné :
# System.Management.Automation.RuntimeException + System.DivideByZeroException
#Pour d'autres type d'exception ce n'est pas tjr le cas.
if ($_.Exception) # -isnot [MYAPPException])
{
$isStopException=$true
}
Throw $_ #le code échoue sur une erreur
} #catch all exceptions

Finally {
try {
if ($isStopException)
{
$FileName=\"$Path\{0:dd-MM-yyyy-HH-mm-ss}-{1}.xml\" -F ([DateTime]::Now),$ActivityName
$CpError=$Global:Error.Clone()
$CpError|Export-clixml $FileName
}
}catch {
$_|set-content $FileName
}
}#Finally
}#Invoke-CommandStopOnAllErrors
[/code:1]

Exemple :
[code:1]
$Error.Clear()
$LogPath=\"C:\temp\"
Invoke-CommandStopOnAllErrors \"MonCode\" $LogPath { Dir ZZ:\ }
$Fichier=Dir \"$LogPath\*.xml\"|
Sort LastWriteTime -Desc|
Select -First 1
If ($Fichier -eq $Null)
{ write-Warning \"Aucun fichier d'erreur trouvé dans $LogPath\" }
else
{
Write-Host \"Chargement du dernier fichier d'erreur généré :\" -Fore Green -Back Black -NoNewLine
Write-Host \" $Fichier\" -Fore Black -Back green
$DernièreErreur=$Fichier|Import-Clixml
}

$DernièreErreur
$DernièreErreur[0].InvocationInfo
#cf ScriptName ....
$DernièreErreur[0].Exception|select *
[/code:1]<br><br>Message édité par: Laurent Dardenne, à: 12/05/12 15:19

Tutoriels PowerShell

Connexion ou Créer un compte pour participer à la conversation.

Temps de génération de la page : 0.068 secondes
Propulsé par Kunena