Script PowerShell per verificare l’integrità di Active Directory: una guida completa 

Introduzione

Il mantenimento dell’integrità dell’ambiente Active Directory (AD) è fondamentale per la stabilità e la sicurezza dei sistemi IT. Una AD non integra può causare errori di autenticazione, problemi di replica e interruzioni più ampie nella rete di un’organizzazione. Questo script PowerShell è stato progettato per semplificare il processo di valutazione e risoluzione dei problemi durante il controllo dell’integrità di Active Directory, offrendo un metodo strutturato e automatizzato per i professionisti IT e i Managed Service Provider (MSP).

Contesto

Active Directory è la spina dorsale di molti ambienti IT aziendali e gestisce l’autenticazione degli utenti, i criteri di gruppo e i servizi di directory. Tuttavia, assicurarne il corretto funzionamento può essere complesso, dato il numero di potenziali punti di guasto. Questo script sfrutta l’utility con riga di comando DCDiag per analizzare lo stato di un controller di dominio, identificare potenziali problemi e riportare i risultati. Per gli MSP e gli amministratori IT, questo strumento è di valore inestimabile, in quanto fornisce un’istantanea chiara dell’integrità di AD e facilita la manutenzione proattiva.

Lo script per verificare l’integrità di Active Directory:

#Requires -Version 5.1

<#
.SYNOPSIS
    Analyzes the state of a domain controller and reports any problems to help with troubleshooting. Optionally, set a WYSIWYG custom field.
    By using this script, you indicate your acceptance of the following legal terms as well as our Terms of Use at https://www.ninjaone.com/terms-of-use.
    Ownership Rights: NinjaOne owns and will continue to own all right, title, and interest in and to the script (including the copyright). NinjaOne is giving you a limited license to use the script in accordance with these legal terms. 
    Use Limitation: You may only use the script for your legitimate personal or internal business purposes, and you may not share the script with another party. 
    Republication Prohibition: Under no circumstances are you permitted to re-publish the script in any script library or website belonging to or under the control of any other software provider. 
    Warranty Disclaimer: The script is provided “as is” and “as available”, without warranty of any kind. NinjaOne makes no promise or guarantee that the script will be free from defects or that it will meet your specific needs or expectations. 
    Assumption of Risk: Your use of the script is at your own risk. You acknowledge that there are certain inherent risks in using the script, and you understand and assume each of those risks. 
    Waiver and Release: You will not hold NinjaOne responsible for any adverse or unintended consequences resulting from your use of the script, and you waive any legal or equitable rights or remedies you may have against NinjaOne relating to your use of the script. 
    EULA: If you are a NinjaOne customer, your use of the script is subject to the End User License Agreement applicable to you (EULA).
.DESCRIPTION
    Analyzes the state of a domain controller and reports any problems to help with troubleshooting. Optionally, set a WYSIWYG custom field.
.EXAMPLE
    (No Parameters)
    
Retrieving Directory Server Diagnosis Test Results.

Passing Tests: CheckSDRefDom, Connectivity, CrossRefValidation, DFSREvent, FrsEvent, Intersite, KccEvent, KnowsOfRoleHolders, MachineAccount, NCSecDesc, NetLogons, ObjectsReplicated, Replications, RidManager, Services, SystemLog, SysVolCheck, VerifyReferences

[Alert] Failed Tests Detected!
Failed Tests: Advertising, LocatorCheck

### Detailed Output ###

Directory Server Diagnosis
Performing initial setup:
   Trying to find home server...
   Home Server = SRV16-DC2-TEST
   * Identified AD Forest. 
   Done gathering initial info.
Doing initial required tests
   Testing server: Default-First-Site-Name\SRV16-DC2-TEST
      Starting test: Connectivity
         ......................... SRV16-DC2-TEST passed test Connectivity
Doing primary tests
   Testing server: Default-First-Site-Name\SRV16-DC2-TEST
      Starting test: Advertising
         Warning: SRV16-DC2-TEST is not advertising as a time server.
         ......................... SRV16-DC2-TEST failed test Advertising
   Running partition tests on : ForestDnsZones
   Running partition tests on : DomainDnsZones
   Running partition tests on : Schema
   Running partition tests on : Configuration
   Running partition tests on : test
   Running enterprise tests on : test.lan

