microsoft / CSS-Exchange

Exchange Server support tools and scripts
MIT License
1.21k stars 332 forks source link

[Issue] Health Checker - Get-LocalGroupMember failing to execute #2110

Open dpaulson45 opened 2 weeks ago

dpaulson45 commented 2 weeks ago

Describe the issue With the release of Health Checker version 24.06.13.1712, we included a check that was testing the server's local group membership to verify that we had the correct groups on the server. In some environments, this cmdlet would fail to run providing the following output.

image

The script then continued, but then failed later on with the following internal error

Error Index: 0
 : You cannot call a method on a null-valued expression.
Inner Exception:    at System.Management.Automation.ExceptionHandlingOps.CheckActionPreference(FunctionContext funcContext, Exception exception)
   at System.Management.Automation.Interpreter.ActionCallInstruction`2.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.EnterTryCatchFinallyInstruction.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.Interpreter.Run(InterpretedFrame frame)
   at System.Management.Automation.Interpreter.LightLambda.RunVoid1[T0](T0 arg0)
   at System.Management.Automation.ScriptBlock.InvokeWithPipeImpl(ScriptBlockClauseToInvoke clauseToInvoke, Boolean createLocalScope, Dictionary`2 functionsToDefine, List`1 variablesToDefine, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo invocationInfo, Object[] args)
   at System.Management.Automation.ScriptBlock.<>c__DisplayClass57_0.<InvokeWithPipe>b__0()
   at System.Management.Automation.Runspaces.RunspaceBase.RunActionIfNoRunningPipelinesWithThreadCheck(Action action)
   at System.Management.Automation.ScriptBlock.InvokeWithPipe(Boolean useLocalScope, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Pipe outputPipe, InvocationInfo invocationInfo, Boolean propagateAllExceptionsToTop, List`1 variablesToDefine, Dictionary`2 functionsToDefine, Object[] args)
   at System.Management.Automation.ScriptBlock.DoInvokeReturnAsIs(Boolean useLocalScope, ErrorHandlingBehavior errorHandlingBehavior, Object dollarUnder, Object input, Object scriptThis, Object[] args)
   at Microsoft.PowerShell.Commands.WhereObjectCommand.ProcessRecord()
   at System.Management.Automation.CommandProcessor.ProcessRecord()
Position Message: At C:\HealthChecker.ps1:1336 char:111
+ ... Member.SID | Where-Object { $_.ToString() -eq $localGroup.SID } ))) {
+                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Script Stack: at <ScriptBlock>, C:\HealthChecker.ps1: line 1336
at Invoke-AnalyzerExchangeInformation, C:\HealthChecker.ps1: line 1336
at Invoke-AnalyzerEngine, C:\HealthChecker.ps1: line 8951
at Get-HealthCheckerData, C:\HealthChecker.ps1: line 15961
at Invoke-HealthCheckerMainReport, C:\HealthChecker.ps1: line 16022
at <ScriptBlock><End>, C:\HealthChecker.ps1: line 16845
at <ScriptBlock>, <No file>: line 1
-----------------------------------

This was then quickly addressed in PR #2102 This allowed the script to continue, but doesn't allow that check to properly notify the customer or support of a problem because we aren't able to collect this information.

Expected behavior The script should continue, and should have a failback option to try to get the local group membership on these problem environments.

Script Output This is the exception that Get-LocalGroupMember was seeing in these environments

Description: Getting Exchange Server Members
Running Script Block Locally without argument list
Calling: 
Error Excluded Count: 13
Error Count: 13
Get-LocalGroupMember : Failed to compare two elements in the array.
Inner Exception:    at System.Collections.Generic.ArraySortHelper`1.Sort(T[] keys, Int32 index, Int32 length, IComparer`1 comparer)
   at System.Array.Sort[T](T[] array, Int32 index, Int32 length, IComparer`1 comparer)
   at System.Collections.Generic.List`1.Sort(Comparison`1 comparison)
   at Microsoft.PowerShell.Commands.GetLocalGroupMemberCommand.ProcessesMembership(IEnumerable`1 membership)
   at Microsoft.PowerShell.Commands.GetLocalGroupMemberCommand.ProcessRecord()
Position Message: At C:\HealthChecker.ps1:13474 char:46
+ ...        LocalGroupMember  = (Get-LocalGroupMember -SID "S-1-5-32-544")
+                                 ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Script Stack: at <ScriptBlock>, C:\HealthChecker.ps1: line 13473
at Invoke-ScriptBlockHandler<Process>, C:\HealthChecker.ps1: line 529
at Get-ExchangeInformation<Process>, C:\HealthChecker.ps1: line 13479
at Get-HealthCheckerExchangeServer<Process>, C:\HealthChecker.ps1: line 15147
at Get-HealthCheckerData, C:\HealthChecker.ps1: line 15952
at Invoke-HealthCheckerMainReport, C:\HealthChecker.ps1: line 16022
at <ScriptBlock><End>, C:\HealthChecker.ps1: line 16845
at <ScriptBlock>, <No file>: line 1

Additional context Need to create some fallback logic to handle this so the check can still be performed.

Was able to 'reproduce' the issue by adding in blah after Get-LocalGroupMember. Nothing else seemed to work the same way as what the customers were reporting with the Continue operation of the error.