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
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- 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))
- 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))
Expand Down
18 changes: 18 additions & 0 deletions src/SPSUpdate.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -632,6 +632,24 @@ function Invoke-SPSAutomaticReboot {
return
}

# Reconcile a deferred reboot already performed out-of-band (pending predates last boot), but
# not when this run itself needs a reboot (fresh -RebootRequired, or Force on a successful install).
if ($hasPending -and -not $RebootRequired -and -not ($rebootCfg.Force -and $InstallPerformed)) {
$pendingStamp = $null
try { $pendingStamp = [datetimeoffset]::Parse((Get-Content -Path $rebootPendingMarker -Raw).Trim(), [cultureinfo]::InvariantCulture, [System.Globalization.DateTimeStyles]::RoundtripKind).UtcDateTime } catch { $pendingStamp = $null }
$lastBoot = $null
try { $lastBoot = (Get-CimInstance -ClassName Win32_OperatingSystem -ErrorAction Stop).LastBootUpTime.ToUniversalTime() } catch { $lastBoot = $null }
if ($null -ne $pendingStamp -and $null -ne $lastBoot -and $lastBoot -gt $pendingStamp) {
Write-Output "Deferred reboot for $thisServer already satisfied out-of-band (last boot $lastBoot > request $pendingStamp); reconciling."
if ($null -ne $rebootDoneMarker) { Set-Content -Path $rebootDoneMarker -Value (Get-Date -Format o) -Force -ErrorAction SilentlyContinue }
Remove-Item -Path $rebootPendingMarker -Force -ErrorAction SilentlyContinue
Write-SPSStatus -Scope 'Reboot' -Phase 'Reboot' -Server $thisServer -State 'Done' -Detail 'Reboot already completed out-of-band'
Add-SPSUpdateEvent -Message "Deferred reboot on $thisServer reconciled: the server was already rebooted out-of-band." -Source 'Restart-SPSServer' -EntryType 'Information' -EventID 3010
Write-SPSDashboard
return
}
}

# Decide whether a reboot is warranted. Force reboots even on a successful no-reboot
# install (exit 0), but only when an install actually ran this time, so an already-patched
# server (null / exit 17025) is never rebooted just because a new campaign started.
Expand Down
Loading