Guide

Calendar Automation with PowerShell

According to Harvard Business Review, executives spend an average of 23 hours per week in meetings, up from 10 hours in the 1960s. Much of that time goes to scheduling logistics. This guide shows how to automate meeting invites, check participant availability, book conference rooms, and send calendar-driven emails from PowerShell using Nylas CLI. Works with Gmail, Outlook, Exchange, Yahoo, iCloud, and IMAP.

By Qasim Muhammad

Setup

Install Nylas CLI and authenticate. See the PowerShell email guide for install details.

irm https://cli.nylas.com/install.ps1 | iex
nylas auth config  # paste your API key

# Verify calendar access
nylas calendar events list --json --limit 1 | ConvertFrom-Json

Check participant availability

Before booking a meeting, check who's free. The availability check queries free/busy data across all participants in one call.

# check-availability.ps1 -- Find open slots for a group meeting
param(
    [string[]]$Participants = @("alice@company.com", "bob@company.com"),
    [string]$Date = (Get-Date).AddDays(1).ToString("yyyy-MM-dd"),
    [int]$DurationMinutes = 30
)

$startTime = "$($Date)T09:00:00"
$endTime = "$($Date)T17:00:00"

$availability = nylas calendar availability check `
    --start $startTime `
    --end $endTime `
    --participants ($Participants -join ',') `
    --json | ConvertFrom-Json

$freeSlots = $availability.time_slots |
    Where-Object { $_.status -eq "free" }

if ($freeSlots.Count -eq 0) {
    Write-Host "No common availability on $Date" -ForegroundColor Red
    exit 1
}

Write-Host "Available slots on $Date:" -ForegroundColor Green
$freeSlots | ForEach-Object {
    $start = [DateTime]::Parse($_.start_time)
    $end = [DateTime]::Parse($_.end_time)
    Write-Host "  $($start.ToString('h:mm tt')) - $($end.ToString('h:mm tt'))"
}

# First slot that fits the requested duration
$bestSlot = $freeSlots | Where-Object {
    $s = [DateTime]::Parse($_.start_time); $e = [DateTime]::Parse($_.end_time)
    ($e - $s).TotalMinutes -ge $DurationMinutes
} | Select-Object -First 1

if ($bestSlot) {
    Write-Host "Recommended: $([DateTime]::Parse($bestSlot.start_time).ToString('h:mm tt'))" -ForegroundColor Cyan
}

Create meeting invites with participants

Create a calendar event with participants. Nylas sends the invite through the provider (Google Calendar, Outlook, Exchange) automatically.

# create-meeting.ps1 -- Book a meeting with availability check
param(
    [string]$Title = "Team Sync",
    [string[]]$Participants = @("alice@company.com", "bob@company.com"),
    [string]$Date,
    [string]$StartTime = "10:00",
    [int]$Duration = 30,
    [string]$Description = ""
)

if (-not $Date) { $Date = (Get-Date).AddDays(1).ToString("yyyy-MM-dd") }

$startDt = "$($Date)T$($StartTime):00"
$endDt = [DateTime]::Parse($startDt).AddMinutes($Duration).ToString("yyyy-MM-ddTHH:mm:ss")

# Check availability first
$avail = nylas calendar availability check `
    --start $startDt --end $endDt `
    --participants ($Participants -join ',') `
    --json | ConvertFrom-Json

$conflicts = $avail.time_slots | Where-Object { $_.status -ne "free" }
if ($conflicts) {
    Write-Host "WARNING: Not all participants are free" -ForegroundColor Yellow
}

# Create the event
$event = nylas calendar events create `
    --title $Title `
    --start $startDt --end $endDt `
    --participants ($Participants -join ',') `
    --description $Description `
    --json | ConvertFrom-Json

Write-Host "Meeting created:" -ForegroundColor Green
Write-Host "  Title: $($event.title)"
Write-Host "  Time:  $startDt to $endDt"
Write-Host "  With:  $($Participants -join ', ')"

Conference room booking

Conference rooms in Google Workspace and Microsoft 365 have their own calendar resource. Check room availability and book in one script.

# book-room.ps1 -- Find a free room and book it
param(
    [string[]]$Rooms = @("room-a@company.com", "room-b@company.com", "room-c@company.com"),
    [string]$Date = (Get-Date).AddDays(1).ToString("yyyy-MM-dd"),
    [string]$StartTime = "14:00",
    [int]$DurationMinutes = 60,
    [string]$Title = "Project Review",
    [string[]]$Attendees = @("alice@company.com", "bob@company.com")
)

$startDt = "$($Date)T$($StartTime):00"
$endDt = [DateTime]::Parse($startDt).AddMinutes($DurationMinutes).ToString("yyyy-MM-ddTHH:mm:ss")

$availableRoom = $null

