AzLocal.UpdateManagement
0.8.4
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-AzLocalServicePrincipal Start-AzLocalClusterUpdate Get-AzLocalClusterUpdateReadiness Get-AzLocalClusterInventory Get-AzLocalClusterInfo Get-AzLocalUpdateSummary Get-AzLocalAvailableUpdates Get-AzLocalUpdateRuns Set-AzLocalClusterUpdateRingTag Invoke-AzLocalFleetOperation Get-AzLocalFleetProgress Test-AzLocalFleetHealthGate Export-AzLocalFleetState Resume-AzLocalFleetUpdate Stop-AzLocalFleetUpdate Test-AzLocalClusterHealth Get-AzLocalFleetStatusData New-AzLocalFleetStatusHtmlReport Test-AzLocalUpdateScheduleAllowed Reset-AzLocalSideloadedTag Get-AzLocalItsmConfig Test-AzLocalItsmConnection New-AzLocalIncident Copy-AzLocalPipelineExample Update-AzLocalPipelineExample Copy-AzLocalItsmSample Get-AzLocalFleetHealthFailures Test-AzLocalApplyUpdatesScheduleCoverage Get-AzLocalUpdateRunFailures Get-AzLocalApplyUpdatesScheduleConfig Resolve-AzLocalCurrentUpdateRing Get-AzLocalApplyUpdatesScheduleNextFirings New-AzLocalApplyUpdatesScheduleConfig Update-AzLocalApplyUpdatesScheduleConfig Get-AzLocalFleetHealthOverview Get-AzLocalLatestSolutionVersion Get-AzLocalFleetConnectivityStatus New-AzLocalFleetConnectivityStatusSummary
PSEditions
Dependencies
This module has no dependencies.
Release Notes
## Version 0.8.4 - Step.3 advisor enhancements (NoWindowTag CSV remediation + Cycle calendar + Exclusion windows summary) + Step.6 per-cluster Step Summary + Node 24 opt-in + version banner on every install step + RBAC custom role renamed to `Azure Stack HCI Update Operator (custom)`
Step.3 advisor enhancement release. No public API removed. One new optional parameter on `Test-AzLocalApplyUpdatesScheduleCoverage`: `-ClusterCsvPath <path>`. Two new informational sections on `-View Recommend` that render whenever `-SchedulePath` is supplied (Step.3 yml now passes it). All v0.8.3 behaviour preserved unchanged.
- **Enhancement A - NoWindowTag CSV remediation (new `-ClusterCsvPath` parameter).** When the operator supplies the path to the source-controlled cluster inventory CSV (the file Step.2 consumes - default `config/ClusterUpdateRings.csv`), `-View Recommend` emits a new `## Action required - NoWindowTag remediation` section. For each cluster that has an `UpdateRing` tag but no `UpdateStartWindow` tag, the advisor proposes a **peer-derived `UpdateStartWindow` value** (mode of peers' values in the same ring) plus a source label explaining the choice (unanimous / majority / sole peer / no peers). It then looks up the cluster in the CSV - **case-insensitive on `ResourceId` first, falling back to `ClusterName + ResourceGroup`** for older CSVs that pre-date the `ResourceId` column - and tells the operator either to edit the `UpdateStartWindow` cell on that row, or (if the cluster is absent from the CSV) to re-run Step.1 to regenerate the inventory artifact and replace the source-controlled CSV with it. ARG query also projects `UpdateExclusionsWindow` so the new Enhancement C section has data to render.
- **Enhancement B - Cycle calendar (informational, auto-emits when `-SchedulePath` is supplied).** A new `## Cycle calendar - next N day(s)` table renders one row per UTC day for one full cycle (`CycleWeeks * 7` days starting today). Each row shows Date, Day-of-week, CycleWeek (`X of N`, with `(cycle wraps)` annotation on the wrap row), Eligible rings (UNION of all matching schedule rows), and effective `AllowedUpdateVersions` (or `_(no constraint)_`). Re-uses `Resolve-AzLocalCurrentUpdateRing` per-day so cycle-week, UNION, and allow-list math is identical to runtime - no duplicate ISO-8601 / week-arithmetic logic to drift. Lets operators verify ring coverage matches policy and spot dead days where no ring is eligible.
- **Enhancement C - Configured exclusion windows summary (informational, auto-emits when at least one cluster has a non-empty `UpdateExclusionsWindow` tag).** A new `## Configured exclusion windows (UpdateExclusionsWindow tag)` section groups tagged clusters by `(UpdateRing, UpdateExclusionsWindow)` and renders a rollup table (cluster count + first 10 cluster names + `+N more`). Plus a per-ring breakdown of clusters that have NO `UpdateExclusionsWindow` tag (so operators can spot drift where some clusters in a ring have a blackout configured and others do not).
- **Step.3 GH + ADO yml: new `cluster_csv_path` / `clusterCsvPath` input** (default `config/ClusterUpdateRings.csv`). Validates the file exists at job time - missing file skips Enhancement A quietly (vs throwing) so repos that don't version-control a cluster CSV yet keep getting the legacy advisor output. Both yml templates now also pass `-SchedulePath` to the `-View Recommend` invocation so Enhancements B+C render in the Step Summary.
- **Pester suite updates**: drift-sync test bumped to `'0.8.4'`; new It blocks for CSV-lookup paths, peer-derivation modes, cycle-calendar math + cycle-wrap rendering + UNION rows, and exclusion-windows rollup grouping.
- **Step.6 Enhancement D - per-cluster Step Summary in `apply-updates` (GH + ADO).** `apply-updates` step persists `apply-results.json`; Summary renders new `### Cluster Actions` (icon + Status + UpdateName + Duration + Message per cluster handed to apply) + `### Clusters Skipped at Readiness Gate` (reads `readiness-report.csv`, capped at 100 rows). Eliminates JUnit-artifact downloads to identify per-cluster outcomes.
- **Node.js 24 opt-in across all 10 GH yml.** `FORCE_JAVASCRIPT_ACTIONS_TO_NODE24: true` at workflow level, ahead of GitHub's platform-wide cutover.
- **Version banner appended to every install step** - one banner per yml across all 20 bundled `Step.{0..9}.yml` templates (Step.6 ADO has 2 install steps but the second deliberately skips upload to avoid duplicating the banner): `_Pipeline YAML v<g> | Module v<i> installed (<pin>) | PSGallery latest <l> | <verdict>_` rendered in the Summary view, eliminating "is my YAML / module out of date?" investigation lag.
- **RBAC custom role renamed: `Azure Stack HCI Update Operator` -> `Azure Stack HCI Update Operator (custom)`.** Bundled JSON `Name` updated; `Actions[]` byte-identical to v0.8.3. Existing tenants: `az role definition update --role-definition ./azlocal-update-management-custom-role.json` is an in-place rename - GUID + every existing role assignment preserved; zero pipeline downtime. Reference by `roleDefinitionId` (GUID) in automation, not display name.
- **All 20 bundled `Step.{0..9}.yml` templates** bump `GENERATED_AGAINST_MODULE_VERSION` from `'0.8.3'` to `'0.8.4'`.
## Version 0.8.3 - Test-AzLocalApplyUpdatesScheduleCoverage Step.3 advisor accuracy + readability fixes: Recommend now diff-prunes against `-PipelineYamlPath`, Step.3 yml `pipeline_path` REQUIRED, Allow-list heading reframed, closing-fence typo fixed
## Version 0.8.2 - Test-AzLocalApplyUpdatesScheduleCoverage operator-UX release: -View Recommend snippet embeds `# All cron times below are UTC` comment + `Indent tip` blockquote; -View Audit `NoWindowTag` row now names affected clusters grouped by `UpdateRing` + sorts AFTER Covered; Step.3 GH/ADO Allow-list section trimmed; five new internal pipeline-host helpers (Get/Set/Add/Write-AzLocalPipeline*) laid down as foundations for the upcoming executable-YAML refactor
## Version 0.8.1 - Test-AzLocalApplyUpdatesScheduleCoverage -View Recommend GH snippet emits ONLY the `schedule:` block (no `on:` / `workflow_dispatch:` lines) so it can be pasted straight into Step.6_apply-updates.yml without producing a duplicate-key YAML error
## Version 0.8.0 - Step.7 form-default regressions fixed (criticalElapsedDays 7->3, updateRing Wave1->empty) + Pii-Guard.Tests.ps1 (repo-hygiene guard) + Publish-Module.ps1 excludes maintainer-only RELEASE-PROCESS.md
## Version 0.7.99 - Property/Summary renames (AvailableUpdates -> AllAvailableUpdates, AvailableUpdatesCount -> ActionableUpdatesCount, Ready/NotReady Summary -> ReadyForUpdate/UpToDate/NotReadyForUpdate) + Step.7 CRITICAL elapsed-days 7->3 + artifact zip names prefixed with step.X-
For full v0.7.x and v0.8.x release notes see:
https://github.com/NeilBird/Azure-Local/blob/main/AzLocal.UpdateManagement/CHANGELOG.md
FileList
- AzLocal.UpdateManagement.nuspec
- Public\Resolve-AzLocalCurrentUpdateRing.ps1
- Automation-Pipeline-Examples\azure-devops\Step.2_manage-updatering-tags.yml
- Automation-Pipeline-Examples\github-actions\Step.3_apply-updates-schedule-audit.yml
- docs\images\auth-smoke-test-validate-oidc.png
- Private\ConvertFrom-AzLocalUpdateSideloaded.ps1
- Private\Get-AzLocalItsmTriggerDecision.ps1
- Private\Get-TagValue.ps1
- Private\Invoke-FleetOpClusterAction.ps1
- Private\Test-AzLocalUpdateExclusion.ps1
- Public\Copy-AzLocalPipelineExample.ps1
- Public\Get-AzLocalFleetStatusData.ps1
- Public\Resume-AzLocalFleetUpdate.ps1
- AzLocal.UpdateManagement.psd1
- Automation-Pipeline-Examples\azure-devops\Step.3_apply-updates-schedule-audit.yml
- Automation-Pipeline-Examples\github-actions\Step.4_fleet-connectivity-status.yml
- docs\images\inventory-clusters-run-output.png
- Private\ConvertFrom-AzLocalUpdateWindow.ps1
- Private\Get-AzLocalModuleRootManifestPath.ps1
- Private\Import-AzLocalFleetState.ps1
- Private\Read-AzLocalApplyUpdatesYamlCrons.ps1
- Private\Test-AzLocalUpdateSideloadedAllowed.ps1
- Public\Export-AzLocalFleetState.ps1
- Public\Get-AzLocalItsmConfig.ps1
- Public\Set-AzLocalClusterUpdateRingTag.ps1
- AzLocal.UpdateManagement.psm1
- Automation-Pipeline-Examples\azure-devops\Step.4_fleet-connectivity-status.yml
- Automation-Pipeline-Examples\github-actions\Step.5_assess-update-readiness.yml
- docs\images\README.md
- Private\ConvertTo-AzLocalAdditionalProperties.ps1
- Private\Get-AzLocalPipelineCustomiseMarkers.ps1
- Private\Install-AzGraphExtension.ps1
- Private\Resolve-AzLocalItsmSecret.ps1
- Private\Test-AzLocalUpdateVersionInProgressMatch.ps1
- Public\Get-AzLocalApplyUpdatesScheduleConfig.ps1
- Public\Get-AzLocalLatestSolutionVersion.ps1
- Public\Start-AzLocalClusterUpdate.ps1
- example-update-request.json
- Automation-Pipeline-Examples\azure-devops\Step.5_assess-update-readiness.yml
- Automation-Pipeline-Examples\github-actions\Step.6_apply-updates.yml
- ITSM\ITSM-Config-Reference.md
- Private\ConvertTo-AzLocalUpdateRingKqlFilter.ps1
- Private\Get-AzLocalPipelineHost.ps1
- Private\Invoke-AzCliJson.ps1
- Private\Resolve-AzLocalUpdateRunDeepestError.ps1
- Private\Test-AzLocalUpdateWindow.ps1
- Public\Get-AzLocalApplyUpdatesScheduleNextFirings.ps1
- Public\Get-AzLocalUpdateRunFailures.ps1
- Public\Stop-AzLocalFleetUpdate.ps1
- README.md
- Automation-Pipeline-Examples\azure-devops\Step.6_apply-updates.yml
- Automation-Pipeline-Examples\github-actions\Step.7_monitor-updates.yml
- ITSM\ITSM-Connector-Plan.md
- Private\ConvertTo-SafeCsvCollection.ps1
- Private\Get-AzLocalRunEndTime.ps1
- Private\Invoke-AzLocalItsmHttp.ps1
- Private\Resolve-SafeOutputPath.ps1
- Private\Test-ExportPathWritable.ps1
- Public\Get-AzLocalAvailableUpdates.ps1
- Public\Get-AzLocalUpdateRuns.ps1
- Public\Test-AzLocalApplyUpdatesScheduleCoverage.ps1
- Test-Pipelines.ps1
- Automation-Pipeline-Examples\azure-devops\Step.7_monitor-updates.yml
- Automation-Pipeline-Examples\github-actions\Step.8_fleet-update-status.yml
- ITSM\README.md
- Private\ConvertTo-SafeCsvField.ps1
- Private\Get-CurrentStepPath.ps1
- Private\Invoke-AzLocalServiceNowAdapter.ps1
- Private\Resolve-WildcardDate.ps1
- Private\Write-AzLocalPipelineNotice.ps1
- Public\Get-AzLocalClusterInfo.ps1
- Public\Get-AzLocalUpdateSummary.ps1
- Public\Test-AzLocalClusterHealth.ps1
- Automation-Pipeline-Examples\apply-updates-schedule.example.yml
- Automation-Pipeline-Examples\azure-devops\Step.8_fleet-update-status.yml
- Automation-Pipeline-Examples\github-actions\Step.9_fleet-health-status.yml
- Private\Add-AzLocalPipelineStepSummary.ps1
- Private\ConvertTo-ScrubbedCliOutput.ps1
- Private\Get-DeepestActiveStep.ps1
- Private\Invoke-AzLocalSideloadedAutoReset.ps1
- Private\Resolve-WildcardDateRange.ps1
- Private\Write-AzLocalPipelineWarning.ps1
- Public\Get-AzLocalClusterInventory.ps1
- Public\Invoke-AzLocalFleetOperation.ps1
- Public\Test-AzLocalFleetHealthGate.ps1
- Automation-Pipeline-Examples\azlocal-update-management-custom-role.json
- Automation-Pipeline-Examples\azure-devops\Step.9_fleet-health-status.yml
- docs\cmdlet-reference.md
- Private\Convert-AzLocalScheduleSchemaVersion.ps1
- Private\Export-ResultsToJUnitXml.ps1
- Private\Get-DeepestErrorMessage.ps1
- Private\Invoke-AzLocalSideloadedAutoResetForCluster.ps1
- Private\Set-AzLocalClusterTagsMerge.ps1
- Private\Write-Log.ps1
- Public\Get-AzLocalClusterUpdateReadiness.ps1
- Public\New-AzLocalApplyUpdatesScheduleConfig.ps1
- Public\Test-AzLocalItsmConnection.ps1
- Automation-Pipeline-Examples\README.md
- Automation-Pipeline-Examples\docs\appendix-pipelines.md
- docs\concepts.md
- Private\Convert-AzLocalUpdateWindowToCron.ps1
- Private\Format-AzLocalDurationHuman.ps1
- Private\Get-ExportFormat.ps1
- Private\Invoke-AzLocalUpdateApply.ps1
- Private\Set-AzLocalPipelineOutput.ps1
- Private\Write-UpdateCsvLog.ps1
- Public\Get-AzLocalFleetConnectivityStatus.ps1
- Public\New-AzLocalFleetConnectivityStatusSummary.ps1
- Public\Test-AzLocalUpdateScheduleAllowed.ps1
- Automation-Pipeline-Examples\.itsm\azurelocal-itsm.yml
- Automation-Pipeline-Examples\docs\appendix-release-history.md
- docs\rbac.md
- Private\ConvertFrom-AzLocalCronExpression.ps1
- Private\Format-AzLocalIncidentBody.ps1
- Private\Get-HealthCheckFailureSummary.ps1
- Private\Invoke-AzResourceGraphQuery.ps1
- Private\Test-AzCliAvailable.ps1
- Private\Write-Utf8NoBomFile.ps1
- Public\Get-AzLocalFleetHealthFailures.ps1
- Public\New-AzLocalFleetStatusHtmlReport.ps1
- Public\Update-AzLocalApplyUpdatesScheduleConfig.ps1
- Automation-Pipeline-Examples\.itsm\templates\incident-body.md
- Automation-Pipeline-Examples\github-actions\Step.0_authentication-test.yml
- docs\release-history.md
- Private\ConvertFrom-AzLocalScheduleYaml.ps1
- Private\Format-AzLocalUpdateRun.ps1
- Private\Get-LastUpdateRunErrorSummary.ps1
- Private\Invoke-AzRestJson.ps1
- Private\Test-AzLocalAllowedUpdateVersionsString.ps1
- Public\Connect-AzLocalServicePrincipal.ps1
- Public\Get-AzLocalFleetHealthOverview.ps1
- Public\New-AzLocalIncident.ps1
- Public\Update-AzLocalPipelineExample.ps1
- Automation-Pipeline-Examples\azure-devops\Step.0_authentication-test.yml
- Automation-Pipeline-Examples\github-actions\Step.1_inventory-clusters.yml
- docs\troubleshooting.md
- Private\ConvertFrom-AzLocalUpdateExcluded.ps1
- Private\Get-AzLocalClusterUpdateRuns.ps1
- Private\Get-LatestUpdateByYYMM.ps1
- Private\Invoke-FleetJobsInParallel.ps1
- Private\Test-AzLocalUpdateExcludedAllowed.ps1
- Public\Copy-AzLocalItsmSample.ps1
- Public\Get-AzLocalFleetProgress.ps1
- Public\Reset-AzLocalSideloadedTag.ps1
- Automation-Pipeline-Examples\azure-devops\Step.1_inventory-clusters.yml
- Automation-Pipeline-Examples\github-actions\Step.2_manage-updatering-tags.yml
- docs\images\apply-updates-summary.png
- Private\ConvertFrom-AzLocalUpdateExclusion.ps1
- Private\Get-AzLocalItsmDedupeKey.ps1
Version History
| Version | Downloads | Last updated |
|---|---|---|
| 0.8.6 | 19 | 6/10/2026 |
| 0.8.5 | 15 | 6/10/2026 |
| 0.8.4 (current version) | 27 | 6/9/2026 |
| 0.8.3 | 10 | 6/9/2026 |
| 0.8.2 | 6 | 6/9/2026 |