358 lines
18 KiB
Markdown
358 lines
18 KiB
Markdown
---
|
|
external help file: DSInternals.PowerShell.dll-Help.xml
|
|
Module Name: DSInternals
|
|
online version: https://github.com/MichaelGrafnetter/DSInternals/blob/master/Documentation/PowerShell/New-ADDBRestoreFromMediaScript.md
|
|
schema: 2.0.0
|
|
---
|
|
|
|
# New-ADDBRestoreFromMediaScript
|
|
|
|
## SYNOPSIS
|
|
Generates a PowerShell script that can be used to restore a domain controller from an IFM-equivalent backup (i.e. ntds.dit + SYSVOL).
|
|
|
|
## SYNTAX
|
|
|
|
```
|
|
New-ADDBRestoreFromMediaScript [-BootKey <Byte[]>] [-SysvolPath <String>]
|
|
-SafeModeAdministratorPassword <SecureString> -DatabasePath <String> [-LogPath <String>] [<CommonParameters>]
|
|
```
|
|
|
|
## DESCRIPTION
|
|
The New-ADDBRestoreFromMediaScript cmdlet was created to save the day under certain specific circumstances. Imagine a company that had been attacked by some ransomware to the extent that all their domain controllers have been wiped. Moreover, no proper System State backups of DCs are available, only file-level ones. As a consequence, they are not able to restore Active Directory, the time is ticking and their only option seems to be reinstalling the entire AD forest from scratch. It might be hard to believe that someone would have violated all the best practices and neglected planning for disaster recovery, but, alas, such situations have occurred in large enterprises during the 2017 NotPetya outbreak. I have therefore come up with a domain controller recovery method that I call Restore from Media (RFM). As already hinted, this method can be used to restore domain controllers from file-level backups.
|
|
|
|
Unlike the [Install from Media (IFM)](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc816722(v=ws.10)) method, the Restore from Media method does not require network connectivity to a live writable domain controller. Nevertheless, the same installation source ([IFM backup](https://docs.microsoft.com/en-us/previous-versions/windows/it-pro/windows-server-2008-R2-and-2008/cc816574(v=ws.10)) with SYSVOL) can be used with both methods of DC installation.
|
|
|
|
To perform the Restore from Media operation, you need to have the following:
|
|
|
|
- A full Install from Media (IFM) backup of a domain controller or equivalent file-level backup. The backup must contain these files:
|
|
|
|
- Domain database file (ntds.dit)
|
|
|
|
- SYSTEM registry hive or a corresponding Boot Key / SysKey
|
|
|
|
- SYSVOL directory
|
|
|
|
- A freshly installed Windows Server of the same version as the domain controller originally running the database that is to be restored. This information can be retrieved from the corresponding ntds.dit file using the [Get-ADDBDomainController](Get-ADDBDomainController.md) cmdlet.
|
|
|
|
- An isolated VLAN / virtual network as connectivity to any existing production domain controllers would have unforseen consequences.
|
|
|
|
Follow these steps on the target server in order to restore the domain controller:
|
|
|
|
1. In case of Windows Server 2008 (R2), run the `$PSVersionTable.PSVersion` to verify that at least PowerShell 3 is installed. [Upgrade](https://docs.microsoft.com/en-us/powershell/wmf/overview) if necessary.
|
|
|
|
2. Verify that the [PowerShell Script Execution Policy](https://docs.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_execution_policies?view=powershell-6) is set to RemoteSigned, Unrestricted or Bypass in the LocalMachine scope.
|
|
|
|
3. [Install](https://github.com/MichaelGrafnetter/DSInternals/wiki/Installation) the DSInternals PowerShell module for all users.
|
|
|
|
4. Copy the backup data to a local drive, e.g. C:\Backup.
|
|
|
|
5. Run the `New-ADDBRestoreFromMediaScript -DatabasePath 'C:\Backup\Active Directory\ntds.dit' | Invoke-Expression` command.
|
|
|
|
6. Sit back and watch the magic happen. Up to 3 reboots will follow and the entire process may take up to 20 minutes to finish. You should then end up with a fully functional domain controller.
|
|
|
|
The script that is generated by the `New-ADDBRestoreFromMediaScript` cmdlet does the following actions:
|
|
|
|
- Rename the server to match the original domain controller.
|
|
|
|
- Install a new forest by promoting the server to a domain controller.
|
|
|
|
- Replace the newly generated database file (ntds.dit) and SYSVOL directory by the original ones.
|
|
|
|
- Re-encrypt the database using the local Boot Key.
|
|
|
|
- Write the newly generated machine account password into ntds.dit.
|
|
|
|
- Update the LSA Policy to match the SID and GUID of the domain that is being restored.
|
|
|
|
- Reset the Invocation ID of the domain controller.
|
|
|
|
- Reconfigure SYSVOL replication in case it has been restored to a different path.
|
|
|
|
## EXAMPLES
|
|
|
|
### Example 1
|
|
```powershell
|
|
PS C:\> New-ADDBRestoreFromMediaScript -DatabasePath 'C:\IFM\Active Directory\ntds.dit' | Invoke-Expression
|
|
```
|
|
|
|
Restores a domain controller from a previously created IFM backup.
|
|
|
|
### Example 2
|
|
```powershell
|
|
PS C:\> New-ADDBRestoreFromMediaScript -DatabasePath 'C:\IFM\Active Directory\ntds.dit' -BootKey 610bc29e6f62ca7004e9872cd51a0116 -SysvolPath 'C:\IFM\SYSVOL'
|
|
```
|
|
|
|
Generates a domain controller restoration script from a previously created IFM backup. The script can then be reviewed, modified if necessary and executed manually.
|
|
|
|
### Example 3
|
|
```cmd
|
|
ntdsutil.exe "activate instance ntds" ifm "create sysvol full c:\IFM" quit quit
|
|
```
|
|
|
|
Creates an Install From Media (IFM) backup of a running domain controller. This backup can later be used by the New-ADDBRestoreFromMediaScript cmdlet.
|
|
|
|
### Example 4
|
|
This is a sample PowerShell script generated by the New-ADDBRestoreFromMediaScript cmdlet:
|
|
|
|
```powershell
|
|
<#
|
|
.SYNOPSIS
|
|
Restores the LON-DC1 domain controller from ntds.dit.
|
|
|
|
.REMARKS
|
|
This script should only be executed on a freshly installed Windows Server 2012 R2 Datacenter Evaluation. Use at your own risk.
|
|
The DSInternals PowerShell module must be installed for all users on the target server.
|
|
|
|
|
|
Author: Michael Grafnetter
|
|
|
|
#>
|
|
#Requires -Version 3 -Modules DSInternals,ServerManager,PSScheduledJob -RunAsAdministrator
|
|
|
|
# Perform a VSS backup before doing anything else.
|
|
Write-Host 'Creating a snapshot of the system drive to make rollback possible...'
|
|
$vssResult = ([wmiclass] 'Win32_ShadowCopy').Create("$env:SystemDrive\", 'ClientAccessible')
|
|
|
|
# The PS module must be present as workflows cannot contain non-existing activities.
|
|
Write-Host 'Installing the Active Directory module for Windows PowerShell...'
|
|
Add-WindowsFeature -Name RSAT-AD-PowerShell -ErrorAction Stop
|
|
|
|
# All the other operations will be executed by a restartable workflow running in SYSTEM context.
|
|
Write-Host 'Registering restartable workflows...'
|
|
|
|
# Delete any pre-existing scheduled jobs with the same names before registering new ones.
|
|
Unregister-ScheduledJob -Name DSInternals-RFM-Initializer,DSInternals-RFM-Resumer -Force -ErrorAction SilentlyContinue
|
|
|
|
# The DSInternals-RFM-Initializer job will only be executed once in order to register the workflow and to invoke it for the first time.
|
|
$initTask = Register-ScheduledJob -Name DSInternals-RFM-Initializer -ScriptBlock {
|
|
workflow Restore-DomainController
|
|
{
|
|
if ($env:COMPUTERNAME -ne 'LON-DC1')
|
|
{
|
|
# A server rename operation is required.
|
|
Rename-Computer -NewName 'LON-DC1' -Force
|
|
|
|
# We explicitly suspend the workflow as Restart-Computer with the -Wait parameter does not survive local reboots.
|
|
shutdown.exe /r /t 5
|
|
Suspend-Workflow -Label 'Waiting for reboot'
|
|
}
|
|
|
|
if ((Get-Service NTDS -ErrorAction SilentlyContinue) -eq $null)
|
|
{
|
|
# A DC promotion is required.
|
|
# Note: In order to maintain compatibility with Windows Server 2008 R2, the ADDSDeployment module is not used.
|
|
# Advice: It is recommenced to change the DSRM password after DC promotion.
|
|
dcpromo.exe /unattend /ReplicaOrNewDomain:Domain /NewDomain:Forest /NewDomainDNSName:"adatum.com" /DomainNetBiosName:"ADATUM" /DomainLevel:7 /ForestLevel:7 '/SafeModeAdminPassword:"Pa$$w0rd"' /DatabasePath:"$env:SYSTEMROOT\NTDS" /LogPath:"$env:SYSTEMROOT\NTDS" /SysVolPath:"$env:SYSTEMROOT\SYSVOL" /AllowDomainReinstall:Yes /CreateDNSDelegation:No /DNSOnNetwork:No /InstallDNS:Yes /RebootOnCompletion:No
|
|
Set-ItemProperty -Path registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\ServerManager\Roles\10 -Name ConfigurationStatus -Value 2 -Force
|
|
|
|
<# Alternative approach for Winows Server 2012+
|
|
Install-WindowsFeature -Name AD-Domain-Services
|
|
Install-ADDSForest -DomainName 'adatum.com' `
|
|
-DomainNetbiosName 'ADATUM' `
|
|
-ForestMode WinThreshold `
|
|
-DomainMode WinThreshold `
|
|
-DatabasePath "$env:SYSTEMROOT\NTDS" `
|
|
-LogPath "$env:SYSTEMROOT\NTDS" `
|
|
-SysvolPath "$env:SYSTEMROOT\SYSVOL" `
|
|
-InstallDns `
|
|
-CreateDnsDelegation:$false `
|
|
-NoDnsOnNetwork `
|
|
-SafeModeAdministratorPassword (ConvertTo-SecureString -String 'Pa$$w0rd' -AsPlainText -Force)`
|
|
-NoRebootOnCompletion `
|
|
-Force
|
|
#>
|
|
}
|
|
|
|
# Reboot the computer into the Directory Services Restore Mode.
|
|
bcdedit.exe /set safeboot dsrepair
|
|
shutdown.exe /r /t 5
|
|
Suspend-Workflow -Label 'Waiting for reboot'
|
|
|
|
# Re-encrypt the DB with the new boot key.
|
|
$currentBootKey = Get-BootKey -Online
|
|
Set-ADDBBootKey -DatabasePath 'C:\Backup\Active Directory\ntds.dit' -LogPath 'C:\Backup\Active Directory' -OldBootKey 610bc29e6f62ca7004e9872cd51a0116 -NewBootKey $currentBootKey -Force
|
|
|
|
# Clone the DC account password.
|
|
$ntdsParams = Get-ItemProperty -Path registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters
|
|
InlineScript {
|
|
# Note: SupplementalCredentials do not get serialized properly without using the InlineScript activity.
|
|
$dcAccount = Get-ADDBAccount -SamAccountName 'LON-DC1$' -DatabasePath $using:ntdsParams.'DSA Database file' -LogPath $using:ntdsParams.'Database log files path' -BootKey $using:currentBootKey
|
|
Set-ADDBAccountPasswordHash -ObjectGuid 9bb4d6f4-060a-4585-9f18-625774e7c088 -NTHash $dcAccount.NTHash -SupplementalCredentials $dcAccount.SupplementalCredentials -DatabasePath 'C:\Backup\Active Directory\ntds.dit' -LogPath 'C:\Backup\Active Directory' -BootKey $using:currentBootKey -Force
|
|
}
|
|
|
|
# Replace the database and transaction logs.
|
|
robocopy.exe 'C:\Backup\Active Directory' $ntdsParams.'DSA Working Directory' *.dit *.edb *.chk *.jfm /MIR /NP /NDL /NJS
|
|
robocopy.exe 'C:\Backup\Active Directory' $ntdsParams.'Database log files path' *.log *.jrs /MIR /NP /NDL /NJS
|
|
|
|
# Replace SYSVOL.
|
|
robocopy.exe 'C:\Backup\SYSVOL\Adatum.com' "$env:SYSTEMROOT\SYSVOL\domain" /MIR /XD DfsrPrivate /XJ /COPYALL /SECFIX /TIMFIX /NP /NDL
|
|
|
|
# Reconfigure LSA policies. We would get into a BSOD loop if they do not match the corresponding values in the database.
|
|
Set-LsaPolicyInformation -DomainName 'ADATUM' -DnsDomainName 'Adatum.com' -DnsForestName 'Adatum.com' -DomainGuid 279b615e-ae79-4c86-a61a-50f687b9f7b8 -DomainSid S-1-5-21-1817670852-3242289776-1304069626
|
|
|
|
# Tell the DC that its DB has intentionally been restored. A new InvocationID will be generated as soon as the service starts.
|
|
Set-ItemProperty -Path registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters -Name 'Database restored from backup' -Value 1 -Force
|
|
Remove-ItemProperty -Path registry::HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\NTDS\Parameters -Name 'DSA Database Epoch' -Force
|
|
|
|
# Disable DSRM and do one last reboot.
|
|
bcdedit.exe /deletevalue safeboot
|
|
shutdown.exe /r /t 5
|
|
Suspend-Workflow -Label 'Waiting for reboot'
|
|
|
|
# Reconfigure SYSVOL replication in case it has been restored to a different path.
|
|
|
|
# Update DFS-R subscription if present in AD.
|
|
$dfsrSubscriptionDN = 'CN=SYSVOL Subscription,CN=Domain System Volume,CN=DFSR-LocalSettings,CN=LON-DC1,OU=Domain Controllers,DC=Adatum,DC=com'
|
|
$dfsrSubscription = Set-ADObject -Identity $dfsrSubscriptionDN -Server localhost -PassThru -ErrorAction SilentlyContinue -Replace @{
|
|
'msDFSR-RootPath' = "$env:SYSTEMROOT\SYSVOL\domain";
|
|
'msDFSR-StagingPath' = "$env:SYSTEMROOT\SYSVOL\staging areas\Adatum.com"
|
|
}
|
|
|
|
if($dfsrSubscription -ne $null)
|
|
{
|
|
# Download the updated DFS-R configuration from AD.
|
|
Invoke-WmiMethod -Class DfsrConfig -Name PollDsNow -ArgumentList localhost -Namespace ROOT\MicrosoftDfs
|
|
}
|
|
|
|
# Update FRS subscription if present in AD.
|
|
$frsSubscriptionDN = 'CN=Domain System Volume (SYSVOL share),CN=NTFRS Subscriptions,CN=LON-DC1,OU=Domain Controllers,DC=Adatum,DC=com'
|
|
$frsSubscription = Set-ADObject -Identity $frsSubscriptionDN -Server localhost -PassThru -ErrorAction SilentlyContinue -Replace @{
|
|
'fRSRootPath' = "$env:SYSTEMROOT\SYSVOL\domain";
|
|
'fRSStagingPath' = "$env:SYSTEMROOT\SYSVOL\staging\domain"
|
|
}
|
|
|
|
if($frsSubscription -ne $null)
|
|
{
|
|
# Download the updated FRS configuration from AD.
|
|
InlineScript { ntfrsutl.exe poll /now }
|
|
}
|
|
}
|
|
|
|
# Delete any pre-existing workflows with the same name before starting a new one.
|
|
Remove-Job -Name DSInternals-RFM-Workflow -Force -ErrorAction SilentlyContinue
|
|
|
|
# Start the workflow.
|
|
Restore-DomainController -JobName DSInternals-RFM-Workflow
|
|
}
|
|
|
|
# The DSInternals-RFM-Resumer job will be executed after each reboot to unpause the workflow.
|
|
$resumeTask = Register-ScheduledJob -Name DSInternals-RFM-Resumer -Trigger (New-JobTrigger -AtStartup) -ScriptBlock {
|
|
# Unregister the one-time task that must already have been executed.
|
|
Unregister-ScheduledJob -Name DSInternals-RFM-Initializer -Force -ErrorAction SilentlyContinue
|
|
|
|
# Resume the workflow after the computer is rebooted.
|
|
Resume-Job -Name DSInternals-RFM-Workflow -Wait | Wait-Job | where State -In Completed,Failed,Stopped | foreach {
|
|
# Perform cleanup when finished.
|
|
Remove-Job -Job $PSItem -Force
|
|
Unregister-ScheduledJob -Name DSInternals-RFM-Resumer -Force
|
|
}
|
|
}
|
|
|
|
# Configure the scheduled tasks to run under the SYSTEM account.
|
|
# Note: In order to maintain compatibility with Windows Server 2008 R2, the ScheduledTasks module is not used.
|
|
schtasks.exe /Change /TN '\Microsoft\Windows\PowerShell\ScheduledJobs\DSInternals-RFM-Initializer' /RU SYSTEM | Out-Null
|
|
schtasks.exe /Change /TN '\Microsoft\Windows\PowerShell\ScheduledJobs\DSInternals-RFM-Resumer' /RU SYSTEM | Out-Null
|
|
|
|
# Start the workflow task and let the magic happen.
|
|
Write-Host 'The LON-DC1 domain controller will now be restored from media. Up to 3 reboots will follow.'
|
|
pause
|
|
$initTask.RunAsTask()
|
|
```
|
|
|
|
## PARAMETERS
|
|
|
|
### -BootKey
|
|
Specifies the system key that encrypts secrets stored in the database specified by the -DatabasePath parameter. If none is specified, it is automatically extracted from a backup of the SYSTEM registry hive, provided that it is present in the ..\registry\SYSTEM path relative to the -DatabasePath parameter.
|
|
|
|
```yaml
|
|
Type: Byte[]
|
|
Parameter Sets: (All)
|
|
Aliases: key, SysKey, SystemKey
|
|
|
|
Required: False
|
|
Position: Named
|
|
Default value: None
|
|
Accept pipeline input: False
|
|
Accept wildcard characters: False
|
|
```
|
|
|
|
### -DatabasePath
|
|
Specifies a non-UNC path to the backup of domain database (ntds.dit file) that will be used to restore the domain controller.
|
|
|
|
```yaml
|
|
Type: String
|
|
Parameter Sets: (All)
|
|
Aliases: Database, DBPath, DatabaseFilePath, DBFilePath
|
|
|
|
Required: True
|
|
Position: Named
|
|
Default value: None
|
|
Accept pipeline input: False
|
|
Accept wildcard characters: False
|
|
```
|
|
|
|
### -LogPath
|
|
Specifies a non-UNC path to a directory that contains the backup of domain log files. If not specified, the value of the DatabasePath parameter is used.
|
|
|
|
```yaml
|
|
Type: String
|
|
Parameter Sets: (All)
|
|
Aliases: Log, TransactionLogPath
|
|
|
|
Required: False
|
|
Position: Named
|
|
Default value: None
|
|
Accept pipeline input: False
|
|
Accept wildcard characters: False
|
|
```
|
|
|
|
### -SafeModeAdministratorPassword
|
|
Supplies the password for the administrator account when the computer is started in Safe Mode or a variant of Safe Mode, such as Directory Services Restore Mode. If no value is specified for this parameter, the cmdlet prompts you to enter and confirm a masked password. If specified with a value, the value must be a secure string.
|
|
|
|
```yaml
|
|
Type: SecureString
|
|
Parameter Sets: (All)
|
|
Aliases: SafeModeAdminPassword, AdminPassword, DSRMPassword
|
|
|
|
Required: True
|
|
Position: Named
|
|
Default value: None
|
|
Accept pipeline input: False
|
|
Accept wildcard characters: False
|
|
```
|
|
|
|
### -SysvolPath
|
|
Specifies a non-UNC path to a directory that contains the backup of Sysvol data. If none is specified, the ..\SYSVOL\ path relative to the -DatabasePath parameter is used.
|
|
|
|
```yaml
|
|
Type: String
|
|
Parameter Sets: (All)
|
|
Aliases: SysVol
|
|
|
|
Required: False
|
|
Position: Named
|
|
Default value: None
|
|
Accept pipeline input: False
|
|
Accept wildcard characters: False
|
|
```
|
|
|
|
### CommonParameters
|
|
This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable, -InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose, -WarningAction, and -WarningVariable. For more information, see [about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
|
|
|
|
## INPUTS
|
|
|
|
### None
|
|
|
|
## OUTPUTS
|
|
|
|
### System.String
|
|
|
|
## NOTES
|
|
|
|
This recovery procedure is NOT SUPPORTED by Microsoft. Use at your own risk in situations when Active Directory forest reinstallation is the only other option.
|
|
|
|
## RELATED LINKS
|
|
|
|
[Get-BootKey](Get-BootKey.md)
|
|
[Get-ADDBDomainController](Get-ADDBDomainController.md)
|