ericcsinger / ericcsinger.github.io

1 stars 0 forks source link

PowerShell: Remove a failed domain controller - Eric's Blog #1

Open utterances-bot opened 3 years ago

utterances-bot commented 3 years ago

PowerShell: Remove a failed domain controller | Eric C. Singers Blog

Just another IT blog

https://ericcsinger.com/PowerShell-Remove-a-failed-domain-controller

davidmi711 commented 1 year ago

This article saved me hours of work. Thank you for posting this! I did however add the below code to the DNS cleanup as the current code did not remove the NS entries:

{$_ -eq "NS"} { If ($Record.RecordData.NameServer -like "$($AD_DC_Name_To_Remove)") { Write-Host "Removing DNS record" -ForegroundColor Yellow $Record $Record | Remove-DnsServerResourceRecord -ZoneName $ZoneName -ComputerName $($env:ComputerName) -Confirm:$false -Force } ;break }

ericcsinger commented 1 year ago

Glad I could help!

I added your suggestion to the blog post for others as well. Good catch

mickdubs commented 1 year ago

Forgive me for being noob but why am i getting an error for #GettingtheForest

mickdubs commented 1 year ago

The error im getting for #GettingtheForest is

Get-ADForest : Cannot validate argument on parameter 'Identity'. The argument is null. Provide a valid value for the argument, and then try running the command again. At line:31 char:34

Sorry for mutiple post

ericcsinger commented 1 year ago

Hi,

It seems like you may have forgotten to fill in all the parameters.

Check out the parameters section of this page.

kaedeleo1 commented 1 year ago

Hi,Eric "$Forest_Fully_Qualified_Domain_Name = "Forest.com" Does the variable "$Forest_Fully_Qualified_Domain_Name" need to modify as "$Forest_Domain_Name" ? Otherwise I get the same error as @mickdubs .

ericcsinger commented 1 year ago

It's been a while since i've had to use this. It looks like I may have some values out of order. I'll need to lab this up to know for sure. That said, The idea here is to dynamically populate the variables. If you know the answers, then you can hard code them to get around it.

kaedeleo1 commented 1 year ago

Thanks, Eric. This is a huge help here. I have made some changes to adapt to my lab. I will post later, tomorrow maybe, and it works like a charm with 0 error. Great script anyway.

kaedeleo1 commented 1 year ago

https://kaedeleo.top/f84c4b07-6c48-4228-bd0c-4aa6179d67fc

Hi, Eric, I've add the $ip variable to compelte the DNSRecord cleaning process.

$ip="10.1.1.57"

Hi, Eric, I've modified the cmdlet here with "foreach" cause the original version of the code not work properly.

If ($All_Roles_To_Move_Count -gt 0) { foreach ($role in $All_Roles_To_Move ) { Move-ADDirectoryServerOperationMasterRole -Identity $AD_DC_Replacement_Name -OperationMasterRole $role -Force -confirm:$false } }


I will delete the article later on my blog. Thanks a lot!

Protheophage commented 3 weeks ago

I know this post is super old, but I wanted to say thanks. It saved me a massive amount of time by providing the bulk of a function I was creating. To say thanks I wanted to share that function as well as two other functions I had previously created for moving fsmo, and cleaning out DNS. Hope these help someone

Protheophage commented 3 weeks ago

