Advertisement
dantpro

Auto cleanup of DCs removed from a forest

Apr 4th, 2014
1,176
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
  1. <#  ==============================================================================================================================================
  2.    CleanupDCs.ps1 V1.51: Performs automatic cleanup of DCs removed from a forest
  3.  
  4.                    Usage: .\CleanupDCs -action <action>
  5.                    ======
  6.  
  7.                    Parameters:
  8.                    ===========
  9.                       -action can be set to:
  10.                             ListDCs:                   Creates a file called DClist.txt conatining al the DCs in the forest
  11.                             MetadataCleanup:           Performs a metadata cleanup of the DCs of DCList.txt
  12.                             DNSCleanup:                Deletes all DNS records registered by the DCs in DCList.txt
  13.                             AccountCleanup:            Deletes the computer account of the DCs of DCLIST.txt
  14.                             ResetTrustPwd:             Resets the password of every trust relationship of the domain
  15.  
  16.                    Logs the output in CleanupDCs.log in the current directory
  17.  
  18.  
  19.                    How to use for ADRES:
  20.                    =====================
  21.                        - On the first DC restored (the DC of the forest root domain), logon with the root domain administrator account (rid 500):
  22.                            - Run .\CleanupDcs.ps1 -action ListDCs to create file DCList.txt containing all the DCs of the forest
  23.                            - Edit DCList.txt and remove the DCs you want to keep.
  24.                            - Run .\CleanupDcs.ps1 -action MetadataCleanup to perform a metadata Cleanup of the root domain DCs present in DCList.txt
  25.                            - Run .\CleanupDcs.ps1 -action DNSCleanup to delete the DNS records registered by the root domain DCs present in DCList.txt
  26.                            - Run .\CleanupDcs.ps1 -action ResetTrustPwd to restore the password of every trust relationship of the root domain
  27.  
  28.                        - On the first DC restored of each child domain, logon with the child domain administrator account (rid 500):
  29.                            - Copy DCList.txt from the Root DC.
  30.                            - Run .\CleanupDcs.ps1 -action AccountCleanup to delete the computer account of the child domain DCs present in DCList.txt
  31.                            - Run .\CleanupDcs.ps1 -action DNSCleanup to delete the DNS records of the child domain DCs present in DCList.txt
  32.                            - Run .\CleanupDcs.ps1 -action ResetTrustPwd to restore the password of every trust relationship of the child domain
  33.  
  34.  Disclaimer:
  35.  This sample script is not supported under any Microsoft standard support program or service.
  36.  The sample script is provided AS IS without warranty of any kind. Microsoft further disclaims
  37.  all implied warranties including, without limitation, any implied warranties of merchantability
  38.  or of fitness for a particular purpose. The entire risk arising out of the use or performance of
  39.  the sample scripts and documentation remains with you. In no event shall Microsoft, its authors,
  40.  or anyone else involved in the creation, production, or delivery of the scripts be liable for any
  41.  damages whatsoever (including, without limitation, damages for loss of business profits, business
  42.  interruption, loss of business information, or other pecuniary loss) arising out of the use of or
  43.  inability to use the sample scripts or documentation, even if Microsoft has been advised of the
  44.  possibility of such damages
  45.  
  46.  ========================================================================================================================================================
  47. #>
  48. param ([parameter(Mandatory=$true)]$action)
  49. $debugPreference = "inquire"
  50.  
  51.     # Function ListKeptDCs
  52.     #    Displays the DCs that will be kept and returns their number
  53.     # ---------------------------------------------------------------
  54.     function ListKeptDCs
  55.     {
  56.           $keptDCs=0
  57.           $DCList = get-content DCList.txt
  58.           write-host "The following DCs will be kept:"
  59.           $ldapQuery = "(&(objectCategory=nTDSDSA))"
  60.           $ObjAD = new-object System.DirectoryServices.DirectoryEntry
  61.           $ADSearcher = new-object system.directoryservices.directorysearcher –argumentlist $ObjAD,$ldapQuery
  62.           $Root = New-Object DirectoryServices.DirectoryEntry "LDAP://CN=Sites,CN=Configuration,$ForestRootDomain"
  63.           $ADSearcher.SearchRoot = $Root
  64.           try
  65.           {
  66.                 $QueryResult = $ADSearcher.findall()
  67.                 $QueryResult |
  68.                 foreach {
  69.                       $ldapObj=$_.Path.replace("LDAP://CN=NTDS Settings,","")
  70.                       if (!($DCList | where {$_ -eq $ldapObj}))
  71.                       {
  72.                             $keptDCs++
  73.                             write-host "  $ldapObj"
  74.                       }
  75.                 }
  76.           }
  77.           catch
  78.           {
  79.               write-host $_ -fore red
  80.               break
  81.           }
  82.          
  83.           return $KeptDCs
  84.     }        
  85.  
  86.  
  87.     #  Initialization
  88.     # ----------------
  89.         start-transcript .\CleanupDCs.Log
  90.         $listedDCs=0
  91.         $removedDCs=0
  92.         $DNSCleanupDCs=0
  93.         $ComputerAccountCleanupDCs=0
  94.         $TrustPwdReset=0
  95.         $rep=""
  96.         $Info = "CleanupDC.ps1 V1.5 "
  97.    
  98.         $usage = @"
  99. Usage: .\CleanupDCs -action <action>
  100. Valid actions are:
  101.      ListDCs:         Creates a file called DClist.txt containing all DCs in the forest
  102.      MetadataCleanup: Performs a Metadata cleanup of all the DCs of DCList.txt
  103.      DNSCleanup:      Deletes all DNS records registered by the DCs in DCList.txt
  104.      AccountCleanup:  Deletes the computer account a Metadata cleanup of all the DCs of DCList.txt
  105.      ResetTrustPwd:   Resets the password of every trust relationship of the domain
  106. Example:
  107.      .\CleanupDCs -action ListDCs
  108.  
  109. "@
  110.  
  111.         cls
  112.         switch ($Action) {
  113.               "ListDCs"           {$Info = $Info + "List forest DCs in DCList.txt"}
  114.               "DNSCleanup"        {$Info = $Info + "Cleanup DNS records registered by DCs of DCList.txt"}
  115.               "MetadataCleanup"   {$Info = $Info + "Perform a MetadataCleanup of all DCs of DCList.txt"}
  116.               "AccountCleanup"    {$Info = $Info + "Deletes the computer account of all DCs of DCList.txt"}
  117.               "ResetTrustPwd"     {$Info = $Info + "Resets the password of every trust relationship oof the domain"}
  118.               default {
  119.                     write-host $info
  120.                     write-host $usage
  121.                     stop-transcript
  122.                     exit
  123.               }
  124.         }
  125.    
  126.         Write-host $Info `n
  127.    
  128.         try
  129.         {
  130.             $RootDSE=([ADSI]"LDAP://RootDSE")
  131.             $ForestRootDomain=$RootDSE.rootDomainNamingContext
  132.             $CurrentDomain=$RootDSE.Get("defaultNamingContext")
  133.         }
  134.         catch
  135.         {
  136.             write-host $_ -fore red
  137.             break
  138.         }
  139.        
  140.        
  141.  
  142.     #  Action: List DCs
  143.     #  -------------------
  144.         if ($action -eq "ListDCs")
  145.         {
  146.               if (test-path .\DCList.txt)
  147.               {
  148.                     remove-item .\DCList.txt
  149.               }
  150.  
  151.               $ldapQuery = "(&(objectClass=nTDSDSA))"
  152.               $ObjAD = new-object System.DirectoryServices.DirectoryEntry
  153.               $ADSearcher = new-object system.directoryservices.directorysearcher –argumentlist $ObjAD,$ldapQuery
  154.               $Root = New-Object DirectoryServices.DirectoryEntry "LDAP://CN=Sites,CN=Configuration,$ForestRootDomain"
  155.               $ADSearcher.SearchRoot = $Root
  156.               write-host "`nThe following DCs will be added to DCList.txt:"
  157.               try
  158.               {
  159.                     $QueryResult = $ADSearcher.findall()
  160.                     $QueryResult |
  161.                     foreach {
  162.                           $ldapObj=$_.Path.replace("LDAP://CN=NTDS Settings,","")
  163.                           add-content -path .\DCList.txt -value $ldapObj
  164.                           write-host "    $ldapObj"
  165.                           $ListedDCs++
  166.                     }
  167.               }
  168.               catch
  169.               {
  170.                   write-host $_ -fore red
  171.                   break
  172.               }
  173.               $KeptDCs="na"
  174.               $TrustPwdReset="na"
  175.         }
  176.  
  177.  
  178.     #  Action: MetadataCleanup
  179.     #  -----------------------
  180.         if ($action -eq "MetadataCleanup")
  181.         {
  182.               # Check DCList.txt is present
  183.               if(!(test-path .\DCList.txt))
  184.               {
  185.                     write-host "File DCList.txt not found, please select action ListDCs to create the file`n" -fore red
  186.                     stop-transcript
  187.                     exit
  188.               }
  189.              
  190.               # Lists the DCs that will be kept and make sure not all of them will be removed
  191.               $KeptDCs=ListKeptDCs
  192.               if (!($KeptDCs))
  193.               {
  194.                     write-host "None`n`n"
  195.                     write-host "The procedure would cleanup ALL DCs of the forest, as a result it will not be performed" -fore red
  196.                     write-host "Pleasea make sure you removed the DCs you want to keep from DCList.txt`n" -fore red
  197.                     stop-transcript
  198.                     exit
  199.               }
  200.        
  201.               # Prompts the user to proceed
  202.               write-host "`nWe are now ready to remove ALL other DCs of the forest."
  203.               write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
  204.               write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
  205.               write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
  206.               $rep=""
  207.               while (!($rep -eq "Metadata Cleanup DCs"))
  208.               {
  209.                     if ($rep -eq "q")
  210.                     {
  211.                          stop-transcript    
  212.                          exit
  213.                     }
  214.                     else
  215.                     {    
  216.                          $rep=read-host ("`nPlease enter `"Metadata Cleanup DCs`" to perform a metadata cleanup of all other DCs or `"q`" to quit")
  217.                     }
  218.               }
  219.              
  220.               # Perform the metdata cleanup of the DCs
  221.               $DCList = get-content DCList.txt
  222.               write-host "`nPerforming a metadata cleanup of the following DCs:"
  223.               foreach ($DCName in $DCList) {
  224.                     $NTDSobj=[ADSI]"LDAP://CN=NTDS Settings,$dcName"
  225.                     if ($NTDSObj.name)   # makes sure object NTDS setting exists
  226.                     {
  227.                           write-host "  $DCName" -fore yellow
  228.                           # Uncomment the following line to perform the metadata cleanup
  229.                           ntdsutil.exe “metadata cleanup” “remove selected server $DCName” quit quit
  230.                           $removedDCs++
  231.                     }
  232.                     else
  233.                     {
  234.                           write-host "  $DCName has no NTDS Settings object" -fore red
  235.                     }
  236.               }
  237.               write-host "`n`n"
  238.               $TrustPwdReset="na"  
  239.         }
  240.  
  241.  
  242.     #  Action: DNSCleanup
  243.     #  ------------------
  244.         if ($action -eq "DNSCleanup")
  245.         {
  246.               if(!(test-path .\DCList.txt))
  247.               {
  248.                     write-host "File DCList.txt not found, please select action ListDCs to create the file`n" -fore red
  249.                     stop-transcript
  250.                     exit
  251.               }
  252.  
  253.               # Lists the DCs that will be kept and make sure not all of them will be removed
  254.               $KeptDCs=ListKeptDCs
  255.               if (!($KeptDCs))
  256.               {
  257.                     write-host "The procedure would delete DNS records of ALL DCs of the forest, as a result it will not be performed" -fore red
  258.                     write-host "Please make sure you removed the DCs you want to keep from DCList.txt`n" -fore red
  259.                     stop-transcript
  260.                     exit
  261.               }
  262.        
  263.               # Prompts the user to proceed
  264.               write-host "`nWe are now ready to remove DNS records from ALL other DCs of the forest."
  265.               write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
  266.               write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
  267.               write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
  268.               $rep=""
  269.               while (!($rep -eq "DNS Cleanup"))
  270.               {
  271.                     if ($rep -eq "q")
  272.                     {
  273.                          stop-transcript    
  274.                          exit
  275.                     }
  276.                     else
  277.                     {    
  278.                          $rep=read-host("`nPlease enter `"DNS Cleanup`" to delete DNS records of other DCs or `"q`" to quit")
  279.                     }
  280.               }
  281.              
  282.               # Deletes the DNS records of the DCs
  283.               $DCList = get-content DCList.txt
  284.               write-host "`nDeleting DNS records of the following DCs:"        
  285.               try
  286.               {
  287.                     foreach ($DCName in $DCList) {
  288.                           $DCShortName = ($DCName.split(",")[0]).split("cn=")[1]
  289.                           (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType"  |where {$_.TextRepresentation -like "*$DCShortName*"}) |
  290.                           foreach {
  291.                                 $DCIPAddr = $_.IPAddress
  292.                                 # Deletes the A record with the IP address
  293.                                 (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_AType"  |where {$_.IPAddress -like "*$DCIPAddr"}) | remove-wmiObject
  294.                                 # Deletes the A records with the DC name
  295.                                 $_ | remove-wmiObject
  296.                           }
  297.                           # Deletes the NS records
  298.                           (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_NSType"  |where {$_.TextRepresentation -like "*$DCShortName*"})  | remove-wmiObject
  299.                           # Deletes the SRV DNS records  
  300.                           (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_SRVType"  |where {$_.TextRepresentation -like "*$DCShortName*"}) | remove-wmiObject
  301.                           # Deletes the CNAME DNS records  
  302.                           (Get-WmiObject -Namespace "root\MicrosoftDNS" -Class "MicrosoftDNS_CNAMEType"  |where {$_.RecordData -like "*$DCShortName*"})  |remove-wmiObject
  303.    
  304.                           write-host "    $DCShortName"  -fore yellow
  305.                           $DNSCleanupDCs++
  306.                     }
  307.               }
  308.               catch
  309.               {
  310.                     write-host $_ -fore red
  311.                     break
  312.               }
  313.  
  314.               write-host "`n`n"
  315.               $TrustPwdReset="na"  
  316.         }
  317.  
  318.  
  319.     #  Action: Accountcleanup
  320.     #  ----------------------
  321.         if ($action -eq "AccountCleanup")
  322.         {
  323.               if(!(test-path .\DCList.txt))
  324.               {
  325.                     write-host "File DCList.txt not found, please select action ListDCs to create the file`n" -fore red
  326.                     stop-transcript
  327.                     exit
  328.               }
  329.  
  330.               # Lists the DCs that will be kept and make sure not all of them will be removed
  331.               $KeptDCs=ListKeptDCs
  332.               if (!($KeptDCs))
  333.               {
  334.                     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
  335.                     write-host "Please make sure you removed the DCs you want to keep from DCList.txt`n" -fore red
  336.                     stop-transcript
  337.                     exit
  338.               }
  339.        
  340.               # Prompts the user to proceed
  341.               write-host "`nWe are now ready to delete the computer account of ALL other DCs of the forest."
  342.               write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
  343.               write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
  344.               write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
  345.               $rep=""
  346.               while (!($rep -eq "Account Cleanup"))
  347.               {
  348.                     if ($rep -eq "q")
  349.                     {
  350.                          stop-transcript    
  351.                          exit
  352.                     }
  353.                     else
  354.                     {    
  355.                          $rep=read-host("`nPlease enter `"Account Cleanup`" to delete the computer account of other DCs or `"q`" to quit")
  356.                     }
  357.               }
  358.              
  359.               # Deletes the computer accounts and their child objects
  360.               $DCList = get-content DCList.txt
  361.               write-host "`nDeleting computer account of the following DCs:"
  362.               foreach ($DCName in $DCList) {
  363.                     $DCShortName = ($DCName.split(",")[0]).split("cn=")[1]                    
  364.                     $ldapQuery = "(&(cn=$DCShortName))"                       # We need to perform a LDAP query since the computer account might be in a sub OU
  365.                     $ObjAD = new-object System.DirectoryServices.DirectoryEntry
  366.                     $ADSearcher = new-object system.directoryservices.directorysearcher –argumentlist $ObjAD,$ldapQuery
  367.                     $Root = New-Object DirectoryServices.DirectoryEntry "LDAP://OU=Domain Controllers,$CurrentDomain"
  368.                     $ADSearcher.SearchRoot = $Root
  369.                    
  370.                     try
  371.                     {
  372.                           $QueryResult = $ADSearcher.findall()
  373.                           if ($QueryResult.count -ne 0)
  374.                           {
  375.                                 [ADSI]$computerAccount = $QueryResult[0].path
  376.                                 $ComputerAccount.psbase.deleteTree()
  377.                                 $ComputerAccount.psbase.commitChanges()
  378.                                 write-host "    $DCShortName deleted"  -fore yellow
  379.                                 $ComputerAccountCleanupDCs++
  380.                           }
  381.                           else
  382.                           {
  383.                                 write-host "    $DCShortName not present in current domain"  -fore yellow
  384.                           }
  385.                          
  386.                     }
  387.                     catch
  388.                     {
  389.                           write-host $_ -fore red
  390.                           break
  391.                     }
  392.  
  393.  
  394.               }
  395.               write-host "`n`n"    
  396.               $TrustPwdReset="na"
  397.         }
  398.  
  399.     #  Action: ResetTrustPwd
  400.     #  ----------------------
  401.         if ($action -eq "ResetTrustPwd")
  402.         {
  403.               # Prompts the user to proceed
  404.               write-host "`nWe are now ready to reset the password of all trusts relationships of domain $CurrentDomain"
  405.               write-host " !!!   This operation should be done ONLY in a test envrironment" -fore red
  406.               write-host " !!!   In a production environment, it will lead to a major outage highly impacting production" -fore red
  407.               write-host " !!!   Only run in production in case of a real disaster recovery" -fore red
  408.               $rep=""
  409.               while (!($rep -eq "Reset Trusts Password"))
  410.               {
  411.                     if ($rep -eq "q")
  412.                     {
  413.                          stop-transcript    
  414.                          exit
  415.                     }
  416.                     else
  417.                     {    
  418.                          $rep=read-host("`nPlease enter `"Reset Trusts Password`" to reset the domain's trust relationships password or `"q`" to quit")
  419.                     }
  420.               }
  421.              
  422.               $TrustPass=read-host "Please enter the trust password" -asSecureString
  423.               $currentDomainFQDN = (Get-Item env:USERDNSDOMAIN).value
  424.                              
  425.               try
  426.               {
  427.                     $trustCollection=[System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain().GetAllTrustRelationships()
  428.                     $trustCollection |
  429.                     foreach {
  430.                           write-host "Resetting password of trust with domain $($_.targetName)" -fore yellow
  431.                           netdom trust $currentDomainFQDN /domain:$($_.targetName) /resetOneSide /passwordT:$TrustPass
  432.                           $TrustPwdReset++
  433.                     }
  434.               }
  435.               catch
  436.               {
  437.                     write-host $_ -fore red
  438.                     break
  439.               }
  440.  
  441.  
  442.               write-host "`n`n"  
  443.               $KeptDCs="na"
  444.         }
  445.      
  446.  
  447.     # Statistics
  448.     # --------------
  449.     Write-Host "`n=================================="
  450.     Write-Host " Statistics:" -fore green
  451.     Write-Host "      DCs Listed: $listedDCs" -fore green
  452.     Write-Host "      DCs metadata cleanup: $removedDCs" -fore green
  453.     Write-Host "      DCs computer account deleted: $ComputerAccountCleanupDCs" -fore green
  454.     Write-Host "      DCs Removed from DNS: $DNSCleanupDCs" -fore green
  455.     Write-Host "      DCs Kept: $KeptDCs" -fore green
  456.     Write-Host "      Trusts password reset: $TrustPwdReset" -fore green
  457.     Write-Host "=================================="
  458.     stop-transcript
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement