PowerShell Slack Notifications: Send Messages via Webhook

A backup script that completes at 3 AM leaves you guessing whether it succeeded until you check the server manually the next morning. Configuring PowerShell to send Slack notifications means your script reports its own completion, errors, and key metrics directly to your team channel — so you know the moment something finishes or fails, wherever you are.
Quick Answer / TL;DR
Create a Slack Incoming Webhook, then post to it with Invoke-RestMethod -Uri $webhookUrl -Method Post -Body ($payload | ConvertTo-Json -Depth 5). The payload must be valid JSON.
Create a Slack Incoming Webhook
Slack Incoming Webhooks are created in the Slack API portal or through your workspace’s App settings. Each webhook URL is tied to a specific channel. Keep the URL secret — treat it like a password since anyone with the URL can post to that channel.
# Store the webhook URL in an environment variable or secrets vault — never hardcode
# $webhookUrl = 'https://hooks.slack.com/services/T00000000/B00000000/XXXXXXXXXXXX'
# Retrieve from environment variable (safer)
$webhookUrl = $env:SLACK_WEBHOOK_URL
# Quick test — send a plain message
$body = @{ text = 'PowerShell script started.' } | ConvertTo-Json
Invoke-RestMethod -Uri $webhookUrl -Method Post -ContentType 'application/json' -Body $body
Send a Basic Message
The simplest Slack message requires only a text field in the JSON payload. Invoke-RestMethod posts the JSON body to the webhook endpoint. Slack accepts the message and delivers it to the configured channel immediately.
$webhookUrl = $env:SLACK_WEBHOOK_URL
function Send-SlackMessage {
param(
[string]$Message,
[string]$WebhookUrl = $env:SLACK_WEBHOOK_URL
)
$payload = @{ text = $Message } | ConvertTo-Json -Depth 5
Invoke-RestMethod -Uri $WebhookUrl -Method Post `
-ContentType 'application/json' -Body $payload | Out-Null
}
Send-SlackMessage -Message "Backup completed on $env:COMPUTERNAME at $(Get-Date -Format 'HH:mm')"
Format with Blocks and Attachments
Slack’s Block Kit provides rich message formatting with sections, dividers, and context blocks. Use blocks for multi-part messages with headers and structured data. The blocks array replaces the simple text field.
$blocks = @(
@{
type = 'header'
text = @{ type = 'plain_text'; text = 'Deployment Complete' }
},
@{
type = 'section'
fields = @(
@{ type = 'mrkdwn'; text = "*Server:*`n$env:COMPUTERNAME" },
@{ type = 'mrkdwn'; text = "*Time:*`n$(Get-Date -Format 'yyyy-MM-dd HH:mm')" }
)
},
@{ type = 'divider' }
)
$payload = @{ blocks = $blocks } | ConvertTo-Json -Depth 10
Invoke-RestMethod -Uri $env:SLACK_WEBHOOK_URL -Method Post `
-ContentType 'application/json' -Body $payload | Out-Null
Send Error Alerts with Color
Use legacy attachments (still supported by Slack) for color-coded status messages. Green for success, red for failure, yellow for warnings. This makes error alerts visually distinct in a busy channel.
function Send-SlackAlert {
param(
[string]$Title,
[string]$Message,
[ValidateSet('good','warning','danger')]
[string]$Color = 'good'
)
$payload = @{
attachments = @(
@{
color = $Color
title = $Title
text = $Message
footer = "PowerShell on $env:COMPUTERNAME"
ts = [int](Get-Date -UFormat %s)
}
)
} | ConvertTo-Json -Depth 10
Invoke-RestMethod -Uri $env:SLACK_WEBHOOK_URL -Method Post `
-ContentType 'application/json' -Body $payload | Out-Null
}
# Usage
Send-SlackAlert -Title 'Backup Failed' -Message 'Robocopy returned exit code 8' -Color 'danger'
Send-SlackAlert -Title 'Backup Complete' -Message '15,432 files copied successfully' -Color 'good'
Include Script Output in Message
Capture script output and include a summary in the Slack message. Use backtick formatting (```) in Slack markdown to format code/output blocks in the message.
$output = robocopy C:\Source \\server\backup /MIR /LOG:C:\Logs\robocopy.log 2>&1
$exitCode = $LASTEXITCODE
$summary = ($output | Select-Object -Last 10) -join "`n"
$status = if ($exitCode -le 1) { 'good' } elseif ($exitCode -le 7) { 'warning' } else { 'danger' }
$message = "Exit code: $exitCode`n``````$summary``````"
Send-SlackAlert -Title 'Robocopy Result' -Message $message -Color $status
Reusable Send-SlackMessage Function
A production-ready function with parameter validation, error handling, and support for both simple text and block-kit messages. Store this in a shared module imported by all automation scripts.
function Send-SlackMessage {
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string]$WebhookUrl,
[string]$Text,
[hashtable[]]$Blocks,
[string]$Channel
)
$payload = @{}
if ($Text) { $payload.text = $Text }
if ($Blocks) { $payload.blocks = $Blocks }
if ($Channel) { $payload.channel = $Channel }
try {
$body = $payload | ConvertTo-Json -Depth 10 -Compress
Invoke-RestMethod -Uri $WebhookUrl -Method Post `
-ContentType 'application/json' -Body $body -ErrorAction Stop | Out-Null
Write-Verbose 'Slack message sent successfully'
} catch {
Write-Warning "Slack notification failed: $($_.Exception.Message)"
}
}
Common Errors and Fixes
- Webhook URL must stay secret — do not hardcode in shared scripts. Committing a webhook URL to version control exposes it to anyone with repository access. Store it in an environment variable, Windows Credential Manager, or a secrets vault. Rotate the URL if it is accidentally exposed.
- Payload must be valid JSON — ConvertTo-Json before POST. Posting a raw PowerShell hashtable to
Invoke-RestMethodwithout converting to JSON first sends URL-encoded form data, not JSON. Always callConvertTo-Json -Depth 5(or higher for nested blocks) before the POST. Use-ContentType 'application/json'to set the correct content type header.
Related Cmdlets / See Also
Wrapping Up
Slack webhook notifications turn silent scheduled scripts into communicative automation. Start with a simple text payload, upgrade to blocks for rich formatting, and use color-coded attachments for status alerts. Keep the webhook URL in environment variables or a secrets store, and always convert your payload to JSON before posting.


