Azure, AWS, Microsoft Graph, and Cloud PowerShell Modules
Choose between cloud CLIs and PowerShell modules deliberately, understand Azure/AWS/Graph identity and target context, handle scale concerns, and normalize provider-specific objects into one inventory contract without requiring real cloud accounts.
Learning objectives
- Compare native cloud CLIs with PowerShell modules.
- Identify the supported Az, AWS.Tools, and Microsoft Graph module families.
- Treat tenant/account/subscription/region and permissions as explicit inputs.
- Explain pagination, throttling, retries, and module-version pinning.
- Normalize provider-specific objects into a stable inventory contract.
- Complete a credential-free multi-cloud mock lab.
1. Cloud CLI or PowerShell module? Choose for the operating environment
Cloud platforms expose HTTP APIs. A native cloud CLI and a PowerShell module are two client surfaces over those APIs. Neither is automatically “more DevOps.” Choose based on team skill, runner images, required service coverage, object handling, startup/module footprint, and the environment where the automation must run.
| Client surface | Strength | Tradeoff |
|---|---|---|
| Native CLI | Often compact, language-neutral, easy in mixed-shell teams | Returns text/JSON and requires native process handling |
| PowerShell module | Returns PowerShell/.NET objects and composes naturally with pipeline/functions | Module dependency footprint and version compatibility |
| Direct REST/API | Smallest abstraction and precise control | You own auth headers, pagination, API versions, retries, schemas |
2. Azure: Az is the supported PowerShell module family
Microsoft's supported Azure PowerShell family is Az; AzureRM is deprecated. The verified current Az rollup is 16.0.0. Authentication creates an Azure context containing account, tenant, subscription, and token information. If an identity has access to more than one subscription, explicitly select the intended context.
# Read-only capability/context inspection. These commands run only if Az is installed.
if (Get-Module -ListAvailable Az.Accounts) {
Import-Module Az.Accounts
Get-AzContext -ListAvailable |
Select-Object Name,@{N='Subscription';E={$_.Subscription.Id}},@{N='Tenant';E={$_.Tenant.Id}}
# In an authenticated lab, select deliberately:
# Set-AzContext -Subscription '<subscription-id>' -Tenant '<tenant-id>'
} else {
'Az.Accounts is not installed; use the mock inventory path below.'
}
Interactive Connect-AzAccount is useful for an operator session, but unattended automation should use an approved workload identity/service principal/managed identity model rather than embedding a password.
3. AWS: AWS.Tools V5 is the current modular recommendation
AWS publishes several PowerShell packaging styles. For current production use, AWS documentation recommends modular AWS.Tools, where you install only the service modules you need plus common infrastructure. The current documentation line is V5.
$awsModules = Get-Module -ListAvailable 'AWS.Tools.*' |
Sort-Object Name,Version -Unique |
Select-Object Name,Version,Path
$awsModules | Format-Table
# Region/credential context should be explicit in real automation.
# Example read-only shape if AWS.Tools.EC2 is installed and authenticated:
# Get-EC2Instance -Region 'us-east-1' ...
AWS credentials can come from supported credential providers, profiles, environment variables, role-based metadata, SSO, or workload identity patterns. The lesson deliberately does not ask for real AWS credentials.
4. Microsoft Graph PowerShell is the supported Graph/Entra SDK path
Microsoft Graph PowerShell wraps Microsoft Graph APIs and is the supported replacement for the older Azure AD PowerShell and MSOnline modules. Authentication can be delegated or app-only. Always request only the scopes/permissions the task requires.
if (Get-Module -ListAvailable Microsoft.Graph.Authentication) {
Import-Module Microsoft.Graph.Authentication
# Inspect an existing authenticated context only; no sign-in is forced by this lab.
$ctx = Get-MgContext
if ($ctx) {
$ctx | Select-Object ClientId,TenantId,AuthType,Scopes
} else {
'Microsoft Graph module is available, but no Graph context is active.'
}
}
For unattended scripts, app-only authentication or managed identity may be appropriate depending on host and service. Permissions are a security design decision, not a convenience flag.
5. Account, tenant, subscription, and region are first-class inputs
Cloud automation mistakes are often target-selection mistakes. Make the identity and target context observable before any change. Azure emphasizes tenant/subscription context; AWS uses account/role and region; Microsoft Graph uses tenant plus permission scopes.
function New-CloudTargetRecord {
param(
[ValidateSet('Azure','AWS','MicrosoftGraph')][string]$Provider,
[string]$Account,
[string]$Tenant,
[string]$Subscription,
[string]$Region
)
[pscustomobject]@{
Provider = $Provider
Account = $Account
Tenant = $Tenant
Subscription = $Subscription
Region = $Region
}
}
New-CloudTargetRecord -Provider Azure -Tenant 'tenant-demo' -Subscription 'sub-dev'
New-CloudTargetRecord -Provider AWS -Account '111122223333' -Region 'us-east-1'
6. Cloud scale adds pagination, throttling, and retries
Cloud APIs frequently return partial pages and rate-limit high request volume. Modules may hide some mechanics, but scripts still need to understand continuation tokens/next links, retryable failures, and bounded retries. Do not assume a single command result represents an unlimited global inventory.
function Invoke-BoundedRetry {
param(
[Parameter(Mandatory)][scriptblock]$Operation,
[int]$MaxAttempts = 3
)
for ($attempt = 1; $attempt -le $MaxAttempts; $attempt++) {
try { return & $Operation }
catch {
if ($attempt -eq $MaxAttempts) { throw }
Start-Sleep -Seconds ([math]::Min(2 * $attempt, 6))
}
}
}
# Provider-neutral pagination shape using local pages.
$pages = @{
start = [pscustomobject]@{ Items=@('a','b'); NextToken='page2' }
page2 = [pscustomobject]@{ Items=@('c'); NextToken=$null }
}
$token = 'start'
$allItems = [System.Collections.Generic.List[string]]::new()
while ($token) {
$page = Invoke-BoundedRetry { $pages[$token] }
foreach ($item in $page.Items) { $allItems.Add($item) }
$token = $page.NextToken
}
$allItems
Retry only failures you have classified as transient. Authorization errors, invalid resource names, and schema/validation errors are usually permanent until input/configuration changes.
7. Normalize multi-cloud inventory before downstream processing
The Azure, AWS, and Graph object models differ. If the business question is simply “which compute-like resources exist, in what scope, and with what state?”, define your own inventory contract. Keep the raw provider object optional for debugging rather than forcing every consumer to know three SDKs.
function ConvertTo-CloudInventoryRecord {
param(
[string]$Provider,
[string]$Scope,
[string]$Name,
[string]$Type,
[string]$Location,
[string]$State,
[string]$Id
)
[pscustomobject]@{
Provider = $Provider
Scope = $Scope
Name = $Name
Type = $Type
Location = $Location
State = $State
Id = $Id
}
}8. Lab: normalize mocked Azure, AWS, and Graph data
No cloud account is needed. The fixtures mimic the small subset of fields the normalization layer consumes.
$azure = @(
[pscustomobject]@{ Name='api-vm'; ResourceGroupName='rg-dev'; Location='westeurope'; PowerState='VM running'; Id='/subscriptions/demo/vm/api-vm' }
)
$aws = @(
[pscustomobject]@{ InstanceId='i-demo123'; Name='worker'; Region='us-east-1'; State='running'; Account='111122223333' }
)
$graph = @(
[pscustomobject]@{ DisplayName='build-runner'; Id='device-demo'; OperatingSystem='Windows'; TenantId='tenant-demo' }
)
$inventory = @(
foreach ($x in $azure) {
ConvertTo-CloudInventoryRecord -Provider Azure -Scope $x.ResourceGroupName -Name $x.Name -Type 'VirtualMachine' -Location $x.Location -State $x.PowerState -Id $x.Id
}
foreach ($x in $aws) {
ConvertTo-CloudInventoryRecord -Provider AWS -Scope $x.Account -Name $x.Name -Type 'EC2Instance' -Location $x.Region -State $x.State -Id $x.InstanceId
}
foreach ($x in $graph) {
ConvertTo-CloudInventoryRecord -Provider MicrosoftGraph -Scope $x.TenantId -Name $x.DisplayName -Type 'Device' -Location $null -State $x.OperatingSystem -Id $x.Id
}
)
$inventory | Sort-Object Provider,Name | Format-Table
$inventory | ConvertTo-Json -Depth 5 | Set-Content ./cloud-inventory.json
Expected observations
Provider-specific source shapes become one stable object contract without any credentials or network calls.
Verification checklist
- Each record identifies its provider and scope.
- Provider-specific IDs are preserved without pretending they share one format.
- Missing location for Graph is represented as null, not invented data.
- The JSON report is provider-neutral enough for later release/reporting code.
Cleanup
Remove-Item ./cloud-inventory.json -ErrorAction SilentlyContinue9. Cloud module versions belong in the dependency contract
Cloud modules update frequently because service APIs evolve. Pin or at least constrain versions in production automation, test upgrades, and read release notes. “Latest on every run” trades reproducibility for surprise. If you need multiple service modules, prefer the platform's recommended modular installation model where practical.
10. Common cloud automation mistakes
- Authenticating interactively in a headless runner with no fallback design.
- Hard-coding client secrets in source or logs.
- Ignoring active subscription/region/tenant and acting on the wrong target.
- Assuming one command returns every page.
- Retrying permission or validation errors as if they were transient.
- Forwarding raw SDK objects as a supposedly stable cross-cloud contract.
11. Knowledge check
Question 1. When might a cloud CLI be preferable to a PowerShell module?
Question 2. What is the current supported Azure PowerShell family?
Question 3. Which AWS PowerShell packaging model is currently recommended for production?
Question 4. What replaced Azure AD PowerShell/MSOnline for Graph/Entra API automation?
Question 5. Why normalize cloud responses?
12. Summary and bridge
Cloud modules remove some native-process plumbing, but they do not remove identity, context, pagination, throttling, versioning, or least-privilege concerns. Lesson 5 now combines source metadata, quality evidence, artifact checksums, environment selection, and machine-readable manifests into a provider-neutral release orchestration skeleton.
13. Authoritative references
Keep the academy open
Support free, practical DevOps education.
Every lesson is designed to remain readable in a browser, downloadable from GitHub, and usable without a paid learning platform. Contributions help expand and maintain the curriculum.
0x716c4Ab160C4B66F31a28AE2448BfF68fc3a2ef0
Send only Ethereum/ERC-20 compatible assets to this address.