Tuesday, February 15, 2022

Create Calendar Event on all user mailboxes

The other day I was asked by our HR department if it was possible to create a calendar event on all user mailboxes. They didn’t want to send a “normal” meeting invite to dozens of thousands of users that people would have to accept, reject, or ignore. All they wanted was a simple all-day calendar event that would notify users about this particular event.

In my opinion, this has always been one of those features I don’t know why Microsoft never added to Exchange. I can think of so many cases where this would be so useful for so many organisations, but here we are. I remembered reading about something like this a few years back, but it turned out I was thinking about the Remove-CalendarEvents cmdlet introduced in Exchange 2019 and Online. This cmdlet allows admins to cancel future meetings in user or resource mailboxes, which is great when someone leaves the organisation for example.

So that was not an option. I thought about using Exchange Web Services (EWS). I’ve written quite a few EWS scripts and that was an option. However, it is all about Graph API nowadays, so that was by far the best option. But can this be done using Graph API? Of course it can! For that, we use the Create Event method:

POST /users/{id | userPrincipalName}/events

POST /users/{id | userPrincipalName}/calendar/events

POST /users/{id | userPrincipalName}/calendars/{id}/events

 

I’ve also written many Graph API scripts and they work great! However, I’ve had to use lengthy functions to get a token, query Graph API, etc., which made these scripts long and complex... However, with the Graph API SDK, this is far from the case! Now it is extremely easy for admins and developers to write PowerShell Graph API scripts! It is really, really straightforward, and no need to rely on HTTP Post requests!

 

Requirements

You will need to have, or create, an app registration in Azure and use a digital certificate for authentication. This link explains how to easily set this up: Use app-only authentication with the Microsoft GraphPowerShell SDK.

The Graph API permissions required for the script to work are 'Calendars.ReadWrite' and 'User.Read.All' (again, if using the -AllUsers switch). Both of type Application.

With the Graph API SDK, you will need the 'Microsoft.Graph.Calendar' and 'Microsoft.Graph.Users' (if using the -AllUsers switch, more on this later) modules. For more information on the SDK and how to start using it with PowerShell, please visit this link.

  

Script Parameters

-UsersFile

TXT file containing the email addresses or UPNs of the mailboxes to create a calendar event on.

 

-ExcludeUsersFile

TXT file containing the email addresses of the mailboxes NOT to create a calendar event on.

Whenever the script successfully creates an event on a user’s mailbox, it saves the user’s SMTP/UPN to a file named 'CreateCalendarEvent_Processed.txt'. This is so the file can be used to re-run the script for any remaining users (in case of a timeout or any other issues) without the risk of duplicating calendar entries.

 

-AllUsers

Creates a calendar event on all Exchange Online mailboxes of enabled users that have an EmployeeID. This can, and should, be adapted to your specific environment or requirement.

The script does not use Exchange Online to retrieve the list of mailboxes. It retrieves all users from Azure AD that have the Mail and EmployeeID attributes populated.

 

Script Outputs

  1. The script prints to the screen any errors, as well as all successful calendar entries created.
  2. It also generates a log file named ‘CreateCalendarEvent_Log_date’ with the same information.
  3. Whenever it successfully creates an event on a user's mailbox, it outputs the user's SMTP/UPN to a file named ‘CreateCalendarEvent_Processed.txt’. This is so the file can be used to re-run the script for any remaining users (in case of a timeout or any other issues) without the risk of duplicating calendar entries.
  4. For any failures when creating a calendar event, the script writes the user's SMTP/UPN to a file named ‘CreateCalendarEvent_Failed.txt’ so admins can easily analyse failures (the same is written to the main log file).

 

Notes

When using the -AllUsers parameter, the script uses the Get-MgUser cmdlet to retrieve Azure Active Directory user objects. I decided not to use Exchange Online cmdlets to keep things simple and because I wanted only mailboxes linked to users that have an EmployeeID. Obviously, every scenario is going to be different, but it should be easy to adapt the script to your specific requirements.

One thing I found, was that running Get-MgUser against a large number of users (in my case, 25000+ users), PowerShell 5.1 was crashing for no apparent reason. Other users on the internet were having the exact same problem when running for a few thousand users. It turns out PowerShell 5.1 default memory allocation will cause the script to crash when fetching large data sets… The good news is that it works great with PowerShell 7+!

The script is slow... When I ran it for 37000+ users, it took approximately 1 second per user. Need to look into JSON batching to create multiple events in one single request.

The script will throw errors in an Hybrid environment with mailboxes on-prem (as they are returned by Get-MgUser). If this is your case, you might want to use an Exchange Online cmdlet instead of Get-MgUser (or get all your mailboxes and then use the -UsersFile parameter).

 

Script

You can get the script on GitHub here.

 

Examples

C:\PS> .\CreateCalendarEvent.ps1 -AllUsers

This command will:

  1. Retrieve all users from Azure AD that have the Mail and EmployeeID attributes populated;
  2. Create a calendar event on their mailboxes. The properties of the calendar event are detailed and configurable within the script.

 

C:\PS> .\CreateCalendarEvent.ps1 -AllUsers -ExcludeUsersFile .\CreateCalendarEvent_Processed.txt

This command will:

  1. Retrieve all users from Azure AD that have the Mail and EmployeeID attributes populated;
  2. Create a calendar event on their mailboxes, unless they are in the 'CreateCalendarEvent_Processed.txt' file.

No comments:

Post a Comment