Skip to content
6 min read·Lesson 8 of 8

Cross-Platform PowerShell and DevOps

Using pwsh 7 on Linux and macOS, mixing with Bash / Python, packaging into containers, and where PowerShell fits the modern DevOps stack.

The PowerShell 7 release in 2020 (rebuilt on .NET Core) changed PowerShell from a Windows shell into a credible general-purpose tool. macOS and Linux engineers can run the same scripts their Windows colleagues do. CI containers ship pwsh alongside Bash and Python. Az and Microsoft Graph modules work natively on all platforms.

This last lesson covers the cross-platform story honestly — what works, what doesn't, and where pwsh sits next to Bash and Python in the modern engineer's toolkit.

What Works Cross-Platform

  • Core language — variables, types, control flow, pipelines, classes, modules
  • Most utility cmdletsGet-Process, Get-ChildItem, Test-Connection, Invoke-WebRequest, Invoke-RestMethod, ConvertFrom-Json, Import-Csv
  • Az PowerShell — fully cross-platform
  • Microsoft Graph PowerShell — fully cross-platform
  • PSReadLine — same interactive polish on every platform
  • Pester — testing framework, runs anywhere
  • Modules from PSGallery — most modern modules target pwsh 7

What Doesn't (or only partially) Work

Cmdlet / moduleStatus on Linux/macOS
CIM / WMI cmdlets (Get-CimInstance)Windows only — they use the WMI API
Get-EventLog, Get-WinEventWindows only
Active Directory module (RSAT-AD-PowerShell)Windows only; use Graph for Entra ID
Group Policy managementWindows only
Get-Service / Start-Service / Stop-ServiceCross-platform for systemd; Linux service control works
Out-Printer / printer cmdletsWindows only
Workflow runbooksDeprecated; do not use

Rule of thumb: anything that wraps Windows-specific APIs is Windows-only. Everything else, including all the cloud and HTTP work, runs everywhere.

Platform-Aware Scripts

Detect platform at runtime:

if ($IsWindows) { ... }
elseif ($IsLinux) { ... }
elseif ($IsMacOS) { ... }

# Path joins respect platform
$config = Join-Path $HOME ".config" "app.json"

# Environment variables — same on all
$env:HOME            # works on Linux/macOS
$env:USERPROFILE     # only on Windows; but on Linux it's empty

Use Join-Path, Split-Path, and [System.IO.Path] rather than hardcoded backslashes or slashes.

Running in Containers

Microsoft publishes official PowerShell images:

# Pull and run
docker run -it mcr.microsoft.com/powershell:lts-ubuntu-22.04

# Available tags include
#   mcr.microsoft.com/powershell:7.4-ubuntu-22.04
#   mcr.microsoft.com/powershell:lts-alpine-3.20
#   mcr.microsoft.com/powershell:7.4-mariner-2.0

A minimal Dockerfile for a containerised script:

FROM mcr.microsoft.com/powershell:lts-alpine-3.20

WORKDIR /app
COPY . .

RUN pwsh -NoProfile -Command "Install-Module Az -Force -Scope AllUsers -AcceptLicense"

ENTRYPOINT ["pwsh", "-NoProfile", "-File", "/app/run.ps1"]

Container size: 70-200 MB depending on base. Plenty small for CI / Functions / runbook use.

Mixing with Bash and Python

Three patterns:

Call pwsh from Bash

#!/usr/bin/env bash
set -euo pipefail

