You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Try {$RpcPingResult=rpcping.exe-s $Hostname} # Attempt to RPCPING the target host
# Check for RPCPING.exe command and execution errors
Catch [System.Exception]
{
If ($Error.FullyQualifiedErrorId-eq'CommandNotFoundException') {Write-Host-ForegroundColor Red "The 'RPCPING.exe' utility is not available. Install it and/or add its location to the path and retry... exiting."; Exit}
Write-Host-ForegroundColor Red "An unknown error occurred when attempting to execute 'RPCPING.exe'... exiting."; Exit
If ($RpcPingResult-like"*Exception 5*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'="$Hostname - Access is denied. Ensure your credentials have the required rights on the target host."})}
If ($RpcPingResult-like"*Exception 1722*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'="$Hostname - RPC server unavailable. Check firewall rules and name resolution for the target host."})}
If ($RpcPingResult-like"*Exception*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'="$Hostname - RPC to the target host failed for an unknown reason."})}
# Check for REPADMIN.exe command and execution errors
Catch [System.Exception]
{
If ($Error.FullyQualifiedErrorId-eq'CommandNotFoundException') {Write-Host-ForegroundColor Red "The 'REPADMIN.exe' utility is not available. Install it and/or add its location to the path and retry... exiting."; Exit}
Write-Host-ForegroundColor Red "An unknown error occurred when attempting to execute 'REPADMIN.exe'... exiting."; Exit
}
# Check output of REPADMIN for success
If ($RepAdminResult-like"*Successfully replicated object*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$true; 'Message'="$ObjectDN - Successfully replicated from $SourceDC to $TargetDC."})}
# Check output of REPADMIN for exceptions
If ($RepAdminResult-like"*Exception 5*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'="$ObjectDN - $SourceDC access is denied. Ensure your credentials have the required rights on the target host."})}
If ($RepAdminResult-like"*Exception 1722*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'="$ObjectDN - $SourceDC server unavailable. Check firewall rules and name resolution for the target host."})}
If ($RepAdminResult-like"*Exception*") {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'="$ObjectDN - Failed to replicate from $SourceDC to $TargetDC for an unknown reason."})}
}
functionShuffle-Array
{
Param([Array] $a)
$rnd=(New-Object System.Random)
For($i=0;$i-lt$a.Length;$i+=1)
{
$newpos=$i+$rnd.Next($a.Length-$i);
$tmp=$a[$i];
$a[$i]=$a[$newpos];
$a[$newpos]=$tmp
}
Return$a
}
functionNew-ComplexPassword
{
Param([string]$Username, [int]$PasswordLength)
# Keep the password length within bounds
If ($PasswordLength-lt8) {$PasswordLength=8}
If ($PasswordLength-gt28) {$PasswordLength=28}
# Define base characters for complex password and avoid ambiguous characters like I,i,1,L,l,O,o,0, etc.
If (($Error.FullyQualifiedErrorId-eq'ActiveDirectoryCmdlet:System.UnauthorizedAccessException,Microsoft.ActiveDirectory.Management.Commands.SetADAccountPassword') -and ($Error.CategoryInfo-like"*PermissionDenied*"))
{Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'='Krbtgt key reset failed due to insufficient permissions.'})}
Else {Return (New-Object-TypeName PSObject -Property @{'Success'=$false; 'Message'='Krbtgt key reset failed for an unknown reason.'})}
$ExpirationTimeForNMinusOneTickets= (($Krbtgt.PasswordLastSet.AddHours($MaxTgtLifetimeHrs)).AddMinutes($MaxClockSkewMins)).AddMinutes($MaxClockSkewMins) # Doubling the clock skew to account for skew in both directions
If (!$DC.IsReachableViaRpc) {$Status.RpcToDCsPassed=$false; Write-Host-ForegroundColor Red 'FAILED'}
Else {Write-Host-ForegroundColor Green 'PASSED'}
}
If ($Status.RpcToDCsPassed) {Write-Host-ForegroundColor Green ' Check for RPC connectivity to writable domain controllers PASSED: All writable DCs were reachable.'}
Else {Write-Host-ForegroundColor Red ' Check for RPC connectivity to writable domain controllers FAILED. One or more writable DCs was unreachable.'}
If ($Status.ScriptMode-gt1-and$Status.PreFlightPassed-and$Status.DomainModePassed-and$Status.RpcToDCsPassed)
{
Write-Host'Replicating krbtgt object to all writable domain controllers that are reachable...'
If ($Status.ScriptMode-eq2)
{
Write-Host-ForegroundColor Yellow ' The krbtgt object replication WILL BE triggered if you proceed. Are you sure you wish to proceed?'
If (!((Read-Host' (Enter ''Y'' to proceed or any other key to exit)').ToUpper() -eq'Y')) {Write-Host-ForegroundColor Yellow ' Replication of krbtgt was skipped at the user''s request...exiting'; Exit}
}
$ImpactStartTime= (Get-Date).ToUniversalTime()
########## THIS IS WHERE KRBTGT PASSWORD RESET OCCURS IN MODE 3 ##########
Write-Host' Replication of krbtgt from'$TargetDomain.PDCEmulator'to'$DC.Hostname'...'-NoNewline
If ($DC.IsReachableViaRpc)
{
$ReplAttemptStart= (Get-Date).ToUniversalTime()
If ((Replicate-ADSingleObject $DC.Hostname$TargetDomain.PDCEmulator$Krbtgt.DistinguishedName).Success) {Write-Host-ForegroundColor Green 'SUCCEEDED'-NoNewline}
Else {$Status.ReplicationCheckSucceeded=$false; Write-Host-ForegroundColor Red 'FAILED'-NoNewline}
If ($Status.ReplicationCheckSucceeded) {Write-Host-ForegroundColor Cyan 'The total duration of impact when running Mode 3 will be approximately:'$TotalImpactTime}
Else {Write-Host-ForegroundColor Red 'Single object replication failed to one or more writable domain controllers. All failures should be remediated before attempting Mode 3.'}
If ($Status.ScriptMode-eq3-and$Status.PreFlightPassed-and$Status.DomainModePassed-and$Status.RpcToDCsPassed-and$Status.ReplicationCheckSucceeded)
{
Write-Host'Resetting krbtgt key and replicating krbtgt object to all reachable domain controllers...'
Write-Host''
Write-Host-ForegroundColor Red ' WARNING!!! The krbtgt key WILL BE reset AND krbtgt object replication WILL BE triggered if you proceed. Are you sure you wish to proceed?'
Write-Host-ForegroundColor Red ' If you proceed, the impact duration of Mode 3 (described above) will begin and not end until all DCs obtained the new krbtgt key.'
If (!((Read-Host' (Enter ''Y'' to proceed or any other key to exit)').ToUpper() -eq'Y')) {Write-Host-ForegroundColor Yellow ' The krbtgt reset and replication was skipped at the user''s request...exiting'; Exit}
Write-Host''
If (!$Status.NMinusOneTicketExpirationPassed)
{
Write-Host-ForegroundColor Red ' The last change of the krbtgt key for this domain occurred: '-NoNewline; Write-Host-ForegroundColor Cyan $Krbtgt.PasswordLastSet'according to'$TargetDomain.PDCEmulator
Write-Host-ForegroundColor Red ' and the domain Kerberos policy is configured with a maximum user ticket (TGT) lifetime of '-NoNewline; Write-Host-ForegroundColor Cyan $MaxTgtLifetimeHrs'hours'
Write-Host-ForegroundColor Red ' and a maximum tolerance for computer clock synchronization of '-NoNewline; Write-Host-ForegroundColor Cyan $MaxClockSkewMins'minutes'
Write-Host-ForegroundColor Red ' That means that if you reset the krbtgt key again before '-NoNewline; Write-Host-ForegroundColor Cyan $ExpirationTimeForNMinusOneTickets
Write-Host-ForegroundColor Red ' A major impact is very likely. Are you sure you wish to proceed?'
If (!((Read-Host' (Enter ''Y'' to proceed or any other key to exit)').ToUpper() -eq'Y')) {Write-Host-ForegroundColor Yellow ' The krbtgt reset and replication was skipped at the user''s request...exiting'; Exit}
Write-Host''
}
$ImpactStartTime= (Get-Date).ToUniversalTime() # Record start time
If ($Status.ResetSucceeded) {Write-Host-ForegroundColor Green 'SUCCEEDED'}
Else {Write-Host-ForegroundColor Red 'FAILED'; Write-Host-ForegroundColor Red ' Krbtgt reset failed. Check to ensure you have sufficient rights to reset the krbtgt account. Replication will be skipped'}
Write-Host' Replication of krbtgt from'$TargetDomain.PDCEmulator'to'$DC.Hostname'...'-NoNewline
If ($DC.IsReachableViaRpc)
{
$ReplAttemptStart= (Get-Date).ToUniversalTime()
If ((Replicate-ADSingleObject $DC.Hostname$TargetDomain.PDCEmulator$Krbtgt.DistinguishedName).Success) {Write-Host-ForegroundColor Green 'SUCCEEDED'-NoNewline}
Else {$Status.PostResetReplicationSucceeded=$false; Write-Host-ForegroundColor Red 'FAILED'-NoNewline}
If ($KrbtgtKeyLastSetOnThisDc-ne$KrbtgtKeyLastSetOnPdc) {Write-Host-ForegroundColor Red "FAILED"-NoNewline; $Status.NewKrbtgtKeyReplValidationPassed=$false}
Else {Write-Host-ForegroundColor Green "PASSED"-NoNewline}
Write-Host-ForegroundColor Cyan ' Last set:'$KrbtgtKeyLastSetOnThisDc
}
Else {Write-Host-ForegroundColor Yellow "SKIPPED (could not connect to server)"}
}
}
}
}
Write-Host''
If (!$Status.NewKrbtgtKeyReplValidationPassed) {Write-Host-ForegroundColor Red ' Check if krbtgt key on all writable domain controllers was in sync with PDC emulator FAILED. One or more reachable DCs was out of sync with the PDC emulator.'}
Else {Write-Host-ForegroundColor Green ' Check if krbtgt key on all writable domain controllers was in sync with PDC emulator PASSED. All reachable DCs were in sync with the PDC emulator..'}
Write-Host''
}
If ((!$Status.PreFlightPassed-or!$Status.DomainModePassed-or!$Status.RpcToDCsPassed) -or ($Status.ScriptMode-gt1-and!$Status.ReplicationCheckSucceeded))
{Write-Host-ForegroundColor Red 'One or more items failed. Resolve failures and retry.'}