Contents
Introduction
Welcome to the official page for ArmClient-PS — a single-script Azure Resource Manager (ARM) support utility designed for redistribution.
ArmClient-PS recreates the core ARMClient workflow by using Invoke-AzRestMethod and a locally bundled Modules folder, instead of requiring runtime installation from the PowerShell Gallery. It is intentionally built to be a zip-friendly support package that an engineer can hand off, extract, and run — without internet access to the Gallery and without polluting the user’s installed module list.
It supports the standard ARM verbs (GET, POST, PUT, PATCH, DELETE), ships with a built-in catalog of common ARM operation presets, polls long-running ARM operations to completion, validates its own packaged files before use, and prefers secure, process-scoped authentication behavior by default.
Note
ArmClient-PS is compatible with Windows PowerShell 5.1 and PowerShell 7.x, and supports all Azure cloud environments —
AzureCloud,AzureUSGovernment,AzureChinaCloud,AzureUSNat,AzureUSSec, and any custom environment registered withAdd-AzEnvironment(such as Azure Stack Hub).
Source Code
Source code is hosted on GitHub: https://github.com/blakedrumm/AzArmClient-PS
To get started, clone the repository or download the latest source as a ZIP from the Code button on GitHub.
Prerequisites
Before running ArmClient-PS, make sure the following requirements are met:
- PowerShell host — Windows PowerShell 5.1 or PowerShell 7.x.
- Az.Accounts — bundled with the package; no installation required. A newer locally installed version is used automatically when valid.
-
Azure sign-in — an account that can sign in to the target Azure environment (
AzureCloud,AzureUSGovernment,AzureChinaCloud,AzureUSNat,AzureUSSec, or any environment registered withAdd-AzEnvironment). - ARM permissions — the signed-in identity needs the appropriate RBAC role for the resource the call targets (for example, Reader for GET and Contributor for write verbs).
- Network access — outbound HTTPS to the target ARM endpoint and any Azure-AD authority for the chosen cloud.
-
Intact package layout — the script,
Modules\, andManifest\folders must ship together so SHA-256 validation can succeed.
Goals
The design goals describe why ArmClient-PS exists. The concrete capabilities that satisfy each goal are listed in the Key Features section below.
- Be redistributable — ship as a single zip-friendly support package that runs without internet access to the PowerShell Gallery.
- Stay secure by default — prefer process-scoped authentication and never persist credentials past the session.
- Be tamper-evident — validate packaged files before they are loaded or executed.
-
Behave predictably across hosts — produce the same module resolution result on any engineer’s workstation, regardless of installed
Az.*versions. - Lower the barrier to ARM calls — let engineers run common operations without remembering ARM paths or API versions.
- Hide async plumbing — treat long-running ARM operations like synchronous calls from the caller’s perspective.
Package Layout
The tool ships as a self-contained folder structure:
.
├── ArmClient-PS.ps1
├── Build-BundledModules.ps1
├── Modules\
├── Manifest\
│ ├── Files.sha256.json
│ └── Versions.json
├── Logs\
└── Output\
Note
Logs\andOutput\are runtime folders and are not intended for source control. They are created and populated as the script executes.
Key Features
-
Single-file PowerShell script —
ArmClient-PS.ps1is the entire runtime. -
Bundled
Az.Accountsand dependencies loaded from a siblingModulesfolder. - TLS 1.2 enforced for every HTTPS call before any request leaves the host.
-
Process-scoped authentication —
Disable-AzContextAutosave -Scope Processruns at startup so credentials never persist past the session. - SHA-256 manifest validation of every packaged file with line-ending normalization so hashes match across Windows and non-Windows hosts.
-
Optional Authenticode signature validation through
-EnforceSignatureValidation. - Token and credential redaction in all log output (Bearer tokens, secrets, cookies, and assertions).
- Built-in operation preset catalog spanning ARM core, resources, deployments, governance, and Azure Communication Services email.
-
Automatic long-running operation polling that honors the
Azure-AsyncOperation,Operation-Location,Location, andRetry-Afterheaders. - Interactive tenant and subscription selection when ARM cannot resolve them automatically (with friendly numbered menus).
-
Custom header support with a deny-list for dangerous headers (
Authorization,Cookie,Host, etc.) and CRLF-injection protection. -
JSON body validation for both inline
-Bodyand-BodyFilepayloads before the request is sent. - Built-in self-test that validates folders, manifests, hashes, module resolution, and Az context.
Runtime Usage
Show context
Display the currently resolved Azure context the script will use:
.\ArmClient-PS.ps1 -ShowContext
Run a GET request
Issue a standard ARM GET against any resource path:
.\ArmClient-PS.ps1 `
-Method GET `
-RelativePath "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>" `
-ApiVersion "2021-04-01"
Save a response to disk
Pipe the response body straight into a file under the Output\ folder:
.\ArmClient-PS.ps1 `
-Method GET `
-RelativePath "/subscriptions/<subscriptionId>/resourceGroups/<resourceGroupName>" `
-ApiVersion "2021-04-01" `
-OutputFile "resource-group.json"
Send a request body (PUT/PATCH/POST)
Either supply inline JSON with -Body or point at a file with -BodyFile:
.\ArmClient-PS.ps1 `
-Method PUT `
-RelativePath "/subscriptions/<subscriptionId>/resourceGroups/rg-example" `
-ApiVersion "2021-04-01" `
-Body '{"location":"eastus","tags":{"environment":"dev"}}'
Use a sovereign cloud
.\ArmClient-PS.ps1 `
-Environment AzureUSGovernment `
-Method GET `
-RelativePath "/subscriptions/<subscriptionId>" `
-ApiVersion "2022-12-01"
Inspect resolved module versions
See exactly which Az.* module versions the script will load — bundled vs. installed:
.\ArmClient-PS.ps1 -ShowResolvedModuleVersions
Run the built-in package self-test
Validate folder layout, file hashes, manifests, module resolution, and the current Az context:
.\ArmClient-PS.ps1 -SelfTest
Operation Presets
To remove the friction of remembering ARM paths and API versions, ArmClient-PS ships with a curated catalog of operation presets. Each preset bundles an HTTP method, a parameterized path template, a default API version, a list of known good API versions, and (for write operations) an example request body.
The catalog covers:
- ARM core — providers, subscriptions
- ARM resources — resource groups (list/get/create/delete), resources by group
- ARM deployments — list, get, validate, what-if, create-or-update
- ARM governance — policy assignments and management locks at subscription and resource-group scope
-
Azure Communication Services email — email services and email domains, including
initiateVerificationandcancelVerificationforDomain,SPF,DKIM,DKIM2, andDMARC
List all operation presets
.\ArmClient-PS.ps1 -ListOperations
Show full details for one preset
.\ArmClient-PS.ps1 -Operation ArmResourceGroupGet -ShowOperationDetails
Show known API versions for a preset
.\ArmClient-PS.ps1 -Operation AcsEmailDomainGet -ApiVersions
Run an operation preset
.\ArmClient-PS.ps1 `
-Operation ArmResourceGroupGet `
-OperationParameters @{
subscriptionId = '<subscription-id>'
resourceGroupName = 'rg-example'
}
For presets that require a JSON body (such as AcsEmailDomainInitiateVerification), the script will auto-build the body from -OperationParameters if -Body and -BodyFile are both omitted:
.\ArmClient-PS.ps1 `
-Operation AcsEmailDomainInitiateVerification `
-OperationParameters @{
subscriptionId = '<subscription-id>'
resourceGroupName = 'rg-example'
emailServiceName = 'mailsvc1'
domainName = 'contoso.com'
verificationType = 'DKIM2'
}
Long-Running Operations
Many ARM operations (resource group deletes, deployments, ACS domain verification, etc.) return 202 Accepted and complete asynchronously. ArmClient-PS handles this for you automatically:
- Detects
Azure-AsyncOperationandOperation-Locationresponse headers. - Honors
Retry-Afterfor service-friendly polling intervals. - Tracks operation state through both the
statusfield andproperties.provisioningState. - Throws on
Failed/Canceledwith the parsed ARM error code and message. - On success, re-
GETs the original resource (except forDELETE) so you receive the final resource state, not just the operation status. - Times out after 30 minutes by default to avoid runaway waits.
Security Notes
ArmClient-PS is intended to be safe to drop onto a support engineer’s machine:
- TLS 1.2 is enforced at process startup before any HTTPS call.
- Runtime execution disables Az context autosave for the current process.
- Runtime SHA-256 hash validation is enabled by default and re-runs immediately before each bundled module import.
-
Authenticode signature validation is available through
-EnforceSignatureValidation. -
Tokens, secrets, and cookies are redacted from log output (Bearer tokens,
Authorization,access_token,refresh_token,id_token,client_secret,password,assertion,Cookie,Set-Cookie). -
Dangerous custom headers are blocked —
Authorization,Proxy-Authorization,Cookie,Set-Cookie,Content-Length,Host,Connection,Transfer-Encoding. - CRLF injection protection for all custom headers.
- JSON validation for every inline body and body file before the request is sent.
-
-NoLoginlets you reuse an existing process context without triggering a new sign-in. -
-ClearContextOnExitdisconnects and clears the Az context when the script finishes. -
Logs\andOutput\are runtime folders and are not intended for source control.
Module Resolution Behavior
Default behavior is deterministic and predictable:
- Use a bundled module when no newer valid installed version is available.
- Prefer a newer installed version when it is valid and importable.
- Use
-PreferBundledModulesto force bundled content and ignore any installed copy, even if it is newer. - Use
-PreferInstalledModulesto always prefer an installed copy when one is valid and importable, even if the bundled version is newer.
Module dependencies are resolved depth-first based on each manifest’s RequiredModules, and circular references are surfaced as a clean error rather than an infinite loop. This means the same package behaves consistently across engineer workstations, even when their local Az.* versions drift.
Maintainer Build Workflow
If you maintain or fork the tool, the build script regenerates the bundled modules and manifests for you.
Rebuild bundled modules and manifests:
.\Build-BundledModules.ps1 -ToolVersion 1.0.0 -Clean -Force
Optional signing flow (recommended for redistribution inside an organization):
.\Build-BundledModules.ps1 `
-ToolVersion 1.0.0 `
-Clean `
-Force `
-CodeSigningThumbprint "<thumbprint>"
Distribution Guidance
Before distributing the package to other engineers or customers:
- Run
Build-BundledModules.ps1on a maintainer machine. - Confirm
Manifest\Files.sha256.jsonandManifest\Versions.jsonwere regenerated. - Run
.\ArmClient-PS.ps1 -SelfTestfrom the packaged folder. - Zip the entire folder structure without removing the
ModulesorManifestfolders.
Following this flow guarantees that the package on the receiving end will pass its own self-test on first run.
Final Thoughts
ARMClient has been a staple troubleshooting tool for years, but installing it (and the Az modules it depends on) isn’t always practical in restricted or sovereign environments. ArmClient-PS is my answer to that — a single, validated, redistributable PowerShell script that lets you make ARM calls the same way, with bundled dependencies, process-scoped auth, automatic long-running operation polling, and a curated set of operation presets for the calls support engineers reach for most often.
Source code & releases: https://github.com/blakedrumm/AzArmClient-PS
If you have ideas, run into issues, or want to extend the operation catalog for your own workflows, feel free to reach out — I’m always happy to help troubleshoot or share lessons learned.
Share on: