Changing the Kerberos password (krbtgt)

Changing the Kerberos password (krbtgt)

11 November 2019 0 By editeur

The KRBTGT account is a default local account that acts as a service account for the Key Distribution Center (KDC) service. This account can not be deleted and the account name can not be changed. The KRBTGT account can not be enabled in Active Directory.

KRBTGT is also the security principal name used by the KDC for a Windows Server domain, as specified by RFC 4120. The KRBTGT account is the entity for the KRBTGT security principal. It is created automatically when a new domain is created.

Windows Server Kerberos authentication is achieved through the use of a special Kerberos Ticket Grant (TGT) ticket encrypted with a symmetric key. This key is derived from the password of the server or service to which access is requested. The TGT password for the KRBTGT account is known only to the Kerberos service. In order to request a session ticket, the TGT must be presented to the KDC. The TGT is sent to the Kerberos client from the KDC.

A single change to the Krbtgt account password has no impact on authentication.

On the other hand, if a second modification is desired, it must be ensured that the first modification has been replicated on all the domain controllers, and that all the TGTs and TGS issued with the old password have expired.

We must therefore count:

(Full replication duration + TGTs expiration + TGS expiration)

By default, the expiration time of TGTs is 10 hours.

kerberos policy

By default, the TGS expiration time is 600 minutes.

kerberos policy

This script will allow you to reset the krbtgt account password and associated keys while minimizing the risk of Kerberos authentication issues caused by the operation.

IMPORTANT NOTE: This script currently supports only English execution.

options:

(1) perform a single reset of the password hash of the krbtgt account and associated keys (it can be run multiple times)

(2) immediately replicate the krbtgt account and its new keys on all write data

(3) verify that all domain controllers have successfully replicated the new keys

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
function Test-Command
{
Param([string]$Command)

Try {Invoke-Expression $Command}
Catch [System.Exception] {If ($Error.FullyQualifiedErrorId -eq 'CommandNotFoundException') {Return $false}}
Return $true
}

function Test-RpcToHost
{
Param([string]$Hostname)

Try {$RpcPingResult = rpcping.exe -s $Hostname -u 9 -a connect} # 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
}

# Check output of RPCPING for success
If ($RpcPingResult -like "*Completed*") {Return (New-Object -TypeName PSObject -Property @{'Success'=$true; 'Message'="$Hostname - RPC connectivity successful."})}

# Check output of RPCPING for exceptions
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."})}
}

function Start-CtmADSingleObjectReplication
{
Param([string]$TargetDC, [string]$SourceDC, [string]$ObjectDN)

Try {$RepAdminResult = repadmin.exe /replsingleobj $TargetDC $SourceDC $ObjectDN} # Attempt REPADMIN

# 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."})}
}

function Confirm-CtmADPasswordIsComplex
{
Param(
[Parameter(Mandatory=$true,ValueFromPipeline=$true)]
[string]
$Pw
)
Process
{
$CriteriaMet = 0
If ($Pw -cmatch '[A-Z]') {$CriteriaMet++}
If ($Pw -cmatch '[a-z]') {$CriteriaMet++}
If ($Pw -match '\d') {$CriteriaMet++}
If ($Pw -match '[\^~!@#$%^&*_+=`|\\(){}\[\]:;"''<>,.?/]') {$CriteriaMet++}
If ($CriteriaMet -lt 3) {Return $false}
If ($Pw.Length -lt 6) {Return $false}
Return $true
}
}

