ArmClient-PS - A Single-Script Azure Resource Manager Support Tool

Posted by : on

azure   powershell   projects   troubleshooting

:book: 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.

:spiral_notepad: 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 with Add-AzEnvironment (such as Azure Stack Hub).


:arrow_down_small: Source Code

License
Last Commit
Repo Size

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.

View on GitHub


:red_circle: 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 with Add-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\, and Manifest\ folders must ship together so SHA-256 validation can succeed.

:dart: 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: 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\

:spiral_notepad: Note

Logs\ and Output\ are runtime folders and are not intended for source control. They are created and populated as the script executes.


:sparkles: Key Features

  • Single-file PowerShell scriptArmClient-PS.ps1 is the entire runtime.
  • Bundled Az.Accounts and dependencies loaded from a sibling Modules folder.
  • TLS 1.2 enforced for every HTTPS call before any request leaves the host.
  • Process-scoped authenticationDisable-AzContextAutosave -Scope Process runs 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, and Retry-After headers.
  • 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 -Body and -BodyFile payloads before the request is sent.
  • Built-in self-test that validates folders, manifests, hashes, module resolution, and Az context.

:page_with_curl: 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

:compass: 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 initiateVerification and cancelVerification for Domain, SPF, DKIM, DKIM2, and DMARC

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'
  }

:clock3: 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-AsyncOperation and Operation-Location response headers.
  • Honors Retry-After for service-friendly polling intervals.
  • Tracks operation state through both the status field and properties.provisioningState.
  • Throws on Failed / Canceled with the parsed ARM error code and message.
  • On success, re-GETs the original resource (except for DELETE) so you receive the final resource state, not just the operation status.
  • Times out after 30 minutes by default to avoid runaway waits.

:lock: 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 blockedAuthorization, 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.
  • -NoLogin lets you reuse an existing process context without triggering a new sign-in.
  • -ClearContextOnExit disconnects and clears the Az context when the script finishes.
  • Logs\ and Output\ are runtime folders and are not intended for source control.

:gear: 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 -PreferBundledModules to force bundled content and ignore any installed copy, even if it is newer.
  • Use -PreferInstalledModules to 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.


:hammer_and_wrench: 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>"

:outbox_tray: Distribution Guidance

Before distributing the package to other engineers or customers:

  1. Run Build-BundledModules.ps1 on a maintainer machine.
  2. Confirm Manifest\Files.sha256.json and Manifest\Versions.json were regenerated.
  3. Run .\ArmClient-PS.ps1 -SelfTest from the packaged folder.
  4. Zip the entire folder structure without removing the Modules or Manifest folders.

Following this flow guarantees that the package on the receiving end will pass its own self-test on first run.


:speech_balloon: 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.

:link: 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.

Page Views


Share on:
About Blake Drumm
Blake Drumm

I like to collaborate and work on projects. My skills with Powershell allow me to quickly develop automated solutions to suit my customers, and my own needs.

Email :

Website :

About Blake Drumm

My name is Blake Drumm, I am working on the Azure Monitoring Enterprise Team with Microsoft. Currently working to update public documentation for System Center products and write troubleshooting guides to assist with fixing issues that may arise while using the products. I like to blog on Operations Manager and Azure Automation products, keep checking back for new posts. My goal is to post atleast once a month if possible.

Follow @blakedrumm
Useful Links