Share via


Windows Server 2012: Basic Configuration with PowerShell

Introduction

Besides configuration through the GUI, Windows Server 2012 can be configured with a variety of command line tools:

  • netsh for the IP address, default gateway and DNS server
  • netdom renamecomputer for the hostname
  • netdom join for joining the server to a domain

Of course, Microsoft now recommends the use of PowerShell so I wanted to configure a fresh install of Windows Server 2012 using this tool.

When it came to enabling the Remote Desktop or setting Windows Firewall rules, the rather complex process seemed to confirm the idea that, in some cases, the GUI is the better tool. For example, setting time and date is achieved much more efficiently by entering control timedate.cpl and adjusting settings in the resulting window. Likewise for regional settings, in which case we can use control intl.cpl.

Given the new Windows Server 2012 GUI, however, I find it is often just as easy to type commands, rather than clicking multiple times to reach the appropriate icon in the Control Panel.

So, I've used PowerShell as illustrated in the paragraphs that follow to configure...

  • IP address (IPv4 and IPv6)
  • Hostname
  • Domain join
  • Remote Powershell
  • Remote Desktop (RDP)
  • Firewall setting adjustments for Remote Desktop

Note

I've sometimes analyzed in some detail certain aspects of the addressing process. If you are most interested in the cmdlets themselves, please concentrate on the commands in bold.

First, I want to see the name of the network adapter (or "network card") and the general IP status quo.

As we can see below, using the PowerShell cmdlets in question, the name of the network adapter is "Ethernet" (rather than "Local Area Connection" as in previous versions of Windows).

Even before manual configuration of IP settings, some IP addresses, notably IPv6, have been assigned automatically. We also have an IPv4 and IPv6 loopback address, respectively 127.0.0.1 and ::1

Since the output of some of the commands can be quite lengthy, I've used the format-list cmdlet to limit the output to values that I find most useful.

PS C:\ Get-NetAdapter | fl name,interfacedescription,macaddress,linkspeed

name : Ethernet

interfacedescription : Intel(R) 82574L Gigabit Network Connection

MacAddress : 00-0C-29-06-55-CE

LinkSpeed : 1 Gbps

PS C:\ Get-NetIPAddress | fl ipaddress,interfacealias,addressfamily,addressstate

ipaddress : fe80::1fe:23d7:24dc:1847%12

interfacealias : Ethernet

AddressFamily : IPv6

AddressState : Preferred

ipaddress : fd00::de17:18f7:578f:48ca

interfacealias : Ethernet

AddressFamily : IPv6

AddressState : Preferred

ipaddress : fe80::5efe:169.254.24.71%19

interfacealias : Local Area Connection* 11

AddressFamily : IPv6

AddressState : Deprecated

ipaddress : ::1

interfacealias : Loopback Pseudo-Interface 1

AddressFamily : IPv6

AddressState : Preferred

ipaddress : 169.254.24.71

interfacealias : Ethernet

AddressFamily : IPv4

AddressState : Preferred

ipaddress : 127.0.0.1

interfacealias : Loopback Pseudo-Interface 1

AddressFamily : IPv4

AddressState : Preferred

IPCONFIG is still useful - and less verbose:

PS C:\ ipconfig

Windows IP Configuration

Ethernet adapter Ethernet:

Connection-specific DNS Suffix . :

IPv6 Address. . . . . . . . . . . : fd00::de17:18f7:578f:48ca

Link-local IPv6 Address . . . . . : fe80::1fe:23d7:24dc:1847%12

Autoconfiguration IPv4 Address. . : 169.254.24.71

Subnet Mask . . . . . . . . . . . : 255.255.0.0

Default Gateway . . . . . . . . . :

Tunnel adapter Local Area Connection* 11:

Media State . . . . . . . . . . . : Media disconnected

Connection-specific DNS Suffix . :

Now we will configure an IPv4 address - this is roughly the equivalent of the netsh int ipv4 set address command.

PS C:\ New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress 10.1.1.12 -PrefixLength 8 -DefaultGateway 10.1.1.2

IPAddress : 10.1.1.12

InterfaceIndex : 12

InterfaceAlias : Ethernet

AddressFamily : IPv4

Type : Unicast

PrefixLength : 8

PrefixOrigin : Manual

SuffixOrigin : Manual

AddressState : Tentative

...

IPAddress : 10.1.1.12

InterfaceIndex : 12

InterfaceAlias : Ethernet

AddressFamily : IPv4

Type : Unicast

PrefixLength : 8

PrefixOrigin : Manual

SuffixOrigin : Manual

AddressState : Invalid

...

PS C:\ Get-NetIPAddress | where { $_.IPAddress -eq "10.1.1.12" } | fl

IPAddress : 10.1.1.12

InterfaceIndex : 12

InterfaceAlias : Ethernet

AddressFamily : IPv4

Type : Unicast

PrefixLength : 8

PrefixOrigin : Manual

SuffixOrigin : Manual

AddressState : Preferred

...

Note that the state of the address changes. In the output that displayed automatically after the execution of the New-NetIPAddress, it is first "Tentative" and then (for some reason?) "Invalid" but finally "Preferred" - after verification with the cmdlet Get-NetIPAddress.

Here we configure the DNS server:

PS C:\ Set-DnsClientServerAddress "Ethernet" -ServerAddresses 10.1.1.10

So what's changed? Now, instead of the 169.254.24.71 address, we have "10.1.1.12".

PS C:\ Get-NetIPAddress | fl ipaddress,interfacealias,addressfamily,addressstate

[snip]

ipaddress : ::1

interfacealias : Loopback Pseudo-Interface 1

AddressFamily : IPv6

AddressState : Preferred

ipaddress : 10.1.1.12

interfacealias : Ethernet

AddressFamily : IPv4

AddressState : Preferred

ipaddress : 127.0.0.1

interfacealias : Loopback Pseudo-Interface 1

AddressFamily : IPv4

AddressState : Preferred

Now we'll configure an IPv6 address. Unlike the IPv4 address, that replaced the APIPA address (169.254.x.x), the manually assigned IPv6 address can coexist with the IPv6 link local address (and others).

PS C:\ New-NetIPAddress -InterfaceAlias "Ethernet" -IPAddress fd00::12

IPAddress : fd00::12

InterfaceIndex : 12

InterfaceAlias : Ethernet

AddressFamily : IPv6

Type : Unicast

PrefixLength : 128

PrefixOrigin : Manual

SuffixOrigin : Manual

AddressState : Tentative

ValidLifetime : Infinite ([TimeSpan]::MaxValue)

PreferredLifetime : Infinite ([TimeSpan]::MaxValue)

SkipAsSource : False

PolicyStore : ActiveStore

IPAddress : fd00::12

InterfaceIndex : 12

InterfaceAlias : Ethernet

AddressFamily : IPv6

Type : Unicast

PrefixLength : 128

PrefixOrigin : Manual

SuffixOrigin : Manual

AddressState : Invalid

ValidLifetime : Infinite ([TimeSpan]::MaxValue)

PreferredLifetime : Infinite ([TimeSpan]::MaxValue)

SkipAsSource : False

PolicyStore : PersistentStore

Once again, as for the IPv4 address, the status of the address goes from "Tentative" to "Invalid" to "Preferred" (see below).

PS C:\ Get-NetIPAddress | where { $_.IPAddress -eq "fd00::12" } | fl

IPAddress : fd00::12

InterfaceIndex : 12

InterfaceAlias : Ethernet

AddressFamily : IPv6

Type : Unicast

PrefixLength : 128

PrefixOrigin : Manual

SuffixOrigin : Manual

AddressState : Preferred

ValidLifetime : Infinite ([TimeSpan]::MaxValue)

PreferredLifetime : Infinite ([TimeSpan]::MaxValue)