function New-CtmADComplexPassword
{
Param(
[Parameter(Mandatory=$false,ValueFromPipeline=$true)]
[ValidateRange(6,127)]
[Int]
$PwLength=24
)
Process
{
$Iterations = 0
Do
{
If ($Iterations -ge 20)
{
Write-Host "Password generation failed to meet complexity after $Iterations attempts, exiting."
Return $null
}
$Iterations++
$PWBytes = @()
$RNG = New-Object System.Security.Cryptography.RNGCryptoServiceProvider
Do
{
[byte[]]$Byte = [byte]1
$RNG.GetBytes($Byte)
If ($Byte[0] -lt 33 -or $Byte[0] -gt 126) { continue }
$PWBytes += $Byte[0]
}
While
($PWBytes.Count -lt $PwLength)

$Pw = ([char[]]$PWBytes) -join ''
}
Until
(Confirm-CtmADPasswordIsComplex $Pw)
Return $Pw
}
}

function New-CtmADKrbtgtAccountPassword
{
Param([string]$Server)

Try {Set-ADAccountPassword -Identity (Get-ADUser krbtgt -Server $Server).DistinguishedName -Server $Server -Reset -NewPassword (ConvertTo-SecureString ((New-CtmADComplexPassword 32).ToString()) -AsPlainText -Force)}
Catch
{
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.'})}
}
Return (New-Object -TypeName PSObject -Property @{'Success'=$true; 'Message'='Krbtgt key reset successfully.'})
}

<#----------------------------------------------------------------------------------------------------
Initialize
----------------------------------------------------------------------------------------------------#>
#cls

Set-Location (Split-Path $MyInvocation.MyCommand.Path) # Set the path of the script as the working directory

$TimeStamp = Get-Date -Format o | foreach {$_ -replace ":", "."} # Timestamp for logfile

$LogFile = "New-CtmADKrbtgtKeys_$TimeStamp.log" # Logfile

$Status = New-Object -TypeName PSObject # Custom object for status information

<#----------------------------------------------------------------------------------------------------
Display menu options to user
----------------------------------------------------------------------------------------------------#>
$ScriptDescription = @'
This script can be used to perform a single reset of the krbtgt key that is shared by all
writable domain controllers in the domain in which it is run.

This script has 3 modes:
'
@
$Mode1Description = @'
- Le mode 1 est le mode informationnel. Ce mode est sûr à exécuter à tout moment et ne fait aucun changement
à l'
environnement. Il analysera l'environnement et recherchera les problèmes pouvant avoir une incidence sur
l'
exécution réussie du mode 2 ou du mode 3.
'@
$Mode2Description = @'

- Le mode 2 est le mode simulation. Ce mode effectuera toutes les analyses et vérifications incluses
en mode 1. Il lancera également une réplication d'objet unique de l'objet krbtgt à partir de
PDC de l’émulateur PDC vers chaque contrôleur de domaine accessible en écriture. Cette
la réplication ne consiste pas à répliquer les modifications (aucune modification ne sera apportée). Au lieu de cela, cette réplication
est effectuée de sorte que le temps de réplication pour le mode 3 puisse être estimé.
du mode 3.
'@
$Mode3Description = @'