Directory Server Diagnosis
Performing initial setup:
   Trying to find home server...
   Home Server = SRV16-DC2-TEST
   * Identified AD Forest. 
   Done gathering initial info.
Doing initial required tests
   Testing server: Default-First-Site-Name\SRV16-DC2-TEST
      Starting test: Connectivity
         ......................... SRV16-DC2-TEST passed test Connectivity
Doing primary tests
   Testing server: Default-First-Site-Name\SRV16-DC2-TEST
   Running partition tests on : ForestDnsZones
   Running partition tests on : DomainDnsZones
   Running partition tests on : Schema
   Running partition tests on : Configuration
   Running partition tests on : test
   Running enterprise tests on : test.lan
      Starting test: LocatorCheck
         Warning: DcGetDcName(TIME_SERVER) call failed, error 1355
         A Time Server could not be located.
         The server holding the PDC role is down.
         Warning: DcGetDcName(GOOD_TIME_SERVER_PREFERRED) call failed, error
         1355
         A Good Time Server could not be located.
         ......................... test.lan failed test LocatorCheck

PARAMETER: -wysiwygCustomField "ReplaceMeWithaWYSIWYGcustomField"
    Name of a WYSIWYG custom field to optionally save the results to.
.NOTES
    Minimum OS Architecture Supported: Windows 10, Windows Server 2016
    Release Notes: Initial Release
#>

[CmdletBinding()]
param (
    [Parameter()]
    [String]$wysiwygCustomField
)

