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

## [Unreleased]

## [2.3.2] - 2026-06-29

### Fixed

- `Get-AppFabricStatus` (SE branch) iterates Distributed Cache hosts via
`Get-SPServiceInstance` (filtered on `SPDistributedCacheServiceInstance`) and
uses the instance's `Server.Address`, falling back to the short name when the
cluster stores a different form. This fixes the missing Port / Size /
ServiceName / CacheStatus on the actual DC host (typically a WFE) on
SharePoint Subscription Edition (#45).

### Changed

- Farm servers that are not part of the Distributed Cache cluster are now
reported as 'Not a cache host' (informational, `IsInfo = $true`) instead of
a red 'SPService Not Found' alert, since hosting Distributed Cache on a
subset of servers (often a single WFE) is a legitimate topology (#45).

## [2.3.1] - 2026-06-29

### Fixed
Expand Down
14 changes: 9 additions & 5 deletions RELEASE-NOTES.md
Original file line number Diff line number Diff line change
@@ -1,15 +1,19 @@
# SPSWeather - Release Notes

## [2.3.1] - 2026-06-29
## [2.3.2] - 2026-06-29

### Fixed

- `Clear-SPSLog` now actually targets `.log` files (it was filtering on an
undefined variable). Retention 0 disables pruning.
- Distributed Cache report now collects Port / Size / ServiceName / CacheStatus
for the actual cache host on SharePoint Subscription Edition (previously the
details were empty because the cluster expected the FQDN while the call used
the short name).

### Changed

- New config setting `LogRetentionDays` (default 180, 0 disables) replaces the
hardcoded 180-day retention, mirroring `JsonHistoryRetentionDays`.
- Servers that are not part of the Distributed Cache cluster are reported as
'Not a cache host' (informational) instead of a red 'SPService Not Found'
alert. Hosting Distributed Cache on a subset of servers (often a single WFE)
is a legitimate topology.

A full list of changes can be found in the [change log](CHANGELOG.md).
84 changes: 51 additions & 33 deletions src/Modules/SPSWeather.Common/Public/Get-AppFabricStatus.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -42,42 +42,60 @@
$productVersion = (Get-Command $fullPath).FileVersionInfo
}
if ($productVersion.FileMajorPart -eq 16 -and $productVersion.FileBuildPart -gt 13000) {
Write-Verbose -Message 'Get list of SharePoint Servers'
$listSPServer = (Get-SPServer | Where-Object -FilterScript {$_.Role -ne 'Invalid'}).Name
Write-Verbose -Message "'Use-CacheCluster' cmdlet not required for SPSE"
Write-Verbose -Message "Using newer 'Get-SPCacheHostConfig' cmdlet for SPSE"
foreach ($cacheserver in $listSPServer) {
$cacheHostConfig = Get-SPCacheHostConfig -HostName $cacheserver -ErrorAction SilentlyContinue
if ($null -ne $cacheHostConfig) {
$isMailInfo = $true
$cacheHost = Get-SPCacheHost -HostName $cacheHostConfig.HostName -CachePort $cacheHostConfig.CachePort
}
$spCacheSvc = Get-SPServiceInstance -Server $cacheserver | Where-Object -FilterScript {
$_.GetType().Name -eq 'SPDistributedCacheServiceInstance'
}
if ($cacheHost.Status -ne 'Up') {
$isMailInfo = $false
}
if ($null -ne $spCacheSvc) {
$SPInstanceStatus = $spCacheSvc.Status
if ($SPInstanceStatus -ne 'Online') {
$isMailInfo = $false
Write-Verbose -Message "Use-CacheCluster' cmdlet not required for SPSE - using newer Get-SPCacheHostConfig"
$allSPServers = (Get-SPServer | Where-Object -FilterScript { $_.Role -ne 'Invalid' }).Name
$dcInstances = Get-SPServiceInstance | Where-Object -FilterScript {
$_.GetType().Name -eq 'SPDistributedCacheServiceInstance'
}
$reportedServers = New-Object -TypeName System.Collections.ArrayList
foreach ($dcInst in $dcInstances) {
$isMailInfo = $true
$hostFqdn = "$($dcInst.Server.Address)"
$cacheserver = $hostFqdn.Split('.')[0]
$cacheHostConfig = $null
$cacheHost = $null
if ($dcInst.Status -eq 'Online') {
# The cluster may store the host as FQDN or as short name; try both.
foreach ($tryHost in @($hostFqdn, $cacheserver)) {
if ([string]::IsNullOrEmpty($tryHost)) { continue }
$cacheHostConfig = Get-SPCacheHostConfig -HostName $tryHost -ErrorAction SilentlyContinue
if ($null -ne $cacheHostConfig) { break }
}
if ($null -ne $cacheHostConfig) {
$cacheHost = Get-SPCacheHost -HostName $cacheHostConfig.HostName -CachePort $cacheHostConfig.CachePort -ErrorAction SilentlyContinue
}
}
else {
$SPInstanceStatus = 'SPService Not Found'
$isMailInfo = $false
}
if ($null -ne $cacheHost -and $cacheHost.Status -ne 'Up') { $isMailInfo = $false }
$SPInstanceStatus = $dcInst.Status
if ($SPInstanceStatus -ne 'Online') { $isMailInfo = $false }
[void]$tbAppFabricStatus.Add([AppFabricStatus]@{
Farm = $params.Farm
Server = $cacheserver;
Port = $cacheHostConfig.CachePort;
ServiceName = $cacheHost.ServiceName;
Size = $cacheHostConfig.Size;
CacheStatus = $cacheHost.Status;
SPInstanceStatus = $SPInstanceStatus;
IsInfo = $isMailInfo;
})
Farm = $params.Farm
Server = $cacheserver;
Port = $cacheHostConfig.CachePort;
ServiceName = $cacheHost.ServiceName;
Size = $cacheHostConfig.Size;
CacheStatus = $cacheHost.Status;
SPInstanceStatus = $SPInstanceStatus;
IsInfo = $isMailInfo;
})
[void]$reportedServers.Add($cacheserver)
}
# SP servers that are not part of the cache cluster: report them as
# informational (IsInfo=$true) instead of red alerts, since hosting
# Distributed Cache on a subset of servers is a legitimate topology.
foreach ($srv in $allSPServers) {
if ($reportedServers -notcontains $srv) {
[void]$tbAppFabricStatus.Add([AppFabricStatus]@{
Farm = $params.Farm
Server = $srv;
Port = '';
ServiceName = '';
Size = '';
CacheStatus = '';
SPInstanceStatus = 'Not a cache host';
IsInfo = $true;
})
}
}
return $tbAppFabricStatus
}
Expand Down
18 changes: 12 additions & 6 deletions src/Modules/SPSWeather.Common/Public/Join-HtmlBodyFromPSo.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -247,18 +247,24 @@
$htmlTableRows += "<td class=`"tddefault`">$($AppFabricStatusItem.Port)</td>"
$htmlTableRows += "<td class=`"tddefault`">$($AppFabricStatusItem.ServiceName)</td>"
$htmlTableRows += "<td align=`"center`" class=`"tddefault`">$($AppFabricStatusItem.Size)</td>"
if ($AppFabricStatusItem.CacheStatus -ne 'Up') {
$htmlTableRows += "<td align=`"center`" class=`"tdfailed`">$($AppFabricStatusItem.CacheStatus)</td>"
}
else {
if ($AppFabricStatusItem.CacheStatus -eq 'Up') {
$htmlTableRows += "<td align=`"center`" class=`"tdsuccess`">$($AppFabricStatusItem.CacheStatus)</td>"
}
if ($AppFabricStatusItem.SPInstanceStatus -ne 'Online') {
$htmlTableRows += "<td align=`"center`" class=`"tdfailed`">$($AppFabricStatusItem.SPInstanceStatus)</td></tr>"
elseif ([string]::IsNullOrEmpty([string]$AppFabricStatusItem.CacheStatus)) {
$htmlTableRows += "<td align=`"center`" class=`"tddefault`">-</td>"
}
else {
$htmlTableRows += "<td align=`"center`" class=`"tdfailed`">$($AppFabricStatusItem.CacheStatus)</td>"
}
if ($AppFabricStatusItem.SPInstanceStatus -eq 'Online') {
$htmlTableRows += "<td align=`"center`" class=`"tdsuccess`">$($AppFabricStatusItem.SPInstanceStatus)</td></tr>"
}
elseif ($AppFabricStatusItem.SPInstanceStatus -eq 'Not a cache host') {
$htmlTableRows += "<td align=`"center`" class=`"tddefault`">$($AppFabricStatusItem.SPInstanceStatus)</td></tr>"
}
else {
$htmlTableRows += "<td align=`"center`" class=`"tdfailed`">$($AppFabricStatusItem.SPInstanceStatus)</td></tr>"
}
}
$htmlBodyMerge += Join-HtmlTable -TitleH1 'SharePoint Distributed Cache Status' `
-TableRole 'AppFabricStatus' `
Expand Down
2 changes: 1 addition & 1 deletion src/Modules/SPSWeather.Common/SPSWeather.Common.psd1
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
@{
RootModule = 'SPSWeather.Common.psm1'
ModuleVersion = '2.3.1'
ModuleVersion = '2.3.2'
GUID = 'c39bd612-8520-4e65-9037-80060894d654'
Author = 'Jean-Cyril DROUHIN'
CompanyName = 'luigilink'
Expand Down
2 changes: 1 addition & 1 deletion tests/SPSWeather.Common.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ Describe 'SPSWeather.Common module' {
}

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

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