A Step-To-Step-Tutorial
Automate the Productivity Hacks with PowerShell and Microsoft Graph API (P.2- Calendar Automation)
Productivity is a skill that can be acquired and automated.
If you’re searching for ways to turbocharge your efficiency and streamline tasks, you’ve come to the right place. In this series of 2 blog posts, we’ll explore how you can do so by leveraging the power of PowerShell and Mircrosoft Graph API in optimizing Outlook’s email and calendar, specifically:
- Part 1- Email Automation- Enhance email management by automating email classification and responses.
- Part 2- Calendar Automation- Employ calendar as a second brain to optimize your schedule.
2. Calendar Automation
2.1. Why do we need to automate calendar?
A study cited by Harvard Business Review reveals that the top three productivity tips are time boxing, prioritization, and saying no. Good news is that these practices can be implemented and automated using calendar optimization methods.
2.2. What are the productivity hacks?
In Part 1, our aim was to automate Email to minimize the need for context switching while working. But what negative impact does context switching have?
Hack 3: Limit Context Switching
Let’s play a game consisting of two rounds. Begin by dividing a blank paper into two columns:
- Round 1: In the first column, write numbers 1 to 20. In the second column, write Roman numerals I to XX.
- Round 2: This time, write row by row. Begin with 1 in the first column, followed by I in the second column. Then, proceed to 2 in the first column and II in the second column, and continue this pattern until you reach the end.
For most people, completing the first round is considerably faster than the second round. This is because the brain does not need to switch contexts, allowing for faster and smoother retrieval of information.
Hack 4: A productive meeting starts with a well-crafted invitation
t is perhaps one of the most overlooked sciences, disregarded by many individuals. Researches shown that 2 out of 3 employees complain that spending too much time in meetings hinders their overall productivity at work. For employees that attend the meeting, more than 35% found that they waste 2 to 5 hours per day on meetings and calls, but they achieve nothing to show.
These facts raise a valid and crucial question: How to create an efficient meeting? The answer is, an efficient meeting starts with an efficient invitation. An efficient invitation should address 5 following points:
Hack 5: Store the information on the place where you USE it
This is an exceptional and unconventional hack that suggests utilizing the calendar as a second brain by storing information in the locations where we need it, rather than where we organize it.
Many people tend to store information in various convenient locations, such as phone notes, computer documents, and more. However, this scattered approach often results in the same set of information being stored in multiple places. When the need arises to make sense of this information, it becomes time-consuming and energy-draining to gather and consolidate it. In some cases, the information is forgotten and remains unused, rendering the storage efforts pointless. Hence, a more innovative approach is to store information where it is needed, rather than focusing solely on organization. This enables faster retrieval and improved organization. As Albert Einstein once stated, intelligence lies not in the ability to store information, but in knowing where to find it.
“Intelligence is not the ability to store information, but to know where to find it.” -Albert Einstein
For instance, consider the following calendar event that pertains to the Google Cloud Conference I attended last month. Within the event’s note section, I included relevant information about Vertex AI and set a reminder to enable my out-of-office status. This way, I can conveniently refer back to the same calendar event to review my preparation notes and the knowledge I gained from the conference at a later time.
1.3. Implementing with PowerShell and Microsoft Graph API
The challenge now is how to automate those awesome hacks?
First step is to grant access to read and write in calendars and import related modules. Please refer to Part 1- Email Automation for the instruction on how to carry out those steps.
After that, create different calendars for various purposes such as for Marketing related, Finance related, Training, Personal Appointment or simply Team Birthday Reminder, etc.
#2.1: Create Calendars:
$calendar_names = @("Marketing", "Finance","Training","Personal Appointment","Team-Birthdays")
Foreach ($calendar_name in $calendar_names) {
New-MgUserCalendar -UserId $userId -Name $calendar_name
}
In Hack #2 of Part 1, we automated the categorization of incoming emails into relevant Action Folders. Next step, in Hack #3, we will automate the process of reducing context switching by scheduling specific times to check each folder, eliminating the need to constantly interrupt our workflow to check emails.
For instance, the following script schedules a recurring time slot to check the “Personal Appointment” calendar at 2 PM. The duration allotted for checking and responding to emails is set for one hour, from 2 PM to 3 PM.
#2.2: Set up the meeting based on the input from the email, meeting minutes:
# Check snooze 1 hour/ Personal Appointment folder - review emails at 2pm daily:
$calendarId = (Get-MgUserCalendar -UserId $userId -filter "Name eq 'Personal Appointment'" | Select-Object -ExpandProperty id)
$date = Get-Date -Hour 14 -Minute 0 -Second 0
$review_mail = @{
subject = "Check Important Messages"
body = @{
contentType = "HTML"
content = "Those are important but not urgent events"
}
start = @{
dateTime = $date.AddMinutes(0).ToString("yyyy-MM-ddTHH:mm:ss")
timeZone = "Pacific Standard Time"
}
end = @{
dateTime = $date.AddMinutes(60).ToString("yyyy-MM-ddTHH:mm:ss")
timeZone = "Pacific Standard Time"
}
attendees = @(
@{
emailAddress = @{
address = "your email"
}
type = "required"
}
)
allowNewTimeProposals = $true
}
New-MgUserCalendarEvent -UserId $userId -CalendarId $calendarId -BodyParameter $review_mail
The script above can be reused to implement Hack #4. You would just need to modify the content of the template in the example to incorporate the necessary elements such as purpose, agenda, outcome, preparation details, and decision makers.
Here’s an example of an effective meeting invitation that the content template should look like. It includes all five essential elements: purpose, agenda, desired outcome, preparation requirements, and the key decision makers:
To implement Hack #5, the following code can be used to create a prompt for users to input their notes. One of the convenient aspects, as compared to manually using the calendar, is the ability to filter events based on their names, eliminating the need to search for specific dates to locate the desired event in the calendar.
#2.3: Attach the notes
function New-Note {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$filter,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$content
)
#Retrieve the event
$eventId = (Get-MgUserEvent -UserId $userId -Filter "startswith(subject, '$filter')" | Select-Object -ExpandProperty id)
#Insert links/texts
$params = @{
body = @{
contentType = "HTML"
content = $content
}
}
#Update events
Update-MgUserEvent -UserId $userId -EventId $eventId -BodyParameter $params
}
In addition, users have the flexibility to add additional notes using the script provided below.
function Add-Note {
[CmdletBinding()]
param (
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$filter,
[Parameter(Mandatory)]
[ValidateNotNullOrEmpty()]
[string]$content
)
#Retrieve the event
$eventId = (Get-MgUserEvent -UserId $userId -Filter "startswith(subject, '$filter')" | Select-Object -ExpandProperty id)
#Insert links/texts
$params = @{
body = @{
contentType = "HTML"
content = (Get-MgUserEvent -UserId $userId -Filter "startswith(subject, '$filter')").Body.Content + $content
}
}
#Update events
Update-MgUserEvent -UserId $userId -EventId $eventId -BodyParameter $params
}
As a bonus, to create reminders for special events such as birthdays of team memebers, we could implement below script. Begin by filling in the dates for each individual in the parameter $birthdays as below:
#2.4: Reminder for Birthdays
# Set the birthdays
$birthdays = @{
"Alice" = "2023-01-01"
"Bob" = "2023-02-14"
"Charlie" = "2023-07-27"
}
The script below generates a calendar event to remind individuals 24 hours prior to related birthdays. Beside, it displays a message confirming the successful creation of the event for each birthday.
# Create the reminders
#Birthday Calendar
$calendarId = (Get-MgUserCalendar -UserId $userId -filter "Name eq 'Team-Birthdays'" | Select-Object -ExpandProperty id)
foreach ($birthday in $birthdays.GetEnumerator()) {
# Get the name and date of the birthday
$name = $birthday.Key
$date = $birthday.Value
# Calculate the reminder date (1 day before the birthday)
$reminderDate = [DateTime]::ParseExact($date, "yyyy-MM-dd", $null).AddDays(-1)
# Create the event
$birthday_reminder = @{
Subject = "$name's Birthday Reminder"
Body = @{
ContentType = "HTML"
Content = "Don't forget to wish $name a happy birthday tomorrow!"
}
Start = @{
DateTime = $reminderDate.ToString("yyyy-MM-ddTHH:mm:ssZ")
TimeZone = "UTC"
}
End = @{
DateTime = $reminderDate.ToString("yyyy-MM-ddTHH:mm:ssZ")
TimeZone = "UTC"
}
IsReminderOn = $true
ReminderMinutesBeforeStart = 1440 # 24 hours
}
# Create the event in the team calendar
New-MgUserCalendarEvent -UserId $userId -CalendarId $calendarId -BodyParameter $birthday_reminder
# Print the response
Write-Host "Event created for $name's birthday on $($reminderDate.ToString("yyyy-MM-dd")). Response:"
$response | Format-List
}
You can replicate the script to create reminders for other events, such as shopping, sending gift cards, or managing your to-do list, and so on.
Conclusion
Part 1 provides a concise tutorial outlining the step-by-step process to automate email classification and create efficient email templates. On the other hand, Part 2 offers a practical solution for automating calendar management, enabling effective time blocking and prioritization of impactful tasks.
The code above is written and explained clearly in every step so that it could enable even individuals with limited PowerShell knowledge to easily run and customize it according to their specific requirements.
Code is presented at PowerShell Conference 2023 and stored in its repo: https://github.com/psconfeu/2023/blob/main/AnhTran/Productivity%20Hack.ps1
Additionally, you can play around with other features such as checking whether the emails are read https://thesysadminchannel.com/how-to-check-if-an-email-was-read-using-graph-api-powershell-sdk
Feel free to comment below if you have any question. Thanks.