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' } } diff --git a/tests/appveyor.prep.ps1 b/tests/appveyor.prep.ps1 index 1670a58280a0..09ce1d9d64da 100644 --- a/tests/appveyor.prep.ps1 +++ b/tests/appveyor.prep.ps1 @@ -58,7 +58,7 @@ $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 +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