This article will walk you through the provisioning of a new Windows Server 2012 R2 computer using Windows PowerShell. The process is broken down into seven well-defined tasks to give us the opportunity to create the script step-by-step as we highlight the commands that are needed at every phase. After testing each task with PowerShell, the task’s commands are added to a script that will be built in stages. At the end, all the individual tasks will be put together to create an automated provisioning process.

The goal is to write a script that can be used to automate the provisioning of newly installed Windows 2012 R2 Core or full GUI servers. The script will make the following changes to the new servers:

  • Assign a computer name.
  • Reserve an IP Address on DHCP.
  • Join the computer to the domain.
  • Add one or more server roles.

Even though our script targets the initial configuration settings, keep in mind that in a production environment many other tasks could be automated as well. To demonstrate the code, a Windows Server 2012 R2 domain controller name DC1 will be used. DC1 is in an active directory domain named abc.local and it has the DHCP server role configured. The new server will have the default built-in administrator account already set with a local password.

The phases to complete the project are as follows:

  1. Define the initial script parameters.
  2. Use DHCP to verify the new server IP settings.
  3. Create a DHCP Reservation for the new server.
  4. Ensure remote access to the new server.
  5. Add a server role.
  6. Join the Server to the Domain and rename.
  7. Test the Server-Provisioning.ps1 script.

All right, let’s get started.

1. Define the Initial Script Parameters

Some variables in the script, such as the DHCP server name and the domain name, will be hard-coded because they tend to be mostly static in a network environment. However, to create a flexible script that can be reused many times over, it is a best practice to define parameters for values that vary more frequently. In our case, those are the values that will change every time a new server is provisioned, including:

  • The server’s name
  • The server’s IP address
  • The server’s media access control (MAC) address on the network card
  • The roles or features to install on the server
  • The local and domain credentials that are used to access the server

Based on the preceding information, we can open the PowerShell Integrated Scripting Editor to start creating our script. The script name is Server-Provisioning.ps1. Below, you can see the initial code with the parameter definitions entered in the PowerShell Scripting Editor.

