Adding and Subtracting Dates with PowerShell

Doctor Scripto

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 

1 comment

Discussion is closed. Login to edit/delete existing comments.

  • Martijn Balink 0

    Hi Scripting doctor,
    I have a script that disables user accounts when they leave the company, and deletes the account 30 days later. To calculate the day 30 days in the future, I have a simple piece of code:
    # Calculate account deletion date
    $FutureDate=(get-date).AddDays(30)
    $FutureDatePrint = $FutureDate.tostring(“yyyy-MM-dd”)
    I write the date ($FutureDatePrint) back in a CSV file, which I process on a daily basis to see what accounts to delete.
    Not sure if it matters, but this year is a leap year. I disabled a user on January 30th and the deletion date was set to february 30th 2020. My delete script did not appreciate that date :-).
    The server it runs on is a fully patched Windows 2012 R2 server, running powershell 5.1 build 14409 .
    Is this a bug in powershell or is there something wrong with my code?
    Thanks!
    Martijn

Feedback usabilla icon