Function Invoke-MetaDataCleanup{ <# .SYNOPSIS Removes a Domain Controller from Active Directory

.DESCRIPTION
Performs a complete metadata cleanup of a domain controller.
Make sure to seize any roles

.PARAMETER DcToRemove

.EXAMPLE
Remove-DCFromAD -DcToRemove DC01
Performs a metadata cleanup of DC01

#>
[CmdletBinding()]
param(
    $DcToRemove
)
Begin {
    #Gather Domain info
    $FullyQualifiedDomainName = (Get-ADDomain).DNSRoot
    $DomainDistinguishedName = (Get-ADDomain).DistinguishedName

    #Get all AD Sites
    $AllADSites = Get-ADReplicationSite -Filter "*"

    #Formulate the FQDN of the DC
    #$DCToRemoveFQDN = "$($ADDCNameToRemove).$($FullyQualifiedDomainName)"
}
Process {
    :AllADSites Foreach ($AdSite in $AllADSites) {
        Write-Host "Working on site $($AdSite.Name)"

        Write-Host "Checking if site $($AdSite.Name) contains $($DcToRemove)"
        $DC_In_Site = $null
        $DC_In_Site = Get-ADObject -Identity "cn=$($DcToRemove),cn=servers,$($AdSite.DistinguishedName)" -Partition "CN=Configuration,$($DomainDistinguishedName)" -Properties * -ErrorAction SilentlyContinue

        If ($null -ne $DC_In_Site) {
            Write-Host "Site $($AdSite.Name) contains $($DcToRemove)" -ForegroundColor Cyan
            $StandardOut = New-TemporaryFile
            $ErrorOut = New-TemporaryFile

            Write-Host "Attempting to cleanup NTDS for $($DcToRemove)" -ForegroundColor Yellow
            $NTDS = $null
            $NTDS = Start-process -FilePath ntdsutil -argumentList """metadata cleanup"" ""remove selected server cn=$($DcToRemove),cn=servers,$($AdSite.DistinguishedName)"" q q" -wait -nonewwindow -RedirectStandardOutput $StandardOut.FullName -RedirectStandardError $ErrorOut -PassThru

            Get-Content -Path $StandardOut -Raw
            Remove-Item -Path $StandardOut -Confirm:$false -Force

            If ($NTDS.ExitCode -gt 0){
                Get-Content -Path $ErrorOut -Raw
                Remove-Item -Path $ErrorOut -Confirm:$false -Force
                Throw "NTDS exit code was $($NTDS.ExitCode)"
            }

            Write-Host "Cleaned up NTDS for $($DcToRemove)" -ForegroundColor Green

            Write-Host "Attempting to cleanup site object for $($DcToRemove)" -ForegroundColor Yellow
            $DC_In_Site = Get-ADObject -Identity "cn=$($DcToRemove),cn=servers,$($AdSite.DistinguishedName)" -Partition "CN=Configuration,$($DomainDistinguishedName)" -Properties * -ErrorAction SilentlyContinue
            $DC_In_Site | Remove-ADObject -Recursive -Confirm:$false
            Write-Host "Cleaned up site object for $($DcToRemove)" -ForegroundColor Green

            Write-Host "Attempting to cleanup other AD objects with this DC name" -ForegroundColor Yellow
            $All_AD_Objects = Get-ADObject -Filter "*" 
            Foreach ($AD_Object in $All_AD_Objects) {
                If ($AD_Object.DistinguishedName -like "*$($DcToRemove)*") {
                    Write-Host "Attempting to remove AD object $($AD_Object.DistinguishedName)" -ForegroundColor Yellow
                    $AD_Object | Remove-ADObject -Recursive -Confirm:$false 
                    Write-Host "Removed AD object $($AD_Object.DistinguishedName)" -ForegroundColor Green
                }
            }
            break AllADSites
        }    
    }
}

}

Protheophage commented 3 weeks ago

Function Purge-DNSEntries { <# .SYNOPSIS Purge DNS of stale entries

.DESCRIPTION
Finds all DNS Zones. Then searches for all entries that contain the string provided and purges them.  This searches this searches Hostname and Data fields. It also removes all name servers with the string in the name.

.PARAMETER PurgeThis

.EXAMPLE
Purge-DNSEntries -PurgeThis "DC-01"
Finds and removes all entries containing DC-01

#>
[CmdletBinding()]
Param
(
    [parameter(ValueFromPipeline=$True)]
    [String]$PurgeThis
)

PROCESS
{
    $DNSZones = Get-dnsServerZone

    ForEach ($Zone in $DNSZones)
    {
        $records = Get-DnsServerResourceRecord -ZoneName $Zone.ZoneName | Where-Object {
        $_.HostName -match "$PurgeThis" -or
        $_.RecordData.PtrDomainName -match "$PurgeThis" -or
        $_.RecordData.NameServer -match "$PurgeThis"
        }

        foreach ($record in $records) {
                # Remove the resource record
                Remove-DnsServerResourceRecord -ZoneName $zone.ZoneName -InputObject $record -Force
                Write-Host "Removed record with Hostname: $($record.hostname) and Data: $($record.RecordData.NameServer) from zone: $($zone.ZoneName)"
            } 
    }

    Write-Host "Completed removal of all instances of $PurgeThis."
}

}

Protheophage commented 3 weeks ago

function Move-FSMO { <# .SYNOPSIS Moves FSMO roles to selected computer

.DESCRIPTION
Moves FSMO roles to selected computer

.PARAMETER DestDir

.EXAMPLE
Move-FSMO
Moves all the FSMO roles to the computer the command is being executed on

.EXAMPLE
Move-FSMO -DestServer DC02
Moves all FSMO roles to DC02

.EXAMPLE
Move-FSMO -DestServer DC02 -Force
Seizes all FSMO roles to DC02
#>

[CmdletBinding()]
Param (
[string]$DestServer
)
Begin {
    if ([string]::isnullorempty($DestServer)) {
        $DestServer = hostname
    }
}
Process {
    Move-ADDirectoryServerOperationMasterRole -Identity $DestServer -OperationMasterRole DomainNamingMaster,InfrastructureMaster,PDCEmulator,RIDMaster,SchemaMaster
}

}

Protheophage commented 3 weeks ago

Oops posted and old version of move fsmo. Can't see a way to delete my last post.

function Move-FSMO { <# .SYNOPSIS Moves FSMO roles to selected computer

.DESCRIPTION
Moves FSMO roles to selected computer

.PARAMETER DestDir
.PARAMETER Force

.EXAMPLE
Move-FSMO
Moves all the FSMO roles to the computer the command is being executed on

.EXAMPLE
Move-FSMO -DestServer DC02
Moves all FSMO roles to DC02

.EXAMPLE
Move-FSMO -DestServer DC02 -Force
Seizes all FSMO roles to DC02
#>

[CmdletBinding()]
Param (
[string]$DestServer
[switch]$Force
)
Begin {
    if ([string]::isnullorempty($DestServer)) {
        $DestServer = hostname
    }
}
Process {
    If(!($Force)){
        Move-ADDirectoryServerOperationMasterRole -Identity $DestServer -OperationMasterRole DomainNamingMaster,InfrastructureMaster,PDCEmulator,RIDMaster,SchemaMaster
    }
    Else{
        Move-ADDirectoryServerOperationMasterRole -Identity $DestServer -OperationMasterRole DomainNamingMaster,InfrastructureMaster,PDCEmulator,RIDMaster,SchemaMaster -Force
    }
}
End {
    $FSMO = New-Object PSObject -Property @{
        SchemaMaster = (Get-ADForest).SchemaMaster
        DomainNamingMaster = (Get-ADForest).DomainNamingMaster
        PDCEmulator = (Get-ADDomain).PDCEmulator
        RIDMaster = (Get-ADDomain).RIDMaster
        InfrastructureMaster = (Get-ADDomain).InfrastructureMaster
    }
    $FSMO
    Return $FSMO
}

}

ericcsinger commented 2 weeks ago

You are welcome Protheophage, glad it helped!