foreach ($room in $Rooms) {
    Write-Host "Checking $room ..." -NoNewline
    $avail = nylas calendar availability check `
        --start $startDt --end $endDt `
        --participants $room `
        --json | ConvertFrom-Json

    $free = $avail.time_slots | Where-Object { $_.status -eq "free" }
    if ($free) {
        Write-Host " FREE" -ForegroundColor Green
        $availableRoom = $room
        break
    } else {
        Write-Host " BUSY" -ForegroundColor Red
    }
}

if (-not $availableRoom) {
    Write-Host "No rooms available at $StartTime on $Date" -ForegroundColor Red
    exit 1
}

$allParticipants = @($availableRoom) + $Attendees

$event = nylas calendar events create `
    --title "$Title ($($availableRoom -replace '@.*', ''))" `
    --start $startDt --end $endDt `
    --participants ($allParticipants -join ',') `
    --description "Room: $availableRoom" `
    --json | ConvertFrom-Json

Write-Host "Booked $availableRoom for '$Title'" -ForegroundColor Green

Send meeting prep emails

Before each meeting, send yourself a prep email with the agenda and recent email history from each participant.

# meeting-prep.ps1 -- Prep email before upcoming meetings
param([int]$MinutesBefore = 30)

$events = nylas calendar events list --json | ConvertFrom-Json
$now = Get-Date
$prepWindow = $now.AddMinutes($MinutesBefore)

$upcoming = $events | Where-Object {
    $start = [DateTime]::Parse($_.when.start_time)
    $start -gt $now -and $start -le $prepWindow
}

foreach ($event in $upcoming) {
    $participants = $event.participants | ForEach-Object { $_.email }
    if ($participants.Count -eq 0) { continue }

    $recentEmails = foreach ($p in $participants) {
        $emails = nylas email search "from:$p" --json --limit 3 | ConvertFrom-Json
        $emails | ForEach-Object { "  - [$($_.date)] $($_.subject)" }
    }

    $body = @"
Meeting Prep: $($event.title)
Time: $($event.when.start_time)
Participants: $($participants -join ', ')

Recent emails from participants:
$($recentEmails -join "`n")
"@

    nylas email send --to $env:MY_EMAIL `
        --subject "Prep: $($event.title) in $MinutesBefore min" `
        --body $body --yes
    Write-Host "Sent prep for: $($event.title)" -ForegroundColor Green
}

Daily schedule email

Send yourself a morning summary of today's meetings with times, participants, and locations.

# daily-schedule.ps1 -- Morning email with today's calendar
$today = Get-Date -Format "yyyy-MM-dd"
$events = nylas calendar events list --json | ConvertFrom-Json

if ($events.Count -eq 0) {
    $body = "No meetings today. Focus day!"
} else {
    $schedule = $events | ForEach-Object {
        $start = [DateTime]::Parse($_.when.start_time).ToString('h:mm tt')
        $end = [DateTime]::Parse($_.when.end_time).ToString('h:mm tt')
        $who = ($_.participants | ForEach-Object { $_.email }) -join ', '
        "$start - $end: $($_.title)`n  With: $who"
    }
    $body = "Schedule for $today ($($events.Count) meetings)`n`n$($schedule -join "`n`n")"
}

nylas email send --to $env:MY_EMAIL `
    --subject "Schedule: $today ($($events.Count) meetings)" `
    --body $body --yes

Automate recurring meeting follow-ups

# standup-followup.ps1 -- Follow-up email after standup meetings
$events = nylas calendar events list --json | ConvertFrom-Json
$now = Get-Date

$recentStandups = $events | Where-Object {
    $_.title -match 'standup|daily sync|scrum' -and
    [DateTime]::Parse($_.when.end_time) -lt $now -and
    [DateTime]::Parse($_.when.end_time) -gt $now.AddHours(-2)
}

foreach ($standup in $recentStandups) {
    $participants = ($standup.participants | ForEach-Object { $_.email }) -join ','
    $body = @"
Follow-up: $($standup.title) - $(Get-Date -Format 'MMM d')

Action items:
- [ ]
- [ ]

Reply with updates or additional items.
"@
    nylas email send --to $participants `
        --subject "Follow-up: $($standup.title) - $(Get-Date -Format 'MMM d')" `
        --body $body --yes
}

Schedule with Task Scheduler

# Morning schedule at 7:30 AM weekdays
schtasks /create /tn "DailySchedule" `
    /tr "pwsh.exe -NoProfile -File C:\Scripts\daily-schedule.ps1" `
    /sc weekly /d MON,TUE,WED,THU,FRI /st 07:30 /ru "%USERNAME%"

# Meeting prep every 15 minutes
schtasks /create /tn "MeetingPrep" `
    /tr "pwsh.exe -NoProfile -File C:\Scripts\meeting-prep.ps1" `
    /sc minute /mo 15 /ru "%USERNAME%"

Frequently asked questions

How do I check meeting room availability from PowerShell?

Use nylas calendar availability check --participants room-a@company.com --start "..." --end "..." --json. Room calendars in Google Workspace and Microsoft 365 are treated as regular participants. Parse the result and filter for free slots.

Can I send meeting invites from a PowerShell script?

Yes. Use nylas calendar events create --title "Meeting" --start "..." --end "..." --participants "alice@company.com,bob@company.com". The CLI sends invites through the provider automatically.

How do I schedule emails based on calendar events?

List upcoming events with nylas calendar events list --json, find events starting within your window, and send emails with nylas email send. Run via Task Scheduler every 15 minutes.


Next steps