SkipAsSource : False

PolicyStore : ActiveStore

We can use the following commands to verify the status of our network adapters:

PS C:\ ipconfig /all

Windows IP Configuration

Host Name . . . . . . . . . . . . : WIN-6CSB0KQ27BN

Primary Dns Suffix . . . . . . . :

Node Type . . . . . . . . . . . . : Hybrid

IP Routing Enabled. . . . . . . . : No

WINS Proxy Enabled. . . . . . . . : No

Ethernet adapter Ethernet:

Connection-specific DNS Suffix . :

Description . . . . . . . . . . . : Intel(R) 82574L Gigabit Network Connection

Physical Address. . . . . . . . . : 00-0C-29-06-55-CE

DHCP Enabled. . . . . . . . . . . : No

Autoconfiguration Enabled . . . . : Yes

IPv6 Address. . . . . . . . . . . : fd00::12(Preferred)

IPv6 Address. . . . . . . . . . . : fd00::f0a7:570b:489b:a320(Preferred)

Lease Obtained. . . . . . . . . . : Wednesday, November 6, 2013 8:16:55 PM

Lease Expires . . . . . . . . . . : Thursday, November 21, 2013 6:58:10 AM

Link-local IPv6 Address . . . . . : fe80::1fe:23d7:24dc:1847%12(Preferred)

IPv4 Address. . . . . . . . . . . : 10.1.1.12(Preferred)

Subnet Mask . . . . . . . . . . . : 255.0.0.0

Default Gateway . . . . . . . . . : 10.1.1.2

DHCPv6 IAID . . . . . . . . . . . : 251661353

DHCPv6 Client DUID. . . . . . . . : 00-01-00-01-1A-0C-C5-57-00-0C-29-06-55-CE

DNS Servers . . . . . . . . . . . : 10.1.1.10

NetBIOS over Tcpip. . . . . . . . : Enabled

PS C:\ Get-NetIPAddress | fl IPAddress,SuffixOrigin,AddresState

IPAddress : fe80::1fe:23d7:24dc:1847%12

SuffixOrigin : Link

IPAddress : fd00::7f64:7932:81f9:dc56

SuffixOrigin : Dhcp

IPAddress : fd00::12

SuffixOrigin : Manual

IPAddress : fe80::5efe:10.1.1.12%13

SuffixOrigin : Link

IPAddress : ::1

SuffixOrigin : WellKnown

IPAddress : 10.1.1.12

SuffixOrigin : Manual

IPAddress : 127.0.0.1

SuffixOrigin : WellKnown

PS C:\ Get-DnsClientServerAddress | fl interfacealias,ServerAddresses

interfacealias : Ethernet

ServerAddresses : {10.1.1.10}

interfacealias : Ethernet

ServerAddresses : {fd00::10}

[snip]

Hostname

The netdom renamecomputer command requires the designation of the current name of the computer. After experimenting with the first option below, I discovered that Powershell allows us to rename the computer without indicating the current name.

In either case, the cmdlet is Rename-Computer.

Option 1

PS C:\ $oldname = hostname

PS C:\ $oldname

WIN-6CSB0KQ27BN

PS C:\ Rename-Computer -NewName SVR-00X -ComputerName $oldname

WARNING: The changes will take effect after you restart the computer WIN-6CSB0KQ27BN.

PS C:\ Restart-Computer

Option 2

PS C:\Rename-Computer -NewName SVR-004 -force -restart

Note: There are parameters that allow us to perform the operation using specific credentials, local or domain:

-DomainCredential

-LocalCredential

Otherwise, the credentials of the user performing the operation are used by default.

The -force parameter eliminates the confirmation prompt.

The -restart parameter restarts the computer automatically.

Join computer to domain

Note: the command assumes that the computer account and organizational unit in question have already been created in Active Directory.

Creation of OU:

PS C:\ New-ADOrganizationalUnit "Servers"

By default, the OU is created at the domain root. If that is where we want to create the OU, no further parameters are necessary.

Creation of computer account for server:

PS C:\ New-ADComputer SVR-004 -Path "OU=Servers,DC=machlinkit,DC=biz"

Joining server to domain:

PS C:\ Add-Computer -DomainName machlinkit.biz -restart

Note: if logged on with credentials that allow joining a computer to the domain, it is not necessary to enter them.

Enable Remote Powershell

In fact, there is not much to do here.

On Windows 2012, remote access via PowerShell is enabled by default.

In this case, we want to be able to execute Powershell commands on member server SVR-004 from domain controller DC-001.

We can run the following command on previous operating systems, Windows 2008 R2 in particular, or use it to enable PS remoting on a machine where it was disabled:

PS C:\ Enable-PSRemoting -force

WinRM is already set up to receive requests on this computer.

WinRM is already set up for remote management on this computer.

PS C:\

Since the function is already enabled, we have the output shown above.

Note: if necessary, we would run this command on SVR-004 - the target computer.


Note: the -force parameter eliminates the rather verbose confirmation that we would otherwise see. I'll post that output here since it does describe what the command accomplishes:

PS C:\ Enable-PSRemoting

WinRM Quick Configuration

Running command "Set-WSManQuickConfig" to enable remote management of this computer by using the Windows Remote Management (WinRM) service.

This includes:

1. Starting or restarting (if already started) the WinRM service

2. Setting the WinRM service startup type to Automatic

3. Creating a listener to accept requests on any IP address

4. Enabling Windows Firewall inbound rule exceptions for WS-Management traffic (for http only).

Do you want to continue?

[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): A

WinRM is already set up to receive requests on this computer.

WinRM has been updated for remote management.

Configured LocalAccountTokenFilterPolicy to grant administrative rights remotely to local users.

Confirm

Are you sure you want to perform this action?

Performing operation "Set-PSSessionConfiguration" on Target "Name: microsoft.powershell SDDL:

O:NSG:BAD:P(A;;GA;;;BA)(A;;GA;;;RM)S:P(AU;FA;GA;;;WD)(AU;SA;GXGW;;;WD). This will allow selected users to remotely run Windows PowerShell commands on this computer".

[Y] Yes [A] Yes to All [N] No [L] No to All [S] Suspend [?] Help (default is "Y"): A


From DC-001 we can first test the WinRM service on SVR-004: is it running? responding to requests?

PS C:\ Test-WsMan SVR-004

wsmid : http://schemas.dmtf.org/wbem/wsman/identity/1/wsmanidentity.xsd

ProtocolVersion : http://schemas.dmtf.org/wbem/wsman/1/wsman.xsd

ProductVendor : Microsoft Corporation

ProductVersion : OS: 0.0.0 SP: 0.0 Stack: 3.0

To verify (one step further), I'll stop and later start the WinRM service.

Right now it is on.

PS C:\ Get-Service WinRM | fl

Name : WinRM

DisplayName : Windows Remote Management (WS-Management)

Status : Running

DependentServices : {}

[snip]

PS C:\ Stop-Service WinRM

We try Test-WsMan again... this time, failure:

PS C:\ Test-Wsman SVR-004

test-wsman : <f:WSManFault xmlns:f="http://schemas.microsoft.com/wbem/wsman/1/wsmanfault" Code="2150859046" Machine="DC-001.machlinkit.biz"><f:Message>WinRM cannot complete the operation. Verify that the specified computer name is valid, that the computer is accessible over the network, and that a firewall exception for the WinRM service is enabled and allows access from this computer. By default, the WinRM firewall exception for public profiles limits access to remote computers within the same local subnet. </f:Message></f:WSManFault>

If I enable the WinRM on SVR-004 (with Start-Service), the test succeeds once again.

Now I'll start a remote Powershell session on SVR-004 from DC-001 and execute some basic file system commands.

