dantpro icon

Auto cleanup of DCs removed from a forest

dantpro | PRO | 04/04/14 09:21:25 AM UTC | 0 ⭐ | 1584 👁️ | Never ⏰ | []
PowerShell |

21.63 KB

|

None

|

0 👍

/

0 👎

<#  ==============================================================================================================================================
   CleanupDCs.ps1 V1.51: Performs automatic cleanup of DCs removed from a forest
 
                   Usage: .\CleanupDCs -action <action> 
                   ======
 
                   Parameters:
                   ===========
                      -action can be set to:
                            ListDCs:                   Creates a file called DClist.txt conatining al the DCs in the forest
                            MetadataCleanup:           Performs a metadata cleanup of the DCs of DCList.txt
                            DNSCleanup:                Deletes all DNS records registered by the DCs in DCList.txt
                            AccountCleanup:            Deletes the computer account of the DCs of DCLIST.txt
                            ResetTrustPwd:             Resets the password of every trust relationship of the domain 
 
                   Logs the output in CleanupDCs.log in the current directory
 
 
                   How to use for ADRES:
                   =====================
                       - On the first DC restored (the DC of the forest root domain), logon with the root domain administrator account (rid 500):
                           - Run .\CleanupDcs.ps1 -action ListDCs to create file DCList.txt containing all the DCs of the forest
                           - Edit DCList.txt and remove the DCs you want to keep.
                           - Run .\CleanupDcs.ps1 -action MetadataCleanup to perform a metadata Cleanup of the root domain DCs present in DCList.txt 
                           - Run .\CleanupDcs.ps1 -action DNSCleanup to delete the DNS records registered by the root domain DCs present in DCList.txt 
                           - Run .\CleanupDcs.ps1 -action ResetTrustPwd to restore the password of every trust relationship of the root domain 
 
                       - On the first DC restored of each child domain, logon with the child domain administrator account (rid 500):
                           - Copy DCList.txt from the Root DC.
                           - Run .\CleanupDcs.ps1 -action AccountCleanup to delete the computer account of the child domain DCs present in DCList.txt 
                           - Run .\CleanupDcs.ps1 -action DNSCleanup to delete the DNS records of the child domain DCs present in DCList.txt 
                           - Run .\CleanupDcs.ps1 -action ResetTrustPwd to restore the password of every trust relationship of the child domain 
 
 Disclaimer:
 This sample script is not supported under any Microsoft standard support program or service. 
 The sample script is provided AS IS without warranty of any kind. Microsoft further disclaims 
 all implied warranties including, without limitation, any implied warranties of merchantability 
 or of fitness for a particular purpose. The entire risk arising out of the use or performance of 
 the sample scripts and documentation remains with you. In no event shall Microsoft, its authors, 
 or anyone else involved in the creation, production, or delivery of the scripts be liable for any 
 damages whatsoever (including, without limitation, damages for loss of business profits, business 
 interruption, loss of business information, or other pecuniary loss) arising out of the use of or 
 inability to use the sample scripts or documentation, even if Microsoft has been advised of the 
 possibility of such damages
 
 ========================================================================================================================================================
#>
param ([parameter(Mandatory=$true)]$action)
$debugPreference = "inquire"
 
    # Function ListKeptDCs
    #    Displays the DCs that will be kept and returns their number
    # ---------------------------------------------------------------
    function ListKeptDCs
    {
          $keptDCs=0
          $DCList = get-content DCList.txt 
          write-host "The following DCs will be kept:"
          $ldapQuery = "(&(objectCategory=nTDSDSA))"
          $ObjAD = new-object System.DirectoryServices.DirectoryEntry
          $ADSearcher = new-object system.directoryservices.directorysearcher –argumentlist $ObjAD,$ldapQuery
          $Root = New-Object DirectoryServices.DirectoryEntry "LDAP://CN=Sites,CN=Configuration,$ForestRootDomain"
          $ADSearcher.SearchRoot = $Root
          try 
          {
                $QueryResult = $ADSearcher.findall()
                $QueryResult | 
                foreach {
                      $ldapObj=$_.Path.replace("LDAP://CN=NTDS Settings,","")
                      if (!($DCList | where {$_ -eq $ldapObj}))
                      {
                            $keptDCs++
                            write-host "  $ldapObj"
                      }
                }
          }
          catch 
          {
              write-host $_ -fore red
              break
          }
          
          return $KeptDCs
    }         
 
 
    #  Initialization
    # ----------------
        start-transcript .\CleanupDCs.Log
        $listedDCs=0
        $removedDCs=0
        $DNSCleanupDCs=0
        $ComputerAccountCleanupDCs=0
        $TrustPwdReset=0
        $rep=""
        $Info = "CleanupDC.ps1 V1.5 "
    
        $usage = @"