begin {
    # If script form variables are used, replace command line parameters with their value. 
    if ($env:wysiwygCustomFieldName -and $env:wysiwygCustomFieldName -notlike "null") { $wysiwygCustomField = $env:wysiwygCustomFieldName }

    # Function to test if the current machine is a domain controller
    function Test-IsDomainController {
        $OS = if ($PSVersionTable.PSVersion.Major -lt 5) {
            Get-WmiObject -Class Win32_OperatingSystem
        }
        else {
            Get-CimInstance -ClassName Win32_OperatingSystem
        }

        # Check if the OS is a domain controller (ProductType 2)
        if ($OS.ProductType -eq "2") {
            return $true
        }
    }

    function Get-DCDiagResults {
        # Define the list of DCDiag tests to run
        $DCDiagTestsToRun = "Connectivity", "Advertising", "FrsEvent", "DFSREvent", "SysVolCheck", "KccEvent", "KnowsOfRoleHolders", "MachineAccount", "NCSecDesc", "NetLogons", "ObjectsReplicated", "Replications", "RidManager", "Services", "SystemLog", "VerifyReferences", "CheckSDRefDom", "CrossRefValidation", "LocatorCheck", "Intersite"
    
        foreach ($DCTest in $DCDiagTestsToRun) {
            # Run DCDiag for the current test and save the output to a file
            $DCDiag = Start-Process -FilePath "DCDiag.exe" -ArgumentList "/test:$DCTest", "/f:$env:TEMP\dc-diag-$DCTest.txt" -PassThru -Wait -NoNewWindow

            # Check if the DCDiag test failed
            if ($DCDiag.ExitCode -ne 0) {
                Write-Host "[Error] Running $DCTest!"
                exit 1
            }

            # Read the raw results from the output file and filter out empty lines
            $RawResult = Get-Content -Path "$env:TEMP\dc-diag-$DCTest.txt" | Where-Object { $_.Trim() }
            
            # Find the status line indicating whether the test passed or failed
            $StatusLine = $RawResult | Where-Object { $_ -match "\. .* test $DCTest" }

            # Extract the status (passed or failed) from the status line
            $Status = $StatusLine -split ' ' | Where-Object { $_ -like "passed" -or $_ -like "failed" }

            # Create a custom object to store the test results
            [PSCustomObject]@{
                Test   = $DCTest
                Status = $Status
                Result = $RawResult
            }

            # Remove the temporary output file
            Remove-Item -Path "$env:TEMP\dc-diag-$DCTest.txt"
        }
    }

    function Set-NinjaProperty {
        [CmdletBinding()]
        Param(
            [Parameter(Mandatory = $True)]
            [String]$Name,
            [Parameter()]
            [String]$Type,
            [Parameter(Mandatory = $True, ValueFromPipeline = $True)]
            $Value,
            [Parameter()]
            [String]$DocumentName
        )
    
        $Characters = $Value | Out-String | Measure-Object -Character | Select-Object -ExpandProperty Characters
        if ($Characters -ge 200000) {
            throw [System.ArgumentOutOfRangeException]::New("Character limit exceeded: the value is greater than or equal to 200,000 characters.")
        }
        
        # If requested to set the field value for a Ninja document, specify it here.
        $DocumentationParams = @{}
        if ($DocumentName) { $DocumentationParams["DocumentName"] = $DocumentName }
        
        # This is a list of valid fields that can be set. If no type is specified, assume that the input does not need to be changed.
        $ValidFields = "Attachment", "Checkbox", "Date", "Date or Date Time", "Decimal", "Dropdown", "Email", "Integer", "IP Address", "MultiLine", "MultiSelect", "Phone", "Secure", "Text", "Time", "URL", "WYSIWYG"
        if ($Type -and $ValidFields -notcontains $Type) { Write-Warning "$Type is an invalid type. Please check here for valid types: https://ninjarmm.zendesk.com/hc/en-us/articles/16973443979789-Command-Line-Interface-CLI-Supported-Fields-and-Functionality" }
        
        # The field below requires additional information to set.
        $NeedsOptions = "Dropdown"
        if ($DocumentName) {
            if ($NeedsOptions -contains $Type) {
                # Redirect error output to the success stream to handle errors more easily if nothing is found or something else goes wrong.
                $NinjaPropertyOptions = Ninja-Property-Docs-Options -AttributeName $Name @DocumentationParams 2>&1
            }
        }
        else {
            if ($NeedsOptions -contains $Type) {
                $NinjaPropertyOptions = Ninja-Property-Options -Name $Name 2>&1
            }
        }
        
        # If an error is received with an exception property, exit the function with that error information.
        if ($NinjaPropertyOptions.Exception) { throw $NinjaPropertyOptions }
        
        # The types below require values not typically given to be set. The code below will convert whatever we're given into a format ninjarmm-cli supports.
        switch ($Type) {
            "Checkbox" {
                # Although it's highly likely we were given a value like "True" or a boolean data type, it's better to be safe than sorry.
                $NinjaValue = [System.Convert]::ToBoolean($Value)
            }
            "Date or Date Time" {
                # Ninjarmm-cli expects the GUID of the option to be selected. Therefore, match the given value with a GUID.
                $Date = (Get-Date $Value).ToUniversalTime()
                $TimeSpan = New-TimeSpan (Get-Date "1970-01-01 00:00:00") $Date
                $NinjaValue = $TimeSpan.TotalSeconds
            }
            "Dropdown" {
                # Ninjarmm-cli expects the GUID of the option we're trying to select, so match the value we were given with a GUID.
                $Options = $NinjaPropertyOptions -replace '=', ',' | ConvertFrom-Csv -Header "GUID", "Name"
                $Selection = $Options | Where-Object { $_.Name -eq $Value } | Select-Object -ExpandProperty GUID
        
                if (-not $Selection) {
                    throw [System.ArgumentOutOfRangeException]::New("Value is not present in dropdown options.")
                }
        
                $NinjaValue = $Selection
            }
            default {
                # All the other types shouldn't require additional work on the input.
                $NinjaValue = $Value
            }
        }
        
        # Set the field differently depending on whether it's a field in a Ninja Document or not.
        if ($DocumentName) {
            $CustomField = Ninja-Property-Docs-Set -AttributeName $Name -AttributeValue $NinjaValue @DocumentationParams 2>&1
        }
        else {
            $CustomField = $NinjaValue | Ninja-Property-Set-Piped -Name $Name 2>&1
        }
        
        if ($CustomField.Exception) {
            throw $CustomField
        }
    }
   
    function Test-IsElevated {
        $id = [System.Security.Principal.WindowsIdentity]::GetCurrent()
        $p = New-Object System.Security.Principal.WindowsPrincipal($id)
        $p.IsInRole([System.Security.Principal.WindowsBuiltInRole]::Administrator)
    }

    if (!$ExitCode) {
        $ExitCode = 0
    }
}
process {
    # Check if the script is run with Administrator privileges
    if (!(Test-IsElevated)) {
        Write-Host -Object "[Error] Access Denied. Please run with Administrator privileges."
        exit 1
    }

    # Check if the script is run on a Domain Controller
    if (!(Test-IsDomainController)) {
        Write-Host -Object "[Error] This script needs to be run on a Domain Controller."
        exit 1
    }

    # Initialize lists to store passing and failing tests
    $PassingTests = New-Object System.Collections.Generic.List[object]
    $FailedTests = New-Object System.Collections.Generic.List[object]

    # Notify the user that the tests are being retrieved
    Write-Host -Object "`nRetrieving Directory Server Diagnosis Test Results."
    $TestResults = Get-DCDiagResults

    # Process each test result
    foreach ($Result in $TestResults) {
        $TestFailed = $False

        # Check if any status in the result indicates a failure
        $Result.Status | ForEach-Object {
            if ($_ -notmatch "pass") {
                $TestFailed = $True
            }
        }

        # Add the result to the appropriate list
        if ($TestFailed) {
            $FailedTests.Add($Result)
        }
        else {
            $PassingTests.Add($Result)
        }
    }

    # Optionally set a WYSIWYG custom field if specified
    if ($wysiwygCustomField) {
        try {
            Write-Host -Object "`nBuilding HTML for Custom Field."

            # Create an HTML report for the custom field
            $HTML = New-Object System.Collections.Generic.List[object]

            $HTML.Add("<h1 style='text-align: center'>Directory Server Diagnosis Test Results (DCDiag.exe)</h1>")
            $FailedPercentage = $([math]::Round((($FailedTests.Count / ($FailedTests.Count + $PassingTests.Count)) * 100), 2))
            $SuccessPercentage = 100 - $FailedPercentage
            $HTML.Add(
                @"
<div class='p-3 linechart'>
    <div style='width: $FailedPercentage%; background-color: #C6313A;'></div>
    <div style='width: $SuccessPercentage%; background-color: #007644;'></div>
        </div>
        <ul class='unstyled p-3' style='display: flex; justify-content: space-between; '>
            <li><span class='chart-key' style='background-color: #C6313A;'></span><span>Failed ($($FailedTests.Count))</span></li>
            <li><span class='chart-key' style='background-color: #007644;'></span><span>Passed ($($PassingTests.Count))</span></li>
        </ul>
"@
            )

            # Add failed tests to the HTML report
            $FailedTests | Sort-Object Test | ForEach-Object {
                $HTML.Add(
                    @"
<div class='info-card error'>
    <i class='info-icon fa-solid fa-circle-exclamation'></i>
    <div class='info-text'>
        <div class='info-title'>$($_.Test)</div>
        <div class='info-description'>
            $($_.Result | Out-String)
        </div>
    </div>
</div>
"@
                )
            }

            # Add passing tests to the HTML report
            $PassingTests | Sort-Object Test | ForEach-Object {
                $HTML.Add(
                    @"
<div class='info-card success'>
    <i class='info-icon fa-solid fa-circle-check'></i>
    <div class='info-text'>
        <div class='info-title'>$($_.Test)</div>
        <div class='info-description'>
            Test passed.
        </div>
    </div>
</div>
"@
                )
            }

            # Set the custom field with the HTML report
            Write-Host -Object "Attempting to set Custom Field '$wysiwygCustomField'."
            Set-NinjaProperty -Name $wysiwygCustomField -Value $HTML
            Write-Host -Object "Successfully set Custom Field '$wysiwygCustomField'!"
        }
        catch {
            Write-Host -Object "[Error] $($_.Exception.Message)"
            $ExitCode = 1
        }
    }

    # Display the list of passing tests
    if ($PassingTests.Count -gt 0) {
        Write-Host -Object ""
        Write-Host -Object "Passing Tests: " -NoNewline
        Write-Host -Object ($PassingTests.Test | Sort-Object) -Separator ", "
        Write-Host -Object ""
    }

    # Display the list of failed tests with detailed output
    if ($FailedTests.Count -gt 0) {
        Write-Host -Object "[Alert] Failed Tests Detected!"
        Write-Host -Object "Failed Tests: " -NoNewline
        Write-Host -Object ($FailedTests.Test | Sort-Object) -Separator ", "

        Write-Host -Object "`n### Detailed Output ###"
        $FailedTests | Sort-Object Test | ForEach-Object {
            Write-Host -Object ""
            Write-Host -Object ($_.Result | Out-String)
            Write-Host -Object ""
        }
    }
    else {
        Write-Host -Object "All Directory Server Diagnosis Tests Pass!"
    }

    exit $ExitCode
}
end {
    
    
    
}

 

