Skip to content
Menu
The Lonely Administrator
  • PowerShell Tips & Tricks
  • Books & Training
  • Essential PowerShell Learning Resources
  • Privacy Policy
  • About Me
The Lonely Administrator

Friday Fun: Tickle Me PowerShell!

Posted on July 24, 2015July 24, 2015

I work at home for myself which means I have to act as my own assistant, reminding me of important events and tasks. And sometimes I need a little help. So why not use PowerShell? In the past I've used and written about using a background job to wait until a certain number of minutes have passed and then display a popup message using the MSG.EXE command line utility. The drawback to my previous approach is that if I close my PowerShell session I lose the background job. For reminders in the next 10-30 minutes perhaps that's ok. But for longer term reminders, I need a better solution.

Manage and Report Active Directory, Exchange and Microsoft 365 with
ManageEngine ADManager Plus - Download Free Trial

Exclusive offer on ADManager Plus for US and UK regions. Claim now!

I don't know why I didn't go this route from the beginning, but I can accomplish the same result using a PowerShell scheduled job. A PowerShell scheduled job runs via the task scheduler which means it persists outside of PowerShell. All I really need are three things:

  1. The time to kick off the task
  2. The command to run
  3. A registered scheduled job object

The time to kick off is the Job Trigger. Here's how I can create a trigger for 30 minutes from now. My reminder only needs to run once.

$trigger = New-Jobtrigger -Once -at (Get-Date).AddMinutes(30)

The command will be the MSG.EXE command.

$cmd = "msg.exe $env:username Important phone call in 5 minutes"

This needs to be in the form of a script block.

$sb = {
Param($cmd,$jobname)
Invoke-Expression $cmd
#forcibly remove the scheduledjob
Get-ScheduledJob -Name $jobname | Unregister-ScheduledJob -Force
}

In my scriptblock I'm also going to delete the scheduled job. Finally I need to register it.

$jobname = "phone call"
Register-ScheduledJob -ScriptBlock $sb -Name $jobName -MaxResultCount 1 -Trigger $Trigger -ArgumentList $cmd,$jobname

When the time arrives I get a popup message on my screen.

sample popup reminder
sample popup reminder

You can configure how long the message will be displayed before it is automatically dismissed. That's the essential part of the process. Here is the complete script to define the function, including an optional alias.

#requires -version 4.0
#requires -module PSScheduledJob

