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
54 changes: 54 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,60 @@
The format is based on and uses the types of changes according to [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

## [3.1.1] - 2026-05-11

### Added

scripts/Modules/util.psm1:

- Added `Test-SPSPendingReboot` to detect pending reboot state using multiple Windows markers (Windows Update, CBS, pending file rename, pending computer rename, and ConfigMgr).

scripts/Modules/sps.util.psm1:

- Added missing `Clear-ComObject` helper used by `Get-SPSLocalVersionInfo` to safely release COM objects.

tests/Modules/util.Tests.ps1:

- Added tests for `Test-SPSPendingReboot` and module export validation for the new helper.
- Added regression tests for `Start-SPSScheduledTask` `TaskPath` parameter support and task path normalization behavior.

tests/Modules/sps.util.Tests.ps1:

- Added regression test ensuring `Start-SPSProductUpdate` no longer exposes `InstallAccount`.

tests/SPSUpdate.Tests.ps1:

- Added assertions for consolidated reboot detection (`Test-SPSPendingReboot`) in ProductUpdate flow.
- Added regression assertion to prevent reintroduction of legacy ProductUpdate MOF cleanup code.

### Fixed

scripts/Modules/util.psm1:

- Fixed `Start-SPSScheduledTask` to support `TaskPath` and use that path when resolving and starting tasks.
- Normalized scheduled task paths to the expected `\<TaskPath>` format for `Get-ScheduledTask` and `Start-ScheduledTask`.
- Changed `Add-SPSScheduledTask` behavior to create or update existing tasks instead of skipping them.

scripts/Modules/sps.util.psm1:

- Fixed runtime failure in `Get-SPSLocalVersionInfo` when `Clear-ComObject` was missing.

scripts/SPSUpdate.ps1:

- Updated ProductUpdate to run update binaries without `InstallAccount`.
- Replaced single reboot check with consolidated reboot detection and detailed marker reporting.
- Removed legacy ProductUpdate `finally` block used for old DSC MOF cleanup.
- Enabled script-level verbose forwarding (`-Verbose`) to downstream module cmdlets.
- Added transcript file path output (`Transcript log file: ...`) at startup for easier log discovery.
- Updated installed SharePoint version output to print `FileVersion` explicitly.

### Changed

Documentation:

- Updated ProductUpdate examples and guidance to remove `InstallAccount` requirement.
- Removed stale references to temporary MOF cleanup after ProductUpdate.

## [3.1.0] - 2026-05-07

### Added
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ Impersonation is handled using the `Invoke-Command` cmdlet in PowerShell, togeth

## ProductUpdate

The `ProductUpdate` action runs the SharePoint update binaries directly. You only need the update files accessible on the target server and a valid `InstallAccount`.
The `ProductUpdate` action runs the SharePoint update binaries directly on the local server. You only need the update files accessible on that server.

## Documentation

Expand Down
67 changes: 27 additions & 40 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,70 +1,57 @@
# SPSUpdate - Release Notes

## [3.1.0] - 2026-05-07
## [3.1.1] - 2026-05-11

### Added

scripts/Modules/util.psm1:

- Added `Test-SPSPendingReboot` to detect pending reboot state using multiple Windows markers (Windows Update, CBS, pending file rename, pending computer rename, and ConfigMgr).

scripts/Modules/sps.util.psm1:

- Added missing `Clear-ComObject` helper used by `Get-SPSLocalVersionInfo` to safely release COM objects.

tests/Modules/util.Tests.ps1:

- New Pester test suite for util.psm1 module with 11 test cases
- Module loading validation tests
- Tests for Get-SPSInstalledProductVersion function (callable, return type validation)
- Tests for Add-SPSUpdateEvent function with parameter validation (Message/Source mandatory, EntryType/EventId optional)
- Tests for Invoke-SPSCommand function structure validation (Credential, Server, ScriptBlock parameters)
- Added tests for `Test-SPSPendingReboot` and module export validation for the new helper.
- Added regression tests for `Start-SPSScheduledTask` `TaskPath` parameter support and task path normalization behavior.

tests/Modules/sps.util.Tests.ps1:

- Comprehensive Pester test suite for sps.util.psm1 with 4 test cases
- Get-SPSLocalVersionInfo: Tests DisplayVersion fallback when patch metadata is missing
- Start-SPSProductUpdate: Tests file blocking detection with Add-SPSUpdateEvent logging
- Start-SPSProductUpdate: Tests exit code reporting ($setupInstall.ExitCode)
- Start-SPSProductUpdate: Tests service startup type restoration with SP 2015/2019 compatibility
- Added regression test ensuring `Start-SPSProductUpdate` no longer exposes `InstallAccount`.

tests/SPSUpdate.Tests.ps1:

- Main script validation test suite with expanded coverage for script structure, task handling, and event logging
- File validation: Existence, file extension matching, PowerShell syntax validation
- Content validation: param block, script version declaration, module imports (util, sps.util), Start-Transcript logging, try-catch error handling, Administrator privilege checks
- Dependency validation: Module files (util.psm1, sps.util.psm1), folders (credentialmanager, Config), sample JSON configuration files
- Configuration file validation: JSON validity, required ConfigurationName property
- Scheduled task validation: task name constants, task existence checks, TaskPath usage, and default action task management patterns
- Error logging validation: catchMessage pattern and Add-SPSUpdateEvent coverage for initialization, task scheduling, product update, credential, and configuration wizard failures
- Added assertions for consolidated reboot detection (`Test-SPSPendingReboot`) in ProductUpdate flow.
- Added regression assertion to prevent reintroduction of legacy ProductUpdate MOF cleanup code.

### Fixed

scripts/Modules/util.psm1:

- Get-SPSInstalledProductVersion: Changed return type from string to System.Diagnostics.FileVersionInfo object to enable proper version property access (ProductMajorPart, ProductBuildPart)
- Fixed `Start-SPSScheduledTask` to support `TaskPath` and use that path when resolving and starting tasks.
- Normalized scheduled task paths to the expected `\<TaskPath>` format for `Get-ScheduledTask` and `Start-ScheduledTask`.
- Changed `Add-SPSScheduledTask` behavior to create or update existing tasks instead of skipping them.

scripts/Modules/sps.util.psm1:

- Get-SPSLocalVersionInfo (Lines 393-502): Fixed uninitialized $versionInfo variable by adding proper initialization in all code paths (if block, catch block, fallback assignments)
- Start-SPSProductUpdate (Lines 494-647): Fixed incorrect variable name $setup.ExitCode → $setupInstall.ExitCode for accurate error code reporting
- Start-SPSProductUpdate: Fixed version detection to use ProductMajorPart property instead of non-existent FileMajorPart on FileVersionInfo object
- Start-SPSProductUpdate (Lines 838-851): Fixed service restoration logic to use original $service.StartType from saved JSON instead of forcing all services to Disabled startup type
- Start-SPSProductUpdate (Lines 693-710): Removed misleading exception placeholder from blocked-file error message for clearer error reporting
- Start-SPSProductUpdate: Added credentialed Start-Process execution with Windows identity safety guard for cross-platform compatibility
- Fixed runtime failure in `Get-SPSLocalVersionInfo` when `Clear-ComObject` was missing.

scripts/SPSUpdate.ps1:

- Added Test-ConfigurationFile to validate JSON structure and required configuration properties before execution
- Centralized scheduled task names and task folder path into script-scoped constants
- Added scheduled task existence checks before recreating full and sequence tasks
- Standardized catch blocks around key operations by composing catchMessage strings and logging failures through Add-SPSUpdateEvent
- Extended task handling in Default mode to use task variables, TaskPath, and event logging consistently
- Updated ProductUpdate to run update binaries without `InstallAccount`.
- Replaced single reboot check with consolidated reboot detection and detailed marker reporting.
- Removed legacy ProductUpdate `finally` block used for old DSC MOF cleanup.
- Enabled script-level verbose forwarding (`-Verbose`) to downstream module cmdlets.
- Added transcript file path output (`Transcript log file: ...`) at startup for easier log discovery.
- Updated installed SharePoint version output to print `FileVersion` explicitly.

### Changed

.github/workflows/pester.yml:

- Updated PSScriptAnalyzer code quality step to exclude credentialmanager folder (third-party dependency)
- Filter implemented: Get-ChildItem excludes files matching '*credentialmanager*' pattern before analysis
- Improved CI/CD reliability by preventing false positives from third-party code analysis

README.md and wiki/Getting-Started.md:
Documentation:

- Removed outdated SharePointDsc and DSC-based prerequisite/setup guidance
- Updated documentation to describe native `ProductUpdate` execution of SharePoint update binaries
- Replaced the DSC CredSSP example with direct PowerShell CredSSP configuration commands
- Updated ProductUpdate examples and guidance to remove `InstallAccount` requirement.
- Removed stale references to temporary MOF cleanup after ProductUpdate.

A full list of changes in each version can be found in the [change log](CHANGELOG.md)
48 changes: 24 additions & 24 deletions scripts/Modules/sps.util.psm1
Original file line number Diff line number Diff line change
@@ -1,3 +1,26 @@
function Clear-ComObject {
[CmdletBinding()]
param
(
[Parameter()]
[System.Object]
$ComObject
)

if ($null -eq $ComObject) {
return
}

try {
if ([System.Runtime.InteropServices.Marshal]::IsComObject($ComObject)) {
[void][System.Runtime.InteropServices.Marshal]::FinalReleaseComObject($ComObject)
}
}
catch {
Write-Verbose -Message "Unable to release COM object: $($_.Exception.Message)"
}
}

function Get-SPSServersPatchStatus {
[CmdletBinding()]
param
Expand Down Expand Up @@ -515,10 +538,6 @@ function Start-SPSProductUpdate {
[CmdletBinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')]
param
(
[Parameter(Mandatory = $true)]
[System.Management.Automation.PSCredential]
$InstallAccount,

[Parameter(Mandatory = $true)]
[System.String]
$SetupFile,
Expand Down Expand Up @@ -612,27 +631,8 @@ Setup file is blocked! Please use 'Unblock-File -Path $SetupFile' to unblock the


}
$setupProcessParams = @{
FilePath = $SetupFile
ArgumentList = '/quiet /passive'
Wait = $true
PassThru = $true
}

$currentIdentity = $null
try {
$currentIdentity = [Security.Principal.WindowsIdentity]::GetCurrent().Name
}
catch {
Write-Verbose -Message 'Unable to resolve current Windows identity; skipping Start-Process credential override.'
}

if ($InstallAccount.UserName -and $currentIdentity -and $InstallAccount.UserName -ne $currentIdentity) {
Write-Verbose -Message "Starting setup using provided InstallAccount: $($InstallAccount.UserName)"
$setupProcessParams.Credential = $InstallAccount
}

$setupInstall = Start-Process @setupProcessParams
$setupInstall = Start-Process -FilePath $SetupFile -ArgumentList '/quiet /passive' -Wait -PassThru
# Error codes: https://aka.ms/installerrorcodes
switch ($setupInstall.ExitCode) {
0 {
Expand Down
Loading
Loading