Touch-Free PowerShell DCPROMO in Windows Server 2012

DCPROMO Keeping You Up At Night?

Do you schedule DCPROMO activities for the weekend?  After hours?  Middle of the night?  I remember those days.  Often it was hard to get in the right frame of mind to think through all of the exact procedural steps during those late night change controls.  It was always good to have a thorough implementation plan.

Today’s post will show you how to easily promote and demote a Windows Server 2012 domain controller remotely with a script.  You don’t even need to logon to the target server.

PowerShell DCPROMO in Windows Server 2012

In Windows Server 2012 DCPROMO is gone.  The replacement is the ADDSDeployment module, and it is packed full of PowerShell goodness.  Another key fact is that remoting is enabled by default in Windows Server 2012.  See the potential here?  Now that we’re in PowerShell land we can use remoting to promote a DC without logging on.  The new Server Manager GUI uses this same technique.

 

 PS C:\> Get-Command -Module ADDSDeployment | ft Name

Name
----
Add-ADDSReadOnlyDomainControllerAccount
Install-ADDSDomain
Install-ADDSDomainController
Install-ADDSForest
Test-ADDSDomainControllerInstallation
Test-ADDSDomainControllerUninstallation
Test-ADDSDomainInstallation
Test-ADDSForestInstallation
Test-ADDSReadOnlyDomainControllerAccountCreation
Uninstall-ADDSDomainController

 

Change control.  Can’t live with it.  Can’t live without it.

Scripting a change control is handy for several reasons:

  • If your shop has a separate implementation team, then you know they should execute it precisely.
  • You can test it in a lab, and then do it the same way in production.
  • You know exactly what changed.
  • You don’t have to worry about missing a step at 3AM.

Generally change controls have three plans:

  • Implementation
  • Validation
  • Back-Out

You have all three of these scripts for DCPROMO in today’s post.  Read through the scripts and the comments to see how easy it can be.

Script Overview

The DCPROMO implementation script hinges on three key cmdlets:

  1. Install-WindowsFeature
  2. Invoke-Command
  3. Install-ADDSDomainController

First, we install the role for Active Directory Domain Services using the ComputerName parameter.  Next we use Invoke-Command to remotely execute the DCPROMO with Install-ADDSDomainController.  Notice the comments in the code for Invoke-Command. It is really important to understand the $using variable prefix. This little item tripped me up for several hours until a peer reminded me about it. See about_Remote_Variables for the full explanation.

The validation script is short and sweet.  It checks for the new AD domain controller object, key services, and the SYSVOL share.  Obviously there are many other checks you could add.  See the link at the bottom of this post for a great DC validation checklist.

Finally, the back-out script is much like the implementation script, except it calls the uninstall cmdlets in reverse order.

Implementation

 # Prompt for credentials to reuse throughout the script            
$cred = Get-Credential Cohovineyard\Administrator            
            
 # Echo the date for reference in the console output            
Get-Date            
            
 # Query the current list of domain controllers before the new one            
Get-ADDomainController -Filter * |            
    Format-Table Name, Site, IPv4Address -AutoSize            
            
 # Import the module containing Get-WindowsFeature            
Import-Module ServerManager            
            
 # List the currently installed features on the remote server            
Get-WindowsFeature -ComputerName cvmember1.cohovineyard.com |             
    Where-Object Installed | Format-Table Name            
            
 # Install the role for AD-Domain-Services            
Install-WindowsFeature –Name AD-Domain-Services ` 
    –ComputerName cvmember1.cohovineyard.com ` 
    -IncludeManagementTools            
            
 # List the currently installed features on the remote server            
# Notice AD-Domain-Services is now in the list            
Get-WindowsFeature -ComputerName cvmember1.cohovineyard.com |             
    Where-Object Installed | Format-Table Name            
            
 # Promote a new domain controller in the existing domain            
# Adjust the parameters to meet your own needs            
# Notice we're going to handle the reboot ourselves            
##### BIG THING TO NOTICE #####            
# Notice that the -Credential parameter variable is prefaced with "$using:".            
# This is a PS v3 feature, and it is required when passing variables            
# into a remote session. Invoke-Command is based on PowerShell remoting.            
# Any other parameters that you turn into variables will need "$using:".            
Invoke-Command –ComputerName cvmember1.cohovineyard.com –ScriptBlock {            
            
    Import-Module ADDSDeployment;            
            
    Install-ADDSDomainController ` 
        -NoGlobalCatalog:$false ` 
        -CreateDnsDelegation:$false ` 
        -CriticalReplicationOnly:$false ` 
        -DatabasePath "C:\Windows\NTDS" ` 
        -DomainName "CohoVineyard.com" ` 
        -InstallDns:$true ` 
        -LogPath "C:\Windows\NTDS" ` 
        -NoRebootOnCompletion:$true ` 
        -ReplicationSourceDC "CVDC1.CohoVineyard.com" ` 
        -SiteName "Ohio" ` 
        -SysvolPath "C:\Windows\SYSVOL" ` 
        -Force:$true ` 
        -Credential $using:cred ` 
        -Confirm:$false ` 
        -SafeModeAdministratorPassword ` 
            (ConvertTo-SecureString 'P@ssw0rd' -AsPlainText -Force)            
}            
            
 # We are going to manage the restart ourselves.            
