Question Exécution de code dans une portée protégée
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
Réduire
Plus d'informations
- Messages : 6302
- Remerciements reçus 68
il y a 11 ans 11 mois #11783
par Laurent Dardenne
Tutoriels PowerShell
Exécution de code dans une portée protégée a été créé 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
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
- Vous êtes ici :
- Accueil
- forum
- PowerShell
- Contributions à la communauté
- Exécution de code dans une portée protégée