Question [Astuce]Cmt utiliser DebugView avec PS ?
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
On utilise l'outil de SysInternal DebugView ( technet.microsoft.com/fr-fr/sysinternals/bb896647(en-us).aspx )
Qui permet de visualiser des messages envoyés de PowerShell vers DebugView.
[code:1]
#exécute DebugView
&\"G:\PS\debug\DebugView\Dbgview.exe\"
Start-Sleep 2
# On perd le focus de la console :/
#http://blogs.msdn.com/powershell/archive/2008/06/03/show-powershell-hide-powershell.aspx
#Hide-PowerShell
#Show-PowerShell
#envoi un message
[int] $level=1
[string] $category=\"Warning\"
[string] $message=\"Test\"
[System.Diagnostics.Debugger]::Log($level, $category, $message)
# Affiche le contenu de $A en chaine de caractères uniquement
$A=Dir
[System.Diagnostics.Debugger]::Log(2,\"Commentaire\", $A)
#Si on termine DebugView.
#\"Closes a process that has a user interface by sending a close message to its main window. \"
(get-process dbgview).CloseMainWindow()
#Dans ce cas l'exécution du code suivant ne pose pas de problème
[System.Diagnostics.Debugger]::Log(2,\"Commentaire\", $A)
[/code:1]
A noter que les appels à Debug.Write au sein du code d'une classe sont récupérés par DbgView.
Si on exécute le code suivant on peut se connecter à VS, en le sélectionnant
[code:1]
[System.Diagnostics.Debugger]::Launch()
[/code:1]
Dans ce cas le code de la classe ,compilé en debug, envoi les infos de trace sur VS( avec un projet actif) et sur DbgWiew
[code:1]
$DllPath=\"G:\PS\debug\AppDebugLog\AppDebugLog\bin\Debug\AppDebugLog.dll\"
[void][Reflection.Assembly]::LoadFile($DllPath)
$obj=new-object AppDebugLog.ClassTest
$obj.Affiche()
[/code:1]
Le code de test C# :
namespace AppDebugLog
{
public class ClassTest
{
public void Affiche(){
Console.WriteLine(\"Affichage par Console.Writeline\");
Debug.Write(3, \"Message via Debug.Write par la classe\");
}
}
}
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
En utilisant une variable contrainte il est possible de tracer toutes les affectations d'une variable globale :
On crée une classe de contrainte personnalisé :
[code:1]
namespace PowerShell.Attributes
{
[AttributeUsageAttribute(AttributeTargets.Property | AttributeTargets.Field)]
public sealed class ValidateViewDebugAttribute : ValidateArgumentsAttribute
{
protected override void Validate(object arguments, EngineIntrinsics engineIntrinsics)
{
PSVariable varInvocation=engineIntrinsics.SessionState.PSVariable.Get(\"Myinvocation\"«»);
InvocationInfo Values = varInvocation.Value as InvocationInfo;
if (arguments != null)
{
//Debug.Write(3, String.Format(\"Script:{0} ; Nom : {1} ; Valeur :{2}\", varInvocation.Value[\"ScriptName\"], varInvocation.Name, varInvocation.ToString()));
Debug.Write(3, String.Format(\"Valeur :{0} ; Type appelant({1}) ligne ({2}); Call : {3}\", arguments.ToString(),
Values.MyCommand.CommandType.ToString(),
Values.ScriptLineNumber,
Values.ScriptName + \".\" + Values.MyCommand.Name));
}
else
{
Debug.Write(3, String.Format(\"Valeur : $null ; Type appelant({0}) ligne ({1}); Call : {2}\", Values.MyCommand.CommandType.ToString(),
Values.ScriptLineNumber,
Values.ScriptName + \".\" + Values.MyCommand.Name));
}
}
}
}
[/code:1]
Qui ne fait qu'envoyer des traces au debugger et valide toujours la valeur en cours d'affectation.
Malheureusement le nom de la variable concernée par l'affectation ne peut être récupérée car cette méthode n'a pas à la connaître.
[code:1]
&\"G:\PS\debug\DebugView\Dbgview.exe\"
# Assembly sans nom fort, on doit préciser le chemin complet
$FullPath = \"VotreChemin\ValidateViewDebugAttribute.dll\"
[void][Reflection.Assembly]::LoadFile($FullPath)
[/code:1]
Ensuite on déclare 2 fonctions :
[code:1]
Function Add-ContrainteVariableDbgView([System.Management.Automation.PSVariable] $Var){
# Ajoute une contrainte de validation ViewDebug
# Cette contrainte affiche, dans le debuger, des inforamtions de trace lors de chaque modification
# du contenu de la variable $Var
#
# Renvoi -1 si la contrainte existe déjà ou le numéro d'index dans la collection Attributes de la variable $Var
#
if ($Var -eq $null)
{ throw (New-Object System.ArgumentException \"Le paramètre `$Var est à `$null.\"«») }
$Attribut=New-object \"PowerShell.Attributes.ValidateViewDebugAttribute\"
$Count=$Var.Attributes.Count
#Liste existante
if ($Count -ne 0)
{ $Index=$Var.Attributes.IndexOf($Attribut)
#Contrainte existante
if ( $Index -ne -1)
{
Write-Debug \"Une contrainte ViewDebug est déjà déclarée sur la variable `$$($Var.Name).\"
return -1
}
}
$Var.Attributes.add($Attribut)
Write-Debug \"Contrainte ViewDebug déclarée sur la variable `$$($Var.Name).\"
#L'index de la nouvelle entrée = $Var.Attributes.Count-1 c'est à dire l'ancienne valeur de $Count.
return $Count
}
Function Remove-ContrainteVariableDbgView([System.Management.Automation.PSVariable] $Var){
# Supprime une contrainte de validation ViewDebug s'il en existe une
if ($Var -eq $null)
{ throw (New-Object System.ArgumentException \"Le paramètre `$Var est à `$null.\"«») }
$Attribut=New-object \"PowerShell.Attributes.ValidateViewDebugAttribute\"
$Index=$Var.Attributes.IndexOf($Attribut)
#Contrainte existante
if ( $Index -ne -1)
{
$Var.Attributes.RemoveAt($Index)
Write-Debug \"Contrainte ViewDebug supprimé pour la variable `$$($Var.Name).\"
}
else {Write-Debug \"Aucune contrainte ViewDebug de déclarée sur la variable `$$($Var.Name).\"}
}
[/code:1]
Quelques tests sur le comportement de ces fonctions :
[code:1]
$X=10
$DefX=Get-Variable X
$DebugPreference=\"Continue\"
#Tests
Remove-ContrainteVariableDbgView $null
Add-ContrainteVariableDbgView $null
Remove-ContrainteVariableDbgView $DefX
#ou Remove-ContrainteVariableDbgView (Get-Variable X)
Add-ContrainteVariableDbgView $DefX
#Ou Add-ContrainteVariableDbgView (Get-Variable X)
Add-ContrainteVariableDbgView $DefX
Remove-ContrainteVariableDbgView $DefX
Add-ContrainteVariableDbgView $DefX
$DebugPreference=\"SilentlyContinue\"
#Ajoute une contrainte défini dans les API de PS
#$SMA=\"System.Management.Automation\"
#$ContraintedEtendu=New-object \"$SMA.ValidateRangeAttribute\" 2,15
#$DefX.Attributes.add($ContraintedEtendu)
[/code:1]
Visualisation des traces par l'affection d'une nouvelle valeur à $X :
[code:1]
$x=11
function Calcule {$global:«»x++}
calcule
# Fichier Test.ps1
#
# function Interne{$global:«»x++}
# function Interne{$global:«»x++;Calcule}
# $global:«»x++
# Interne
# Calcule
# $y=$global:«»X
# $global:«»x=$null
# #la variable globale X existe toujours seul son contenu est à affecté à $null
# $global:«»X=$y
.\Test.ps1
$x=$null
[/code:1]
Une fois déclaré la contrainte sur la variable,$X=10, voici les résultats obtenus dans le debugger.
Lors de l'appel à Add-ContrainteVariableDbgView
Pour une affection dans la console : $x=11Valeur :10 ; Type appelant(Function) ligne (1); Call : .Add-ContrainteVariableDbgView: 3
Valeur :11 ; Type appelant(Script) ligne (0); Call : .: 3
Pour un accés au sein d'une fonction ( function Calcule {$global:x++}), appelée dans la console : Calcule
Valeur :12 ; Type appelant(Function) ligne (1); Call : .Calcule: 3
Pour un accés au sein du script externe Test.ps1 on obtient respectivement :
Pour tracer dans quelque script assez long et ne disposant pas de code debug il faut redéclarer dans chaque portée une contrainte sur la variable à tracer et la supprimer en fin de traitement, attention au clause return :Valeur :13 ; Type appelant(ExternalScript) ligne (1); Call : .Test.ps1: 3
Valeur :14 ; Type appelant(Function) ligne (4); Call : G:\PS\debug\Test.ps1.Interne: 3
Valeur :15 ; Type appelant(Function) ligne (2); Call : G:\PS\debug\Test.ps1.Calcule: 3
Valeur :16 ; Type appelant(Function) ligne (5); Call : G:\PS\debug\Test.ps1.Calcule: 3
Valeur : $null ; Type appelant(ExternalScript) ligne (1); Call : .Test.ps1: 3
Valeur :16 ; Type appelant(ExternalScript) ligne (1); Call : .Test.ps1: 3
Valeur : $null ; Type appelant(Script) ligne (0); Call : .: 3
[code:1]
Add-ContrainteVariableDbgView (Get-variable xxx)
...
Remove-ContrainteVariableDbgView (Get-variable xxx)
[/code:1]
Cela peut aider dans quelque cas sinon mieux vaut investir dans un debugger
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
La pièce jointe ValidateViewDebugAttribute.zip est absente ou indisponible
Tutoriels PowerShell
Pièces jointes :
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
[code:1]
function Write-ObjectProperties ($From, $PropertyName =\"*\", [Switch] $Pipeline, [Switch] $Debug)
{ #Affiche le contenu de toutes les propriétés d'un objet
#
# $From : l'objet à interroger,
# $PropertyName : le nom de la propriété, ce nom peut contenir des jokers,
# $Pipeline : indique si le résultat est émis dans le pipeline
# $Debug : indique si le résultat est envoyé vers le debugger
#
#Exemples :
# $a=dir
# Write-Properties $a[-1]
# Write-Properties $a[-1] -Pipeline |%{Write-host $_ -fore DarkGreen}
# Res=Write-Properties $a[-1] -Debug -Pipeline
foreach ($p in Get-Member -In $From -MemberType *Property -Name $propertyName|Sort name)
{
$Result =\"$($P.Name) : $($From.$($P.Name))\"
if ( $Pipeline.IsPresent) {$result}
else {Write-Host $Result}
if ( $Debug.IsPresent)
{
#CommandLineParameters en PS v2 seulement
$Source=$MyInvocation.CommandLineParameters.\"From\".ToString()
[int] $level=1
[string] $category=\"WP-$Source\"
#Inopérant si aucun débugger n'est actif
[System.Diagnostics.Debugger]::Log($level, $category, $Result)
}
}
}
[/code:1]
A notez que l'instruction $MyInvocation.CommandLineParameters n'est valide quà partir de la version 2 ctp2.
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
[code:1]
Set-Alias -name $AliasName -value Write-Properties
function Write-Properties($From, $PropertyName =\"*\",[Switch] $Passthru, [Switch] $Silently)
{ #Adaptation d'un script de J.Snoover
#Emet le contenu de toutes les propriétés d'un objet dans le pipeline, sur la console et sur un debugger actif
#
# $From : l'objet à interroger,
# $PropertyName : le nom de la propriété, ce nom peut contenir des jokers.
# C'est un tableau de string
# $Silently : N'émet plus les informations sur la console mais seulement vers le debugger actif
#
#Exemples :
# $a=dir
# Write-Properties $a[-1]
# Write-Properties $a[-1] -pass |%{Write-host $_ -fore DarkGreen}
# $Res=Write-Properties $a[-1] -pass
# wp $A[-1] Name,Extension,L*
begin
{
$IsDebuggerAttached=[System.Diagnostics.Debugger]::IsAttached
$CS=\"Call : {0}\" -F $MyInvocation.InvocationName
Write-Debug $CS
function WriteProperties{
if ($IsDebuggerAttached) # faire [System.Diagnostics.Debugger]::Launch()
{
$sbDbgWrite={[System.Diagnostics.Debug]::WriteLine($Args[0])} #Pour VS
[System.Diagnostics.Debug]::Indent()
}
else {$sbDbgWrite={[System.Diagnostics.Debug]::Write($Args[0])}} #Pour DbgView
#La chaine $CS est envoyé vers le debugger actif
&$sbDbgWrite $CS
foreach ($P in Get-Member -In $From -MemberType *Property -Name $propertyName|Sort name)
{
$Result =\"$($P.Name) : $($From.$($P.Name))\"
#Affiche ou non sur la console.
#Dans tous les cas on affiche sur le débugger
if (!$Silently) {Write-Host $Result}
if ((get-Variable psversiontabl[e]) -ne $null)
{ #CommandLineParameters en PS v2 seulement
$Source=$MyInvocation.CommandLineParameters.\"From\".ToString()
$Result=\"$Source : $Result\"
}
&$sbDbgWrite $Result
if ($Passthru) {$Result}
}
if ($IsDebuggerAttached)
{[System.Diagnostics.Debug]::Unindent() }
}
}
process
{
if ($_)
{
WriteProperties -From $_ $PropertyName -Silently:$Silently
$_
}
}
end
{
if ($From)
{ WriteProperties -From $From $PropertyName -Silently:$Silently }
}
} #Write-Properties
[/code:1]
On peut utiliser soit dbgView soit VisualStudio (version Express ou > ), dans ce cas l'affichage des propriétés est indenté.
L'utilisation de la classe System.Diagnostics.Debug nécessite moins de code.
Voir aussi
[code:1]
[System.Diagnostics.Debug]::Assert($xyz -ne $null)
[/code:1]
Si le test est faux le framework affiche une fenêtre de confirmation.
Le choix de \"Ignorer\" continue le script, \"Abandonner\" ferme la session PS et \"Recommencer\" permet de lancer un des debuggers recensés.<br><br>Message édité par: Laurent Dardenne, à: 17/02/09 16:37
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Laurent Dardenne
- Auteur du sujet
- Hors Ligne
- Modérateur
-
- Messages : 6311
- Remerciements reçus 68
Ajout du switch Passthru permettant d'envoyer le résultat dans le pipeline.
On peut donc émettre le résultat sur la console et dans le debugger et/ou dans le pipeline.
Tutoriels PowerShell
Connexion ou Créer un compte pour participer à la conversation.
- Vous êtes ici :
-
Accueil
-
forum
-
PowerShell
-
Contributions à la communauté
- [Astuce]Cmt utiliser DebugView avec PS ?