Summary: Microsoft Scripting Guy, Ed Wilson, talks about adding and subtracting dates with Windows PowerShell.
Microsoft Scripting Guy, Ed Wilson, is here. One of the things I really like about Windows PowerShell is the way it simplifies adding and subtracting from dates. For example, if I want to find users who haven’t logged in to the domain for 120 days, I need to be able to create a date that was 120 days ago. Then I need to get the date of their last log-in, and see if that date is more recent than 120 days ago.
I may need to do the same thing with the last time that files were accessed or to examine the date that print jobs were submitted to a print server. I may simply want to see all events from the security log that occurred within a specific date range. I may want to see how many days until a user's password expires so that I can warn them when the password comes within 10 days of expiring.
Whatever the need, quite often dates come into play. When I know how to create a specific DateTime object, whether in the past, in the future, or even for the present, I can use that DateTime object as an input parameter for other Windows PowerShell cmdlets.
There are six core Windows PowerShell cmdlets that accept DateTime objects as input parameters. These cmdlets are:
PS C:\> Get-Command -ParameterType [datetime] | ft -AutoSize
CommandType Name ModuleName
----------- ---- ----------
Cmdlet Get-Date Microsoft.PowerShell.Utility
Cmdlet Get-EventLog Microsoft.PowerShell.Management
Cmdlet Get-Job Microsoft.PowerShell.Core
Cmdlet New-TimeSpan Microsoft.PowerShell.Utility
Cmdlet Set-Date Microsoft.PowerShell.Utility
Cmdlet Test-Path Microsoft.PowerShell.Management
To find which parameters accept a DateTime object, I can use the Get-Help cmdlet and look at the syntax for the various parameter sets. This technique is shown here for the Test-Path cmdlet:
PS C:\> (Get-Help test-path).syntax
Test-Path [-Path] <String[]> [-Credential <PSCredential>] [-Exclude <String[]>]
[-Filter <String>] [-Include <String[]>] [-IsValid] [-PathType <TestPathType>]
[-UseTransaction [<SwitchParameter>]] [<CommonParameters>]
Test-Path [-Credential <PSCredential>] [-Exclude <String[]>] [-Filter <String>]
[-Include <String[]>] [-IsValid] [-PathType <TestPathType>] -LiteralPath
<String[]> [-UseTransaction [<SwitchParameter>]] [<CommonParameters>]
Test-Path [-NewerThan <DateTime>] [-OlderThan <DateTime>] [<CommonParameters>]
Adding dates and times—the easy way
If I want to add hours to a DateTime object, all I need to do is to create an instance of a DateTime object, and call the AddHours method. Here is an example using the Get-Date cmdlet:
PS C:\> (Get-Date).AddHours(2)
Friday, January 16, 2015 6:27:46 PM
I can also use an intermediate variable to hold the DateTime object and to call the method. This technique appears here:
PS C:\> $dte = Get-Date
PS C:\> $dte.AddHours(3)
Friday, January 16, 2015 7:29:00 PM
It is also possible to convert a string into a DateTime object by using the [dateTime] type accelerator. I first create a specific date and time, and then I call the AddHours method:
PS C:\> $dte = Get-Date
PS C:\> $dte.AddHours(3)
Friday, January 16, 2015 7:29:00 PM
If I want to add days, it is the same technique, but I call the AddDays method instead of AddHours. This technique is shown here by using the Get-Date cmdlet:
PS C:\> Get-Date
Friday, January 16, 2015 4:32:57 PM
PS C:\> (Get-date).AddDays(12)
Wednesday, January 28, 2015 4:33:00 PM
I can add lots of stuff to DateTime objects. Here is a list of the various Add methods.
PS C:\> Get-date | Get-Member -MemberType Method -Name a*
TypeName: System.DateTime
Name MemberType Definition
---- ---------- ----------
Add Method datetime Add(timespan value)
AddDays Method datetime AddDays(double value)
AddHours Method datetime AddHours(double value)
AddMilliseconds Method datetime AddMilliseconds(double value)
AddMinutes Method datetime AddMinutes(double value)
AddMonths Method datetime AddMonths(int months)
AddSeconds Method datetime AddSeconds(double value)
AddTicks Method datetime AddTicks(long value)
AddYears Method datetime AddYears(int value)
If I want to create a DateTime object that represents a date in the past, I still use the appropriate Add method, but I supply a negative number. So in the following example, I create a DateTime object that is 12 days in the past:
PS C:\> Get-Date
Friday, January 16, 2015 4:34:53 PM
PS C:\> (Get-Date).adddays(-12)
Sunday, January 4, 2015 4:35:12 PM
The technique works exactly the same way for subtracting hours. Here, I create a DateTime object that is five hours in the past:
PS C:\> Get-Date
Friday, January 16, 2015 4:36:24 PM
PS C:\> (Get-Date).AddHours(-5)
Friday, January 16, 2015 11:36:46 AM
I can even combine methods, so I do not have to add -1 day and then add -2 hours by using intermediate expressions (unless I want to). Here is an example of using intermediate expressions:
$dte = Get-Date
$dte = $dte.AddDays(-1)
$dte = $dte.AddHours(-2)
$dte
But I can simplify this into a single line as shown here:
PS C:\> ((Get-Date).AddDays(-1)).addhours(-2)
Thursday, January 15, 2015 2:42:28 PM
The advantage of using the intermediate expressions is it is probably easier to read.
Some fun with DateTime objects
Because it is so easy to use WMI to find the remaining runtime on a laptop battery, and it is so easy to add minutes, I created a simple script to let me know when my laptop will shut down. I use the Get-CimInstance cmdlet to retrieve the Win32_Battery WMI class. I then choose the EstimatedRunTime property (which displays in minutes remaining on the battery), and I store the result in the $MinutesRunTime variable.
I then use the AddMinutes method from the DateTime object that I get from Get-Date, and I display the result. Because I want to perform the date calculation before I display the string, I use the subexpression $() to force the evaluation of the expression first. Here is the script:
$MinutesRunTime = (Get-CimInstance win32_battery).EstimatedRunTime
"The laptop will shut down at $((Get-Date).AddMinutes($MinutesRunTime))"
Note I only have an instance of Win32_Battery if I am using a laptop or other portable device (such as a Microsoft Surface). Also, if I am plugged in and charging, it does not display accurate results.
That is all there is to adding and subtracting dates. Date Time Week will continue tomorrow when I will talk about more cool stuff.
I invite you to follow me on Twitter and Facebook. If you have any questions, send email to me at scripter@microsoft.com, or post your questions on the Official Scripting Guys Forum. See you tomorrow. Until then, peace.
Ed Wilson, Microsoft Scripting Guy