Active Directory Infra check using PowerShell

Some of our customers have an Active Directory environment that needs upgrading. To get a good overview of their environment, I always check many things before writing a report and a recommendation about which steps we need to take. In this blog post, I will show you a script that gathers information about the Active Directory Domain, which saves a lot of command-line checking and starting up Management Consoles 😉

How the script works

The script gathers information using the Active Directory PowerShell module, this needs to be installed on your system or run the script on a Domain Controller, and it connects to each Domain Controller to see what is installed (DNS/DHCP/CA). It also gathers information about SYSVOL replication (FRS or DFSR), if there are Exchange servers if Azure AD Connect is installed, and on which server. It also shows Functional Levels, UPN Suffixes, Active Directory Recycle Bin status, and Trusts to other domains, if any.

Running the script

Save the contents of the script below to c:\script\Get-ADDomaininfo.ps1 and start it in your session by running:

. c:\scripts\Get-ADDomaininfo.ps1

Now that the function is available, you can run Get-ADdomaininfo to scan your current or specify one using the -Domain parameter and the DNS name. (For example, Contoso.local)

Below is the output when running the script on my test Hyper-V VM Domain Controller on my laptop:

There’s only one Domain Controller in my Domain. It will show all Domain Controllers found with their details.

The script

The Get-ADDomaininfo.ps1 script is below, save it somewhere and run it to get a simple overview of the environment 🙂

function Get-ADDomaininfo {
    param (
        [Parameter(Mandatory = $false, HelpMessage = "Specify the domain, i.e. contoso.local")][string]$domain
    )
    
    #Test if specified domain is accessible
    if ($domain) {
        if (-not (Get-ADDomain -Identity $domain)) {
            Write-Warning ("Specified domain 0} is not accessible, please check spelling and access. Exiting..." -f $domain)
            return
        }
    }

    #Set $domain to current domain if not specified as parameter
    if (-not $domain) {
        $domain = (Get-ADDomain).dnsroot
    }

    #Gather overview of Domain Controllers
    $domainControllers = foreach ($domainController in (Get-ADDomain).ReplicaDirectoryServers) {
        $info = Get-ADDomainController -Identity $domainController
        [PSCustomObject]@{
            Name                    = $info.HostName
            IPv4Address             = $info.IPv4Address
            IPv6Address             = if ($info.IPv6Address)
            { $info.IPv6Address }
            else {
                "None"
            }
            "Certificate Authority" = if ((Get-WindowsFeature -ComputerName $DomainController -Name ADCS-Cert-Authority).InstallState -eq 'Installed') {
                "Installed"
            }
            else {
                "Not installed"
            }
            "DHCP Server"           = if ((Get-WindowsFeature -ComputerName $DomainController -Name DHCP).InstallState -eq 'Installed') {
                "Installed"
            }
            else {
                "Not installed"
            }
            "DNS Server"            = if ((Get-WindowsFeature -ComputerName $DomainController -Name DNS).InstallState -eq 'Installed') {
                "Installed"
            }
            else {
                "Not installed"
            }
            GlobalCatalog           = $info.IsGlobalCatalog
            "Operating System"      = $info.OperatingSystem
            FSMO                    = if ($info.OperationMasterRoles) {
                $info.OperationMasterRoles -join ", " 
            }
            else {
                "None"
            }
            Site                    = $info.Site
            OU                      = $info.ComputerObjectDN
        }
 
    }

    #Check for FSR configuration (https://kiwix.ounapuu.ee/serverfault.com_en_all_2019-02/A/question/876823.html)
    $searchFRS = New-Object DirectoryServices.DirectorySearcher
    $searchFRS.Filter = "(&(objectClass=nTFRSSubscriber)(name=Domain System Volume (SYSVOL share)))"
    $searchFRS.SearchRoot = $dcObjectPath
    
    #Gather Domain information
    $domainInfo = [PSCustomObject]@{
        "Active Directory Sites"       = [System.DirectoryServices.ActiveDirectory.Forest]::GetCurrentForest().Sites.Name -join ", "
        "Active Directory Recycle Bin" = if ((Get-ADOptionalFeature -Filter 'Name -eq "Recycle Bin Feature"').EnabledScopes) {
            "Enabled"
        }
        else {
            "Not Enabled"
        }
        "Azure AD Connect Server(s)"   = if (Get-ADUser -LDAPFilter "(description=*configured to synchronize to tenant*)" -Properties description | ForEach-Object { $_.description.SubString(142, $_.description.IndexOf(" ", 142) - 142) }) {
            Get-ADUser -LDAPFilter "(description=*configured to synchronize to tenant*)" -Properties description | ForEach-Object { $_.description.SubString(142, $_.description.IndexOf(" ", 142) - 142) -join ", " }
        }
        else {
            "None"
        }
        "Domain Functional Level"      = (Get-ADDomain).DomainMode
        "Exchange Server(s)"           = if (Get-ADGroup -Filter { SamAccountName -eq "Exchange Servers" }) {
            (Get-ADGroupMember -Identity "Exchange Servers" | Where-Object ObjectClass -eq 'Computer').Name -join ", "
        }
        else {
            "None"
        }
        "Forest Functional Level"      = (Get-ADForest).ForestMode
        "FRS or DFSR for Sysvol"       = if ($searchFRS.FindAll().Count -eq '0') {
            "DFRS"
        }
        else {
            "FRS"
        }
        "Trusts"                       = if (Get-ADTrust -Filter *) {
            (Get-ADTrust -Filter *).Name -join ", "
        }
        else {
            "None"
        }
        "UPN Suffixes"                 = if ((Get-ADForest).UPNSuffixes) {
            (Get-ADForest).UPNSuffixes -join ", "
        }
        else {
            "None"
        }
    }   

    #Return all results
    return $domainControllers, $domainInfo
}

Download the script(s) from GitHub here

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.