Prof. Powershell
Perfect Timing with New-Object
Create a timer object with PowerShell New-Object cmdlet to schedule recurring tasks at intervals.
- By Jeffery Hicks
- 03/06/2012
You may have scenarios where you want to execute some PowerShell code at repeated intervals. One way to accomplish this would be to go through the effort of creating a scheduled task to run a PowerShell script or command. There's nothing wrong with this approach, but sometimes it is a lot of work, especially if you only need a temporary solution. Let me show you an alternative with a special type of object and event subscriptions.
In Windows, things happen all the time: services start, processes terminate, files are closed etc. When one of these predefined actions, or events, occurs, it is said to have "fired." In Windows programming we can create special objects to listen for these events, called event subscribers. We can also use Windows PowerShell and it doesn't require any programming skills.
In the scenario I outlined at the beginning, the type of object we want to subscribe to is a timer object, which we can easily create with the New-Object cmdlet:
PS C:\> $timer = new-object timers.timer
Here's what we created:
PS C:\> $timer
AutoReset : True
Enabled : False
Interval : 100
Site :
SynchronizingObject :
Container :
The key properties are Enabled and Interval. The former should be self-explanatory. The latter is the number of milliseconds that the timer will count down. The default is 100. When the timer reaches zero, it will start counting down again. You can control that behavior with the AutoReset property. I'll go ahead and set a few values:
PS C:\> $timer.interval=10000
PS C:\> $timer.Enabled=$true
The timer will now count down every 10 seconds and it is ready to go, although we haven't started it yet. Before we go any further, let's look more closely at this object.
PS C:\> $timer | get-member
TypeName: System.Timers.Timer
Name MemberType Definition
---- ---------- ----------
Disposed Event System.EventHandler Disposed(System.Obj...
Elapsed Event System.Timers.ElapsedEventHandler Elaps...
BeginInit Method System.Void BeginInit()
Close Method System.Void Close()
CreateObjRef Method System.Runtime.Remoting.ObjRef CreateOb...
Dispose Method System.Void Dispose()
EndInit Method System.Void EndInit()
Equals Method bool Equals(System.Object obj)
GetHashCode Method int GetHashCode()
GetLifetimeService Method System.Object GetLifetimeService()
GetType Method type GetType()
InitializeLifetimeService Method System.Object InitializeLifetimeService()
Start Method System.Void Start()
Stop Method System.Void Stop()
ToString Method string ToString()
AutoReset Property System.Boolean AutoReset {get;set;}
Container Property System.ComponentModel.IContainer Contai...
Enabled Property System.Boolean Enabled {get;set;}
Interval Property System.Double Interval {get;set;}
Site Property System.ComponentModel.ISite Site {get;s...
SynchronizingObject Property System.ComponentModel.ISynchronizeInvok...
Notice the events at the beginning? These are things we can subscribe to. To do that we will need to create an event subscription using the Register-ObjectEvent cmdlet:
PS C:\> Register-ObjectEvent -InputObject $Timer -EventName Elapsed -SourceIdentifier Test
The event name is what we're watching for. When the timer reaches zero the Elapsed event fires, and we'll be notified. It is a good idea to include a SourceIdentifier to name the subscription. Finally, in order for this to do anything we need to start the timer object.
PS C:\> $timer.start()
Now that it is running let's quickly look at what we created when we registered for the event.
PS C:\> Get-EventSubscriber
SubscriptionId : 1
SourceObject : System.Timers.Timer
EventName : Elapsed
SourceIdentifier : Test
Action :
HandlerDelegate :
SupportEvent : False
ForwardEvent : False
If you have a many event subscriptions using SourceIdentifier really comes in handy. At this point probably at least 10 seconds have expired so let's see if anything was detected. We'll use the Get-Event cmdlet.
PS C:\> get-event | select –first 2
ComputerName :
RunspaceId : afed5fc4-0309-4d82-8beb-b50c5c4cf787
EventIdentifier : 1
Sender : System.Timers.Timer
SourceEventArgs : System.Timers.ElapsedEventArgs
SourceArgs : {System.Timers.Timer, System.Timers.ElapsedEventArgs}
SourceIdentifier : Test
TimeGenerated : 2/2/2012 5:01:10 PM
MessageData :
ComputerName :
RunspaceId : afed5fc4-0309-4d82-8beb-b50c5c4cf787
EventIdentifier : 2
Sender : System.Timers.Timer
SourceEventArgs : System.Timers.ElapsedEventArgs
SourceArgs : {System.Timers.Timer, System.Timers.ElapsedEventArgs}
SourceIdentifier : Test
TimeGenerated : 2/2/2012 5:01:20 PM
MessageData :
You can see from TimeGenerated that these are 10 seconds apart. The timer will continue to generate events until I exit PowerShell, get rid of the subscription (I'll cover that next time) or simply stop the timer.
PS C:\> $timer.stop
If I later restart the timer, I'll continue to get event notifications for as long as I have a subscriber. That's all I have time for this time, but hopefully you've grasped the fundamental concepts. Next time, I'll show you how to hook up an action to this event.
About the Author
Jeffery Hicks is an IT veteran with over 25 years of experience, much of it spent as an IT infrastructure consultant specializing in Microsoft server technologies with an emphasis in automation and efficiency. He is a multi-year recipient of the Microsoft MVP Award in Windows PowerShell. He works today as an independent author, trainer and consultant. Jeff has written for numerous online sites and print publications, is a contributing editor at Petri.com, and a frequent speaker at technology conferences and user groups.