PowerShell Reminder Jobs

timerThis is something that might be better suited to one of my Friday Fun columns, but I’m enjoying this so much I couldn’t wait to share it. I don’t know about you but I spend much of my day in PowerShell or at least with a PowerShell session running. I have an ongoing quest to do as much as I can from PowerShell. This includes just about any sort of task that might be automated.

In the past I’ve blogged about my tickle system that run when I start PowerShell. But often I have short term tickler or reminder needs. For example, since I work at home I may need to remember to switch over the laundry or that I have a phone call at 2:00PM. Sure, I could set up calendar alerts in an email client but I’d rather have something as quick and easy as a PowerShell command. So I wrote this script, New-Reminderjob.ps1.

In short, the script creates a background job that will use the MSG.EXE command line tool to display a message to myself. The job action sleeps the specified number of seconds and then runs my MSG.EXE command. I could have used a variety of ways to display the message, but MSG.EXE is built in and I didn’t see any reason to re-invent the wheel.

The script, which you could revise into a function if you want, requires the reminder text and then when to “deliver” the reminder. You can specify a number of minutes, the default is 1, or a date and/or time. If you specify a time like “9:00AM” the script will assume you mean 9AM today. The script converts your start time into a number of seconds it has to wait and builds that into the job scriptblock.

When the time comes I get a popup message like this.
The message will automatically dismiss after about 1 minute. Or I’ve configure my script to allow you to require that you acknowledge the message through the -Wait parameter. This is useful for important reminders you want to make sure you don’t miss.

Because I might have several daily reminders, I wanted an easy way to identify them. One thing I did with my script is to give all of my reminder jobs a custom name that starts with ‘Reminder’. I use a regular expression to find the number from the most recent reminder job and increment it by one. The other useful step is that I added some custom properties to the job object itself. These properties embed values from the script into the job object. Now I can do interesting commands like this:


The custom properties have no effect on any other job objects. If I find myself using these properties a lot, I might create some additional functions to save some typing.

This system is meant for ad-hoc, daily reminders to myself which is why I didn’t use scheduled jobs. I didn’t want to have to deal with cleaning up a bunch of one time jobs. These reminder jobs only last for as long as my PowerShell session is open. But be aware, that each running reminder will start a new PowerShell process so I wouldn’t recommend setting this up with dozens of reminders. Actually, if you need that many reminders you either need to get a new job or an assistant!

I hope you’ll try it out and let me know what you think or where you think it can be improved. Enjoy!

A Better PowerShell Get Scheduled Job Results

Yesterday I posted a quick update on my code to get the most recent scheduled job result in PowerShell. I had been using a simple script. But the more I thought about it, the more I realized I really did need to turn it into a function with more flexibility. When creating a PowerShell based tool you need to think about who might be using it. Even though I only wanted the last result for all enabled jobs, there might be situations where I wanted say the last 2 or 3. Any maybe I wanted to only get results for a specific job. Or maybe all jobs. The bottom line is that I needed more flexibility. Now I have the Get-ScheduledJobResult function.

The function takes parameters that I can pass to Get-ScheduledJob and Get-Job. For the most part the core functionality remains the same: I get the X number of most recent jobs for scheduled jobs. The difference is that now these values are controlled by parameters. The other benefit to my revision is error handling. Before I had a single pipelined expression, but now I use a Try/Catch block to get the scheduled job by name, using * as the default. You’ll also notice I’m using my own error variable. If there is an error, I can handle it more gracefully. I’ll let you test it with a bogus scheduled job name to see what happens.

But perhaps the biggest change is that I define my own object type, based on the Job object.

For every job result insert a new typename. Because I might have multiple objects I need to insert the typename for each one. As I was working on this I originally was inserting my typename into the Microsoft.PowerShell.ScheduledJob.ScheduledJob object. But my custom formatting wasn’t working property, so I found that by selecting all properties, which has the effect of creating a Selected.Microsoft.PowerShell.ScheduledJob.ScheduledJob my changes worked.

Inserting the typename is only part of the process. In the script file that defines the function, I included code to take advantage of Update-TypeData. In PowerShell 3.0 we no longer need to deal with XML files. Now type updates can be done on-the-fly. So instead of creating my custom properties with Select-Object and custom hash tables, I add them as alias properties. I so something similar to create the Run property.

The last part of my revision is to define the default display property set. The effect is that when I run my function, if I don’t specify any other formatting, by default I’ll see the properties I want.

And I still have access to all of the other properties as well.


Now I have a tool, complete with an alias, with defaults that work for me, but if I need to see something else I can adjust the output based on my parameters. If you want to try this, save the function and type information to the same script file.