Restart-Computer cvmember1.cohovineyard.com ` 
    -Wait -For PowerShell -Force -Confirm:$false            
            
 # Once fully restarted and promoted, query for a fresh list of DCs.            
# Notice our new DC in the list.            
Get-ADDomainController -Filter * |            
    Format-Table Name, Site, IPv4Address -AutoSize            
            
 # Echo the date and time for job completion.            
Get-Date 

Validation

 Import-Module ActiveDirectory            
            
 # Query the current list of domain controllers            
Get-ADDomainController -Filter * |            
    Format-Table Name, Site, IPv4Address -AutoSize            
            
 # Check random services common to DCs            
Get-Service adws,kdc,netlogon,dns -ComputerName cvdc1
 # Check for presence of SYSVOL            
Test-Path \\cvdc1\SYSVOL            

Back-Out

 # Prompt for credentials to reuse throughout the script            
$cred = Get-Credential Cohovineyard\Administrator            
            
 # Echo the date for reference in the console output            
Get-Date            
            
 # Query the current list of domain controllers before the removal            
Get-ADDomainController -Filter * |            
    Format-Table Name, Site, IPv4Address -AutoSize            
            
 # Reset the error variable            
$error.Clear()            
            
 # Remove the domain controller in the existing domain            
##### BIG THING TO NOTICE #####            
# Notice that the -Credential parameter variable is prefaced with "$using:".            
# This is a PS v3 feature, and it is required when passing variables            
# into a remote session. Invoke-Command is based on PowerShell remoting.            
# Any other parameters that you turn into variables will need "$using:".            
Invoke-Command –ComputerName cvmember1.cohovineyard.com –ScriptBlock {            
            
    Uninstall-ADDSDomainController -Confirm:$false ` 
       -LocalAdministratorPassword ` 
            (ConvertTo-SecureString 'P@ssw0rd' -AsPlainText -Force) ` 
       -DemoteOperationMasterRole:$true ` 
       -Credential $using:cred ` 
       -Force:$true            
}            
            
 # Exit if the uninstall was unsuccessful            
If ($error) {break}            
            
 # Give the server time to go down            
Start-Sleep -Seconds 5            
            
 # The DC removal also removes the host A record in DNS.            
# This effectively disables any other remoting until the server reboots.            
# Therefore we tell the Uninstall to do the reboot by omitting the            
# switch -NoRebootOnCompletion, and then we loop until we can confirm            
# the server is reachable again and services are started.            
Do    { Start-Sleep -Seconds 1 }            
Until (Get-CIMInstance Win32_Bios ` 
        -ComputerName cvmember1.cohovineyard.com ` 
        -ErrorAction SilentlyContinue)            
            
 # Uninstall the AD DS & DNS roles            
Import-Module ServerManager            
Uninstall-WindowsFeature ` 
    –Name AD-Domain-Services, DNS, RSAT-AD-Tools, RSAT-AD-PowerShell ` 
    –ComputerName cvmember1.cohovineyard.com ` 
    -IncludeManagementTools ` 
    -Confirm:$false            
            
 # Restart the server and wait for services to come back up            
Restart-Computer cvmember1.cohovineyard.com ` 
    -Wait -For PowerShell -Force -Confirm:$false            
            
 # View the roles to verify that AD-Domain-Services is really gone            
Get-WindowsFeature -ComputerName cvmember1.cohovineyard.com |             
    Where-Object Installed | Format-Table Name            
            
 # Query for a fresh list of DCs. Confirm it is gone from the list.            
Get-ADDomainController -Filter * |            
    Format-Table Name, Site, IPv4Address -AutoSize            
            
 # Echo the date and time for job completion.            
Get-Date 

Script Notes

Like other demo scripts I’ve posted there is plenty of room for improvement.  Consider these key opportunities regarding the scripts above:

  • The functionality in these scripts requires Windows 8 with RSAT or Windows Server 2012.
  • Be sure to adjust the values for the parameters on the cmdlets that do all of the heavy lifting.
  • Use Read-Host to prompt for the password instead of embedding it in plain text.
  • Add a Start-Transcript and Stop-Transcript for logging your activity.
  • End the script with a Send-MailMessage that attaches the transcript in an email to you.
  • You can swap out all of the hard-coded computer names with variables to make it more reusable.
  • You could promote the DC from your smartphone with one hand tied behind your back.
  • You could schedule the script to run at 3AM while you are nestled in bed.

Download the full code from the TechNet Script Gallery

See this TechNet article for the complete textbook explanation of promoting a new DC in Windows Server 2012:
Install a Replica Windows Server 2012 Domain Controller in an Existing Domain (Level 200)

My buddies over at the AskPFEPlat blog have a great checklist for introducing and removing DCs.  Use this list to build your own robust validation script:
First, Do No Harm

Another buddy on AskPFEPlat has written a great article for your first 2012 DC:
Introducing the first Windows Server 2012 Domain Controller (Part 1 of 2)