Skip to content
6 min read·Lesson 7 of 8

Automation Accounts and Runbooks

Where to actually run PowerShell in production — Azure Automation runbooks, Azure Functions, scheduled tasks, and GitHub Actions.

Writing the script is half the work. Running it reliably, on schedule, with good observability — that is what production automation needs. PowerShell has good options at every scale.

Azure Automation Accounts

Azure Automation is the managed service for running PowerShell (and Python) at scale, on a schedule or in response to webhooks. The unit of work is a runbook.

Runbook types

TypeWhen to use
PowerShellGeneral scripts, most common type
PowerShell 7.2 / 7.4Modern PS, cross-platform Az / Graph modules
Python 3Same model, different language
PowerShell WorkflowLegacy; avoid for new work
GraphicalDesigned in portal; rarely used

Use PowerShell 7.x for new runbooks.

Creating a runbook

  1. Create an Automation Account (portal, CLI, Bicep).
  2. Enable a system-assigned Managed Identity on it.
  3. Grant the MI permissions to the target resources (e.g., Contributor on a resource group).
  4. Create a runbook; paste your PowerShell.
  5. Test pane to dry-run; publish when ready.
  6. Schedule (cron-like) or wire to a webhook.

A simple runbook

# shutdown-dev-vms.ps1 — runbook content

Param(
    [string]$ResourceGroupName = "rg-dev",
    [string[]]$ExcludeNames = @()
)

Connect-AzAccount -Identity

$vms = Get-AzVM -ResourceGroupName $ResourceGroupName |
    Where-Object Name -notin $ExcludeNames

foreach ($vm in $vms) {
    Write-Output "Stopping $($vm.Name)"
    Stop-AzVM -Name $vm.Name -ResourceGroupName $vm.ResourceGroupName -Force | Out-Null
}

Schedule for 19:00 UTC every weekday. Cost: pennies per month.

Modules and dependencies

Automation Account has a module catalogue — install Az, Microsoft.Graph, your own modules into the account. Pin versions in production. Recent PS7.2+ supports automatic dependency resolution which makes this simpler.

Hybrid Runbook Workers

Need to run against on-prem or AWS / GCP? Install the Hybrid Runbook Worker on a machine in that environment. The runbook executes on that worker, with full network access to the local environment. Common pattern for cross-cloud automation orchestrated from Azure.

Azure Functions with PowerShell

Functions is a better fit when:

  • Trigger is HTTP, Service Bus, Event Grid, Timer, Blob — not just a schedule
  • You want sub-second cold start and per-request scaling
  • The code is more "API endpoint" than "scheduled batch"
# run.ps1 — HTTP-triggered function
using namespace System.Net

param($Request, $TriggerMetadata)

$name = $Request.Query.Name
if (-not $name) { $name = "world" }

Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
    StatusCode = [HttpStatusCode]::OK
    Body = "Hello, $name!"
})

Functions supports the same Managed Identity, Application Insights logging, and modules story. Pricing: Consumption plan = pay per execution; Premium / Dedicated for predictable load.

Scheduled Tasks (Windows on-prem)

For Windows servers without Azure:

# Register a scheduled task
$action  = New-ScheduledTaskAction -Execute "pwsh.exe" -Argument "-File C:\scripts\backup.ps1"
$trigger = New-ScheduledTaskTrigger -Daily -At 2am
$principal = New-ScheduledTaskPrincipal -UserId "NT AUTHORITY\SYSTEM" -RunLevel Highest

Register-ScheduledTask -TaskName "DailyBackup" -Action $action -Trigger $trigger -Principal $principal

Use pwsh.exe (PowerShell 7) rather than powershell.exe (5.1). Log to a file the script controls; do not rely on Task Scheduler's logging.

systemd timers (Linux pwsh)

# /etc/systemd/system/backup.service
[Unit]
Description=Daily backup

[Service]
Type=oneshot
ExecStart=/usr/bin/pwsh /opt/scripts/backup.ps1

# /etc/systemd/system/backup.timer
[Unit]
Description=Run backup daily at 02:00

[Timer]
OnCalendar=*-*-* 02:00:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl enable --now backup.timer
sudo systemctl list-timers backup.timer
journalctl -u backup.service       # logs

CI / CD Pipelines

GitHub Actions

name: Weekly Audit
on:
  schedule:
    - cron: '0 7 * * 1'
  workflow_dispatch:

jobs:
  audit:
    runs-on: ubuntu-latest
    permissions:
      id-token: write       # for OIDC
      contents: read
    steps:
      - uses: actions/checkout@v4

      - uses: azure/login@v2
        with:
          client-id: ${{ secrets.AZ_CLIENT_ID }}
          tenant-id: ${{ secrets.AZ_TENANT_ID }}
          subscription-id: ${{ secrets.AZ_SUB_ID }}

      - shell: pwsh
        run: |
          Set-StrictMode -Version Latest
          $ErrorActionPreference = "Stop"
          ./scripts/Audit-Resources.ps1 | Tee-Object audit.json

      - uses: actions/upload-artifact@v4
        with:
          name: audit-report
          path: audit.json

The azure/login action handles federated identity. Inside shell: pwsh blocks you have full PowerShell 7 with Az pre-installed.

Azure DevOps

Same pattern with AzurePowerShell@5 tasks and Service Connections backed by workload identity federation.

Observability

  • Automation Accounts have built-in job history; integrate Application Insights for structured logs.
  • Functions auto-integrate with Application Insights — every Write-Information and exception flows there.
  • Scheduled / systemd tasks rely on your own logging — JSON to a file, shipped via Fluent Bit / Filebeat / Azure Monitor agent.
  • CI — workflow logs plus artifacts for reports.

Standardise on JSON structured logs (lesson 4's Write-Log pattern) so wherever the script runs, the logs are queryable.

Choosing Where to Run

NeedBest fit
Scheduled Azure resource managementAutomation Account runbook
Event-driven (webhook, message)Azure Function
HTTP API endpointAzure Function
On-prem Windows server taskScheduled Task
On-prem Linux server tasksystemd timer
Periodic audit / report against many resourcesGitHub Actions scheduled workflow
Cross-cloud automation orchestrated from AzureHybrid Runbook Worker
Bash CI pipelines using Azure CLI patternsGitHub Actions + Az CLI / Az PowerShell

Best Practices for Production Runbooks

  1. Use Managed Identity wherever possible — no secrets.
  2. Pin module versions; freeze in a separate test runbook before pushing to prod.
  3. Idempotent design — a runbook should be safe to re-run.
  4. Emit structured logs to Application Insights / Log Analytics.
  5. Alert on runbook failure via Azure Monitor.
  6. Use a parameter for "dry-run" so you can validate logic safely.
  7. Store runbook source in Git; deploy via Bicep / Terraform / GitHub Actions, not portal copy-paste.
  8. Tag the Automation Account and runbook for cost / ownership.

With runbook plumbing covered, the final lesson looks at the modern cross-platform pwsh story and where PowerShell fits in a polyglot DevOps world.

Key Takeaways

  • Azure Automation Accounts host PowerShell runbooks, scheduled or webhook-triggered, with Managed Identity.
  • Azure Functions with PowerShell can replace runbooks for event-driven and HTTP-triggered scenarios.
  • On-prem: Scheduled Tasks (Windows) or systemd timers (Linux) with pwsh 7.
  • CI/CD: GitHub Actions and Azure DevOps pipelines support PowerShell natively.
  • Hybrid Runbook Workers extend Automation to on-prem and other clouds.

Test your knowledge

Try exam-style practice questions to reinforce what you've learned.

Practice Questions →