Determine the Last Day of the Previous Month with PowerShell

I recently had a need to determine the last day of the previous month with PowerShell. Unless I'm overlooking something, PowerShell doesn't natively have a way to determine this.

Luckily, the System.Time class in the .NET Framework has a DaysInMonth method that returns the number of days in a specific month which effectively gives you the last day of the month. The command to determine what I needed was simple enough:

1$PriorMonth = (Get-Date).AddMonths(-1)
2$LastDay = [System.DateTime]::DaysInMonth($PriorMonth.Year, $PriorMonth.Month)
3[datetime]"$($PriorMonth.Month), $LastDay, $($PriorMonth.Year), 23:59:59.999"

lastdayofmonth0.jpg

I went ahead and created a well documented and reusable function that is more dynamic to use in similar scenarios in the future:

 1function Get-MrLastDayOfMonth {
 2
 3<#
 4.SYNOPSIS
 5    Determines the last day of the specified month(s).
 6
 7.DESCRIPTION
 8    Get-MrLastDayOfMonth is a function that returns the last day of one or
 9    more months that are specified via parameter or pipeline input.
10
11.PARAMETER Date
12    The date(s) to determine the last day for. The default is the previous month.
13
14.EXAMPLE
15    Get-MrLastDayOfMonth
16
17.EXAMPLE
18     Get-MrLastDayOfMonth -Date (Get-Date).AddMonths(1)
19
20.EXAMPLE
21     (Get-Date).AddMonths(-3) | Get-MrLastDayOfMonth
22
23.EXAMPLE
24    6..1 | Foreach-Object {(Get-Date).AddMonths(-$_)} | Get-MrLastDayOfMonth
25
26.INPUTS
27    DateTime
28
29.OUTPUTS
30    DateTime
31
32.NOTES
33    Author:  Mike F Robbins
34    Website: http://mikefrobbins.com
35    Twitter: @mikefrobbins
36#>
37
38    [CmdletBinding()]
39    param (
40        [Parameter(ValueFromPipeline=$true)]
41        [ValidateNotNullOrEmpty()]
42        [datetime[]]$Date = (Get-Date).AddMonths(-1)
43    )
44
45    PROCESS {
46        foreach ($d in $Date) {
47            $LastDay = [System.DateTime]::DaysInMonth($d.Year, $d.Month)
48            [datetime]"$($d.Month), $LastDay, $($d.Year), 23:59:59.999"
49        }
50    }
51
52}

I'll work through the examples of the function so you can see how it can be used. Running it without any parameters causes it to default to finding the last day of the previous month:

1. .\Get-MrLastDayOfMonth.ps1
2Get-MrLastDayOfMonth

lastdayofmonth1.jpg

The second example shows providing parameter input to get the last day for next month:

1Get-MrLastDayOfMonth -Date (Get-Date).AddMonths(1)

lastdayofmonth2.jpg

The third example shows determining the last day of the month, three months ago:

1(Get-Date).AddMonths(-3) | Get-MrLastDayOfMonth

lastdayofmonth3.jpg

And the final example shows determining the last day of the month for the previous six months via pipeline input:

16..1 | Foreach-Object {(Get-Date).AddMonths(-$_)} | Get-MrLastDayOfMonth

lastdayofmonth4.jpg

I actually figured out another way to accomplish this task in PowerShell between the time I wrote this blog and the time I published it, but I thought I would leave the previous content intact as well.

You know the first of a month is always going to be number 1 so you can actually subtract one millisecond from the first to receive the last day of the month:

1(Get-Date -Date 6/1/14).AddMilliseconds(-1)

lastdayofmonth5.jpg

And for a more dynamic version of the previous one-liner, you could do something crazy like this:

1(Get-Date | ForEach-Object {Get-Date -Date ([datetime]"$($_.Month) 1, $($_.Year)")}).AddMilliseconds(-1)

lastdayofmonth6.jpg

I don't normally publish commands with aliases on my blog, but since that previous command is fairly cryptic already, I'll make an exception in this scenario:

1(date|%{date("$($_.Month) 1,$($_.Year)")}).AddMilliseconds(-1)

lastdayofmonth7.jpg

Whatever you do, please don't use aliases or positional parameters in your scripts!

µ