Risparmia tempo con gli oltre 300 script del Dojo NinjaOne.

Accedi oggi stesso.

Analisi dettagliata

Funzionalità dello script per verificare l’integrità di Active Directory

  1. Controllo dei privilegi di amministratore
    Lo script inizia verificando che sia in esecuzione con privilegi elevati, assicurandosi di avere le autorizzazioni necessarie per eseguire i comandi diagnostici.
  2. Convalida del controller di dominio
    Controlla se lo script per verificare l’integrità di Active Directory viene eseguito su un controller di dominio. In caso contrario, esce con un messaggio di errore appropriato.
  3. Esecuzione dei test DCDiag
    Viene eseguita una serie di test DCDiag critici, tra cui controlli di connettività, advertising, replica, registri di sistema e altro ancora. I risultati vengono analizzati per separare i test che hanno risultato positivo da quelli che invece falliscono.
  4. Categorizzazione dei risultati
    I risultati sono suddivisi in categorie di superamento e fallimento, con output dettagliati per ogni test fallito. Questo aiuta gli amministratori a concentrarsi sui problemi che richiedono un’attenzione immediata.
  5. Campi personalizzati opzionali per il reporting
    Lo script supporta un parametro opzionale per visualizzare i risultati in un campo personalizzato WYSIWYG (What You See Is What You Get), utile per l’integrazione con strumenti come NinjaOne.
  6. Generazione di report HTML
    Per una maggiore leggibilità, lo script per verificare l’integrità di Active Directory genera un report HTML che riassume i risultati dei test in un formato visivamente intuitivo, con le percentuali di successo e di fallimento visibili.

