diff --git a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 index ddf1e2890..340825a65 100644 --- a/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/Analyzer/Invoke-AnalyzerExchangeInformation.ps1 @@ -315,7 +315,9 @@ function Invoke-AnalyzerExchangeInformation { $displayMissingGroups.Add("Unable to determine Local System Membership as the results were blank.") } - if ($null -ne $exchangeInformation.ComputerMembership.ADGroupMembership) { + if ($exchangeInformation.ComputerMembership.ADGroupMembership -eq "NoAdModule") { + $displayMissingGroups.Add("Missing Active Directory Module. Run 'Install-WindowsFeature RSat-AD-PowerShell'") + } elseif ($null -ne $exchangeInformation.ComputerMembership.ADGroupMembership) { foreach ($adGroup in $adGroupList) { if (($null -eq ($exchangeInformation.ComputerMembership.ADGroupMembership.SID | Where-Object { $_.ToString() -eq $adGroup.SID }))) { $displayMissingGroups.Add("$($adGroup.WellKnownName) - AD Group Membership") diff --git a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 index 88cd754c1..848015de9 100644 --- a/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 +++ b/Diagnostics/HealthChecker/DataCollection/ExchangeInformation/Get-ExchangeInformation.ps1 @@ -231,10 +231,70 @@ function Get-ExchangeInformation { # AD Module cmdlets don't appear to work in remote context with Invoke-Command, this is why it is now moved outside of the Invoke-ScriptBlockHandler. try { - $adPrincipalGroupMembership = (Get-ADPrincipalGroupMembership (Get-ADComputer ($Server.Split(".")[0]) -ErrorAction Stop).DistinguishedName -ErrorAction Stop) + Write-Verbose "Trying to get the computer DN" + $adComputer = (Get-ADComputer ($Server.Split(".")[0]) -ErrorAction Stop -Properties MemberOf) + $computerDN = $adComputer.DistinguishedName + Write-Verbose "Computer DN: $computerDN" + $params = @{ + Identity = $computerDN + ErrorAction = "Stop" + } + try { + $serverId = ([ADSI]("GC://$([System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain().Name)/RootDSE")).dnsHostName.ToString() + Write-Verbose "Adding ServerId '$serverId' to the Get-AD* cmdlets" + $params["Server"] = $serverId + } catch { + Write-Verbose "Failed to find the root DSE. Inner Exception: $_" + Invoke-CatchActions + } + $adPrincipalGroupMembership = (Get-ADPrincipalGroupMembership @params) + } catch [System.Management.Automation.CommandNotFoundException] { + if ($_.TargetObject -eq "Get-ADComputer") { + $adPrincipalGroupMembership = "NoAdModule" + Invoke-CatchActions + } else { + # If this occurs, do not run Invoke-CatchActions to let us know what is wrong here. + Write-Verbose "CommandNotFoundException thrown, but not for Get-ADComputer. Inner Exception: $_" + } } catch { - # Current do not add Invoke-CatchActions as we want to be aware if this doesn't fix some things. Write-Verbose "Failed to get the AD Principal Group Membership. Inner Exception: $_" + Invoke-CatchActions + if ($null -eq $adComputer -or + $null -eq $adComputer.MemberOf -or + $adComputer.MemberOf.Count -eq 0) { + Write-Verbose "Failed to get the ADComputer information to be able to find the MemberOf with Get-ADObject" + } else { + $adPrincipalGroupMembership = New-Object System.Collections.Generic.List[object] + foreach ($memberDN in $adComputer.MemberOf) { + try { + $params = @{ + Filter = "distinguishedName -eq `"$memberDN`"" + Properties = "objectSid" + ErrorAction = "Stop" + } + + if (-not([string]::IsNullOrEmpty($serverId))) { + $params["Server"] = "$($serverId):3268" # Needs to be a GC port incase we are looking for a group outside of this domain. + } + $adObject = Get-ADObject @params + + if ($null -eq $adObject) { + Write-Verbose "Failed to find AD Object with filter '$($params.Filter)' on server '$($params.Server)'" + continue + } + + $adPrincipalGroupMembership.Add([PSCustomObject]@{ + Name = $adObject.Name + DistinguishedName = $adObject.DistinguishedName + ObjectGuid = $adObject.ObjectGuid + SID = $adObject.objectSid + }) + } catch { + # Currently do not add Invoke-CatchActions as we want to be aware if this doesn't fix some things. + Write-Verbose "Failed to run Get-ADObject against '$memberDN'. Inner Exception: $_" + } + } + } } $computerMembership = [PSCustomObject]@{ diff --git a/docs/Diagnostics/HealthChecker/ExchangeComputerMembership.md b/docs/Diagnostics/HealthChecker/ExchangeComputerMembership.md index 5ebaf1057..9e233c26b 100644 --- a/docs/Diagnostics/HealthChecker/ExchangeComputerMembership.md +++ b/docs/Diagnostics/HealthChecker/ExchangeComputerMembership.md @@ -8,6 +8,7 @@ This check is done by using the ADModule with using the cmdlets `Get-LocalGroupM If an issue is detected, the group will display with where the problem is located. Either `Local System Membership` if the group isn't part of the local system account or `AD Group Membership` if the computer object isn't a member of the group provided. +If the script is run from a computer that doesn't have Active Directory PowerShell module installed on it, `Get-ADComputer` will fail with the exception `CommandNotFoundException`. The output will then display that you should run `Install-WindowsFeature RSat-AD-PowerShell` on the computer to get the module installed. This is how you get this feature to then start reporting correctly. **Included in HTML Report?**