Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- <# ==============================================================================================================================================
- 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
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement