Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 9 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,15 +5,23 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## [Unreleased]

## [4.4.0] - 2026-10-07

### Changed

- The one-shot `SPSUpdate-RebootConfirm` boot task (automatic reboot) now runs as **`NT AUTHORITY\SYSTEM`** instead of the farm InstallAccount decrypted from `secrets.psd1`. This removes the stored-credential dependency that could abort the reboot at task registration (`0x8007052E` when the secret did not match the account password) and decouples the reboot from password rotation. `Add-SPSScheduledTask` gains a `-RunAsSystem` switch (mutually exclusive with `-ExecuteAsCredential`). Because a `SYSTEM` task reaches a UNC status store as the computer account, the share must grant the farm computer accounts (e.g. `Domain Computers`) Modify — add them to `New-SPSDashboardSite.ps1 -WriteAccounts`; `-Action ConfirmReboot` logs a clear, actionable warning (and retries on the next boot) when the grant is missing. ([#64](https://github.com/luigilink/SPSUpdate/issues/64))

### Added

- **SharePoint 2016 / 2019 compatibility restored on the `4.x` line.** This maintenance line keeps the full feature set of the `5.x` (Subscription Edition) line but re-introduces support for SharePoint Server 2016 and 2019: the SharePoint cmdlets are loaded through the legacy `Microsoft.SharePoint.PowerShell` snap-in on 2016/2019 (and the `SharePointServer` module on Subscription Edition), both locally and in remote sessions, and `Get-SPSLocalVersionInfo` is version-aware again (`2016`/`2019`/`SE`) so the correct product-name string is matched in the registry. SharePoint 2016, 2019 and Subscription Edition all share the same `16.0` hive and `OSearch16` search service, so no other paths change. Version detection is automatic at runtime (no configuration change). As an added safety check on this multi-version line, `Start-SPSProductUpdate` now compares the update package's product line (2016/2019/SE, derived from the CU build) with the installed SharePoint line and fails fast — before stopping any service or launching the installer — when they do not match. ([#38](https://github.com/luigilink/SPSUpdate/issues/38))
- A deferred automatic reboot that was already performed **out-of-band** (a manual restart or a Windows Update reboot) is now reconciled instead of restarting the server again: when a `.pending` reboot request predates the server's last boot time, `Invoke-SPSAutomaticReboot` marks the Reboot phase `Done` ("Reboot already completed out-of-band"), clears the pending marker and skips the restart. A fresh reboot required by an install performed in the same run is unaffected. ([#68](https://github.com/luigilink/SPSUpdate/issues/68))
- `-Action ProductUpdate` now refreshes the installed server's live **Patch Status** on the Binaries Installation card after the cumulative update is installed, so the column reflects the real post-install state (typically `Upgrade Required` until the Configuration Wizard runs) instead of keeping the pre-install value (`No Action Required`) until the next `Default` run. It reuses the same master-side patch-status read as the `Default` baseline (no remoting) and is status-only — the Content Databases and Configuration Wizard cards still evolve only during a `Default` run. A failed read preserves the last-known-good value. ([#59](https://github.com/luigilink/SPSUpdate/issues/59))

## [4.3.0] - 2026-10-06

### Added

- **SharePoint 2016 / 2019 compatibility restored on the `4.x` line.** This maintenance line keeps the full feature set of the `5.x` (Subscription Edition) line but re-introduces support for SharePoint Server 2016 and 2019: the SharePoint cmdlets are loaded through the legacy `Microsoft.SharePoint.PowerShell` snap-in on 2016/2019 (and the `SharePointServer` module on Subscription Edition), both locally and in remote sessions, and `Get-SPSLocalVersionInfo` is version-aware again (`2016`/`2019`/`SE`) so the correct product-name string is matched in the registry. SharePoint 2016, 2019 and Subscription Edition all share the same `16.0` hive and `OSearch16` search service, so no other paths change. Version detection is automatic at runtime (no configuration change). As an added safety check on this multi-version line, `Start-SPSProductUpdate` now compares the update package's product line (2016/2019/SE, derived from the CU build) with the installed SharePoint line and fails fast — before stopping any service or launching the installer — when they do not match. ([#38](https://github.com/luigilink/SPSUpdate/issues/38))

- The near real-time dashboard now refreshes the live farm status at key transitions (the pre-patch baseline, after the Configuration Wizard completes, and the final render) instead of only at the pre-patch baseline. The master re-reads each server's patch status and re-publishes the content-database inventory with fresh upgrade status, so a successful campaign no longer shows a stale `Upgrade Required` Patch Status or a lingering pre-patch inconsistency banner once the farm is back to `No Action Required`. The Content Databases card also shows a database that SPSUpdate has already upgraded (State `Done`) as `No update pending` even before the next refresh. Server patch status and role are shown with short readable labels (for example `Upgrade Required`, `Application with Search`) via the new public helpers `ConvertTo-SPSPatchStatusLabel` and `ConvertTo-SPSRoleLabel`, instead of the raw enum names. ([#51](https://github.com/luigilink/SPSUpdate/issues/51))
- A standalone, idempotent helper `New-SPSDashboardSite.ps1` (in `src/`) that provisions the dashboard hosting target on an IIS/pull server — folder, SMB share (Modify for the write accounts), NTFS permissions, a static-file `web.config`, and either a dedicated IIS site or a sub-application under an existing site. It has no dependency on the `SPSUpdate.Common` module, so it can be copied on its own to the IIS server. A new wiki page, *Hosting the dashboard on IIS*, documents the validated setup (and the manual equivalent). ([#49](https://github.com/luigilink/SPSUpdate/issues/49))
- `Test-SPSUpdateReadiness.ps1` now checks the optional `Dashboard.OutputPath`: it verifies the folder exists and is writable, and warns when it is a master-local (drive-letter) path rather than a shared UNC path that worker runs can also reach. ([#49](https://github.com/luigilink/SPSUpdate/issues/49))
Expand Down
22 changes: 17 additions & 5 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,24 @@
# SPSUpdate - Release Notes

## [5.0.1] - 2026-09-21
## [4.4.0] - 2026-10-07

This patch fixes the near real-time patching dashboard on farms that have no content
databases (for example a dedicated search farm).
SPSUpdate 4.4.0 backports to the **`4.x` maintenance line** (SharePoint Server 2016 / 2019 and
Subscription Edition) three fixes already shipped on the `5.x` line in **v5.2.0**. The only
difference from the `5.x` line remains how the SharePoint cmdlets are loaded (the legacy
`Microsoft.SharePoint.PowerShell` snap-in on 2016/2019, the `SharePointServer` module on Subscription
Edition); the ported logic is otherwise identical.

### Fixed
> ⚠️ SharePoint Server 2016 and 2019 reached **Microsoft end of support on 14 July 2026** and no
> longer receive security updates. This line restores SPSUpdate **tooling compatibility** only; it
> does **not** restore vendor support. Plan a migration to Subscription Edition (and the `5.x` line).

- On a farm without content databases, the mount/upgrade sequences were shown as **Failed** with "Cannot bind argument to parameter 'Name' because it is an empty string." The inventory generator (`Initialize-SPSContentDbJsonFile`) now always writes a valid file with four (possibly empty) sequences; the master run skips the mount/upgrade sequences entirely when there is no content database (so the dashboard shows only ProductUpdate, the Configuration Wizard and side-by-side); and each sequence sub-run defensively ignores empty entries.
### Changed

- **Reboot-confirm boot task runs as `NT AUTHORITY\SYSTEM`.** The one-shot `SPSUpdate-RebootConfirm` task (automatic reboot) no longer depends on the farm InstallAccount decrypted from `secrets.psd1`, removing a stored-credential failure at task registration (`0x8007052E`) and decoupling the reboot from password rotation. `Add-SPSScheduledTask` gains a `-RunAsSystem` switch. Because a `SYSTEM` task reaches a UNC status store as the computer account, the share must grant the farm computer accounts (e.g. `Domain Computers`) Modify; `-Action ConfirmReboot` logs a clear, actionable warning and retries on the next boot when the grant is missing. ([#64](https://github.com/luigilink/SPSUpdate/issues/64))

### Added

- **Live Patch Status after a CU install.** `-Action ProductUpdate` now refreshes the installed server's Patch Status on the Binaries Installation card after a real install, so the column reflects the post-install state (typically `Upgrade Required` until the Configuration Wizard runs) instead of keeping the pre-install value until the next `Default` run. Status-only, no remoting, and a failed read preserves the last-known-good value. ([#59](https://github.com/luigilink/SPSUpdate/issues/59))
- **Out-of-band reboot reconciliation.** A deferred automatic reboot already performed out-of-band (a manual restart or a Windows Update reboot) is reconciled instead of restarting the server again: when a `.pending` reboot request predates the server's last boot time, `Invoke-SPSAutomaticReboot` marks the Reboot phase `Done`, clears the pending marker and skips the restart. A fresh reboot required by an install performed in the same run is unaffected. ([#68](https://github.com/luigilink/SPSUpdate/issues/68))

A full list of changes in each version can be found in the [change log](CHANGELOG.md)
2 changes: 1 addition & 1 deletion src/Modules/SPSUpdate.Common/SPSUpdate.Common.psd1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@{
RootModule = 'SPSUpdate.Common.psm1'
ModuleVersion = '5.0.1'
ModuleVersion = '4.4.0'
GUID = 'd6f4e2b7-3a1c-4d8e-9f2a-6c5b7e0a1d34'
Author = 'Jean-Cyril DROUHIN'
CompanyName = 'luigilink'
Expand Down
4 changes: 2 additions & 2 deletions tests/SPSUpdate.Common.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ Describe 'SPSUpdate.Common module' {
{ Test-ModuleManifest -Path $modulePath -ErrorAction Stop } | Should -Not -Throw
}

It 'manifest version is 5.0.0 or higher' {
(Test-ModuleManifest -Path $modulePath).Version | Should -BeGreaterOrEqual ([version]'5.0.0')
It 'manifest version is 4.0.0 or higher' {
(Test-ModuleManifest -Path $modulePath).Version | Should -BeGreaterOrEqual ([version]'4.0.0')
}

It 'exports exactly the expected public functions' {
Expand Down
Loading