- Le mode 3 est le mode de réinitialisation. Ce mode effectuera toutes les analyses et vérifications incluses
en mode 1. Il effectuera également une réinitialisation unique de la clé krbtgt sur le contrôleur de domaine d'émulateur PDC.
Si la réinitialisation de krbtgt aboutit, un seul objet sera automatiquement lancé.
réplication de krbtgt de l’émulateur DC de PDC vers chaque contrôleur de domaine accessible en écriture qui
est accessible. Une fois la réplication terminée, le temps total d'
impact sera affiché.
Pendant la durée d'impact du mode 3 (estimé dans le mode 2), les impacts suivants peuvent
être observé:
'
@
$Mode3Impact1 = @'
- checs de validation Kerberos PAC: jusqu'
à ce que la nouvelle clé krbtgt soit répliquée sur tous
inscriptibles dans le domaine, les applications qui tentent de valider la validation KDC PAC peuvent
faites l'expérience des échecs de validation KDC PAC. C’est possible quand un client dans une
site accède à une application authentifiée par Kerberos qui se trouve sur un autre site.
Si cette application ne fait pas partie du système d'
exploitation de confiance, elle peut tenter
pour valider le PAC du ticket de service Kerberos du client par rapport au KDC (DC) dans
son site. Si le CD dans son site ne possède pas encore la nouvelle clé krbtgt, ce KDC PAC
la validation échouera. Cela se manifestera probablement au client en tant que
erreurs d'authentification pour cette application. Une fois que tous les pays en développement ont la nouvelle clé krbtgt,
certains clients affectés peuvent récupérer normalement et reprendre leur fonctionnement normalement. Si non,
Le redémarrage du ou des clients affectés résoudra le problème. Ce problème peut ne pas se produire si
la réplication de la nouvelle clé krbtgt est rapide et réussie et aucune application
essayez de valider le KDC PAC contre un contrôleur de domaine désynchronisé pendant cette période.
'
@
$Mode3Impact2 = @'
- Échecs de la demande Kerberos TGS: jusqu'
à ce que la nouvelle clé krbtgt soit répliquée sur tous les droits en écriture.
DC du domaine, un client peut rencontrer des échecs d’authentification Kerberos. C'est
lorsqu'
un client d'un site a obtenu un ticket d'utilisateur Kerberos (TGT) auprès d'un contrôleur de domaine qui a
le nouveau krbtgt, mais tente ensuite d'
obtenir un ticket de service via un TGS
demande contre un contrôleur de domaine dans un site différent. Si ce DC n’a pas aussi le nouveau krbtgt
clé, il ne sera pas en mesure de déchiffrer le TGT du client, ce qui entraînera une TGS
échec de la demande. Cela se manifestera au client en tant qu'authentificateurs d'erreurs.
Cependant, il convient de noter que cet impact est très improbable, car il est très
peu probable qu'un client tente d'obtenir un ticket de service auprès d'un autre contrôleur de domaine
que celle à partir de laquelle leur TGT a été obtenu, en particulier pendant la période relativement courte
durée de l'
impact du mode 3.
'@
$ScriptRecommendation = @'

Il est fortement recommandé d’exécuter le mode 1 en premier, puis le mode 2, puis le mode 3.
'@
$Menu = @'

Dans quel mode souhaitez-vous exécuter le script?

