All scripts
Microsoft 365 812
Bulk Set Mailbox Auto-Reply Status
Turns Outlook automatic replies on, off, or scheduled for a batch of mailboxes at once, reading the mailbox list and messages from a CSV file instead of clicking through each mailbox one by one.
Set-BulkMailboxAutoReply.ps1
<#
.SYNOPSIS
Sets Outlook automatic reply (out of office) status for a batch of mailboxes from a CSV file.
.DESCRIPTION
Reads a CSV of mailboxes and turns automatic replies on or off for each one in Exchange
Online, with separate internal and external messages and optional start/end times for a
scheduled reply. Useful for things like setting an out of office message for a whole team
before a public holiday, or clearing replies for everyone the morning after.
The CSV needs these columns:
Mailbox - the email address or alias of the mailbox
State - Enabled, Disabled, or Scheduled
InternalMessage - message shown to people inside the organization
ExternalMessage - message shown to people outside the organization
StartTime - only needed when State is Scheduled, format yyyy-MM-dd HH:mm
EndTime - only needed when State is Scheduled, format yyyy-MM-dd HH:mm
.AUTHOR
Shehryar Hassan
.EXAMPLE
.\Set-BulkMailboxAutoReply.ps1 -CsvPath .\autoreply-list.csv
Reads autoreply-list.csv and applies the auto-reply settings to every mailbox listed in it.
.EXAMPLE
.\Set-BulkMailboxAutoReply.ps1 -CsvPath .\autoreply-list.csv -WhatIf
Shows what would change for each mailbox without actually applying anything.
#>
[CmdletBinding(SupportsShouldProcess = $true)]
param(
[Parameter(Mandatory = $true)]
[string]$CsvPath
)
if (-not (Get-Module -ListAvailable -Name ExchangeOnlineManagement)) {
Write-Error "The ExchangeOnlineManagement module is not installed. Run: Install-Module ExchangeOnlineManagement"
return
}
if (-not (Get-ConnectionInformation)) {
Write-Host "Connecting to Exchange Online..."
Connect-ExchangeOnline -ShowBanner:$false
}
if (-not (Test-Path $CsvPath)) {
Write-Error "CSV file not found at path: $CsvPath"
return
}
$rows = Import-Csv -Path $CsvPath
if ($rows.Count -eq 0) {
Write-Warning "No rows found in $CsvPath, nothing to do."
return
}
$results = @()
foreach ($row in $rows) {
$mailbox = $row.Mailbox
$state = $row.State
if ([string]::IsNullOrWhiteSpace($mailbox)) {
Write-Warning "Skipping a row with no mailbox value."
continue
}
if ($state -notin @("Enabled", "Disabled", "Scheduled")) {
Write-Warning "Skipping $mailbox, State must be Enabled, Disabled, or Scheduled, got '$state'."
continue
}
$params = @{
Identity = $mailbox
AutoReplyState = $state
InternalMessage = $row.InternalMessage
ExternalMessage = $row.ExternalMessage
}
if ($state -eq "Scheduled") {
if ([string]::IsNullOrWhiteSpace($row.StartTime) -or [string]::IsNullOrWhiteSpace($row.EndTime)) {
Write-Warning "Skipping $mailbox, State is Scheduled but StartTime or EndTime is missing."
continue
}
$params.StartTime = [datetime]$row.StartTime
$params.EndTime = [datetime]$row.EndTime
}
if ($PSCmdlet.ShouldProcess($mailbox, "Set auto-reply state to $state")) {
try {
Set-MailboxAutoReplyConfiguration @params -ErrorAction Stop
$results += [pscustomobject]@{
Mailbox = $mailbox
State = $state
Status = "Updated"
}
}
catch {
$results += [pscustomobject]@{
Mailbox = $mailbox
State = $state
Status = "Failed: $($_.Exception.Message)"
}
}
}
}
$results | Format-Table -AutoSize
$failed = $results | Where-Object { $_.Status -like "Failed*" }
if ($failed) {
Write-Warning "$($failed.Count) mailbox(es) failed, check the Status column above for details."
}
Read it before you run it, and test in a safe tenant first.