microsoft / CSS-Exchange

Exchange Server support tools and scripts
MIT License
1.22k stars 341 forks source link

[Issue] - Health Checker computer group membership check #2128

Open kadmos36 opened 4 months ago

kadmos36 commented 4 months ago

Provide Version Number 24.06.24.2018

Describe the issue New Group Membership check uses $env:computername instead of $server, and suggestion for hardened ADs

Expected behavior Get Membership of wanted server

Script Output Membership of computer executing the script to check remote server

Additional context Look at code starting in line 13480. I would suggest to replace $env:computername with $server. In Addition, in our hardened Activ Directory the cmdlet Get-ADPrincipalGroupMembership dos not work. i would suggest using Get-ADComputer $server -Properties memberof | select -ExpandProperty memberof which works if global group membership search is prohibited in the Active Directory

dpaulson45 commented 4 months ago

Using $env:COMPUTERNAME should not be causing a problem.

https://github.com/microsoft/CSS-Exchange/blob/0848d672668108d3f858efc30af6e7f3e4611eaa/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1#L207

The reason being is because we are inside a ScriptBlock that will execute on the $Server variable. So, the $env:ComputerName is the remote server.

But if we are having issues with running that cmdlet in locked down environments, we will need to attempt to add in a catch for this as well. This would be similar to issue #2110 where the other cmdlet is also failing in some environments.

kadmos36 commented 4 months ago

Thank you for your quick response, David.

Okay, I haven't thinked of the ScriptBlock behaviour. Sorry. Looks like it must be wrong.

I would suggest to check if it might be possible to modify it for hardened environments

try { $ADGroupMembership = (Get-ADPrincipalGroupMembership (Get-ADComputer $env:COMPUTERNAME).DistinguishedName -ErrorAction Stop) } catch { $ADGroupMembership = Get-ADComputer $env:COMPUTERNAME -Properties MemberOf | Select-Object -ExpandProperty MemberOf | Get-ADObject }

This might fix it. The only Group missing in $ADGroupMembership would be Domain Computers if the catch block is hit.

dpaulson45 commented 4 months ago

That is interesting that Domain Computers doesn't show up in the other cmdlet.

We are going to need to do a little more than just what you provided, as we need to be able to get the SID and should really try to make sure we get all the same properties that we would have gotten from Get-ADPrincipalGroupMembership. I will have to look at this some more when I am back in the office.

kadmos36 commented 4 months ago

The thing with Domain Computers could be because of AD hardening.

I compared the output of the Get-ADPrincipalGroupMembership variants. The output of Get-ADcomputer has the properties GroupCategory and GroupScope missing. If replaced with Get-ADGroup the Output properties are the same.

ltoddnelson commented 3 months ago

Am seeing this when running the Health Checker (Version 24.08.08.1523) against our 'Exchange 2019 CU14 Apr24HU' server installed on Core.

Exchange Server Membership | Unknown - Wasn't able to get the Computer Membership information

The command on line 13654 runs without issue. But the command on line 13655 errors out on 'Get-ADComputer' with 'Get-ADComputer : The term 'Get-ADComputer' is not recognized as the name of a cmdlet, function, script file, or operable program.'

Please advise.

grimson73 commented 1 month ago

According to this page it seems the Active Directory PowerShell module is used to make this command work: Get-ADPrincipalGroupMembership.

For me:

HC Script running on server without AD PowerShell module installed:

HC Script running on server with AD PowerShell module installed:

Also it seems that Get-ADPrincipalGroupMembership (Get-ADComputer $env:COMPUTERNAME).DistinguishedName doesn't work for remote computers like starting the script with the -server parameter as tested.

My suggestion is adding some sort of check for the availability of the AD PowerShell module and a reworked routine so it can be run on a computer with the AD module installed and a remote target server (-server parameter). That of course if I got things right in the first place :).

kadmos36 commented 1 month ago

I have experimented with some workarounds for our environment and found an possible patch. Or even an starting point for an patch...

@grimson73 , @ltoddnelson feel free to test if the following solves your Problems. Any feedback is welcome. I think @dpaulson45 may be thankfull to.

  1. Run Health Checker and double proof you got the latest Version of Health Checker: Exchange Health Checker version 24.09.17.1810
  2. Open HealthChecker.ps1 for editing in Notepad or Visual Studio Code
  3. Go to line number 13742
  4. replace the if block from line 13742 to 13755 with the following code and try if it fixes the error:
  5. 
        if ($getExchangeServer.IsEdgeServer -eq $false) {
            $params = @{
                ComputerName           = $Server
                ScriptBlockDescription = "Getting Exchange Server Members"
                CatchActionFunction    = ${Function:Invoke-CatchActions}
                ScriptBlock            = {
                    [PSCustomObject]@{
                        LocalGroupMember  = (Get-LocalGroupMember -SID "S-1-5-32-544" -ErrorAction Stop)
                        ADGroupMembership = @()
                    }
                }
            }
            $computerMembership = Invoke-ScriptBlockHandler @params
            $computerMembership.ADGroupMembership = (Get-ADComputer -Filter 'dnshostname -eq $Server' -Properties MemberOf | Select-Object -ExpandProperty MemberOf | Get-ADObject -Properties objectSid | select-object @{name="SID";expression={$_.objectsid}})
        }
grimson73 commented 1 month ago

I have experimented with some workarounds for our environment and found an possible patch. Or even an starting point for an patch...

@grimson73 , @ltoddnelson feel free to test if the following solves your Problems. Any feedback is welcome. I think @dpaulson45 may be thankfull to.

Hi, thanks for helping. I tried in on my lab Exchange Server and several times I checked the replacement lines but this is what I get:

[PS] C:\Temp>& '.\HealthChecker - Copy.ps1'
WARNING: Unable to check for a script update as no script with the same name was found.
This can happen if the script has been renamed. Please check manually if there is a newer version of the script.
Exchange Health Checker version 24.09.17.1810
Failed to Health Checker against SV-EXCH-01

My issue is that the Active Directory PowerShell module isn't installed so i think 'Get-ADComputer' doesn't work in the replacement part. But thanks again!

I think the original HC-Script does assume the AD PS Module is installed but when it's not it doesn't notify the user but does give the 'unkown' warning message leaving the user confused about what is happening, I guess.