[CmdletBinding()]
Param(
    [Parameter(Mandatory=$True)]
    [string]$MACAddress,

   $LocalCredential = (Get-Credential -Message "Provide
       			credential to access local server"),

   $DomainCredential = (Get-Credential -Message "Provide
		domain credential to join server to domain"),

 	 [Parameter(Mandatory=$True)]
 	 [string]$ServerName,

 	 [Parameter(Mandatory=$True)]
 	 [string]$IPAddress,

 	 [Parameter(Mandatory=$True)]
 	 [string]$Role,

     [string]$Domain = "ABC",

  	[Parameter(Mandatory=$True)]
  	[string]$ScopeID,

 	[Parameter(Mandatory=$True)]
  	[string]$DHCPServerName
	)

2. Use DHCP to Verify the New Server IP Settings

By default, new servers use a randomly assigned name and they are configured to obtain a dynamic IP address. Let’s verify the initial configuration in our newly installed Windows Server 2012 R2. The screenshot below shows the random computer name and default workgroup settings.

Running the ipconfig /all command displays the MAC address (physical address) and the initial dynamic IP address assigned to the computer.

Using PowerShell, it is possible to validate the lease IP address from the DHCP service running on DC1.

Running the Get-DhcpServerv4Scope cmdlet verifies that the DHCP server contains only one scope as the screenshot below shows.

For testing purposes, we can assign values to some of the parameters defined on step 1.

$DHCPServerName = “DC1”
$ScopeID = “192.168.2.0”

After entering those values, the following command will display the IP addresses leased out of the 192.168.2.0 scope:

Get-DHCPServerv4Lease –ScopeId $ScopeID –ComputerName $DHCPServerName

In the output below, you can confirm that the IP address 192.168.2.91 has been leased to our new server. Both the hostname and the MAC address match the values exposed on step 1.

Let’s define one more parameter:

$MACAddress =”00-0C-29-4F-0C-7C” #. This is the MAC address of the new server.

To store the IP Address of the new server, run the following code:

$DHCPAddress = Get-DHCPServerv4Lease `
–ScopeId $ScopeID `
–ComputerName $DHCPServerName |
Where-Object {$_.ClientID –eq $MACAddress} |
Select-Object –ExpandProperty IPAddress |
Select-Object –ExpandProperty IPAddressToString

The command below converts the IP address to a string object:

$DHCPAddress = "$DHCPAddress"

The screenshot below displays the output of the previous code in the PowerShell Integrated Scripting Editor:

After testing the code, we can update the script to include the following:

 [CmdletBinding()]
 Param(
    [Parameter(Mandatory=$True)]
    [string]$MACAddress,

    $LocalCredential = (Get-Credential -Message "Provide
        			credential to access local server"),

   $DomainCredential = (Get-Credential -Message "Provide
			domain credential to join server to domain"),

    [Parameter(Mandatory=$True)]
    [string]$ServerName,

    [Parameter(Mandatory=$True)]
    [string]$IPAddress,

    [Parameter(Mandatory=$True)]
    [string]$Role,

    [string]$Domain = "ABC",

    [Parameter(Mandatory=$True)]
    [string]$ScopeID,

    [Parameter(Mandatory=$True)]
    [string]$DHCPServerName
	)

	$DHCPAddress = Get-DHCPServerv4Lease `
	–ScopeId $ScopeID `	
	–ComputerName $DHCPServerName |
	Where-Object { $_.ClientID –eq $MACAddress } |
	Select-Object –ExpandProperty IPAddress |
	Select-Object –ExpandProperty IPAddressToString

	$DHCPAddress = "$DHCPAddress" # To convert the IP address
							# to a string object 

After writing the commands to discover an IP address from the DHCP based on the MAC address of the server, let’s create a reservation on the DHCP server.

3. Create a DHCP Reservation for the New Server

The new computer already received a valid IP address from the DHCP server, but for most servers, network administrators prefer a static IP or a reserved IP address to ensure that the IP settings remain unchanged.

The following code will create a DHCP reservation for the new server:

Add-DhcpServerv4Reservation `
-ClientId $MACAddress `
-IPAddress $IPAddress `
-ScopeId $ScopeID `
-ComputerName $DHCPServerName

Let’s update the script to add the previous code:

 [CmdletBinding()]
 Param(
    [Parameter(Mandatory=$True)]
    [string]$MACAddress,

    $LocalCredential = (Get-Credential -Message "Provide
        			credential to access local server"),

   $DomainCredential = (Get-Credential -Message "Provide
			domain credential to join server to domain"),

    [Parameter(Mandatory=$True)]
    [string]$ServerName,

    [Parameter(Mandatory=$True)]
    [string]$IPAddress,

    [Parameter(Mandatory=$True)]
    [string]$Role,

    [string]$Domain = "ABC",

    [Parameter(Mandatory=$True)]
    [string]$ScopeID,

    [Parameter(Mandatory=$True)]
    [string]$DHCPServerName
	)

	$DHCPAddress = Get-DHCPServerv4Lease `
	–ScopeId $ScopeID `	
	–ComputerName $DHCPServerName |
	Where-Object { $_.ClientID –eq $MACAddress } |
	Select-Object –ExpandProperty IPAddress |
	Select-Object –ExpandProperty IPAddressToString

	$DHCPAddress = "$DHCPAddress" # To convert the IP address
							# to a string object 

	# Add a DHCP server reservation
	Add-DhcpServerv4Reservation `
	-ClientId $MACAddress `
 	-IPAddress $IPAddress `
 	-ScopeId $ScopeID `
  	-ComputerName $DHCPServerName

4. Ensure Remote Access to the New Server

Windows Server 2012 R2 servers come with the Windows Remote Management (WinRM) service and is enabled by default; this allows administrators to use PowerShell remoting to access those servers.

However, by default, remoting requires mutual authentication which is not a problem when the computer is a member of a domain, but in our case, this is a new server and we need to remote into it to manage the initial configuration. For a complete explanation and demonstration on remoting to non-domain computers check the previous article: Remote Management with PowerShell – Part 2.

This script will modify the TrustedHosts list to do away with the mutual authentication requirement so that the computer from which you run the script can connect to the new server to begin provisioning.

Nothing is trusted in the TrustedHosts list by default. The script will add the Dynamic IP address from the new server to the TrustedHosts list and then remove it to leave the list with nothing trusted again.

Running the following command will confirm that no computer is trusted by default in the TrustedHosts list:

Get-Item WSMan:\localhost\Client\TrustedHosts | Select-Object –ExpandProperty Value

To add the new server’s IP address to the TrustedHosts list, run the command below:

Set-Item WSMan:\localhost\Client\TrustedHosts –Value “$DHCPAddress”

To confirm that the new server’s IP address has been added to the TrustedHosts list, run:

Get-Item WSMan:\localhost\Client\TrustedHosts

To restore the list to the default value, run:

Set-Item WSMan:\localhost\Client\TrustedHosts –Value ” “

Now, let’s update the script to add the necessary commands to remote into the new server.

 [CmdletBinding()]
 Param(
    [Parameter(Mandatory=$True)]
    [string]$MACAddress,

    $LocalCredential = (Get-Credential -Message "Provide
        			credential to access local server"),

   $DomainCredential = (Get-Credential -Message "Provide
			domain credential to join server to domain"),

    [Parameter(Mandatory=$True)]
    [string]$ServerName,

    [Parameter(Mandatory=$True)]
    [string]$IPAddress,

    [Parameter(Mandatory=$True)]
    [string]$Role,

    [string]$Domain = "ABC",

    [Parameter(Mandatory=$True)]
    [string]$ScopeID,

    [Parameter(Mandatory=$True)]
    [string]$DHCPServerName
	)

	$DHCPAddress = Get-DHCPServerv4Lease `
	–ScopeId $ScopeID `	
	–ComputerName $DHCPServerName |
	Where-Object { $_.ClientID –eq $MACAddress } |
	Select-Object –ExpandProperty IPAddress |
	Select-Object –ExpandProperty IPAddressToString

	$DHCPAddress = "$DHCPAddress" # To convert the IP address
							# to a string object 

	# Add a DHCP server reservation
	Add-DhcpServerv4Reservation `
	-ClientId $MACAddress `
 	-IPAddress $IPAddress `
 	-ScopeId $ScopeID `
  	-ComputerName $DHCPServerName

	# Add new server’s IP address to TrustedHosts list
	Set-Item WSMan:\localhost\Client\TrustedHosts ` 
	–Value $DHCPAddress




	# Restore TrustedHosts list to default value
	Set-Item WSMan:\localhost\Client\TrustedHosts -Value " " 

Next, the script will add a server role to the Windows Server 2012 R2 computer.

5. Add a Server Role

On step 1, the $LocalCredential parameter was defined as:

$LocalCredential = (Get-Credential -Message “Provide credential to access local server”).

When this command runs you will be prompted to enter the local administrator username and password so that those credentials can be stored on the $localCredential variable. See the following code:

Invoke-Command –ComputerName $DHCPAddress
–Credential $LocalCredential
–ScriptBlock { Add-WindowsFeature DNS }

For demonstration purposes this script will add just one role. However, in a production environment, you may want to add multiple roles.

Let’s update the script to add the DNS server role:

 [CmdletBinding()]
 Param(
    [Parameter(Mandatory=$True)]
    [string]$MACAddress,

    $LocalCredential = (Get-Credential -Message "Provide
        			credential to access local server"),

   $DomainCredential = (Get-Credential -Message "Provide
			domain credential to join server to domain"),

    [Parameter(Mandatory=$True)]
    [string]$ServerName,

    [Parameter(Mandatory=$True)]
    [string]$IPAddress,

    [Parameter(Mandatory=$True)]
    [string]$Role,

    [string]$Domain = "ABC",

    [Parameter(Mandatory=$True)]
    [string]$ScopeID,

    [Parameter(Mandatory=$True)]
    [string]$DHCPServerName
	)

	$DHCPAddress = Get-DHCPServerv4Lease `
	–ScopeId $ScopeID `	
	–ComputerName $DHCPServerName |
	Where-Object { $_.ClientID –eq $MACAddress } |
	Select-Object –ExpandProperty IPAddress |
	Select-Object –ExpandProperty IPAddressToString

	$DHCPAddress = "$DHCPAddress" # To convert the IP address
							# to a string object 

	# Add a DHCP server reservation
	Add-DhcpServerv4Reservation `
	-ClientId $MACAddress `
 	-IPAddress $IPAddress `
 	-ScopeId $ScopeID `
  	-ComputerName $DHCPServerName

	# Add new server’s IP address to TrustedHosts list
	Set-Item WSMan:\localhost\Client\TrustedHosts ` 
	–Value $DHCPAddress

	# Add the DNS role to the new server
	Invoke-Command -ComputerName $DHCPAddress `
	-Credential $LocalCredential `
	-ScriptBlock { Add-WindowsFeature DNS } 





	# Restore TrustedHosts list to default value
	Set-Item WSMan:\localhost\Client\TrustedHosts -Value " " 

Our next step is to examine the code to ensure that the new server will join the abc.local domain.

6. Join Server to the Domain and Rename

The script will use Windows PowerShell remoting to send instructions over the network to the new

Server where the code is executed locally. For a more detailed explanation and demonstration of Windows PowerShell remoting options, you can review the article Remote management with PowerShell –Part1.

For the script to run successfully, variable information such as the server’s new name and domain credentials must be transmitted over the network. However, any variable defined on the local computer will not be directly recognized on the remote computer when using the –ScriptBlock parameter with the Invoke-Command cmdlet. Nonetheless, it is possible to solve this conundrum and still use the Invoke-Command cmdlet by executing the –ArgumentList parameter along with a Param() block inside the –ScriptBlock parameter’s value. See the code below:

# Join server to the domain and rename
Invoke-Command –ComputerName $DHCPAddress `
–Credential $LocalCredential `
–ScriptBlock { param($a,$b) Add-Computer –DomainName ABC `
–NewName $a `
–Credential $b `
–Restart  } `
–ArgumentList $ServerName,$DomainCredential 

The preceding code is the last key part to complete the script before it is fully tested. The final update looks like this:

 [CmdletBinding()]
 Param(
    [Parameter(Mandatory=$True)]
    [string]$MACAddress,

    $LocalCredential = (Get-Credential -Message "Provide
        			credential to access local server"),

   $DomainCredential = (Get-Credential -Message "Provide
			domain credential to join server to domain"),

    [Parameter(Mandatory=$True)]
    [string]$ServerName,

    [Parameter(Mandatory=$True)]
    [string]$IPAddress,

    [Parameter(Mandatory=$True)]
    [string]$Role,

    [string]$Domain = "ABC",

    [Parameter(Mandatory=$True)]
    [string]$ScopeID,

    [Parameter(Mandatory=$True)]
    [string]$DHCPServerName
	)

	$DHCPAddress = Get-DHCPServerv4Lease `
	–ScopeId $ScopeID `	
	–ComputerName $DHCPServerName |
	Where-Object { $_.ClientID –eq $MACAddress } |
	Select-Object –ExpandProperty IPAddress |
	Select-Object –ExpandProperty IPAddressToString

	$DHCPAddress = "$DHCPAddress" # To convert the IP address
							# to a string object 

	# Add a DHCP server reservation
	Add-DhcpServerv4Reservation `
	-ClientId $MACAddress `
 	-IPAddress $IPAddress `
 	-ScopeId $ScopeID `
  	-ComputerName $DHCPServerName

	# Add new server’s IP address to TrustedHosts list
	Set-Item WSMan:\localhost\Client\TrustedHosts ` 
	–Value $DHCPAddress

	# Add the DNS role to the new server
	Invoke-Command -ComputerName $DHCPAddress `
	-Credential $LocalCredential `
	-ScriptBlock { Add-WindowsFeature $Role } 

	# Join server to domain and rename it
	Invoke-Command –ComputerName $DHCPAddress `
	–Credential $LocalCredential `
	–Script {param($a,$b) Add-Computer –DomainName ABC `
                                           –NewName $a `
                                           –Credential $b `
                                           –Restart } `
	–ArgumentList $ServerName,$DomainCredential 

	# Restore TrustedHosts list to default value
	Set-Item WSMan:\localhost\Client\TrustedHosts -Value " " 

After all this hard work, the final step is to test the script to see if it preforms as expected.

  1. Test the Server-Provisioning.ps1 script

You will need to enter your own parameter values to run your script. The following values are defined for our test:

-ServerName: Server1 – this will assign the new name to the server

IPAddress: 192.168.2.101 – IP address to be reserved for the new server

-Role: DNS – to install the DNS server role

MACAddress: 00-0C-29-4F-0C-7C – physical address on the server.

-ScopeID: 192.168.2.0 – the pool from which the IP address will be reserved

DHCPServerName: DC1 – DHCP server

You can run the script with the parameters as shown on the screenshot below:

Because the target computer will need to reboot, you will lose connection but once it comes back, you will be able to connect using the new server name or the reserved IP address configured on the script.

Closing Remarks

This article shows the step-by-step process to write a PowerShell script designed to automate the provisioning process on new Windows Server 2012 R2 computers. At each phase the commands are examined before being added to the script to ensure consistent execution. At the end, with all the commands put together, the script is tested providing the required parameter values to validate the results. This script will work on either a new full GUI or server core installation.