Chaining Powershell commands - now with email alerts

Tue, Dec 5, 2017 3-minute read

I recently talked about some simple functionality to chain Powershell commands together so that you can time long-running processes.

I decided to take this concept a little further so that Powershell will send email messages at start and finish so I don’t need to keep checking for when a long-running process has actually finished.

The idea is simple:

  • You send a message when it starts
  • You run the process
  • You send a message when it ends

Note: this assumes you’re in a Windows domain environment with access to an Exchange server. In order to authenticate against Exchange, you obviously need a domain account and be aware, there may be some things about your Exchange environment that does not allow this functionality (e.g., no relaying etc.) If you’re not in an Exchange environment, you’ll need to set the SMTP server of whatever you’re using.

Assuming you’re OK with that, here’s how it works.

First thing to do is to set the hostname of your Exchange server in Powershell:

$PSEmailServer = "exchange"

Depending on your Exchange environment, you probably need to specify either the hostname of an Exchange end point server or you may need the FQDN.

You probably want to test this first:

$cred = get-credential
Send-MailMessage -to $cred.Username -from $cred.Username -credential $cred -subject "Test"

If the above works and you receive the email, then you should be good to continue. Note: it is highly likely that the From has to be the same as the credential you supplied otherwise you’ll get a 5.7.1 Cannot relay issue.

Now to wrap this is in a reusable script:

param
(
[PSCredential]$creds,
$msg
)
 
function SendMessage($creds, $msg)
{
                $to = $creds.Username
                $from = $creds.Username
                $credential = $creds
               
                $subject = "Process " + $msg + " at " + $(get-date)
               
                Send-MailMessage -to $to -from $from -credential $credential -subject $subject
}
 
if($null -eq $creds)
{
                $creds = get-credential
}
 
if($null -eq $msg)
{
                $msg = ""
}
 
SendMessage -creds $creds -msg $msg
 
return [PSCredential]$creds

Save that in a file called “Test.ps1” or similar. It could obviously be simplified but somewhat but have left it verbose so it’s clearer what it’s doing. Also, there’s no explicit error handling in there… e.g., if your SMTP server wasn’t there, it would fail uglily.

The theory here is that the first time you run the script it will prompt you for credentials:

powershell prompt for credentials

But we capture the credentials entered so that we can reuse them later (because prompting for them when it’s finished would sorta delete the object! :-;) You can also pass in a custom message to be output with the -msg param.

So by chaining commands together, usage would look like this:

$creds = ./Test.ps1 -msg "Started";SomeReallyLongRunningCmdlet;./Test.ps1 -creds $creds -msg "Finished"

The obvious difference here being that in the second call to the script, we pass in the credential we previously prompted for.

And hopefully with this method, you’ll get an email when something has finished, meaning you don’t need to keep checking on it.

Hope this helps… comments below.