PowerShell

PowerShell: Dynamic generation of an iCal/vCalendar (ICS) format file

Generating your own custom calendar or event invites in the iCal (vCalendar) format is pretty easy, once you’ve read the 140+ page spec.

Actually, it’s a pretty complex but flexible way to build schedule items.  Just think about the possibly combinations that exist when you create a new meeting request or appointment in Outlook or your preferred calendar application.  You get recurrences, descriptions, summaries, invitees, location, start time, end time, all-day…. and the list goes on and on.

For this example, we’ll keep it simple and walk through building a function for an event with a yearly recurrence; something like a birthday or an anniversary.

The first part of this function is going to put together some of variables for building out the ICS file.  In this case, the function is going to ask for input for all the fields.  To truly automate, you’ll want to suck this information in from a file or another datasource since you’ll want to minimize the user intervention.

function CreateNewEvent {

# Custom date formats that we want to use
$longDateFormat = "yyyyMMddTHHmmssZ"
$dateFormat = "yyyyMMdd"

# Prompt the user for the start date in a specific format
$startDate = Read-Host -Prompt 'Enter the start date of the event in the format "yyyymmdd"'

# Give the event a name specified by the user
$eventSubject = Read-Host -Prompt 'Enter the event subject'

# This field is optional, but let's ask for the details (description)
$eventDesc = Read-Host -Prompt 'Enter the event description summary (optional)'

# Provide location information (also optional)
$eventLocation = Read-Host -Prompt 'Enter the event location (optional)'

Now that we have all of the info, we’ll start to build out the internal parts of the file.  For this part, we’re going to use the .NET StringBuilder class.  This will help us “string” the pieces together easily.  The first part of this file needs to contain information critical to the spec.

# Instantiate .NET StringBuilder
$sb = [System.Text.StringBuilder]::new()

# Fill in ICS/iCalendar properties based on RFC2445
[void]$sb.AppendLine('BEGIN:VCALENDAR')
[void]$sb.AppendLine('VERSION:2.0')
[void]$sb.AppendLine('METHOD:PUBLISH')
[void]$sb.AppendLine('PRODID:-//Braunweb//PowerShell ICS Creator Sample//EN')

Next, we’ll start to add the details that we collected about the event earlier.  This information is part of the VEVENT “object”.  The VCALENDAR “object” can contain multiple VEVENT definitions.  In our case, we’re keeping it to a single event.

[void]$sb.AppendLine('BEGIN:VEVENT')
[void]$sb.AppendLine("UID:" + [guid]::NewGuid())
[void]$sb.AppendLine("CREATED:" + [datetime]::Now.ToUniversalTime().ToString($longDateFormat))
[void]$sb.AppendLine("DTSTAMP:" + [datetime]::Now.ToUniversalTime().ToString($longDateFormat))
[void]$sb.AppendLine("LAST-MODIFIED:" + [datetime]::Now.ToUniversalTime().ToString($longDateFormat))
[void]$sb.AppendLine("SEQUENCE:0")
[void]$sb.AppendLine("DTSTART:" + $startDate)
[void]$sb.AppendLine("RRULE:FREQ=YEARLY;INTERVAL=1")
[void]$sb.AppendLine("DESCRIPTION:" + $eventDesc)
[void]$sb.AppendLine("SUMMARY:" + $eventSubject)
[void]$sb.AppendLine("LOCATION:" + $eventLocation)
[void]$sb.AppendLine("TRANSP:TRANSPARENT")
[void]$sb.AppendLine('END:VEVENT')

Once we’ve defined our event, we close out the “objects”.

[void]$sb.AppendLine('END:VCALENDAR')
}

Finally we can output the contents of the StringBuilder to an ICS file and then use that file to import into our preferred calendaring application.

# Output ICS File
$fileName = Read-Host -Prompt 'What should we call the ICS file? (end with .ics)'
$sb.ToString() | Out-File $fileName
Write-Host 'Operation complete! ICS file has been generated.'

Now you have a function that you can use to generate ICS files.  With some modifications you could adjust to use with other data sources and roll multiple events into a single ICS file.