Forum Discussion
Add a calendar ics with Powershell
A Parameter cannot be found that matches parameter name 'Name'.
I spent hours asking for help on forums regarding a script, but no one could assist me. I opened a ticket with Microsoft, but they couldn't help either.
So, I decided to try using ChatGPT. I spent hundreds of hours testing to finally get a working script.
I'm posting it here in case someone needs the same thing one day. However, please keep in mind that:
- This script was tailored to my specific situation.
- The script might throw errors due to differences in your environment.
- It's still a temporary, unofficial solution.
- Outlook may need to be run as administrator
- for chatgpt to be more efficient, I also showed it an ics file (so that it manages everything that is date format etc...)
If you encounter any errors, I recommend revising the script with ChatGPT, providing it with the errors each time. Chatgpt is quite good at fixing them.
Script Summary:
This script automates the process of downloading calendar files in .ics format from specified URLs and synchronizing them with the user's Outlook calendar.
Download ICS Files:
- The script downloads two .ics files (you can add more) from given URLs and saves them to a hidden directory. The directory is created automatically if it doesn’t exist.
Processing the ICS Files:
- The script reads the .ics files and extracts calendar event details such as start time, end time, event title, and location.
Creating/Updating Outlook Events:
- It creates or finds corresponding folders in the user's Outlook calendar based on the file name (e.g., "MeetingRoomA").
- It checks for existing events in these Outlook folders:
- If the event already exists, it skips it.
- If the event does not exist, it creates a new appointment with the event details (start/end time, title, location).
- The script also deletes any events from the Outlook calendar that no longer exist in the .ics files, ensuring the Outlook calendar remains up-to-date.
Error Handling & Clean-up:
- Functions are included to handle errors when creating appointments or deleting existing ones, and COM objects used for Outlook interaction are released after processing to prevent performance issues.
Key Features:
- The script ensures no duplicate events are created and removes old events that are no longer in the source calendar.
- The appointments created are customized with categories, reminders, and busy status.
# Define the URLs for downloading and the save paths
$urls = @(
"https://outlook.office365.com/owa/calendar/XXX/XXX/reachcalendar.ics",
"https://outlook.office365.com/owa/calendar/XXX/XXX/reachcalendar.ics"
)
# Get the path to the "CalendarFiles" directory for the current user
$basePath = "C:\Company\CalendarUpdates\CalendarFiles"
if (-not (Test-Path $basePath)) {
$newDirectory = New-Item -Path $basePath -ItemType Directory -Force
$newDirectory.Attributes += "Hidden"
}
$savePaths = @(
"$basePath\MeetingRoomA.ics",
"$basePath\MeetingRoomB.ics"
)
# Download the files
for ($i = 0; $i -lt $urls.Length; $i++) {
Invoke-WebRequest -Uri $urls[$i] -OutFile $savePaths[$i]
}
# Define the path to the folder containing the ICS files
$ICSpath = $basePath
$ICSlist = Get-ChildItem $ICSpath -Filter *.ics
# Create the function to delete an existing appointment
function DeleteAppointment {
param ($eventData, $folder)
$Start = [datetime]::ParseExact($eventData["DTSTART"], "yyyyMMddTHHmmss", $null)
$End = [datetime]::ParseExact($eventData["DTEND"], "yyyyMMddTHHmmss", $null)
foreach ($item in $folder.Items) {
if ($item.Start -eq $Start -and $item.End -eq $End -and $item.Subject -eq $eventData["SUMMARY"]) {
$item.Delete()
break
}
}
}
# Create the function to create an appointment
function CreateAppointment {
param ($eventData, $folder)
if (-not $eventData["DTSTART"] -or -not $eventData["DTEND"] -or -not $eventData["SUMMARY"]) {
return
}
try {
# Delete the existing event if it exists
DeleteAppointment $eventData $folder
# Add the new event
$Start = [datetime]::ParseExact($eventData["DTSTART"], "yyyyMMddTHHmmss", $null)
$End = [datetime]::ParseExact($eventData["DTEND"], "yyyyMMddTHHmmss", $null)
$appointment = $folder.Items.Add(1) # 1 corresponds to olAppointmentItem
$appointment.Start = $Start
$appointment.End = $End
$appointment.Subject = $eventData["SUMMARY"]
if ($eventData["LOCATION"]) { $appointment.Location = $eventData["LOCATION"] }
$appointment.Categories = "Presentations"
$appointment.BusyStatus = 0 # 0=Free
$appointment.ReminderMinutesBeforeStart = 15 # Customize if desired
$appointment.ReminderSet = $false # Disable reminders
$appointment.Save()
} catch {
# Error while creating the appointment
}
}
# Create a new folder in Outlook named after the ICS file
function CreateOutlookFolder {
param ($folderName)
$outlook = New-Object -ComObject Outlook.Application
$namespace = $outlook.GetNamespace("MAPI")
$calendarFolder = $namespace.GetDefaultFolder(9) # 9 corresponds to the Calendar folder
$importedFolder = $calendarFolder.Folders | Where-Object { $_.Name -eq $folderName }
if (-not $importedFolder) {
$importedFolder = $calendarFolder.Folders.Add($folderName)
}
return $importedFolder
}
# Process the ICS files and add appointments to a folder named after the file
foreach ($file in $ICSlist) {
$folderName = [System.IO.Path]::GetFileNameWithoutExtension($file.Name)
$importedFolder = CreateOutlookFolder -folderName $folderName
# Retrieve the content of the ICS file
$content = Get-Content $file.FullName -Encoding UTF8
# List of events to add to Outlook
$eventsToAdd = @()
$eventData = @{}
$content | ForEach-Object {
if ($_ -match '^DTSTART;TZID=.*:(\d{8}T\d{6})') {
$eventData["DTSTART"] = $matches[1]
} elseif ($_ -match '^DTEND;TZID=.*:(\d{8}T\d{6})') {
$eventData["DTEND"] = $matches[1]
} elseif ($_ -match '^SUMMARY:(.*)$') {
$eventData["SUMMARY"] = $matches[1]
} elseif ($_ -match '^LOCATION:(.*)$') {
$eventData["LOCATION"] = $matches[1]
} elseif ($_ -match '^END:VEVENT$') {
# Add the event to the list of events to add
$eventsToAdd += $eventData
$eventData = @{}
}
}
# Retrieve the current events in Outlook
$currentEvents = @()
foreach ($item in $importedFolder.Items) {
$currentEvents += @{
"DTSTART" = $item.Start.ToString("yyyyMMddTHHmmss")
"DTEND" = $item.End.ToString("yyyyMMddTHHmmss")
"SUMMARY" = $item.Subject
"LOCATION" = $item.Location
}
}
# Compare and update events in Outlook
foreach ($event in $eventsToAdd) {
$found = $false
# Check if the event already exists in Outlook
foreach ($item in $importedFolder.Items) {
if ($item.Start.ToString("yyyyMMddTHHmmss") -eq $event["DTSTART"] -and
$item.End.ToString("yyyyMMddTHHmmss") -eq $event["DTEND"] -and
$item.Subject -eq $event["SUMMARY"] -and
($item.Location -eq $event["LOCATION"] -or (!$item.Location -and !$event["LOCATION"]))) {
# The event already exists with the same details
$found = $true
break
}
}
if (!$found) {
# The event doesn't exist, create a new appointment
CreateAppointment $event $importedFolder
}
}
# Delete events in Outlook that are not in $eventsToAdd
foreach ($item in $importedFolder.Items) {
$found = $false
foreach ($event in $eventsToAdd) {
if ($item.Start.ToString("yyyyMMddTHHmmss") -eq $event["DTSTART"] -and
$item.End.ToString("yyyyMMddTHHmmss") -eq $event["DTEND"] -and
$item.Subject -eq $event["SUMMARY"] -and
($item.Location -eq $event["LOCATION"] -or (!$item.Location -and !$event["LOCATION"]))) {
# The event in Outlook is also in $eventsToAdd
$found = $true
break
}
}
if (!$found) {
# The event in Outlook is not in $eventsToAdd, delete it
$item.Delete()
}
}
# Release the COM objects for this folder
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($importedFolder) | Out-Null
}