Powershell | The Last $Error and Emailing it

OMG some things in Powershell are just too confusing to be useful. What if you need to see the last error message again. What if you want to write it into your script to email you when the error happens?

Well first, its all in $Error

However, $Error is an array.  To access it really requires notation like this:

$Error[0]

The [0] says give me back the last error. Where [1] would say to give me back the second to last error message.

The Problem….

Ok now here is where it gets “funky”. If you just type $Error[0] you get the entire error message like so: (note I am using an error message from some Lync work I have been doing, the names have been changed to protect well me lol)

Set-CsUser : Management object not found for identity “Jerry.Springer@Contoso.com”.
At C:\Scripts\EnableLyncUsers.ps1:138 char:15
+                 Set-CsUser <<<<  -Identity $user.UserPrincipalName -SipAddress $user.UserPrincipalName
    + CategoryInfo          : NotSpecified: (:) [Set-CsUser], ManagementException
    + FullyQualifiedErrorId : Microsoft.Rtc.Management.AD.ManagementException,Microsoft.Rtc.Management.AD.Cmdlets.S
   etOcsUserCmdlet

BUT…. if you type write-host $Error[0] you get this:

Management object not found for identity “Jerry.Springer@Contoso.com”.

So what gives right??? Why when you use Write-Host OR even better when you try to email $Error[0] do we get the crappy short error message? Well I don’t have the answer BUT I do have a great work around.

The Solution….

[string]$ErrorString = $Error[0].Exception
[string]$ErrorString = $ErrorString + ” `n `n ”
[string]$ErrorString = $ErrorString + $Error[0].InvocationInfo.PositionMessage

(that’s 3 lines BTW)

As far as I can tell the only thing one needs are the short error message and the line, script, and command. To do this use the code above and then simply use Write-Host or email that new $ErrorString variable. If you need other data follow the info below from how I figured this out.

Emailing the Error? Simply use this code (replace stuff inside of < > then remove the < >):

    [string]$ErrorString = $Error[0].Exception
    [string]$ErrorString = $ErrorString + ” `n `n ”
    [string]$ErrorString = $ErrorString + $Error[0].InvocationInfo.PositionMessage

    $SmtpClient = new-object system.net.mail.smtpClient
    $MailMessage = New-Object system.net.mail.mailmessage
    $SmtpClient.Host = “<SMTP IP OR NAME>”
    $mailmessage.from = <from@domain.com>
    $mailmessage.To.add(“email1@domain.com,email2@domain.com”)
    $mailmessage.Subject = “<Subject of Email>”
    $MailMessage.IsBodyHtml = $false
    $mailmessage.Body = $ErrorString
 
    $smtpclient.Send($mailmessage)

How did I figure this out?

First I indexed $Error to get me the first result [0]

Next I used the power of Get-Member

$Error[0] | Get-Member

This dumped out all the properties

TypeName: System.Management.Automation.ErrorRecord

Name                  MemberType     Definition                                                                    
—-                  ———-     ———-                                                                    
Equals                Method         bool Equals(System.Object obj)                                                
GetHashCode           Method         int GetHashCode()                                                             
GetObjectData         Method         System.Void GetObjectData(System.Runtime.Serialization.SerializationInfo inf…
GetType               Method         type GetType()                                                                
ToString              Method         string ToString()                                                             
CategoryInfo          Property       System.Management.Automation.ErrorCategoryInfo CategoryInfo {get;}            
ErrorDetails          Property       System.Management.Automation.ErrorDetails ErrorDetails {get;set;}             
Exception             Property       System.Exception Exception {get;}                                             
FullyQualifiedErrorId Property       System.String FullyQualifiedErrorId {get;}                                    
InvocationInfo        Property       System.Management.Automation.InvocationInfo InvocationInfo {get;}             
PipelineIterationInfo Property       System.Collections.ObjectModel.ReadOnlyCollection`1[[System.Int32, mscorlib,…
TargetObject          Property       System.Object TargetObject {get;}                                             
PSMessageDetails      ScriptProperty System.Object PSMessageDetails {get=& { Set-StrictMode -Version 1; $this.Exc…

All of the properties normally can be accessed like this:

$Error[0].Exception

But if you try to write-host $Error[0].InvocationInfo you get:

System.Management.Automation.InvocationInfo

Well that’s not very useful… the reason for this is there are deeper items in the $Error[0].InvocationInfo tree. So if we go ahead and whip out get-member again on $Error[0].InvocationInfo lets see what we get:

TypeName: System.Management.Automation.InvocationInfo

Name             MemberType Definition                                                                             
—-             ———- ———-                                                                             
Equals           Method     bool Equals(System.Object obj)                                                         
GetHashCode      Method     int GetHashCode()                                                                      
GetType          Method     type GetType()                                                                         
ToString         Method     string ToString()                                                                      
BoundParameters  Property   System.Collections.Generic.Dictionary`2[[System.String, mscorlib, Version=2.0.0.0, Cu…
CommandOrigin    Property   System.Management.Automation.CommandOrigin CommandOrigin {get;}                        
ExpectingInput   Property   System.Boolean ExpectingInput {get;}                                                   
HistoryId        Property   System.Int64 HistoryId {get;}                                                          
InvocationName   Property   System.String InvocationName {get;}                                                    
Line             Property   System.String Line {get;}                                                              
MyCommand        Property   System.Management.Automation.CommandInfo MyCommand {get;}                              
OffsetInLine     Property   System.Int32 OffsetInLine {get;}                                                       
PipelineLength   Property   System.Int32 PipelineLength {get;}                                                     
PipelinePosition Property   System.Int32 PipelinePosition {get;}                                                   
PositionMessage  Property   System.String PositionMessage {get;}                                                   
ScriptLineNumber Property   System.Int32 ScriptLineNumber {get;}                                                   
ScriptName       Property   System.String ScriptName {get;}                                                        
UnboundArguments Property   System.Collections.Generic.List`1[[System.Object, mscorlib, Version=2.0.0.0, Culture=…

Ah… there’s more stuff. Lastly I just needed to figure out what items inside of $Error[0].InvocationInfo I needed. Turns out just one thing. So to write-host it all I needed to do is call:

Write-Host $Error[0].InvocationInfo.PositionMessage

Hope that opens your mind to how more complex objects work in Powershell.

Hey!

Did I help? Make Sense? Something Wrong? Put it in the comments. Love to hear when my write-ups help folks out.

Enjoy

-Eric

0 Replies to “Powershell | The Last $Error and Emailing it”

  1. All you need to do is $error[0].exception.message the exception property contains a nested object, you’re looking to access the message property of the exception object.

Leave a Reply

Your email address will not be published. Required fields are marked *