From fe1eb5d1d6972bf9095672ec089aadef61dcf3be Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Fri, 20 Mar 2026 19:15:18 +0000 Subject: [PATCH 1/3] Update-ServiceStatus - Fix WinRM error when CIM instances cross runspace boundaries When CIM instances are passed across runspace boundaries (via Invoke-Parallel), they become deserialized and lose their CIM session context. Subsequent calls to Invoke-CimMethod and Get-CimInstance then attempt to create a new connection using WinRM by default, which fails on machines where WinRM is not configured. The fix creates a DCOM-based CIM session inside the runspace scriptblock, avoiding the WinRM dependency. The session is used to obtain fresh CIM instances before invoking service control methods, and for polling service state during restart. Falls back to WinRM if DCOM is unavailable. Fixes #9782 (do *Service*) Co-authored-by: Andreas Jordan --- private/functions/Update-ServiceStatus.ps1 | 59 +++++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/private/functions/Update-ServiceStatus.ps1 b/private/functions/Update-ServiceStatus.ps1 index e01327ebbec6..ef1898f28465 100644 --- a/private/functions/Update-ServiceStatus.ps1 +++ b/private/functions/Update-ServiceStatus.ps1 @@ -71,6 +71,29 @@ function Update-ServiceStatus { $svcControlBlock = { $group = $_.Group $computerName = $_.Name + # Create a CIM session preferring DCOM to avoid requiring WinRM on the target machine. + # CIM instances become deserialized when crossing runspace boundaries and lose their + # session context, causing Invoke-CimMethod to attempt a new WinRM connection by default. + # Using DCOM avoids this WinRM dependency for machines where WinRM is not configured. + $splatCimDcomOption = @{ + Protocol = "Dcom" + } + $cimDcomOption = New-CimSessionOption @splatCimDcomOption + $splatCimSessionDcom = @{ + ComputerName = $computerName + SessionOption = $cimDcomOption + ErrorAction = "Stop" + } + try { + $cimSession = New-CimSession @splatCimSessionDcom + } catch { + # Fall back to default protocol (WinRM) if DCOM is unavailable + try { + $cimSession = New-CimSession -ComputerName $computerName -ErrorAction "Stop" + } catch { + $cimSession = $null + } + } $servicePriorityCollection = $group.ServicePriority | Select-Object -unique | Sort-Object -Property @{ Expression = { [int]$_ }; Descending = $action -ne 'stop' } foreach ($priority in $servicePriorityCollection) { $services = $group | Where-Object { $_.ServicePriority -eq $priority } @@ -104,6 +127,23 @@ function Update-ServiceStatus { $invokeResults = @() foreach ($service in $servicesToRestart) { if ($Pscmdlet.ShouldProcess("Sending $action request to service $($service.ServiceName) on $($service.ComputerName)")) { + # Get a fresh CIM instance via the DCOM session to avoid issues with deserialized + # CIM objects crossing runspace boundaries without their session context. + if ($cimSession) { + try { + $splatGetFreshCim = @{ + CimSession = $cimSession + Namespace = "root\cimv2" + Query = "SELECT * FROM Win32_Service WHERE Name = '$($service.ServiceName)'" + } + $freshCimObj = Get-CimInstance @splatGetFreshCim + if ($freshCimObj) { + $service._CimObject = $freshCimObj + } + } catch { + # Fall back to using the existing deserialized CIM object if session refresh fails + } + } #Invoke corresponding CIM method $invokeResult = Invoke-CimMethod -InputObject $service._CimObject -MethodName $methodName $invokeResults += [psobject]@{ @@ -123,7 +163,19 @@ function Update-ServiceStatus { foreach ($result in ($invokeResults | Where-Object CheckPending -eq $true)) { try { #Refresh Cim instance - not using Get-DbaCmObject because module is not loaded here, but it only refreshes existing object - $result.Service._CimObject = $result.Service._CimObject | Get-CimInstance + if ($cimSession) { + $splatRefreshCim = @{ + CimSession = $cimSession + Namespace = "root\cimv2" + Query = "SELECT State FROM Win32_Service WHERE Name = '$($result.Service.ServiceName)'" + } + $refreshedCimObj = Get-CimInstance @splatRefreshCim + if ($refreshedCimObj) { + $result.Service._CimObject = $refreshedCimObj + } + } else { + $result.Service._CimObject = $result.Service._CimObject | Get-CimInstance + } } catch { $result.ServiceExitCode = -3 $result.ServiceState = 'Unknown' @@ -177,6 +229,11 @@ function Update-ServiceStatus { $result } } + # Clean up the CIM session created for DCOM connections + if ($cimSession) { + Remove-CimSession -CimSession $cimSession -ErrorAction "SilentlyContinue" + $cimSession = $null + } } $actionText = switch ($action) { stop { 'stopped' }; start { 'started' }; restart { 'restarted' } } From d9ea8e2c04f161f1e8cef9e011e7daca692bfbf4 Mon Sep 17 00:00:00 2001 From: Andreas Jordan Date: Sat, 21 Mar 2026 16:25:11 +0100 Subject: [PATCH 2/3] no need to configure WinRM --- tests/appveyor.prep.ps1 | 3 --- 1 file changed, 3 deletions(-) diff --git a/tests/appveyor.prep.ps1 b/tests/appveyor.prep.ps1 index 1670a58280a0..cf523ccf524d 100644 --- a/tests/appveyor.prep.ps1 +++ b/tests/appveyor.prep.ps1 @@ -58,9 +58,6 @@ $null = New-Item -Path C:\Users\appveyor\Documents\DbatoolsExport -ItemType Dire Write-Host -Object "appveyor.prep: Creating temp directory" -ForegroundColor DarkGreen $null = New-Item -Path C:\Temp -ItemType Directory -Write-Host -Object "appveyor.prep: Configuring WSMan (see #9782)" -ForegroundColor DarkGreen -$null = Set-WSManQuickConfig -Force - Write-Host -Object "appveyor.prep: Trust SQL Server Cert (now required)" -ForegroundColor DarkGreen Import-Module dbatools.library Import-Module C:\github\dbatools\dbatools.psd1 From 863f8390dc820f9f31129b2a7b4c5ed37600d92b Mon Sep 17 00:00:00 2001 From: Andreas Jordan Date: Sat, 21 Mar 2026 19:54:30 +0100 Subject: [PATCH 3/3] add configuring WSMan back in --- tests/appveyor.prep.ps1 | 3 +++ 1 file changed, 3 insertions(+) diff --git a/tests/appveyor.prep.ps1 b/tests/appveyor.prep.ps1 index cf523ccf524d..09ce1d9d64da 100644 --- a/tests/appveyor.prep.ps1 +++ b/tests/appveyor.prep.ps1 @@ -58,6 +58,9 @@ $null = New-Item -Path C:\Users\appveyor\Documents\DbatoolsExport -ItemType Dire Write-Host -Object "appveyor.prep: Creating temp directory" -ForegroundColor DarkGreen $null = New-Item -Path C:\Temp -ItemType Directory +Write-Host -Object "appveyor.prep: Configuring WSMan" -ForegroundColor DarkGreen +$null = Set-WSManQuickConfig -Force + Write-Host -Object "appveyor.prep: Trust SQL Server Cert (now required)" -ForegroundColor DarkGreen Import-Module dbatools.library Import-Module C:\github\dbatools\dbatools.psd1