Riepilogo del flusso di lavoro

  1. Convalida i prerequisiti: Privilegi di amministratore e ambiente del controller di dominio.
  2. Esegue i test DCDiag e acquisisce i risultati.
  3. Categorizza e visualizza i risultati.
  4. Genera un report HTML opzionale per l’integrazione dei campi personalizzati.

Casi d’uso potenziali

Scenario concreto

Immagina un amministratore IT responsabile della gestione di un ambiente AD multi-sito. Uno dei controller di dominio inizia a evidenziare errori di autenticazione intermittenti. L’amministratore esegue questo script per verificare l’integrità di Active Directory sul server interessato per diagnosticare il problema. L’output evidenzia i fallimenti dei test Advertising e LocatorCheck , indicando problemi di sincronizzazione temporale e disponibilità del ruolo PDC. L’output dettagliato aiuta l’amministratore a identificare e risolvere rapidamente la causa principale, ripristinando le normali operazioni.

Confronti

Controlli manuali sull’integrità di AD

L’esecuzione manuale dei test DCDiag richiede un notevole investimento di tempo, soprattutto per l’analisi e l’interpretazione dei risultati. Questo script automatizza l’intero processo, fornendo output strutturati e opzioni di integrazione.

Strumenti basati su GUI

Sebbene strumenti GUI come AD Manager o RSAT forniscano un’interfaccia facile da usare per i controlli dell’integrità di AD, spesso mancano della flessibilità e delle capacità di automazione degli script PowerShell. Questo script per verificare l’integrità di Active Directory è particolarmente vantaggioso per gli MSP che gestiscono più ambienti di clienti.

Domande frequenti

  1. Questo script per verificare l’integrità di Active Directory può essere eseguito su qualsiasi server?
    No, deve essere eseguito su un controller di dominio. Gli ambienti non-DC generano un errore.
  2. Quali autorizzazioni sono necessarie?
    I privilegi di amministratore sono obbligatori per eseguire lo script per verificare l’integrità di Active Directory con successo.
  3. I risultati possono essere esportati in un file?
    Sì, lo script per verificare l’integrità di Active Directory include un’opzione per generare un report HTML per l’integrazione con i campi personalizzati.
  4. Come vengono evidenziati i test falliti?
    I test falliti sono elencati separatamente con messaggi diagnostici dettagliati, per facilitare la definizione delle priorità di risoluzione dei problemi.