Function New-ScheduledReminderJob {

<#
.Synopsis
Create a scheduled reminder background job.
.Description
This command uses the MSG.EXE command line tool to send a reminder message to the currently logged on user, presumably yourself. The intention is to set ad-hoc popup reminders for the current user. The message will automatically dismiss after 1 minute unless you use the Wait parameter.

You can schedule the reminder for a certain number of minutes set the reminder to run at a specific date and time. The default is to schedule a reminder in 1 minute.

The function creates a scheduled background job so that you can close your PowerShell session without losing the job as well as persisting during reboots. The scheduled job will be removed upon completion. 

.Parameter Message
The text to display in the popup.
.Parameter Time
The date and time to display the popup. If you enter just a time, it will default to the current day. See examples. 
This parameter has aliases of date and dt. 
.Parameter JobName
A name to assign to the job. If you don't specify a name, the function will use the name Reminder-N where N is an incrementing counter starting at 1. This parameter has an alias of Name.
.Parameter Minutes
The number of minutes to wait before displaying the popup message.
.Parameter Wait
The number of minutes to display the message before it automatically is dismissed. The default is 1 minute.
.Example
PS C:\> new-scheduledreminderjob "Switch over laundry" -minutes 40 -name SwitchLaundry

Id         Name            JobTriggers     Command                                  Enabled   
--         ----            -----------     -------                                  -------   
1          SwitchLaundry   1               ...                                      True

This command creates a new job that will display a message in 40 minutes
.Example
PS C:\> new-scheduledreminderjob "Go home" -time "5:00PM" -wait 2 | out-null

Create a reminder to be displayed at 5:00PM today for 2 minutes but don't display the job result.

.Notes
Last Updated: July 24, 2015
Version     : 2.2
Author      : Jeff Hicks (@JeffHicks)
              https://jdhitsolutions.com/blog

Learn more about PowerShell:
Essential PowerShell Learning Resources
**************************************************************** * DO NOT USE IN A PRODUCTION ENVIRONMENT UNTIL YOU HAVE TESTED * * THOROUGHLY IN A LAB ENVIRONMENT. USE AT YOUR OWN RISK. IF * * YOU DO NOT UNDERSTAND WHAT THIS SCRIPT DOES OR HOW IT WORKS, * * DO NOT USE IT OUTSIDE OF A SECURE, TEST SETTING. * **************************************************************** .Link msg.exe Register-ScheduledJob .Inputs None .Outputs ScheduledJob #> [cmdletbinding(DefaultParameterSetName="Minutes",SupportsShouldProcess)] Param( [Parameter(Position=0,Mandatory,HelpMessage="Enter the alert message text")] [string]$Message, [Parameter(ParameterSetName="Time")] [ValidateNotNullorEmpty()] [Alias("date","dt")] [datetime]$Time, [Parameter(ParameterSetName="Minutes")] [ValidateNotNullorEmpty()] [int]$Minutes = 1, [Alias("Name")] [string]$JobName, [int]$Wait = 1 ) Begin { Write-Verbose -Message "[Starting] $($MyInvocation.Mycommand)" } #begin Process { Write-Verbose -Message "[Trace] Parameter set = $($PSCmdlet.ParameterSetName)" If ($PSCmdlet.ParameterSetName -eq 'Minutes') { #calculate the scheduled job time from the number of minutes [datetime]$Time= (Get-Date).AddMinutes($minutes) } #create the scheduled job trigger $Trigger = New-JobTrigger -At $Time -Once Write-Verbose "[Trace] Reminder Time = $Time" if (-Not $JobName) { #get last job ID to build the jobname #ignore any errors if job not found Write-Verbose "[Status] Checking for previous Reminder scheduled jobs" $lastjob = Get-ScheduledJob -Name "Reminder*" -ErrorAction SilentlyContinue | sort ID | select -last 1 if ($lastjob) { #define a regular expression [regex]$rx ="\d+$" #extract the counter number [string]$counter = ([int]$rx.Match($lastJob.name).Value +1) } else { [string]$counter = 1 } #define the job name $jobName = "Reminder-$Counter" } #if no job name specified Write-Verbose -Message "[Trace] Jobname = $jobname" #define the msg.exe expression [int]$WaitTime = $Wait * 60 Write-Verbose "[Trace] Display Wait time = $WaitTime seconds" Write-Verbose "[Status] Defining expression" [string]$cmd = "msg.exe $env:username /Time:$WaitTime $Message" Write-Verbose "[Trace] Command to execute = $cmd" #the scriptblock to run $sb = { Param($cmd,$jobname) Invoke-Expression $cmd #forcibly remove the scheduledjob Get-ScheduledJob -Name $jobname | Unregister-ScheduledJob -Force } Write-Verbose "[Trace] Scriptblock = $($sb | Out-String)" #add some options to support laptop users Write-Verbose "[Status] Creating scheduled job options" $options = New-ScheduledJobOption -ContinueIfGoingOnBattery -WakeToRun #create the scheduled job Write-Verbose "[Status] Registering the scheduled reminder job" Register-ScheduledJob -ScriptBlock $sb -Name $jobName -MaxResultCount 1 -Trigger $Trigger -ArgumentList $cmd,$jobname } #process End { Write-Verbose -Message "[Status] Ending $($MyInvocation.Mycommand)" } #end } #end function #add an alias Set-Alias -Name Tickle -Value New-ScheduledReminderJob

Now I can easily set reminders for myself, even something tomorrow, next week or next month. I can use the scheduled job cmdlets to manage my reminders. I wrote this with the assumption that you are setting popup reminders for yourself.

Let me know what you think.


Behind the PowerShell Pipeline

Share this:

  • Click to share on X (Opens in new window) X
  • Click to share on Facebook (Opens in new window) Facebook
  • Click to share on Mastodon (Opens in new window) Mastodon
  • Click to share on LinkedIn (Opens in new window) LinkedIn
  • Click to share on Pocket (Opens in new window) Pocket
  • Click to share on Reddit (Opens in new window) Reddit
  • Click to print (Opens in new window) Print
  • Click to email a link to a friend (Opens in new window) Email

Like this:

Like Loading...

Related

1 thought on “Friday Fun: Tickle Me PowerShell!”

  1. Pingback: BPOTW 2015-07-31 | SQL Notes From The Underground

Comments are closed.

reports

Powered by Buttondown.

Join me on Mastodon

The PowerShell Practice Primer
Learn PowerShell in a Month of Lunches Fourth edition


Get More PowerShell Books

Other Online Content

github



PluralSightAuthor

Active Directory ADSI Automation Backup Books CIM CLI conferences console Friday Fun FridayFun Function functions Get-WMIObject GitHub hashtable HTML Hyper-V Iron Scripter ISE Measure-Object module modules MrRoboto new-object objects Out-Gridview Pipeline PowerShell PowerShell ISE Profile prompt Registry Regular Expressions remoting SAPIEN ScriptBlock Scripting Techmentor Training VBScript WMI WPF Write-Host xml

©2025 The Lonely Administrator | Powered by SuperbThemes!
%d