Usage: .\CleanupDCs -action <action> 
Valid actions are:
      ListDCs:         Creates a file called DClist.txt containing all DCs in the forest
      MetadataCleanup: Performs a Metadata cleanup of all the DCs of DCList.txt
      DNSCleanup:      Deletes all DNS records registered by the DCs in DCList.txt
      AccountCleanup:  Deletes the computer account a Metadata cleanup of all the DCs of DCList.txt
      ResetTrustPwd:   Resets the password of every trust relationship of the domain 
Example: 
      .\CleanupDCs -action ListDCs
 
"@
 
        cls
        switch ($Action) {
              "ListDCs"           {$Info = $Info + "List forest DCs in DCList.txt"}
              "DNSCleanup"        {$Info = $Info + "Cleanup DNS records registered by DCs of DCList.txt"}
              "MetadataCleanup"   {$Info = $Info + "Perform a MetadataCleanup of all DCs of DCList.txt"}
              "AccountCleanup"    {$Info = $Info + "Deletes the computer account of all DCs of DCList.txt"}
              "ResetTrustPwd"     {$Info = $Info + "Resets the password of every trust relationship oof the domain"}
              default {
                    write-host $info
                    write-host $usage
                    stop-transcript
                    exit
              }
        }
    
        Write-host $Info `n
    
        try 
        {
            $RootDSE=([ADSI]"LDAP://RootDSE")
            $ForestRootDomain=$RootDSE.rootDomainNamingContext
            $CurrentDomain=$RootDSE.Get("defaultNamingContext")
        }
        catch 
        {
            write-host $_ -fore red
            break
        }
        
        
 
    #  Action: List DCs
    #  -------------------
        if ($action -eq "ListDCs")
        {
              if (test-path .\DCList.txt)
              {
                    remove-item .\DCList.txt
              }
 
              $ldapQuery = "(&(objectClass=nTDSDSA))"
              $ObjAD = new-object System.DirectoryServices.DirectoryEntry
              $ADSearcher = new-object system.directoryservices.directorysearcher –argumentlist $ObjAD,$ldapQuery
              $Root = New-Object DirectoryServices.DirectoryEntry "LDAP://CN=Sites,CN=Configuration,$ForestRootDomain"
              $ADSearcher.SearchRoot = $Root
              write-host "`nThe following DCs will be added to DCList.txt:" 
              try 
              {
                    $QueryResult = $ADSearcher.findall()
                    $QueryResult | 
                    foreach {
                          $ldapObj=$_.Path.replace("LDAP://CN=NTDS Settings,","")
                          add-content -path .\DCList.txt -value $ldapObj
                          write-host "    $ldapObj" 
                          $ListedDCs++
                    }
              }
              catch 
              {
                  write-host $_ -fore red
                  break
              }
              $KeptDCs="na"
              $TrustPwdReset="na"
        }
 
 
    #  Action: MetadataCleanup
    #  -----------------------
        if ($action -eq "MetadataCleanup")
        {
              # Check DCList.txt is present
              if(!(test-path .\DCList.txt))
              {
                    write-host "File DCList.txt not found, please select action ListDCs to create the file`n" -fore red
                    stop-transcript 
                    exit
              }
              
              # Lists the DCs that will be kept and make sure not all of them will be removed
              $KeptDCs=ListKeptDCs
              if (!($KeptDCs))
              {
                    write-host "None`n`n"
                    write-host "The procedure would cleanup ALL DCs of the forest, as a result it will not be performed" -fore red
                    write-host "Pleasea make sure you removed the DCs you want to keep from DCList.txt`n" -fore red
                    stop-transcript 
                    exit
              }
        
              # Prompts the user to proceed
              write-host "`nWe are now ready to remove ALL other DCs of the forest."
              write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
              write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
              write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
              $rep=""
              while (!($rep -eq "Metadata Cleanup DCs"))
              {
                    if ($rep -eq "q")
                    {
                         stop-transcript     
                         exit
                    }
                    else
                    {     
                         $rep=read-host ("`nPlease enter `"Metadata Cleanup DCs`" to perform a metadata cleanup of all other DCs or `"q`" to quit")
                    }
              }
              
              # Perform the metdata cleanup of the DCs
              $DCList = get-content DCList.txt 
              write-host "`nPerforming a metadata cleanup of the following DCs:" 
              foreach ($DCName in $DCList) {
                    $NTDSobj=[ADSI]"LDAP://CN=NTDS Settings,$dcName"
                    if ($NTDSObj.name)   # makes sure object NTDS setting exists
                    {
                          write-host "  $DCName" -fore yellow
                          # Uncomment the following line to perform the metadata cleanup
                          ntdsutil.exe “metadata cleanup” “remove selected server $DCName” quit quit 
                          $removedDCs++
                    }
                    else
                    {
                          write-host "  $DCName has no NTDS Settings object" -fore red
                    }
              }
              write-host "`n`n" 
              $TrustPwdReset="na"   
        }
 
 
    #  Action: DNSCleanup
    #  ------------------
        if ($action -eq "DNSCleanup")
        {
              if(!(test-path .\DCList.txt))
              {
                    write-host "File DCList.txt not found, please select action ListDCs to create the file`n" -fore red
                    stop-transcript
                    exit
              }
 
              # Lists the DCs that will be kept and make sure not all of them will be removed
              $KeptDCs=ListKeptDCs
              if (!($KeptDCs))
              {
                    write-host "The procedure would delete DNS records of ALL DCs of the forest, as a result it will not be performed" -fore red
                    write-host "Please make sure you removed the DCs you want to keep from DCList.txt`n" -fore red
                    stop-transcript
                    exit
              }
        
              # Prompts the user to proceed
              write-host "`nWe are now ready to remove DNS records from ALL other DCs of the forest."
              write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
              write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
              write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
              $rep=""
              while (!($rep -eq "DNS Cleanup"))
              {
                    if ($rep -eq "q")
                    {
                         stop-transcript     
                         exit
                    }
                    else
                    {     
                         $rep=read-host("`nPlease enter `"DNS Cleanup`" to delete DNS records of other DCs or `"q`" to quit")
                    }
              }
             
              # Deletes the DNS records of the DCs
              $DCList = get-content DCList.txt 
              write-host "`nDeleting DNS records of the following DCs:"         
              try 
              {
                    foreach ($DCName in $DCList) {
                          $DCShortName = ($DCName.split(",")[0]).split("cn=")[1]
                          (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType"  |where {$_.TextRepresentation -like "*$DCShortName*"}) | 
                          foreach {
                                $DCIPAddr = $_.IPAddress
                                # Deletes the A record with the IP address
                                (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType"  |where {$_.IPAddress -like "*$DCIPAddr"}) | remove-wmiObject
                                # Deletes the A records with the DC name
                                $_ | remove-wmiObject
                          }
                          # Deletes the NS records
                          (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_NSType"  |where {$_.TextRepresentation -like "*$DCShortName*"})  | remove-wmiObject
                          # Deletes the SRV DNS records  
                          (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_SRVType"  |where {$_.TextRepresentation -like "*$DCShortName*"}) | remove-wmiObject
                          # Deletes the CNAME DNS records  
                          (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_CNAMEType"  |where {$_.RecordData -like "*$DCShortName*"})  |remove-wmiObject
    
                          write-host "    $DCShortName"  -fore yellow
                          $DNSCleanupDCs++
                    } 
              }
              catch 
              {
                    write-host $_ -fore red
                    break
              }
 
              write-host "`n`n" 
              $TrustPwdReset="na"   
        }
 
 
    #  Action: Accountcleanup
    #  ----------------------
        if ($action -eq "AccountCleanup")
        {
              if(!(test-path .\DCList.txt))
              {
                    write-host "File DCList.txt not found, please select action ListDCs to create the file`n" -fore red
                    stop-transcript
                    exit
              }
 
              # Lists the DCs that will be kept and make sure not all of them will be removed
              $KeptDCs=ListKeptDCs
              if (!($KeptDCs))
              {
                    write-host "The procedure would delete the computer account of ALL DCs of the forest, as a result it will not be performed" -fore red
                    write-host "Please make sure you removed the DCs you want to keep from DCList.txt`n" -fore red
                    stop-transcript
                    exit
              }
        
              # Prompts the user to proceed
              write-host "`nWe are now ready to delete the computer account of ALL other DCs of the forest."
              write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
              write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
              write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
              $rep=""
              while (!($rep -eq "Account Cleanup"))
              {
                    if ($rep -eq "q")
                    {
                         stop-transcript     
                         exit
                    }
                    else
                    {     
                         $rep=read-host("`nPlease enter `"Account Cleanup`" to delete the computer account of other DCs or `"q`" to quit")
                    }
              }
             
              # Deletes the computer accounts and their child objects
              $DCList = get-content DCList.txt 
              write-host "`nDeleting computer account of the following DCs:" 
              foreach ($DCName in $DCList) {
                    $DCShortName = ($DCName.split(",")[0]).split("cn=")[1]                    
                    $ldapQuery = "(&(cn=$DCShortName))"                       # We need to perform a LDAP query since the computer account might be in a sub OU
                    $ObjAD = new-object System.DirectoryServices.DirectoryEntry
                    $ADSearcher = new-object system.directoryservices.directorysearcher –argumentlist $ObjAD,$ldapQuery
                    $Root = New-Object DirectoryServices.DirectoryEntry "LDAP://OU=Domain Controllers,$CurrentDomain"
                    $ADSearcher.SearchRoot = $Root
                    
                    try 
                    {
                          $QueryResult = $ADSearcher.findall()
                          if ($QueryResult.count -ne 0)
                          {
                                [ADSI]$computerAccount = $QueryResult[0].path
                                $ComputerAccount.psbase.deleteTree()
                                $ComputerAccount.psbase.commitChanges()
                                write-host "    $DCShortName deleted"  -fore yellow
                                $ComputerAccountCleanupDCs++
                          }
                          else 
                          {
                                write-host "    $DCShortName not present in current domain"  -fore yellow
                          }
                          
                    }
                    catch 
                    {
                          write-host $_ -fore red
                          break
                    }
 
 
              }
              write-host "`n`n"    
              $TrustPwdReset="na"
        }
 
    #  Action: ResetTrustPwd
    #  ----------------------
        if ($action -eq "ResetTrustPwd")
        {
              # Prompts the user to proceed
              write-host "`nWe are now ready to reset the password of all trusts relationships of domain $CurrentDomain"
              write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
              write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
              write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
              $rep=""
              while (!($rep -eq "Reset Trusts Password"))
              {
                    if ($rep -eq "q")
                    {
                         stop-transcript     
                         exit
                    }
                    else
                    {     
                         $rep=read-host("`nPlease enter `"Reset Trusts Password`" to reset the domain's trust relationships password or `"q`" to quit")
                    }
              }
             
              $TrustPass=read-host "Please enter the trust password" -asSecureString
              $currentDomainFQDN = (Get-Item env:USERDNSDOMAIN).value
                             
              try 
              {
                    $trustCollection=[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().GetAllTrustRelationships()
                    $trustCollection |
                    foreach {
                          write-host "Resetting password of trust with domain $($_.targetName)" -fore yellow
                          netdom trust $currentDomainFQDN /domain:$($_.targetName) /resetOneSide /passwordT:$TrustPass
                          $TrustPwdReset++
                    }
              }
              catch 
              {
                    write-host $_ -fore red
                    break
              }
 
 
              write-host "`n`n"   
              $KeptDCs="na" 
        }
     
 
    # Statistics
    # --------------
    Write-Host "`n=================================="
    Write-Host " Statistics:" -fore green
    Write-Host "      DCs Listed: $listedDCs" -fore green
    Write-Host "      DCs metadata cleanup: $removedDCs" -fore green
    Write-Host "      DCs computer account deleted: $ComputerAccountCleanupDCs" -fore green
    Write-Host "      DCs Removed from DNS: $DNSCleanupDCs" -fore green
    Write-Host "      DCs Kept: $KeptDCs" -fore green
    Write-Host "      Trusts password reset: $TrustPwdReset" -fore green
    Write-Host "=================================="
    stop-transcript

Comments