From 3d1e254b25a426057feba00db63a63e05c5ccc2e Mon Sep 17 00:00:00 2001 From: Shannon Graybrook Date: Thu, 3 Aug 2023 11:08:31 -0500 Subject: [PATCH 1/6] Update PendingReboot.psd1 Allow for functions to be exported during testing --- source/PendingReboot.psd1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/PendingReboot.psd1 b/source/PendingReboot.psd1 index 7023d7f..38d11d8 100644 --- a/source/PendingReboot.psd1 +++ b/source/PendingReboot.psd1 @@ -21,7 +21,7 @@ PowerShellVersion = '4.0' # Functions to export from this module - FunctionsToExport = @() + FunctionsToExport = '*' # Cmdlets to export from this module CmdletsToExport = @() From 9e688ce262c7ee48af9281ecbb97dd7cc48e656c Mon Sep 17 00:00:00 2001 From: Shannon Graybrook Date: Thu, 3 Aug 2023 11:08:48 -0500 Subject: [PATCH 2/6] Migrate to Invoke-CimMethod --- source/Public/Test-PendingReboot.ps1 | 127 +++++++++++++++------------ 1 file changed, 71 insertions(+), 56 deletions(-) diff --git a/source/Public/Test-PendingReboot.ps1 b/source/Public/Test-PendingReboot.ps1 index 0f4d85a..4f0bf60 100644 --- a/source/Public/Test-PendingReboot.ps1 +++ b/source/Public/Test-PendingReboot.ps1 @@ -133,108 +133,123 @@ function Test-PendingReboot process { - foreach ($computer in $ComputerName) + foreach ($ComputerNameItem in $ComputerName) { try { - $invokeWmiMethodParameters = @{ - Namespace = 'root/default' - Class = 'StdRegProv' - Name = 'EnumKey' - ComputerName = $computer - ErrorAction = 'Stop' + ## Establish a CimSession + $CredentialSplat = @{} + if ($PSBoundParameters.ContainsKey('Credential')) { + $CredentialSplat.Credential = $Credential } - - $hklm = [UInt32] "0x80000002" - - if ($PSBoundParameters.ContainsKey('Credential')) - { - $invokeWmiMethodParameters.Credential = $Credential + $CimSession = New-CimSession -ComputerName $ComputerNameItem @CredentialSplat -ErrorAction Stop + + $InvokeCimMethodSplat = @{ + CimSession = $CimSession + Namespace = 'root\CIMv2' + ClassName = 'StdRegProv' + Name = 'EnumKey' + Arguments = @{ + hDefKey = [UInt32] "0x80000002" # HKLM + sSubKeyName = $null + } } ## Query the Component Based Servicing Reg Key - $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing\') - $registryComponentBasedServicing = (Invoke-WmiMethod @invokeWmiMethodParameters).sNames -contains 'RebootPending' + $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SOFTWARE\Microsoft\Windows\CurrentVersion\Component Based Servicing' + $RegistryComponentBasedServicing = (Invoke-CimMethod @InvokeCimMethodSplat).sNames -contains 'RebootPending' ## Query WUAU from the registry - $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update\') - $registryWindowsUpdateAutoUpdate = (Invoke-WmiMethod @invokeWmiMethodParameters).sNames -contains 'RebootRequired' + $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update' + $RegistryWindowsUpdateAutoUpdate = (Invoke-CimMethod @InvokeCimMethodSplat).sNames -contains 'RebootRequired' ## Query JoinDomain key from the registry - These keys are present if pending a reboot from a domain join operation - $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Services\Netlogon') - $registryNetlogon = (Invoke-WmiMethod @invokeWmiMethodParameters).sNames - $pendingDomainJoin = ($registryNetlogon -contains 'JoinDomain') -or ($registryNetlogon -contains 'AvoidSpnSet') + $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Services\Netlogon' + $RegistryNetlogon = (Invoke-CimMethod @InvokeCimMethodSplat).sNames + $PendingDomainJoin = ($RegistryNetlogon -contains 'JoinDomain') -or ($RegistryNetlogon -contains 'AvoidSpnSet') ## Query ComputerName and ActiveComputerName from the registry and setting the MethodName to GetMultiStringValue - $invokeWmiMethodParameters.Name = 'GetMultiStringValue' - $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\', 'ComputerName') - $registryActiveComputerName = Invoke-WmiMethod @invokeWmiMethodParameters + $InvokeCimMethodSplat.Name = 'GetStringValue' + + $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName' + $InvokeCimMethodSplat.Arguments.sValueName = 'ComputerName' + $RegistryActiveComputerName = (Invoke-CimMethod @InvokeCimMethodSplat).sValue - $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\', 'ComputerName') - $registryComputerName = Invoke-WmiMethod @invokeWmiMethodParameters + $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName' + $InvokeCimMethodSplat.Arguments.sValueName = 'ComputerName' + $RegistryComputerName = (Invoke-CimMethod @InvokeCimMethodSplat).sValue - $pendingComputerRename = $registryActiveComputerName -ne $registryComputerName -or $pendingDomainJoin + $PendingComputerRename = $RegistryActiveComputerName -ne $RegistryComputerName -or $PendingDomainJoin ## Query PendingFileRenameOperations from the registry if (-not $PSBoundParameters.ContainsKey('SkipPendingFileRenameOperationsCheck')) { - $invokeWmiMethodParameters.ArgumentList = @($hklm, 'SYSTEM\CurrentControlSet\Control\Session Manager\', 'PendingFileRenameOperations') - $registryPendingFileRenameOperations = (Invoke-WmiMethod @invokeWmiMethodParameters).sValue - $registryPendingFileRenameOperationsBool = [bool]$registryPendingFileRenameOperations + $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\Session Manager' + $InvokeCimMethodSplat.Arguments.sValueName = 'PendingFileRenameOperations' + $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue + $RegistryPendingFileRenameOperationsBool = [bool]$RegistryPendingFileRenameOperations + } ## Query ClientSDK for pending reboot status, unless SkipConfigurationManagerClientCheck is present if (-not $PSBoundParameters.ContainsKey('SkipConfigurationManagerClientCheck')) { - $invokeWmiMethodParameters.NameSpace = 'ROOT\ccm\ClientSDK' - $invokeWmiMethodParameters.Class = 'CCM_ClientUtilities' - $invokeWmiMethodParameters.Name = 'DetermineifRebootPending' - $invokeWmiMethodParameters.Remove('ArgumentList') + $InvokeCimMethodSplat = @{ + CimSession = $CimSession + Namespace = 'root\ccm\ClientSDK' + ClassName = 'CCM_ClientUtilities' + Name = 'DetermineifRebootPending' + } + + $SCCMClientSDKError = $null + $SCCMClientSDK = Invoke-CimMethod @InvokeCimMethodSplat -ErrorAction SilentlyContinue -ErrorVariable SCCMClientSDKError - try + if ($SCCMClientSDKError) { - $sccmClientSDK = Invoke-WmiMethod @invokeWmiMethodParameters - $systemCenterConfigManager = $sccmClientSDK.ReturnValue -eq 0 -and ($sccmClientSDK.IsHardRebootPending -or $sccmClientSDK.RebootPending) + $SystemCenterConfigManager = $null + Write-Verbose $SCCMClientSDKError.Exception.Message + Write-Verbose ($script:localizedData.invokeWmiClientSDKError -f $ComputerNameItem) } - catch + else { - $systemCenterConfigManager = $null - Write-Verbose -Message ($script:localizedData.invokeWmiClientSDKError -f $computer) + $SystemCenterConfigManager = $SCCMClientSDK.ReturnValue -eq 0 -and ($SCCMClientSDK.IsHardRebootPending -or $SCCMClientSDK.RebootPending) } + } - $isRebootPending = $registryComponentBasedServicing -or ` - $pendingComputerRename -or ` - $pendingDomainJoin -or ` - $registryPendingFileRenameOperationsBool -or ` - $systemCenterConfigManager -or ` - $registryWindowsUpdateAutoUpdate + $IsRebootPending = $RegistryComponentBasedServicing -or ` + $PendingComputerRename -or ` + $PendingDomainJoin -or ` + $RegistryPendingFileRenameOperations -or ` + $SystemCenterConfigManager -or ` + $RegistryWindowsUpdateAutoUpdate if ($PSBoundParameters.ContainsKey('Detailed')) { [PSCustomObject]@{ - ComputerName = $computer - ComponentBasedServicing = $registryComponentBasedServicing - PendingComputerRenameDomainJoin = $pendingComputerRename + ComputerName = $ComputerNameItem + ComponentBasedServicing = $RegistryComponentBasedServicing + PendingComputerRenameDomainJoin = $PendingComputerRename PendingFileRenameOperations = $registryPendingFileRenameOperationsBool PendingFileRenameOperationsValue = $registryPendingFileRenameOperations - SystemCenterConfigManager = $systemCenterConfigManager - WindowsUpdateAutoUpdate = $registryWindowsUpdateAutoUpdate - IsRebootPending = $isRebootPending + SystemCenterConfigManager = $SystemCenterConfigManager + WindowsUpdateAutoUpdate = $RegistryWindowsUpdateAutoUpdate + IsRebootPending = $IsRebootPending } } else { [PSCustomObject]@{ - ComputerName = $computer - IsRebootPending = $isRebootPending + ComputerName = $ComputerNameItem + IsRebootPending = $IsRebootPending } } } - - catch + finally { - Write-Verbose "$Computer`: $_" + if ( $null -ne $CimSession ) { + Remove-CimSession -CimSession $CimSession + } } } } From 9da33542238c9831a95fae642dee6f77571ee889 Mon Sep 17 00:00:00 2001 From: Daniel Ring Date: Fri, 13 Oct 2023 22:09:46 +0200 Subject: [PATCH 3/6] added statement for multi-string values in reg key --- source/Public/Test-PendingReboot.ps1 | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/source/Public/Test-PendingReboot.ps1 b/source/Public/Test-PendingReboot.ps1 index 4f0bf60..813afe3 100644 --- a/source/Public/Test-PendingReboot.ps1 +++ b/source/Public/Test-PendingReboot.ps1 @@ -187,6 +187,12 @@ function Test-PendingReboot $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\Session Manager' $InvokeCimMethodSplat.Arguments.sValueName = 'PendingFileRenameOperations' $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue + if ($null -eq $RegistryPendingFileRenameOperations) + { + $InvokeCimMethodSplat.Name = 'GetMultiStringValue' + $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue + + } $RegistryPendingFileRenameOperationsBool = [bool]$RegistryPendingFileRenameOperations } From 716c4a143d1c2394a5d3b8399050ecfc72696653 Mon Sep 17 00:00:00 2001 From: Daniel Ring Date: Fri, 13 Oct 2023 22:18:35 +0200 Subject: [PATCH 4/6] changed parameter Name to MethodName --- source/Public/Test-PendingReboot.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/source/Public/Test-PendingReboot.ps1 b/source/Public/Test-PendingReboot.ps1 index 813afe3..0acc2c5 100644 --- a/source/Public/Test-PendingReboot.ps1 +++ b/source/Public/Test-PendingReboot.ps1 @@ -148,7 +148,7 @@ function Test-PendingReboot CimSession = $CimSession Namespace = 'root\CIMv2' ClassName = 'StdRegProv' - Name = 'EnumKey' + MethodName = 'EnumKey' Arguments = @{ hDefKey = [UInt32] "0x80000002" # HKLM sSubKeyName = $null @@ -169,7 +169,7 @@ function Test-PendingReboot $PendingDomainJoin = ($RegistryNetlogon -contains 'JoinDomain') -or ($RegistryNetlogon -contains 'AvoidSpnSet') ## Query ComputerName and ActiveComputerName from the registry and setting the MethodName to GetMultiStringValue - $InvokeCimMethodSplat.Name = 'GetStringValue' + $InvokeCimMethodSplat.MethodName = 'GetStringValue' $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName' $InvokeCimMethodSplat.Arguments.sValueName = 'ComputerName' @@ -189,7 +189,7 @@ function Test-PendingReboot $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue if ($null -eq $RegistryPendingFileRenameOperations) { - $InvokeCimMethodSplat.Name = 'GetMultiStringValue' + $InvokeCimMethodSplat.MethodName = 'GetMultiStringValue' $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue } @@ -204,7 +204,7 @@ function Test-PendingReboot CimSession = $CimSession Namespace = 'root\ccm\ClientSDK' ClassName = 'CCM_ClientUtilities' - Name = 'DetermineifRebootPending' + MethodName = 'DetermineifRebootPending' } $SCCMClientSDKError = $null From 7d8abb9e5302a1472d1b0e87c736d3e99789ed95 Mon Sep 17 00:00:00 2001 From: Daniel Ring Date: Fri, 13 Oct 2023 22:36:10 +0200 Subject: [PATCH 5/6] improved formatting for code and output --- source/Public/Test-PendingReboot.ps1 | 50 ++++++++++++++++------------ 1 file changed, 28 insertions(+), 22 deletions(-) diff --git a/source/Public/Test-PendingReboot.ps1 b/source/Public/Test-PendingReboot.ps1 index 0acc2c5..c84900c 100644 --- a/source/Public/Test-PendingReboot.ps1 +++ b/source/Public/Test-PendingReboot.ps1 @@ -139,17 +139,18 @@ function Test-PendingReboot { ## Establish a CimSession $CredentialSplat = @{} - if ($PSBoundParameters.ContainsKey('Credential')) { + if ($PSBoundParameters.ContainsKey('Credential')) + { $CredentialSplat.Credential = $Credential } $CimSession = New-CimSession -ComputerName $ComputerNameItem @CredentialSplat -ErrorAction Stop $InvokeCimMethodSplat = @{ - CimSession = $CimSession - Namespace = 'root\CIMv2' - ClassName = 'StdRegProv' - MethodName = 'EnumKey' - Arguments = @{ + CimSession = $CimSession + Namespace = 'root\CIMv2' + ClassName = 'StdRegProv' + MethodName = 'EnumKey' + Arguments = @{ hDefKey = [UInt32] "0x80000002" # HKLM sSubKeyName = $null } @@ -187,14 +188,19 @@ function Test-PendingReboot $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\Session Manager' $InvokeCimMethodSplat.Arguments.sValueName = 'PendingFileRenameOperations' $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue + if ($null -eq $RegistryPendingFileRenameOperations) { $InvokeCimMethodSplat.MethodName = 'GetMultiStringValue' $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue + } + if ($null -ne $RegistryPendingFileRenameOperations) + { + $RegistryPendingFileRenameOperations = ($RegistryPendingFileRenameOperations | Where-Object {$_ -match '\S'}).TrimStart("\?") } - $RegistryPendingFileRenameOperationsBool = [bool]$RegistryPendingFileRenameOperations + $RegistryPendingFileRenameOperationsBool = [bool]$RegistryPendingFileRenameOperations } ## Query ClientSDK for pending reboot status, unless SkipConfigurationManagerClientCheck is present @@ -220,27 +226,26 @@ function Test-PendingReboot { $SystemCenterConfigManager = $SCCMClientSDK.ReturnValue -eq 0 -and ($SCCMClientSDK.IsHardRebootPending -or $SCCMClientSDK.RebootPending) } - } - $IsRebootPending = $RegistryComponentBasedServicing -or ` - $PendingComputerRename -or ` - $PendingDomainJoin -or ` - $RegistryPendingFileRenameOperations -or ` - $SystemCenterConfigManager -or ` + $IsRebootPending = $RegistryComponentBasedServicing -or + $PendingComputerRename -or + $PendingDomainJoin -or + $RegistryPendingFileRenameOperations -or + $SystemCenterConfigManager -or $RegistryWindowsUpdateAutoUpdate if ($PSBoundParameters.ContainsKey('Detailed')) { [PSCustomObject]@{ - ComputerName = $ComputerNameItem - ComponentBasedServicing = $RegistryComponentBasedServicing - PendingComputerRenameDomainJoin = $PendingComputerRename - PendingFileRenameOperations = $registryPendingFileRenameOperationsBool - PendingFileRenameOperationsValue = $registryPendingFileRenameOperations - SystemCenterConfigManager = $SystemCenterConfigManager - WindowsUpdateAutoUpdate = $RegistryWindowsUpdateAutoUpdate - IsRebootPending = $IsRebootPending + ComputerName = $ComputerNameItem + ComponentBasedServicing = $RegistryComponentBasedServicing + PendingComputerRenameDomainJoin = $PendingComputerRename + PendingFileRenameOperations = $registryPendingFileRenameOperationsBool + PendingFileRenameOperationsValue = $registryPendingFileRenameOperations + SystemCenterConfigManager = $SystemCenterConfigManager + WindowsUpdateAutoUpdate = $RegistryWindowsUpdateAutoUpdate + IsRebootPending = $IsRebootPending } } else @@ -253,7 +258,8 @@ function Test-PendingReboot } finally { - if ( $null -ne $CimSession ) { + if ($null -ne $CimSession) + { Remove-CimSession -CimSession $CimSession } } From e435484b949a790af5f3aedbdcf2821781de6a83 Mon Sep 17 00:00:00 2001 From: Daniel Ring Date: Sun, 15 Oct 2023 12:31:43 +0200 Subject: [PATCH 6/6] added comments --- source/Public/Test-PendingReboot.ps1 | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/source/Public/Test-PendingReboot.ps1 b/source/Public/Test-PendingReboot.ps1 index c84900c..126f2f3 100644 --- a/source/Public/Test-PendingReboot.ps1 +++ b/source/Public/Test-PendingReboot.ps1 @@ -169,7 +169,7 @@ function Test-PendingReboot $RegistryNetlogon = (Invoke-CimMethod @InvokeCimMethodSplat).sNames $PendingDomainJoin = ($RegistryNetlogon -contains 'JoinDomain') -or ($RegistryNetlogon -contains 'AvoidSpnSet') - ## Query ComputerName and ActiveComputerName from the registry and setting the MethodName to GetMultiStringValue + ## Query ComputerName and ActiveComputerName from the registry and setting the MethodName to GetStringValue $InvokeCimMethodSplat.MethodName = 'GetStringValue' $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName' @@ -182,19 +182,21 @@ function Test-PendingReboot $PendingComputerRename = $RegistryActiveComputerName -ne $RegistryComputerName -or $PendingDomainJoin - ## Query PendingFileRenameOperations from the registry + ## Query PendingFileRenameOperations from the registry and trying with MethodName GetStringValue if (-not $PSBoundParameters.ContainsKey('SkipPendingFileRenameOperationsCheck')) { $InvokeCimMethodSplat.Arguments.sSubKeyName = 'SYSTEM\CurrentControlSet\Control\Session Manager' $InvokeCimMethodSplat.Arguments.sValueName = 'PendingFileRenameOperations' $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue + ### If the query returns $null then retry with MethodName GetMultiStringValue if ($null -eq $RegistryPendingFileRenameOperations) { $InvokeCimMethodSplat.MethodName = 'GetMultiStringValue' $RegistryPendingFileRenameOperations = (Invoke-CimMethod @InvokeCimMethodSplat).sValue } + ### If the query returned something then remove empty lines from the list and remove leading characters from the path strings if ($null -ne $RegistryPendingFileRenameOperations) { $RegistryPendingFileRenameOperations = ($RegistryPendingFileRenameOperations | Where-Object {$_ -match '\S'}).TrimStart("\?")