PS C:\ Enter-PSSession -ComputerName SVR-004

[snip]

[SVR-004]: PS C:\

[SVR-004]: PS C:\ gci

Directory: C:\

Mode LastWriteTime Length Name


d---- 7/26/2012 3:44 AM PerfLogs

d-r-- 11/6/2013 8:14 PM Program Files

d---- 7/26/2012 4:04 AM Program Files (x86)

d---- 11/13/2013 4:50 PM TeamDocuments

d-r-- 11/13/2013 5:12 PM Users

d---- 11/6/2013 10:45 PM Windows

[SVR-004]: PS C:\ sl .\TeamDocuments

[SVR-004]: PS C:\TeamDocuments> New-Item -Name NewFile1.txt -Type File

[snip]

We can also execute a single command on the remote computer using the Invoke-Command cmdlet as shown below. First we need to exit from the current session.

[SVR-004]: PS C:\TeamDocuments> Exit

PS C:\

PS C:\ Invoke-Command SVR-004 -ScriptBlock {gci C:\TeamDocuments}

Directory: C:\TeamDocuments

Mode LastWriteTime Length Name PSComputerName


-a--- 11/13/2013 5:13 PM 0 NewFile.txt SVR-004

-a--- 11/13/2013 5:13 PM 0 NewFile1.txt SVR-004

Note that in both cases, I am able to omit the parameter -ComputerName because it is a positional parameter and do not need to use the -Credential parameter because I am using a domain administrator account that has complete access to both machines.

Note (once again) that "Windows Remote Management" is enabled by default in Windows 2012. It was not necessary for me to adjust firewall settings.

Enable Remote Desktop

This is where I find Powershell to be most lacking. There is not a simple cmdlet that performs the two necessary operations that must be accomplished to enable remote desktop:

  1. Enable Remote Desktop itself

  2. Configure Windows Firewall in consequence.

In my opinion, the simplest - or least complicated way - to achieve this is to manipulate the registry settings that govern Remote Desktop with the Set-ItemProperty cmdlet and then the firewall rules with the Enable-NetFirewallRule cmdlet.

I found an alternate method that uses WMI to manipulate the Remote Desktop setting as well. I will post this alternative at the end (of this already very long post).

***

The parameter that governs Remote Desktop is "fDenyTSConnections" and can be found in the Windows registry in the location below. I will limit the output with the format-list cmdlet.

PS C:\ Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' -Name fDenyTSConnections | fl fDenyTSConnections

fDenyTSConnections : 1

Since the parameters are apparently both positional (meaning they can be omitted), we can abbreviate as follows:

PS C:\ Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' fDenyTSConnections | fl fDenyTSConnections

fDenyTSConnections : 1

The value "1" indicates that Terminal Connections (or Remote Desktop connections) are indeed denied. We will need to change this.

We also need to manage user authentication (enable it or not). It is more secure (thus generally preferable) to enable it. However, older versions of Windows (XP,2003) may not be able to connect this way.

PS C:\ Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp' UserAuthentication | fl UserAuthentication

UserAuthentication : 1

So, Remote Desktop is disabled and User Authentication is enabled. The latter, of course, has no effect, since the former is not enabled.

Now let's look at the status of the Windows Firewall, concerning Remote Desktop access.

PS C:\ Get-NetFirewallRule | where {$_.Name -like "*Desktop*"} | fl Name,Enabled,Profile,Direction

Name : RemoteDesktop-UserMode-In-TCP

Enabled : False

Profile : Public

Direction : Inbound

Name : RemoteDesktop-UserMode-In-UDP

Enabled : False

Profile : Public

Direction : Inbound

This only applies to the Public profile which has no effect on the Domain (or Private) profile which interests me.

Let's try this:

PS C:\ Get-NetFirewallRule -DisplayGroup "Remote Desktop" | fl Name,Enabled,Profile,Direction

Name : RemoteDesktop-UserMode-In-TCP

Enabled : False

Profile : Public

