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

PowerShell Calendaring Revisited

Posted on September 28, 2018September 28, 2018

Early this week, I came across an old snippet of code in my scripts folder, originally published by Lee Holmes. It was an old script, from 2008, on using PowerShell to display a calendar with out of office information.  I seem to recall that I had been trying to do something similar -- display a monthly calendar in the console, when I came across Lee's much better solution. I decided to revive his script and update it. The new version includes a function that displays a calendar in your console.

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!

The original script let you specify a begin and end date of months to display. You could also specify days which would be highlighted with asterisks or square brackets.  I decided to simplify and only kept the code to highlight certain days with asterisks.  I also made the decision to turn the original code, which was a script, into an advanced function. Going to a function, made it easier to use and let me take advantage of advanced function features like parameter sets. Yes, I know you can use many of these features in a script file, but the function makes it all much easier.  In fact, now that I think about the code I've written, give a me a few minutes. I'll be right back.

I realized I needed to take the code and turn it into a proper module. It is now published to the PowerShell Gallery.

Install-Module PSCalendar

The module should work on PowerShell Core with both Windows and Linux platforms. I don't have a Mac to test.  The source code can be found at https://github.com/jdhitsolutions/PSCalendar, although I'm going to explain a few things here.

The primary command is Get-Calendar.  The default behavior is to display the current month and highlight the current date.

get-calendar

You can also specify a range of months.

get-calendar-3

I wanted to have the ability to specify a month, but I also needed the value to be culture-aware. I didn't want to hard-code a ValidateSet attribute because that would have force me to use US values. I started down the path of using a dynamic param but those are not very user-friendly. So I ended up adding an auto-completer to the module.

PowerShell now includes a command called Register-AutoCompleter. This command allows you to define code that will help you autocomplete a parameter value. You've probably seen that when you type Get-Service followed by a space and then a tab, that PowerShell autocompletes possible values. You can add the same functionality to your code.

Register-ArgumentCompleter -CommandName Get-Calendar, Show-Calendar -ParameterName Month -ScriptBlock {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

    #get month names, filtering out blanks
    (Get-Culture).DateTimeFormat.MonthNames | Where-object {$_ -match "\w+" -and $_ -match "$WordToComplete"} |
        ForEach-Object {
        [System.Management.Automation.CompletionResult]::new($_.Trim(), $_.Trim(), 'ParameterValue', $_)
    }
}

The code is very similar to what you see when looking at help for Register-AutoCompleter. In my case, I am defining an autocompleter for the commands Get-Calendar and Show-Calendar (more on this one later) that both have a parameter name of Month. The scriptblock is essentially a function that will be executed. As far as I can tell use the parameters with the scriptblock as I have here. There is very little documentation on this command so I'm working from examples . The first part of the scriptblock is getting the culture specific month names. On my computer I was also getting some blanks so I'm filtering to Where-Object to only keep values with word characters. I'm also using the $WordToComplete variable/parameter. When I run Get-Calendar -Month and begin pressing Tab, PowerShell will start with the first item in the list, January. But if I type "ju" and hit tab, PowerShell will jump to "June".  The "ju" becomes the value of $WordToComplete. Each month name is then added as a completion result. The parameters are CompletionText, ListItemText,ResultType (which is a paramter value), and ToolTip.

I do something similar with the -Year parameter to display the current year plus the next 5.

Register-ArgumentCompleter -CommandName Get-Calendar, Show-Calendar -ParameterName Year -ScriptBlock {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameter)

    $first = (Get-Date).Year
    $last = (Get-Date).AddYears(5).Year
    $first..$last |
        ForEach-Object {
        [System.Management.Automation.CompletionResult]::new($_, $_, 'ParameterValue', $_)
    }
}

Here's what it looks like:

autocomplete-month

Currently, there's nothing preventing a user from entering an invalid month. But I'm assuming the autocompleter provides guidance. Still, I will go back at some point and add some additional error handling for an incorrect month.

Oh, and the command also lets you highlight one or more dates.

get-calendar-2

But I love color. So I also wrote a "wrapper" function called Show-Calendar that uses the same parameters, but this uses Write-Host to write a colorized version to the console.

show-calendar

Get-Calendar writes a string to the pipeline.  So the challenge I had was turning the string into an array of strings and write each line back using Write-Host. The trickiest part was identifying days marked with asterisks so I could display those days in a highlight color. This required a little regular expression magic.

$cal = Get-Calendar @PSBoundParameters

    #turn the calendar into an array of strings
    $calarray = $cal.split("`n")

    # a regular expression pattern to match on highlighted days
    [regex]$m = "(\*)?[\s|\*]\d{1,2}(\*)?"
    foreach ($line in $calarray) {

        if ($line -match "\d{4}") {
            write-Host $line -ForegroundColor Yellow
        }
        elseif ($line -match "\w{3}|-{3}") {
            Write-Host $line -ForegroundColor cyan
        }
        elseif ($line -match "\*") {
            #write-host $line -foregroundcolor Magenta
            $week = $line
            $m.Matches($week).Value| foreach-object {

                $day = "$_"

                if ($day -match "\*") {
                    write-host "$($day.replace('*','').padleft(3," "))  " -NoNewline -ForegroundColor $HighlightColor
                }
                else {
                    write-host "$($day.PadLeft(3," "))  " -nonewline
                }
            }
            write-host ""
        }
        else {
            Write-host $line
        }
    }

But now I can use it like this:

show-calendar-2

I am using Show-Calendar in my PowerShell profile script along with some other code to highlight important dates coming up.

I hope this shows you that old code can still serve a purpose. Give the module a try and let me know what you think. Use the Github repo to report any issues.

 

Enjoy!

 

UPDATE: I was concerned that there might be problems with this code in other cultures and that appears to be the case. It is challenging testing and developing with other cultures. But I've filed an issue with myself and will look into it further.

UPDATE #2: I've pushed v1.2.0 to the PowerShell Gallery. I'm basing a number of cultural decisions based on culture values from [system.threading.thread]::CurrentThread.  For non-US friends, please let me know how this works for you.


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

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