result=$(pwsh -NoProfile -Command "
  Get-AzVM | Where-Object PowerState -eq 'VM running' | ConvertTo-Json -Depth 5
")
echo "$result" | jq '.[].Name'

Call Bash / external commands from pwsh

# Native executable invocation
$tag = git rev-parse --short HEAD
$image = docker build -t "app:$tag" .

# Multi-line external command
$kubectlOut = kubectl get pods -A -o json | ConvertFrom-Json
$kubectlOut.items | Where-Object { $_.status.phase -ne "Running" }

External commands return text by default. Pipe to ConvertFrom-Json when the tool emits JSON (kubectl, jq output, az CLI with -o json).

Call Python from pwsh

$pyResult = python -c "import json, sys; print(json.dumps({'sum': sum(range(100))}))" | ConvertFrom-Json
$pyResult.sum     # 4950

For heavy data work, Python's libraries are richer; for Azure / M365, PowerShell wins. Mix where each is strongest.

Polyglot Project Patterns

A typical platform team's automation repo:

automation/
├── bash/
│   └── ec2-spot-bidding.sh
├── pwsh/
│   ├── audit-azure-tags.ps1
│   ├── tenant-license-report.ps1
│   └── modules/
│       └── PlatformCommon/
├── python/
│   ├── reconcile-finops.py
│   └── chaos-experiment.py
├── .github/
│   └── workflows/
│       ├── weekly-audit.yml         # uses pwsh
│       ├── nightly-finops.yml       # uses python
│       └── spot-rebid.yml           # uses bash

No religious wars. The right language for the job, all running on the same CI runners.

VS Code Integration

The PowerShell extension for VS Code is excellent and cross-platform:

  • IntelliSense from PSScriptAnalyzer
  • Debug PowerShell scripts with breakpoints, watch, call stack
  • Integrated terminal hosts pwsh
  • Run selected line / file with F8 / F5
  • Pester test discovery and run from the explorer

Pair with PSScriptAnalyzer as a linter in CI — catches naming, performance, and style issues.

Where PowerShell Fits (Honestly)

TaskBest tool
Azure resource automationPowerShell (Az) or Azure CLI
Microsoft 365 / Entra ID adminPowerShell (Graph)
Windows Server adminPowerShell
Intune device managementPowerShell
Kubernetes adminkubectl, Helm (Bash or pwsh)
AWS automationAWS CLI / SDK in Bash or Python (PowerShell AWS module exists; less idiomatic)
GCP automationgcloud + Bash/Python; pwsh works but is less common
Linux server adminBash (with pwsh for scripts that need objects)
Data engineeringPython
Web backends / CLIsGo / Rust / TypeScript
Quick text processingBash / awk / sed / jq

PowerShell's home turf is anything Microsoft-flavoured. Outside that, it competes with Python and Bash on merit — sometimes wins, sometimes loses.

Where to Go from Here

  1. Build something small. A weekly Azure tag-audit runbook. A Microsoft Graph script that reports on inactive users. The shape of the language sticks once you ship.
  2. Read PSGallery sources. The Azure PowerShell repo and the Microsoft Graph SDK are both open source.
  3. Cert. AZ-104 (Azure Administrator) tests Az PowerShell knowledge directly. MS-102 covers Graph PowerShell for M365. Both are practical and well-respected.
  4. Contribute upstream. The PowerShell repo accepts PRs; Microsoft Graph SDK welcomes issues.

Recommended Reading

  • PowerShell official documentation
  • Learn PowerShell in a Month of Lunches, 4th ed. — Don Jones, James Petty, Travis Plunk
  • PowerShell 7 Workshop — Nick Parlow (Packt)
  • PSScriptAnalyzer rules — read them, they teach the style guide
  • Pair with the CertQnA Azure Cloud Basics and Cloud FinOps courses.

PowerShell is a niche-dominator: in the Microsoft ecosystem it has no rival, and PowerShell 7 made it credible everywhere else. Add it to your toolkit; you will reach for it more often than you expect.

Key Takeaways

  • pwsh 7 runs natively on Linux and macOS — many cmdlets are platform-aware (Get-Process works on Linux).
  • Use the official mcr.microsoft.com/powershell container for containerised PowerShell.
  • Mix freely with Bash / Python / Node — pwsh is just another shell in your CI pipeline.
  • Some legacy cmdlets are Windows-only (CIM, Get-EventLog, Active Directory module).
  • Choose PowerShell for Azure / M365 / Windows; Bash for Linux ops; Python for cross-cutting; learn all three.
🎉

Course Complete!

You've finished PowerShell for Cloud and Automation. Now put your knowledge to the test with real exam-style practice questions.