1 --- Mode informationnel (aucune modification apportée; aucune réplication déclenchée)
2 --- Mode simulation (aucune modification apportée, mais la réplication SERA déclenchée à des fins d'estimation)
3 --- Mode de réinitialisation (krbtgt SERA réinitialisé une fois et la réplication sera déclenchée)
0 --- sortie

'
@
$MenuPrompt = '(Entrez 1-3 ou 0 pour sortir)'

Write-Host ''
Write-Host $ScriptDescription
Write-Host -ForegroundColor Green $Mode1Description
Write-Host -ForegroundColor Yellow $Mode2Description
Write-Host -ForegroundColor Red $Mode3Description
Write-Host -ForegroundColor Cyan $Mode3Impact1
Write-Host -ForegroundColor Cyan $Mode3Impact2
Write-Host ''
Write-Host $ScriptRecommendation
Write-Host ''
Write-Host $Menu
Write-Host ''

$Status | Add-Member -MemberType NoteProperty -Name 'ScriptMode' -Value (Read-Host $MenuPrompt)

If (($Status.ScriptMode -lt 1) -or ($Status.ScriptMode -gt 3)) {Write-Host 'Sélection invalide ... sortie'; Exit} # Validate input

<#----------------------------------------------------------------------------------------------------
Perform pre-flight checks
----------------------------------------------------------------------------------------------------#>
Write-Host ' Vérification des prérequis du script...'
$Status | Add-Member -MemberType NoteProperty -Name 'PreFlightPassed' -Value $true
Write-Host ''

Write-Host ' Vérification du module Active Directory Powershell.....' -NoNewline
If (Get-Module -List ActiveDirectory) {Write-Host -ForegroundColor Green 'PASSED'}
Else {$Status.PreFlightPassed = $false; Write-Host -ForegroundColor Red 'FAILED'}

Write-Host ' Vérification du module GroupPolicy Powershell.....' -NoNewline
If (Get-Module -List GroupPolicy) {Write-Host -ForegroundColor Green 'PASSED'}
Else {$Status.PreFlightPassed = $false; Write-Host -ForegroundColor Red 'FAILED'}

Write-Host ' Vérifier si RPCPING.exe est installé et dans le chemin.....' -NoNewline
If (Test-Command rpcping.exe) {Write-Host -ForegroundColor Green 'PASSED'}
Else {$Status.PreFlightPassed = $false; Write-Host -ForegroundColor Red 'FAILED'}

Write-Host ' Vérifier si REPADMIN.exe est installé et dans le chemin.....' -NoNewline
If (Test-Command repadmin.exe) {Write-Host -ForegroundColor Green 'PASSED'}
Else {$Status.PreFlightPassed = $false; Write-Host -ForegroundColor Red 'FAILED'}

Write-Host ''
If ($Status.PreFlightPassed -ne $true) {Write-Host -ForegroundColor Red "Les vérifications avant vol ont échoué... exiting."; Exit}

<#----------------------------------------------------------------------------------------------------
Gather and analyze domain information
----------------------------------------------------------------------------------------------------#>
Write-Host 'Collecte et analyse dinformations sur le domaine cible...'
Import-Module ActiveDirectory
Import-Module GroupPolicy

$TargetDomain = Get-AdDomain | Select Name,DNSRoot,NetBIOSName,DomainMode,PDCEmulator

Write-Host ''
Write-Host ' Domain NetBIOS name: ' -NoNewline; Write-Host -ForegroundColor Cyan $TargetDomain.NetBIOSName
Write-Host ' Domain DNS name: ' -NoNewline; Write-Host -ForegroundColor Cyan $TargetDomain.DNSRoot
Write-Host ' PDC emulator: ' -NoNewline; Write-Host -ForegroundColor Cyan $TargetDomain.PDCEmulator
Write-Host ' DomainMode: ' -NoNewline; Write-Host -ForegroundColor Cyan $TargetDomain.DomainMode
Write-Host ' Checking domain functional mode is ''Windows2008Domain'' or higher.....' -NoNewline

$Status | Add-Member -MemberType NoteProperty -Name 'DomainModePassed' -Value (!(($TargetDomain.DomainMode -eq 'Windows2000Domain') -or ($TargetDomain.DomainMode -eq 'Windows2003InterimDomain') -or ($TargetDomain.DomainMode -eq 'Windows2003Domain')))
If ($Status.DomainModePassed) {Write-Host -ForegroundColor Green 'PASSED'}
Else {Write-Host -ForegroundColor Red 'FAILED'}

Write-Host ''

<#----------------------------------------------------------------------------------------------------
Recueillir et analyser les informations sur les krbtgt et la politique Kerberos
----------------------------------------------------------------------------------------------------#>
Write-Host 'Collecte et analyse des informations de compte krbtgt et de la stratégie Kerberos du domaine...'
Write-Host ''

$Krbtgt = Get-ADUser krbtgt -Properties PasswordLastSet -Server $TargetDomain.PDCEmulator

Try
{
[xml]$gpo = Get-GPOReport -Guid '{31B2F340-016D-11D2-945F-00C04FB984F9}' -ReportType Xml
$MaxTgtLifetimeHrs = (($gpo.gpo.Computer.ExtensionData | Where-Object {$_.name -eq 'Security'}).Extension.ChildNodes | Where-Object {$_.Name -eq 'MaxTicketAge'}).SettingNumber
$MaxClockSkewMins = (($gpo.gpo.Computer.ExtensionData | Where-Object {$_.name -eq 'Security'}).Extension.ChildNodes | Where-Object {$_.Name -eq 'MaxClockSkew'}).SettingNumber
}
Catch
{
Write-Warning 'Impossible de rechercher MaxTicketAge (valeur par défaut 10 heures) et MaxClockSkew (valeur par défaut 5 min) dans lobjet de stratégie de groupe "Stratégie de domaine par défaut"; les valeurs par défaut seront donc utilisées.'
$MaxTgtLifetimeHrs = 10
$MaxClockSkewMins = 5
}

$ExpirationTimeForNMinusOneTickets = (($Krbtgt.PasswordLastSet.AddHours($MaxTgtLifetimeHrs)).AddMinutes($MaxClockSkewMins)).AddMinutes($MaxClockSkewMins) # Doubler le décalage de l'horloge pour tenir compte du biais dans les deux sens

Write-Host ' Compte Krbtgt: ' -NoNewline; Write-Host -ForegroundColor Cyan $Krbtgt.DistinguishedName
Write-Host ' Le mot de passe du compte Krbtgt a été défini pour la dernière fois sur lémulateur PDC: ' -NoNewline; Write-Host -ForegroundColor Cyan $Krbtgt.PasswordLastSet
Write-Host ' Durée de vie maximale de Kerberos pour le ticket utilisateur (durée de vie TGT): ' -NoNewline; Write-Host -ForegroundColor Cyan $MaxTgtLifetimeHrs 'hours'
Write-Host ' Tolérance maximale de Kerberos pour la synchronisation de lhorloge de lordinateur: ' -NoNewline; Write-Host -ForegroundColor Cyan $MaxClockSkewMins 'minutes'
Write-Host ' Vérification de lexpiration de tous les tickets basés sur la clé (N-1) krbtgt précédente.....' -NoNewline

$Status | Add-Member -MemberType NoteProperty -Name 'NMinusOneTicketExpirationPassed' -Value ($ExpirationTimeForNMinusOneTickets -lt [DateTime]::Now)
If ($Status.NMinusOneTicketExpirationPassed) {Write-Host -ForegroundColor Green 'PASSED'}
Else {Write-Host -ForegroundColor Red 'FAILED'}
Write-Host ''

<#----------------------------------------------------------------------------------------------------
Gather and analyze domain controller information
----------------------------------------------------------------------------------------------------#>
Write-Host 'Collecte et analyse dinformations de contrôleur de domaine accessibles en écriture...'
Write-Host ''

$RwDcs = @()

Try {$RwDcs = Get-ADDomainController -Filter {IsReadOnly -eq $false} -Server $TargetDomain.PDCEmulator | Select Name,Hostname,Domain,Site}
Catch {Throw $_}

Write-Host ' Vérification de la connectivité RPC avec les contrôleurs de domaine:'
$Status | Add-Member -MemberType NoteProperty -Name 'RpcToDCsPassed' -Value $true

ForEach ($DC in $RwDcs)
{
Write-Host ' Vérification de la connectivité RPC vers'$DC.Hostname'.....' -NoNewline

$DC | Add-Member -MemberType NoteProperty -Name 'IsPdcEmulator' -Value ($DC.Hostname -eq $TargetDomain.PDCEmulator)
$DC | Add-Member -MemberType NoteProperty -Name 'IsReachableViaRpc' -Value ((Test-RpcToHost $DC.Hostname).Success)

If (!$DC.IsReachableViaRpc) {$Status.RpcToDCsPassed = $false; Write-Host -ForegroundColor Red 'FAILED'}
Else {Write-Host -ForegroundColor Green 'PASSED'}
}

If ($Status.RpcToDCsPassed) {Write-Host -ForegroundColor Green ' Vérifiez la connectivité RPC avec les contrôleurs de domaine en écriture PASSED: tous les contrôleurs de domaine en écriture étaient accessibles.'}
Else {Write-Host -ForegroundColor Red ' Vérifiez la connectivité RPC avec les contrôleurs de domaine accessibles en écriture sur FAILE. Un ou plusieurs contrôleurs de disque inscriptibles étaient inaccessibles.'}
Write-Host ''

<#----------------------------------------------------------------------------------------------------
MODES 2 AND 3 - Replicate krbtgt to all writable DCs that are reachable and generate an impact estimate
----------------------------------------------------------------------------------------------------#>
If ($Status.ScriptMode -gt 1 -and $Status.PreFlightPassed -and $Status.DomainModePassed -and $Status.RpcToDCsPassed)
{
Write-Host 'Réplication de lobjet krbtgt sur tous les contrôleurs de domaine accessibles en écriture et accessibles...'

If ($Status.ScriptMode -eq 2)
{
Write-Host -ForegroundColor Yellow ' La réplication de lobjet krbtgt SERA déclenchée si vous continuez. Êtes-vous sûr de vouloir continuer?'
If (!((Read-Host ' (Entrez '' Y '' pour continuer ou nimporte quelle autre touche pour sortir)').ToUpper() -eq 'Y')) {Write-Host -ForegroundColor Yellow ' La réplication de krbtgt a été ignorée à la demande de l''utilisateur ... sortie'; Exit}
}

$ImpactStartTime = (Get-Date).ToUniversalTime()

########## THIS IS WHERE KRBTGT PASSWORD RESET OCCURS IN MODE 3 ##########

# Replicate krbtgt to appropriate DCs
$Status | Add-Member -MemberType NoteProperty -Name 'ReplicationCheckSucceeded' -Value $true
ForEach ($DC in $RwDcs)
{
If (!$DC.IsPdcEmulator)
{
Write-Host ' Replication of krbtgt from'$TargetDomain.PDCEmulator'to'$DC.Hostname'...' -NoNewline
If ($DC.IsReachableViaRpc)
{
$ReplAttemptStart = (Get-Date).ToUniversalTime()
If ((Start-CtmADSingleObjectReplication $DC.Hostname $TargetDomain.PDCEmulator $Krbtgt.DistinguishedName).Success) {Write-Host -ForegroundColor Green 'SUCCEEDED' -NoNewline}
Else {$Status.ReplicationCheckSucceeded = $false; Write-Host -ForegroundColor Red 'FAILED' -NoNewline}
$ReplElapsedTime = ((Get-Date).ToUniversalTime() - $ReplAttemptStart)
Write-Host -ForegroundColor Cyan ' Time:'$ReplElapsedTime
}
Else {Write-Host -ForegroundColor Yellow 'SKIPPED'}
}
}
$TotalImpactTime = (Get-Date).ToUniversalTime() - $ImpactStartTime
Write-Host ''
$Status | Add-Member -MemberType NoteProperty -Name 'ImpactDurationEstimate' -Value $TotalImpactTime

If ($Status.ReplicationCheckSucceeded) {Write-Host -ForegroundColor Cyan 'La durée totale de l’'impact lors de l'’exécution du mode 3 sera approximativement de:' $TotalImpactTime}
Else {Write-Host -ForegroundColor Red 'La réplication d''objet unique a échoué sur un ou plusieurs contrôleurs de domaine accessibles en écriture. Tous les échecs doivent être corrigés avant de tenter le mode 3.'}
}

<#----------------------------------------------------------------------------------------------------
MODE 3 ONLY - Reset the krbtgt key and replicate to all writable DCs that are reachable
----------------------------------------------------------------------------------------------------#>
If ($Status.ScriptMode -eq 3 -and $Status.PreFlightPassed -and $Status.DomainModePassed -and $Status.RpcToDCsPassed -and $Status.ReplicationCheckSucceeded)
{
Write-Host 'Réinitialisation de la clé krbtgt et réplication de l''objet krbtgt sur tous les contrôleurs de domaine accessibles...'
Write-Host ''

Write-Host -ForegroundColor Red ' ATTENTION!!! La clé krbtgt SERA réinitialisée ET la réplication d''objet krbtgt SERA déclenchée si vous continuez. Êtes-vous sûr de vouloir continuer?'
Write-Host -ForegroundColor Red ' Si vous continuez, la durée d''impact du mode 3 (décrit ci-dessus) commencera et ne se terminera pas tant que tous les DC n''auront pas obtenu la nouvelle clé krbtgt.'
If (!((Read-Host ' (Entrez ''Y'' pour continuer ou n''importe quelle autre touche pour sortir)').ToUpper() -eq 'Y')) {Write-Host -ForegroundColor Yellow ' La krbtgt la réinitialisation et la réplication a été sautée à la demande de l' 'utilisateur ... sortie'; Exit}
Write-Host ''

If (!$Status.NMinusOneTicketExpirationPassed)
{
Write-Host -ForegroundColor Red ' La dernière modification de la clé krbtgt pour ce domaine a eu lieu: ' -NoNewline; Write-Host -ForegroundColor Cyan $Krbtgt.PasswordLastSet 'according to'$TargetDomain.PDCEmulator
Write-Host -ForegroundColor Red ' et la stratégie Kerberos du domaine est configurée avec une durée de vie de ticket d''utilisateur maximale (TGT) de '-NoNewline; Write-Host -ForegroundColor Cyan $MaxTgtLifetimeHrs 'hours'
Write-Host -ForegroundColor Red ' et une tolérance maximale pour la synchronisation d''horloge de l''ordinateur ' -NoNewline; Write-Host -ForegroundColor Cyan $MaxClockSkewMins 'minutes'
Write-Host -ForegroundColor Red ' Cela signifie que si vous réinitialisez la clé krbtgt avant ' -NoNewline; Write-Host -ForegroundColor Cyan $ExpirationTimeForNMinusOneTickets
Write-Host -ForegroundColor Red ' Un impact majeur est très probable. Êtes-vous sûr de vouloir continuer?'
If (!((Read-Host ' (Entrez ''Y'' pour continuer ou toute autre touche pour sortir)').ToUpper() -eq 'Y')) {Write-Host -ForegroundColor Yellow ' La réinitialisation de krbtgt et la réplication ont été ignorées à la demande de l''utilisateur...sortie'; Exit}
Write-Host ''
}

$ImpactStartTime = (Get-Date).ToUniversalTime() # Record start time

# Réinitialiser le mot de passe krbtgt
Write-Host -ForegroundColor Cyan ' Resetting krbtgt key.....' -NoNewline
$Status | Add-Member -MemberType NoteProperty -Name 'ResetSucceeded' -Value (New-CtmADKrbtgtAccountPassword $TargetDomain.PDCEmulator).Success
If ($Status.ResetSucceeded) {Write-Host -ForegroundColor Green 'SUCCEEDED'}
Else {Write-Host -ForegroundColor Red 'FAILED'; Write-Host -ForegroundColor Red ' Krbtgt reset a échoué. Vérifiez que vous disposez des droits suffisants pour réinitialiser le compte krbtgt. La réplication sera ignorée'}
Write-Host ''

# Répliquer krbtgt sur les DC appropriés
If ($Status.ResetSucceeded)
{
$Status | Add-Member -MemberType NoteProperty -Name 'PostResetReplicationSucceeded' -Value $true
ForEach ($DC in $RwDcs)
{
If (!$DC.IsPdcEmulator)
{
Write-Host ' Réplication de krbtgt à partir de'$TargetDomain.PDCEmulator'to'$DC.Hostname'...' -NoNewline
If ($DC.IsReachableViaRpc)
{
$ReplAttemptStart = (Get-Date).ToUniversalTime()
If ((Start-CtmADSingleObjectReplication $DC.Hostname $TargetDomain.PDCEmulator $Krbtgt.DistinguishedName).Success) {Write-Host -ForegroundColor Green 'SUCCEEDED' -NoNewline}
Else {$Status.PostResetReplicationSucceeded = $false; Write-Host -ForegroundColor Red 'FAILED' -NoNewline}
$ReplElapsedTime = ((Get-Date).ToUniversalTime() - $ReplAttemptStart)
Write-Host -ForegroundColor Cyan ' Time:'$ReplElapsedTime
}
Else {Write-Host -ForegroundColor Yellow 'SKIPPED'}
}
}
$TotalImpactTime = (Get-Date).ToUniversalTime() - $ImpactStartTime
$Status | Add-Member -MemberType NoteProperty -Name 'ImpactDuration' -Value $TotalImpactTime

If ($Status.PostResetReplicationSucceeded) {Write-Host -ForegroundColor Cyan 'La durée totale de l''impact lors de l''exécution du mode 3 était de:' $TotalImpactTime}
Else {Write-Host -ForegroundColor Red 'La réplication d''objet unique a échoué sur un ou plusieurs contrôleurs de domaine accessibles en écriture.'}
Write-Host ''

# Validez que le dernier mot de passe krbtgt est synchronisé avec l'émulateur PDC
Write-Host ' La validation du dernier mot de passe krbtgt est synchronisée avec l''émulateur PDC ...'
$Status | Add-Member -MemberType NoteProperty -Name 'NewKrbtgtKeyReplValidationPassed' -Value $true
$KrbtgtKeyLastSetOnPdc = (Get-ADUser krbtgt -Properties PasswordLastSet -Server $TargetDomain.PDCEmulator).PasswordLastSet
Write-Host ' PDC émulateur: Le mot de passe du compte Krbtgt a été défini pour la dernière fois sur'$TargetDomain.PDCEmulator'.....' -NoNewline; Write-Host -ForegroundColor Cyan $KrbtgtKeyLastSetOnPdc
ForEach ($DC in $RwDcs)
{
If (!$DC.IsPdcEmulator)
{
Write-Host ' Vérification du dernier mot de passe du compte krbtgt activé '$DC.Hostname'.....' -NoNewline
If (!$DC.IsReachableViaRpc) {Write-Host -ForegroundColor Yellow "SKIPPED"}
Else
{
$CouldConnect = $true
Try {$KrbtgtKeyLastSetOnThisDc = (Get-ADUser krbtgt -Properties PasswordLastSet -Server $DC.Hostname).PasswordLastSet}
Catch
{If ($Error.FullyQualifiedErrorId -eq 'ActiveDirectoryServer:0,Microsoft.ActiveDirectory.Management.Commands.GetADUser') {$CouldConnect = $false}}
If ($CouldConnect)
{
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 (n'a pas pu se connecter au serveur)"}
}
}
}
}
Write-Host ''
If (!$Status.NewKrbtgtKeyReplValidationPassed) {Write-Host -ForegroundColor Red ' Vérifiez si la clé krbtgt de tous les contrôleurs de domaine inscriptibles était synchronisée avec l’'émulateur PDC FAILED. Un ou plusieurs contrôleurs d''accès accessibles n''étaient pas synchronisés avec l''émulateur PDC.'}
Else {Write-Host -ForegroundColor Green '
Vérifiez si la clé krbtgt de tous les contrôleurs de domaine accessibles en écriture était synchronisée avec l''émulateur PDC PASSED. Tous les contrôleurs accessibles étaient synchronisés avec l''émulateur PDC.'}
Write-Host '
'
}

If ((!$Status.PreFlightPassed -or !$Status.DomainModePassed -or !$Status.RpcToDCsPassed) -or ($Status.ScriptMode -gt 1 -and !$Status.ReplicationCheckSucceeded))
{Write-Host -ForegroundColor Red '
Un ou plusieurs éléments ont échoué. Résoudre les échecs et réessayer.'}

# Log status data
$Status | Out-File -FilePath $LogFile -Append
Write-Host "Connecté au fichier: $LogFile"