Direction : Inbound

Name : RemoteDesktop-UserMode-In-UDP

Enabled : False

Profile : Public

Direction : Inbound

Name : {12954380-D013-432D-A2A1-646FC09BB918}

Enabled : False

Profile : Domain, Private

Direction : Inbound

Name : {9CD18D97-6B13-4463-BA5E-A2794D7237E9}

Enabled : False

Profile : Domain, Private

Direction : Inbound

For some reason, in the Powershell output, the name of the firewall rule is a long GUID. I'll deal with that in a moment...

Enable Remote Desktop

OK, that is the status quo. Now let's enable remote desktop with this cmdlet:

PS C:\ Set-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' fDenyTSConnections -value 0

This is the result:

PS C:\ Get-ItemProperty 'HKLM:\SYSTEM\CurrentControlSet\Control\Terminal Server' fDenyTSConnections | fl fDenyTSConnections

fDenyTSConnections : 0

User Authentication is at "1" (enabled) already and we will leave it as that because all clients likely to connect to the Windows 2012 servers are running Windows Vista / Server 2008 or above.

Enable Windows Firewall rules

I found - but am not satisfied - with the following command since it enables Remote Desktop in the Public profile. Although one could argue that it does not matter if we are behind a perimeter firewall anyway.

PS C:\ Enable-NetFirewallRule -DisplayGroup "Remote Desktop"

PS C:\ Get-NetFirewallRule -DisplayGroup "Remote Desktop" | fl Name,Enabled,Profile,Direction

Name : RemoteDesktop-UserMode-In-TCP

Enabled : True

Profile : Public

Direction : Inbound

Name : RemoteDesktop-UserMode-In-UDP

Enabled : True

Profile : Public

Direction : Inbound

Name : {12954380-D013-432D-A2A1-646FC09BB918}

Enabled : True

Profile : Domain, Private

Direction : Inbound

Although more complex, the command that follows (Enable-NetFirewallRule) provides exactly what I prefer.

I first test to see what rules the following cmdlet will produce...

PS C:\ Get-NetFirewallRule | where {$_.DisplayGroup -eq "Remote Desktop" -and $_.Profile -match "Domain"} | fl Name,DisplayGroup,Profile,Enabled

Name : {12954380-D013-432D-A2A1-646FC09BB918}

DisplayGroup : Remote Desktop

Profile : Domain, Private

Enabled : False

Name : {9CD18D97-6B13-4463-BA5E-A2794D7237E9}

DisplayGroup : Remote Desktop

Profile : Domain, Private

Enabled : False

And then pipeline the result to the Enable-NetFirewallRule cmdlet. This allows Remote Desktop access. I will refrain from lengthening this post any longer by posting the result.

PS C:\ Get-NetFirewallRule | where {$_.DisplayGroup -eq "Remote Desktop" -and $_.Profile -match "Domain"} | Enable-NetFirewallRule

To open the Remote Desktop tool from the command line, we can simply type (and then press Enter):

mstsc.exe

And then provide necessary credentials.

***

Alternate method of enabling Remote Desktop using the Get-WMIObject cmdlet with the SetAllowTsConnections method:

PS C:\ (Get-WmiObject -Class "Win32_TerminalServiceSetting" -NameSpace root\cimv2\terminalservices).AllowTsConnections

0

PS C:\ (Get-WmiObject -Class "Win32_TerminalServiceSetting" -NameSpace root\cimv2\terminalservices).SetAllowTsConnections(1)

[snip]

Here we have allowed TsConnections by setting the value to "1".

The result:

PS C:\ (Get-WmiObject -Class "Win32_TerminalServiceSetting" -NameSpace root\cimv2\terminalservices).AllowTsConnections 1

Conclusion

This was a useful though time-consuming adventure with PowerShell but if you have the "Full" install of Windows Server 2012, as opposed to the Server Core install, and want to configure (among others) Remote Desktop, just use the GUI.