Skip to content

Latest commit

 

History

History
357 lines (263 loc) · 17.6 KB

New-ADDBRestoreFromMediaScript.md

File metadata and controls

357 lines (263 loc) · 17.6 KB
external help file Module Name online version schema
DSInternals.PowerShell.dll-Help.xml
DSInternals
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) method, the Restore from Media method does not require network connectivity to a live writable domain controller. Nevertheless, the same installation source (IFM backup 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 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 if necessary.

  2. Verify that the PowerShell Script Execution Policy is set to RemoteSigned, Unrestricted or Bypass in the LocalMachine scope.

  3. Install 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

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

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

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:

<#
.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.

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.

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.

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.

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.

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.

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-ADDBDomainController