AzLocal.UpdateManagement
0.7.41
PowerShell module to manage Azure Local (formerly Azure Stack HCI) cluster updates using Azure Update Manager APIs. Provides functions to start updates, check update status, list available updates, and monitor update runs. Renamed from AzStackHci.ManageUpdates in v0.7.3 to align with the Azure Local product name.
Minimum PowerShell version
5.1
Installation Options
Owners
Copyright
(c) Microsoft. All rights reserved.
Package Details
Author(s)
- Neil Bird Microsoft
Tags
Azure AzureLocal AzureStackHCI Updates UpdateManager HCI Automation CICD Pipeline ServiceNow ITSM Incident
Functions
Connect-AzureLocalServicePrincipal Start-AzureLocalClusterUpdate Get-AzureLocalClusterUpdateReadiness Get-AzureLocalClusterInventory Get-AzureLocalClusterInfo Get-AzureLocalUpdateSummary Get-AzureLocalAvailableUpdates Get-AzureLocalUpdateRuns Set-AzureLocalClusterUpdateRingTag Invoke-AzureLocalFleetOperation Get-AzureLocalFleetProgress Test-AzureLocalFleetHealthGate Export-AzureLocalFleetState Resume-AzureLocalFleetUpdate Stop-AzureLocalFleetUpdate Test-AzureLocalClusterHealth Get-AzureLocalFleetStatusData New-AzureLocalFleetStatusHtmlReport Test-AzureLocalUpdateScheduleAllowed Reset-AzureLocalSideloadedTag Get-AzureLocalItsmConfig Test-AzureLocalItsmConnection New-AzureLocalIncident Copy-AzureLocalPipelineExample
PSEditions
Dependencies
This module has no dependencies.
Release Notes
## Version 0.7.41 - Hotfix: parallel fleet reads broken by v0.7.3 NestedModules refactor
### Fixed
- HIGH: every fleet read function that dispatches through
Invoke-FleetJobsInParallel (Get-AzureLocalUpdateRuns,
Get-AzureLocalUpdateSummary, Get-AzureLocalClusterUpdateReadiness,
Get-AzureLocalAvailableUpdates, Get-AzureLocalFleetProgress,
Invoke-AzureLocalFleetOperation, Test-AzureLocalClusterHealth, and
Start-AzureLocalClusterUpdate's parallel path) failed for every
cluster when invoked with -ThrottleLimit > 1 against the PSGallery-
installed v0.7.4, returning State=Error: "Cannot use '&' to invoke in
the context of module 'Invoke-FleetJobsInParallel' because it is not
imported." Inline (-ThrottleLimit 1) was unaffected. Root cause: the
v0.7.3 NestedModules refactor changed $PSCommandPath inside
Invoke-FleetJobsInParallel.ps1 to point at the helper's own .ps1, not
the root manifest. Per-batch Start-Job scriptblocks then imported only
that .ps1 in the child runspace, so & $mod { ... } against private
helpers always failed.
- HIGH: New-AzureLocalFleetStatusHtmlReport -ThrottleLimit > 1 (via
Get-AzureLocalFleetStatusData) threw at start-up: "Parallel collection
requires module path '...\Public\AzLocal.UpdateManagement.psm1' to be
reachable by background jobs, but it does not exist." Same class of
regression but a separate code path: Get-AzureLocalFleetStatusData was
using Join-Path $PSScriptRoot 'AzLocal.UpdateManagement.psm1', and
after v0.7.3 $PSScriptRoot resolves to Public/, not the module root.
New-AzureLocalFleetStatusHtmlReport's footer fallback had the same flaw.
- Centralised the resolution in a new private helper
Get-AzLocalModuleRootManifestPath, used by all three sites. It prefers
the loaded module's .Path (.psd1 over .psm1) and falls back to walking
up from the caller, so it is correct from any Public/ or Private/ file.
- Added Pester regression tests for the helper and for the trailing
$ModulePath argument that Invoke-FleetJobsInParallel passes to per-
batch scriptblocks. Existing tests only exercised the inline
-ThrottleLimit 1 fast-path and silently masked the v0.7.4 regression.
## Version 0.7.4 - ITSM Connector Phase 1 (ServiceNow)
### Added (Phase 1 scaffold)
- New optional ITSM ticketing surface that lets `apply-updates` and
`fleet-update-status` pipelines open ServiceNow incidents when a cluster
needs operator action. Disabled by default; opt-in via pipeline input
`raise_itsm_ticket=true` plus a `./.itsm/azurelocal-itsm.yml` config file.
- New public functions (Phase 1):
- `Get-AzureLocalItsmConfig` - load + validate the YAML/JSON trigger matrix
- `Test-AzureLocalItsmConnection` - dry-run probe of ITSM endpoint + adapters
- `New-AzureLocalIncident` - consume JUnit results, evaluate trigger matrix,
open / dedupe ServiceNow incidents, return per-cluster Action/TicketId rows
- New internal helpers (Phase 1):
- `Resolve-AzLocalItsmSecret`, `Get-AzLocalItsmDedupeKey`,
`Get-AzLocalItsmTriggerDecision`, `Format-AzLocalIncidentBody`,
`Invoke-AzLocalItsmHttp`, `Invoke-AzLocalServiceNowAdapter`
- New documentation: top-level `ITSM/` folder with `README.md` setup
walkthrough and `ITSM/ITSM-Config-Reference.md` (full schema
reference), plus `Automation-Pipeline-Examples/.itsm/` sample config
+ Mustache-style ticket-body templates.
- Phase 2 (`Sync-AzureLocalIncident` lifecycle close-out) and Phase 3
(Teams / Slack mirror adapters) are **deferred to a future release**;
the Phase 1 surface is feature-complete on its own.
- Secrets: ITSM credentials are referenced from Azure Key Vault
(`kv://<vault>/<secret>`) or native CI secrets (`env://<NAME>`). No raw
secret is ever written to YAML or to disk.
### Added (pipeline-examples convenience)
- New public function `Copy-AzureLocalPipelineExample` copies the bundled
`Automation-Pipeline-Examples/` folder out of the module install
location into a user-chosen destination (default: current directory).
Supports `-Platform GitHub | AzureDevOps | All`, `-Flatten`, `-Force`,
`-PassThru`, `-WhatIf` and `-Confirm`. Saves users from hunting through
`$module.ModuleBase` to find the YAML samples.
## Version 0.7.3 - Module renamed to AzLocal.UpdateManagement + internal refactor
### Renamed
- The module has been renamed from `AzStackHci.ManageUpdates` to `AzLocal.UpdateManagement`
to align with the Azure Local product name (Microsoft retired the `Azure Stack HCI`
brand in late 2024). The module GUID is preserved across the rename so anyone who has
the previous version installed will see this as the same module identity.
- **Migration**: `Uninstall-Module AzStackHci.ManageUpdates -AllVersions; Install-Module AzLocal.UpdateManagement`
- All previously-published `AzStackHci.ManageUpdates` versions have been unlisted from PSGallery.
- A transitional `AzStackHci.ManageUpdates` v0.7.3 stub is published once for users who
have automation that runs `Install-Module AzStackHci.ManageUpdates`; importing it
emits a warning pointing to the new name and exports no functions.
- Default log folder path moved from `C:\ProgramData\AzStackHci.ManageUpdates\` to
`C:\ProgramData\AzLocal.UpdateManagement\`. The old folder is not migrated; remove
it manually after upgrading if desired.
- Repository folder renamed `AzStackHci.ManageUpdates/` to `AzLocal.UpdateManagement/`;
pipeline YAML examples and `Import-Module` paths updated accordingly.
### Refactored
- The monolithic 11,679-line `.psm1` is split into Public/Private dot-sourced files,
matching the layout of `AzLocal.DeploymentAutomation` in this repo. 20 exported
functions live under `Public/`, 40 internal helpers under `Private/`. The manifest
enumerates every file in `NestedModules` (Private first, then Public, alphabetical
within each). No functional change; the full Pester suite (299 tests) remains green.
## Version 0.7.2 - Fleet read paths fixed under -ThrottleLimit > 1
### Bug fixes
- Get-AzureLocalUpdateRuns / Get-AzureLocalUpdateSummary /
Get-AzureLocalClusterUpdateReadiness no longer fail when invoked with
-ThrottleLimit greater than 1. Previously the per-cluster scriptblock
dispatched via Start-Job called module-private helpers directly. After
Import-Module in the child runspace those helpers were not visible at
script command-resolution scope, so every cluster reported
"The term 'Get-AzLocalClusterUpdateRuns' is not recognized..." (or the
equivalent). Inline (-ThrottleLimit 1) execution was unaffected. Fix:
each affected scriptblock now resolves the loaded module reference
(Import-Module -PassThru) and invokes the helper via & $module { ... }
so calls execute against the module's own session state and resolve
all transitive private references. Reported against a 9-cluster Prod
fleet. (See also v0.7.41 which catches a different manifestation of
this class.)
- cp1252 encoding warnings no longer leak into JSON parsing. On Windows
hosts where the console code page is cp1252, az rest / az graph query
emitted "WARNING: Unable to encode the output with cp1252 encoding..."
for ARM responses containing non-cp1252 characters; captured via 2>&1
that warning broke ConvertFrom-Json. PYTHONIOENCODING=utf-8 is
ineffective because az.cmd launches python with -I (isolated). Fix:
pass --only-show-errors to every az rest and az graph query call site
(Azure CLI maintainer's recommended workaround per azure-cli #14426).
See CHANGELOG.md for full detail.
## Version 0.7.1 - EndTime column for update runs + Sideloaded payload workflow
Summary: new optional `UpdateSideloaded` cluster tag and the auto-reset workflow
(Reset-AzureLocalSideloadedTag), EndTime column on Get-AzureLocalUpdateRuns,
CSV-injection sanitisation on intermediate logs, and a switch to
`Generic.List[object]` accumulators for fleet read paths (O(n) instead of
O(n^2)). Fully opt-in; clusters without the tag behave exactly as in v0.7.0.
Full notes in CHANGELOG.md.
## Version 0.7.0 - Fleet-scale correctness, parallelism, and hardening
The jump from 0.6.5 to 0.7.0 reflects the scope of this release: correctness fixes for large
fleets (1500+ clusters), a shift to true parallel execution across all per-cluster read/write
paths, HTML report performance improvements, and a round of bug and security hardening. No
breaking public-surface changes. Highlights: ARG pagination beyond 1000 results, true
parallel fleet execution, ~60% faster HTML render at 1500 clusters, mid-run token refresh,
CSV formula-injection escaping, UpdateWindow tag separator changed to '_'.
For full release notes on this and previous versions, see:
https://github.com/NeilBird/Azure-Local/blob/main/AzLocal.UpdateManagement/CHANGELOG.md
FileList
- AzLocal.UpdateManagement.nuspec
- Automation-Pipeline-Examples\.itsm\templates\incident-body.md
- Automation-Pipeline-Examples\github-actions\fleet-update-status.yml
- Private\ConvertFrom-AzLocalUpdateWindow.ps1
- Private\Format-AzLocalUpdateRun.ps1
- Private\Get-HealthCheckFailureSummary.ps1
- Private\Invoke-AzLocalSideloadedAutoReset.ps1
- Private\Resolve-SafeOutputPath.ps1
- Private\Test-AzLocalUpdateWindow.ps1
- Public\Get-AzureLocalAvailableUpdates.ps1
- Public\Get-AzureLocalUpdateRuns.ps1
- Public\Set-AzureLocalClusterUpdateRingTag.ps1
- AzLocal.UpdateManagement.psd1
- Automation-Pipeline-Examples\azure-devops\apply-updates.yml
- Automation-Pipeline-Examples\github-actions\inventory-clusters.yml
- Private\ConvertTo-AzLocalAdditionalProperties.ps1
- Private\Get-AzLocalClusterUpdateRuns.ps1
- Private\Get-LastUpdateRunErrorSummary.ps1
- Private\Invoke-AzLocalSideloadedAutoResetForCluster.ps1
- Private\Resolve-WildcardDate.ps1
- Private\Test-ExportPathWritable.ps1
- Public\Get-AzureLocalClusterInfo.ps1
- Public\Get-AzureLocalUpdateSummary.ps1
- Public\Start-AzureLocalClusterUpdate.ps1
- AzLocal.UpdateManagement.psm1
- Automation-Pipeline-Examples\azure-devops\assess-update-readiness.yml
- Automation-Pipeline-Examples\github-actions\manage-updatering-tags.yml
- Private\ConvertTo-SafeCsvCollection.ps1
- Private\Get-AzLocalItsmDedupeKey.ps1
- Private\Get-LatestUpdateByYYMM.ps1
- Private\Invoke-AzResourceGraphQuery.ps1
- Private\Resolve-WildcardDateRange.ps1
- Private\Write-Log.ps1
- Public\Get-AzureLocalClusterInventory.ps1
- Public\Invoke-AzureLocalFleetOperation.ps1
- Public\Stop-AzureLocalFleetUpdate.ps1
- CHANGELOG.md
- Automation-Pipeline-Examples\azure-devops\fleet-update-status.yml
- ITSM\ITSM-Config-Reference.md
- Private\ConvertTo-SafeCsvField.ps1
- Private\Get-AzLocalItsmTriggerDecision.ps1
- Private\Get-TagValue.ps1
- Private\Invoke-AzRestJson.ps1
- Private\Set-AzLocalClusterTagsMerge.ps1
- Private\Write-UpdateCsvLog.ps1
- Public\Get-AzureLocalClusterUpdateReadiness.ps1
- Public\New-AzureLocalFleetStatusHtmlReport.ps1
- Public\Test-AzureLocalClusterHealth.ps1
- example-update-request.json
- Automation-Pipeline-Examples\azure-devops\inventory-clusters.yml
- ITSM\ITSM-Connector-Plan.md
- Private\ConvertTo-ScrubbedCliOutput.ps1
- Private\Get-AzLocalModuleRootManifestPath.ps1
- Private\Import-AzureLocalFleetState.ps1
- Private\Invoke-AzureLocalUpdateApply.ps1
- Private\Test-AzCliAvailable.ps1
- Private\Write-Utf8NoBomFile.ps1
- Public\Get-AzureLocalFleetProgress.ps1
- Public\New-AzureLocalIncident.ps1
- Public\Test-AzureLocalFleetHealthGate.ps1
- README.md
- Automation-Pipeline-Examples\azure-devops\manage-updatering-tags.yml
- ITSM\README.md
- Private\Export-ResultsToJUnitXml.ps1
- Private\Get-AzLocalRunEndTime.ps1
- Private\Install-AzGraphExtension.ps1
- Private\Invoke-FleetJobsInParallel.ps1
- Private\Test-AzLocalUpdateExclusion.ps1
- Public\Connect-AzureLocalServicePrincipal.ps1
- Public\Get-AzureLocalFleetStatusData.ps1
- Public\Reset-AzureLocalSideloadedTag.ps1
- Public\Test-AzureLocalItsmConnection.ps1
- Automation-Pipeline-Examples\README.md
- Automation-Pipeline-Examples\github-actions\apply-updates.yml
- Private\ConvertFrom-AzLocalUpdateExclusion.ps1
- Private\Format-AzLocalDurationHuman.ps1
- Private\Get-CurrentStepPath.ps1
- Private\Invoke-AzLocalItsmHttp.ps1
- Private\Invoke-FleetOpClusterAction.ps1
- Private\Test-AzLocalUpdateSideloadedAllowed.ps1
- Public\Copy-AzureLocalPipelineExample.ps1
- Public\Get-AzureLocalItsmConfig.ps1
- Public\Resume-AzureLocalFleetUpdate.ps1
- Public\Test-AzureLocalUpdateScheduleAllowed.ps1
- Automation-Pipeline-Examples\.itsm\azurelocal-itsm.yml
- Automation-Pipeline-Examples\github-actions\assess-update-readiness.yml
- Private\ConvertFrom-AzLocalUpdateSideloaded.ps1
- Private\Format-AzLocalIncidentBody.ps1
- Private\Get-ExportFormat.ps1
- Private\Invoke-AzLocalServiceNowAdapter.ps1
- Private\Resolve-AzLocalItsmSecret.ps1
- Private\Test-AzLocalUpdateVersionInProgressMatch.ps1
- Public\Export-AzureLocalFleetState.ps1
Version History
| Version | Downloads | Last updated |
|---|---|---|
| 0.7.50 | 7 | 5/15/2026 |
| 0.7.41 (current version) | 4 | 5/13/2026 |
| 0.7.3 | 3 | 5/13/2026 |