Back to script library
Entra / Microsoft 365 · Exchange Online

Report calendar items

Generate a report of calendar items for a mailbox.

Connect & set up

Run these once per session. All scopes are read-only unless the script makes changes.

Connect-MgGraph -NoWelcome -Scopes Calendars.ReadBasic, User.ReadBasic.All

Run it

The main script. Copy it, or download the .ps1 and run it from your console.

param(
[int] $LookbackDays = 180,
[string] $StartDate = (Get-Date).AddDays(-$LookbackDays),
[string] $EndDate = (Get-Date).AddDays(1)
)
Connect-MgGraph -NoWelcome -Scopes Calendars.ReadBasic, User.ReadBasic.All
$Start = Get-Date($StartDate) -format s
$End = Get-Date($EndDate) -format s
$User = Get-MgUser -UserId (Get-MgContext).Account
Write-Host ("Fetching calendar information from {0} to {1}..." -f $StartDate, $EndDate)
[array]$Data = Get-MgUserCalendarView -StartDate $Start -EndDateTime $End -UserId $User.Id -All
If ($Data) {
Write-Host ("Found {0} calendar items" -f $Data.Count)
} Else {
Write-Host "No calendar items found."
Break
}
# Find meetings arranged by the user
[array]$Meetings = $Data | Where-Object {$_.Attendees.count -gt 1 -and $_.Organizer.emailaddress.Name -eq $User.displayName}
Write-Host ("{0} meetings found arranged by {1}" -f $Meetings.Count, $User.displayName)
$CalendarInfo = [System.Collections.Generic.List[Object]]::new()
ForEach ($event in $Meetings) {
[datetime]$MeetingStart = Get-Date($Event.start.datetime)
[datetime]$MeetingEnd = Get-Date($Event.end.datetime)
# Calculate meeting duration in minutes. If it's an all-day event, use 480 minutes
If ($Event.IsAllDay -eq $False) {
$Duration = ($MeetingEnd - $MeetingStart).TotalMinutes
} Else {
$Duration = 480
}
$OnlineMeetingProvider = $null
[array]$AllAttendees = ($Event.Attendees | Where-Object {$_.Type -ne "resource"} )
[array]$RequiredAttendees = ($Event.Attendees | Where-Object {$_.Type -eq "required"})
[array]$OptionalAttendees = ($Event.Attendees | Where-Object {$_.Type -eq "optional"})
# Create output line - add one to the total attendees to account for the organizer
If ($Event.onlineMeetingProvider -ne "unknown") {
$OnlineMeetingProvider = $Event.onlineMeetingProvider
}
$DataLine = [PSCustomObject] @{
Type = $Event.type
Organizer = $Event.organizer.emailaddress.name
OrganizerEmail = $Event.organizer.emailaddress.address
Created = Get-Date($Event.createdDateTime) -format 'dd-MMM-yyyy HH:mm'
Modified = Get-Date($Event.lastModifiedDateTime) -format 'dd-MMM-yyyy HH:mm'
TimeZone = $Event.originalStartTimeZone
Subject = $Event.Subject
AllDay = $Event.IsAllDay
Online = $Event.isOnlineMeeting
OnlineProvider = $OnlineMeetingProvider
Start = Get-Date($MeetingStart) -format 'dd-MMM-yyyy HH:mm'
End = Get-Date($MeetingEnd) -format 'dd-MMM-yyyy HH:mm'
Day = (Get-Date($MeetingStart)).DayOfWeek
Duration = $Duration
Location = $event.location.displayname
RequiredAttendees = $RequiredAttendees.emailaddress.name -join ", "
OptionalAttendees = $OptionalAttendees.emailaddress.name -join ", "
TotalAttendees = $AllAttendees.Count
Required = $RequiredAttendees.Count
Optional = $OptionalAttendees.Count
TotalAtEvent = $AllAttendees.Count + 1
}
$CalendarInfo.Add($DataLine)
}
$CalendarInfo = $CalendarInfo | Sort-Object {$_.Start -as [datetime]}
$CalendarInfo | Select-Object Start, End, Subject, Organizer, RequiredAttendees, OnlineProvider | Out-GridView -Title ("Calendar items for {0}" -f $User.displayName)
Write-Host "Generating report..."
If (Get-Module ImportExcel -ListAvailable) {
$ExcelGenerated = $True
Import-Module ImportExcel -ErrorAction SilentlyContinue
$ExcelOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\Calendar Items.xlsx"
If (Test-Path $ExcelOutputFile) {
Remove-Item $ExcelOutputFile -ErrorAction SilentlyContinue
}
$CalendarInfo | Export-Excel -Path $ExcelOutputFile -WorksheetName "Calendar Items" `
-Title ("Calendar Items {0}" -f (Get-Date -format 'dd-MMM-yyyy')) -TitleBold -TableName "CalendarItems"
} Else {
$CSVOutputFile = ((New-Object -ComObject Shell.Application).Namespace('shell:Downloads').Self.Path) + "\Calendar Items.CSV"
$CalendarInfo | Export-Csv -Path $CSVOutputFile -NoTypeInformation -Encoding Utf8
}
If ($ExcelGenerated) {
Write-Host ("An Excel report of calendar items is available in {0}" -f $ExcelOutputFile)
} Else {
Write-Host ("A CSV report of calendar items is available in {0}" -f $CSVOutputFile)
}
Write-Host "All done..."

Parameters

ParameterDefaultNotes
-LookbackDays180Number of days back to include calendar items in the report.
-StartDate(Get-Date).AddDays(-180)Start of the calendar reporting window.
-EndDate(Get-Date).AddDays(1)End of the calendar reporting window.
Attribution