Implicazioni

I risultati di questo script per verificare l’integrità di Active Directory possono rivelare vulnerabilità critiche nell’ambiente AD, come errori di replica o ruoli mal configurati. Se non risolti, questi problemi possono portare a problemi di autenticazione diffusi, ad applicazioni errate delle policy e a rischi per la sicurezza.

Raccomandazioni

  • Esegui lo script regolarmente: Pianifica l’esecuzione periodica dello script per verificare l’integrità di Active Directory per mantenere un controllo continuo dell’integrità di AD.
  • Analizza le tendenze: Confronta i risultati nel tempo per identificare i problemi ricorrenti.
  • Integralo con gli strumenti di monitoraggio: Utilizza l’opzione del campo personalizzato per integrare i risultati in strumenti come NinjaOne per un monitoraggio centralizzato.

Considerazioni finali

Questo script PowerShell offre una soluzione semplificata e automatizzata per verificare l’integrità di Active Directory, riducendo il tempo e l’impegno necessari per la diagnostica manuale. Identificando tempestivamente i problemi, i professionisti IT possono affrontare in modo proattivo le potenziali interruzioni, garantendo un ambiente Active Directory stabile e sicuro. Per gli MSP, strumenti come NinjaOne sono complementari a questo script e forniscono una piattaforma centralizzata per la gestione e il monitoraggio delle operazioni IT. L’utilizzo combinato di script come questo e di una piattaforma RMM come NinjaOne permette di mettere insieme una solida strategia per mantenere l’integrità IT dell’organizzazione.

Passi successivi

La creazione di un team IT efficiente ed efficace richiede una soluzione centralizzata che funga da principale strumento per la fornitura di servizi. NinjaOne consente ai team IT di monitorare, gestire, proteggere e supportare tutti i dispositivi, ovunque essi si trovino, senza la necessità di una complessa infrastruttura locale.

Per saperne di più sulla distribuzione remota di script con NinjaOne, fai un tour dal vivo, o inizia la tua prova gratuita della piattaforma NinjaOne.

Categorie:

Ti potrebbe interessare anche

×

Guarda NinjaOne in azione!

Inviando questo modulo, accetto La politica sulla privacy di NinjaOne.

Termini e condizioni NinjaOne

Cliccando sul pulsante “Accetto” qui sotto, dichiari di accettare i seguenti termini legali e le nostre condizioni d’uso:

  • Diritti di proprietà: NinjaOne possiede e continuerà a possedere tutti i diritti, i titoli e gli interessi relativi allo script (compreso il copyright). NinjaOne ti concede una licenza limitata per l’utilizzo dello script in conformità con i presenti termini legali.
  • Limitazione d’uso: Puoi utilizzare lo script solo per legittimi scopi personali o aziendali interni e non puoi condividere lo script con altri soggetti.
  • Divieto di ripubblicazione: In nessun caso ti è consentito ripubblicare lo script in una libreria di script appartenente o sotto il controllo di un altro fornitore di software.
  • Esclusione di garanzia: Lo script viene fornito “così com’è” e “come disponibile”, senza garanzie di alcun tipo. NinjaOne non promette né garantisce che lo script sia privo di difetti o che soddisfi le tue esigenze o aspettative specifiche.
  • Assunzione del rischio: L’uso che farai dello script è da intendersi a tuo rischio. Riconosci che l’utilizzo dello script comporta alcuni rischi intrinseci, che comprendi e sei pronto ad assumerti.
  • Rinuncia e liberatoria: Non riterrai NinjaOne responsabile di eventuali conseguenze negative o indesiderate derivanti dall’uso dello script e rinuncerai a qualsiasi diritto legale o di equità e a qualsiasi rivalsa nei confronti di NinjaOne in relazione all’uso dello script.
  • EULA: Se sei un cliente NinjaOne, l’uso dello script è soggetto al Contratto di licenza con l’utente finale (EULA) applicabile.