9
votes

Comment retenir ScriptStackTrace dans une exception projetée à partir d'une commande invoke sur un ordinateur distant?

J'écris un script PowerShell qui exécute l'une des étapes de mon processus de construction / de déploiement et qu'il doit exécuter certaines actions sur une machine distante. Le script est relativement complexe, donc si une erreur se produit pendant cette activité à distance, je souhaite une trace de pile détaillée de l'endroit où le script est survenu (au-dessus et au-dessus de la journalisation déjà produite).

Le problème se pose dans celui invoqué -Command perd des informations de trace de pile lors de la relayation des exceptions de terminaison d'une machine distante. Si un bloc de script est invoqué sur la machine locale: p>

Test Error
At line:4 char:3
+         throw "Test Error";
+         ~~~~~~~~~~~~~~~~~~
    + CategoryInfo          : OperationStopped: (Test Error:String) [], RuntimeException
    + FullyQualifiedErrorId : Test Error


4 commentaires

Utilisez quelque chose comme Invoke-Command -errorvariable RougeError Les résultats du flux d'erreur doivent être dans $ RemoteRror ?


Je le reprends -errorvariable ne doit pas contenir les informations dont vous avez besoin. Je pense avoir une idée pensée en utilisant lancer


Est quelque chose sur Cet article utile? "Pour le débogage, au lieu de la commande invoke, il peut être préférable d'utiliser Enter-psession, de sorte que vous puissiez avoir une coquille sur la machine distante pour essayer les choses"


Vous ne pouvez pas utiliser Entrée-psession dans les scripts


3 Réponses :


3
votes

Je suis sûr que quelqu'un avec plus d'expérience peut aider, mais j'aimerais vous donner quelque chose à mâcher pendant la période moyenne. On dirait que vous voulez utiliser lancer code> puisque vous recherchez des exceptions de terminaison. Erreur d'écriture Code> Ecrivez-vous sur le flux d'erreur, mais il ne se termine pas. Quel que soit votre choix, ma suggestion est toujours la même.

Capturer l'exception dans une variable est un bon départ pour cela, je vais donc recommander ce bloc de votre exemple: p> xxx pré>

$ exception code> Ce cas devrait être un désériialized.system.management.Automation.errorrecord code>. Vous pouvez envoyer des objets personnalisés à lancer code> . .. P>

Vous pouvez également lancer un objet errorrecord ou une exception de framework Microsoft .NET. P> BlockQuote>

Mais dans ce cas, cela ne fonctionne pas qui est probablement dû à la désérialisation. À un moment donné, j'ai essayé de créer mon propre objet d'erreur, mais certaines des propriétés nécessaires étaient en lecture seule, alors j'ai sauté cela. p> xxx pré>

Cependant, il suffit d'écrire sur le flux de sortie vous donne les informations correctes que vous l'avez vues. P>

PS M:\Scripts> $exception.InvocationInfo.PositionMessage
At line:4 char:9
+         throw "Test Error";
+         ~~~~~~~~~~~~~~~~~~


1 commentaires

Merci d'avoir fait plus de creuser sur ceci - on dirait que je devrai utiliser cette approche (messages d'exception empilés) combinés aux informations sérialisées de la réponse de Frode F. pour créer une entrée de journal informative.



7
votes

Lorsque vous exécutez du code et que vous échouez, vous recevez un errorrecord code> qui reflète le code vous strong> (ordinateur local) exécuté. Ainsi, lorsque vous utilisez lancer "erreur" code>, vous pouvez accéder à l'involocationInfo et à une exception pour ce code.

Lorsque vous utilisez invoke-commande code>, vous n'exécutez pas Lancer "Erreur" Code> plus, l'ordinateur distant est. Vous (ordinateur local) exécute invoke-commande .... code>, c'est pourquoi le errorrecord code> que vous obtenez reflète que (et pas la réelle exception comme vous le voulait). Ceci est la façon dont il doit être depuis une exception peut provenir de la scriptBlock le compteur distant exécuté, mais il pourrait aussi bien être une exception à partir de invoke-commande code> car il ne pouvait pas se connecter à L'ordinateur distant ou quelque chose de similaire. p>

Lorsque l'exception est lancée à l'origine sur l'ordinateur distant, invoke-commande code> / powerShell jette un RemoteException sur l'ordinateur local. P>

$localexception.Exception.GetType().FullName
System.Management.Automation.ItemNotFoundException

$remoteexception.Exception.SerializedRemoteException.GetType().FullName
System.Management.Automation.PSObject

#Get TypeName from psobject
$remoteexception.Exception.SerializedRemoteException.psobject.TypeNames[0]
Deserialized.System.Management.Automation.ItemNotFoundException


3 commentaires

Super - cela me donne toutes les informations de l'exception dont j'ai besoin. Merci!


@Frodef. Réponse fantastique. Je peux obtenir la positionMessage, mais je ne peux pas sembler obtenir une stacktrace ou une script de script de l'exception sérialisée. Des idées?


La script ScripttackTrace fait partie de l'errorrecord, pas de l'exception. $ RemoteException.ScriptStackTrace fonctionne bien pour moi. En ce qui concerne l'exception StackTrace, je reçois la même sortie dans $ RemoteeException.Exception.serialiséRemoteException.innerex cetion.Stacktrace comme je le fais à partir de $ localException.Exception.innerException.StackTrace . L'exception externe StackTrace ne correspond pas à mon test, mais c'est simplement parce que invoke-commande requis -erroraction stop pour générer l'exception en tant que terminaison.



0
votes

En espérant que quelqu'un avec plus d'expérience puisse commenter à ce sujet, mon commentaire semble être parti oublié.

J'ai trouvé cet article qui offre un aperçu de l'utilisation de Entrée-psession code> p>

ou même mieux, créez une session persistante p> xxx pré>

pour déboguer à l'aide de la traçage, rappelez-vous que vous devez définir le verbosePreference, la transreurure, etc. dans la session distante P>

Invoke-Command $session {$VerbosePreference = ‘continue’}
Invoke-Command $session {Write-Verbose hi}


2 commentaires

Il souhaite accéder à l'exception qui est jetée à l'intérieur du scriptblock utilisé dans invoke-commande . L'utilisation d'une session vs. ComputerName avec la même cmdlet ne modifie pas la manière dont les exceptions sont transmises à «l'ordinateur de gestion».


Comme cela se produit, le script actuel que j'utilise utilise des sessions créées avec une nouvelle psession, mais comme cette partie est horriblement compliquée (beaucoup de déconnexion et de reconnecte de processus) et ne semble pas avoir une incidence sur la manipulation des exceptions dans ce cas, je omis de l'exemple du code. Merci quand même!