Part IV – DSC – One-Click Domain Controller

IntroToDsc

This post is part of the Learning PowerShell DSC Series, here on FoxDeploy. Click the banner to return to the series jump page!


Hey guys, I haven’t forgotten about you, but it’s been a very busy month here, with me traveling to Redmond ( Microsoft HQ! I have to post a pic!) for some exciting Microsoft meetings and then back and forth to Minneapolis for a new client!

2015-06-02 13.48.56

I didn’t know what to do with my hands in this picture.


I’ve been receiving your messages and have now released the final step in this one-click Domain controller DSC Build. To recap, we left off with a DSC Config that would make our machine a domain controller, but that was it.

We didn’t have functional DHCP for clients to find us, or any other bells and whistles. In this post, we’ll be adding on DHCP so clients can get an IP address, as well as DNS to help our Machines Domain Join to our new DC. If you tried Domain Joining with our build from last time, you would have been quite disappointed. Not this time!

What has to go :

Previously, we had a single config file that did some really good stuff for us, setting up a workgroup and then making a new local admin. We’re going to gut all of that stuff, because setting up a system with a DSC Config needs to be idempotent. That means that the config needs to be able to run over and over without breaking stuff, and the previous build would do just that. If we draft a config that will result in changes every time the config is validated, we’ve created a problem.

The issue in our last config stemmed from the fact that it would change the system’s name and also add it to a work group. Then, later in the config we make it a domain controller. What would happen if the DSC config were re-evaluated is that the machine would throw an error when it got to the portion of the .mof telling it to join a workgroup. Domain Controllers can’t leave a domain until they’ve lost all of their FSMO Roles, so this is an invalid config. Bad Stephen!

As it is, that bit about joining a workgroup turned out to be wasted space, so we’ll remove that too. The full code is available below, as well as here on my GitHub site.

What’s new and what does it do

For this post, you’ll need the xNetworking Resource, found here

As well as the xDHCPServer Resource, found here

You’ll also need the xComputerManagement and xActiveDirectory Resources, which can be found here:

Prepare your DSC Target Node by copying the folders in the zips to the Modules folder, in this path

$env:ProgramFiles\WindowsPowerShell\Modules

The big new steps we’re adding are the following:

Set a Static IP Address

The end goal of this whole shebang was to have a working DHCP server, and DHCP can’t give out IP Addresses unless they have a fixed IP themselves. In this config block , we set a Static IP of 10.20.30.1 and rename the Adapter along the way.

xIPAddress NewIPAddress
        {
            IPAddress      = "10.20.30.1"
            InterfaceAlias = "Ethernet"
            SubnetMask     = 24
            AddressFamily  = "IPV4"

        }

Enable the DHCP Windows Feature

This one was kind of a pain, as it was hard to figure out what the name was of the DHCP Server Role! Turns out it’s DHCP not DHCPServer (as it is listed in Get-WindowsFeature). All we do here is make sure that the DHCP server is installed, and we do it after configuring the IP address to prevent an error which would shut down our config.

WindowsFeature DHCP {
            DependsOn = '[xIPAddress]NewIpAddress'
            Name = 'DHCP'
            Ensure = 'PRESENT'
            IncludeAllSubFeature = $true                                                                                                                               

        }  

Enable the DHCP Address Scope

You can get super complex with Windows Server Networking using DHCP and DNS, but I always like to keep things simple, especially in my testlab. This configuration resource essentially runs us through the DHCP Wizard and ensures that a DHCP Scope Exists, giving out IP addresses from 10.20.30.5 all the way up to 250.

   xDhcpServerScope Scope
        {
         DependsOn = '[WindowsFeature]DHCP'
         Ensure = 'Present'
         IPEndRange = '10.20.30.250'
         IPStartRange = '10.20.30.5'
         Name = 'PowerShellScope'
         SubnetMask = '255.255.255.0'
         LeaseDuration = '00:08:00'
         State = 'Active'
         AddressFamily = 'IPv4'
        } 

Specify the DNS server for DHCP clients to use

If you don’t get this part, your DNS Clients will throw up an ‘
ERROR: Could not join to the domain VAS_ERR_DNS: unable to lookup any DNS SRV records for’, which should be your clue to ensure that you’ve specified option 6 in your DNS settings

xDhcpServerOption Option
     {
         Ensure = 'Present'
         ScopeID = '10.20.30.0'
         DnsDomain = 'fox.test'
         DnsServerIPAddress = '10.20.30.1'
         AddressFamily = 'IPv4'
     }

The Complete Config

If you’re following from home, go ahead and delete everything from the last DSC post from line 29 to 54.

Or, if you’re laz–uh, more efficiently minded, copy and paste this code instead.

$secpasswd = ConvertTo-SecureString 'IWouldLiketoRecoverPlease1!' -AsPlainText -Force
$SafeModePW = New-Object System.Management.Automation.PSCredential ('guest', $secpasswd)

$secpasswd = ConvertTo-SecureString 'IveGot$kills!' -AsPlainText -Force
$localuser = New-Object System.Management.Automation.PSCredential ('guest', $secpasswd)

configuration TestLab
{
     param
    (
        [string[]]$NodeName ='localhost',
        [Parameter(Mandatory)][string]$MachineName,  $firstDomainAdmin,
        [Parameter(Mandatory)][string]$DomainName,
        [Parameter()][string]$UserName,
        [Parameter()]$SafeModePW,
        [Parameter()]$Password
    ) 

    #Import the required DSC Resources
    Import-DscResource -Module xActiveDirectory
    Import-DscResource -Module xNetworking
    Import-DscResource -module xDHCpServer
    Import-DscResource -Module xComputerManagement 

    Node $NodeName
    { #ConfigurationBlock 

        xComputer NewNameAndWorkgroup
            {
                Name          = $MachineName

            }

        WindowsFeature ADDSInstall
        { 

            Ensure = 'Present'
            Name = 'AD-Domain-Services'
            IncludeAllSubFeature = $true
        }

        WindowsFeature RSATTools
        {
            DependsOn= '[WindowsFeature]ADDSInstall'
            Ensure = 'Present'
            Name = 'RSAT-AD-Tools'
            IncludeAllSubFeature = $true
        }

        xIPAddress NewIPAddress
        {
            IPAddress      = "10.20.30.1"
            InterfaceAlias = "Ethernet"
            SubnetMask     = 24
            AddressFamily  = "IPV4"

        }

        WindowsFeature DHCP {
            DependsOn = '[xIPAddress]NewIpAddress'
            Name = 'DHCP'
            Ensure = 'PRESENT'
            IncludeAllSubFeature = $true                                                                                                                               

        }  

        WindowsFeature DHCPTools
        {
            DependsOn= '[WindowsFeature]DHCP'
            Ensure = 'Present'
            Name = 'RSAT-DHCP'
            IncludeAllSubFeature = $true
        }  

        xADDomain SetupDomain {
            DomainAdministratorCredential= $firstDomainAdmin
            DomainName= $DomainName
            SafemodeAdministratorPassword= $SafeModePW
            DependsOn='[WindowsFeature]RSATTools'
            DomainNetbiosName = $DomainName.Split('.')[0]
        }

        xDhcpServerScope Scope
        {
         DependsOn = '[WindowsFeature]DHCP'
         Ensure = 'Present'
         IPEndRange = '10.20.30.250'
         IPStartRange = '10.20.30.5'
         Name = 'PowerShellScope'
         SubnetMask = '255.255.255.0'
         LeaseDuration = '00:08:00'
         State = 'Active'
         AddressFamily = 'IPv4'
        } 

        xDhcpServerOption Option
     {
         Ensure = 'Present'
         ScopeID = '10.20.30.0'
         DnsDomain = 'fox.test'
         DnsServerIPAddress = '10.20.30.1'
         AddressFamily = 'IPv4'
     }

    #End Configuration Block
    }
}

$configData = 'a'

$configData = @{
                AllNodes = @(
                              @{
                                 NodeName = 'localhost';
                                 PSDscAllowPlainTextPassword = $true
                                    }
                    )
               }

TestLab -MachineName DSCDC01 -DomainName Fox.test -Password $localuser `
    -UserName 'FoxDeploy' -SafeModePW $SafeModePW -firstDomainAdmin (Get-Credential -UserName 'FoxDeploy' -Message 'Specify Credentials for first domain admin') `
    -ConfigurationData $configData

Start-DscConfiguration -ComputerName localhost -Wait -Force -Verbose -path .\TestLab -Debug

Now that we know what we’re doing, let’s give it a whirl!

Testing it out

My network is laid out like this

Layout

I’ve got my future DHCP Server and a random client Windows 10 VM both sitting on the same network. Now we’re going to enforce the configuration on my DSC Client, and then watch and see my workstation pull down a DHCP Address!

You might be thinking:

‘Hey Stephen, why not just copy the files down with DSC!’

and that’s a great question. As it turns out, you can do something like that by using what’s called a DSC Partial Configuration…which I’m still figuring out. Once I understand it, I’ll write a post about it. The long and short of it now is that you can’t reference a resource and also copy a resource within the same config because…uh…reasons.

You’re boring me, let’s get to it!

The only thing that’s left is to hit F5 and watch as my machine gets config’d! First we apply the new computer name… which needs a reboot

SetComputerName

Now, we reboot and just relaunch the configuration. We could just wait…but it’s more fun to hit -Force and watch the whole thing happen in real time

MakingaDC

If all of this worked (and it looks like it did!) we should now be able to go over to our test machine and run a DHCP /renew and see an IP address come over.

DHCP worked!

An important piece of getting this Domain Controller accepting domain joins is to make sure that new PCs to the domain can find the DC. This means that they need to ask a DNS server for the SRV record of a Domain Controller holding the Global Catalog role. We’ll run a ipconfig /all and see if our DNS Server setting is registered.

DNS server came alone

Now is where I started to get excited. See, my whole reason for going down this path is that I think making a domain controller in a Lab environment can be very daunting for first-timers, and wanted to help lower that barrier to entry. If my client machine can see the DC, then it should be able to Domain Join now. So the moment of truth…

MomentOfTruth

Now…to hit OK…

Welcome to the FoxDeploy Domain!!!
Welcome to the FoxDeploy Domain!!!

Wrapping it up

I will admit, I jumped up and down when I got this part to work. We now have a one-click, single-stop Domain Controller build, perfect to use a stepping stone into whatever else you’d want to do on a domain controller. It really is kind of amazing to me that this all works, knowing how hard it would be to do this level on configuration using something like SCCM/Configuration Manager.

From here? The next step in our series will have us joining clients to this domain as well, and from there, we can do whatever you’d want to do with DSC. If you’ve got an idea or a situation from work, send me a message, and you might just be the next blog post here in this series.

Advertisements

8 thoughts on “Part IV – DSC – One-Click Domain Controller

  1. John Flayn September 1, 2015 / 8:29 am

    I must be missing something. The DHCP server ends up installed and configured, but not Authorised in Active Directory (so it won’t hand out IPs until that is done). But I can’t work out how to use DSC to set it as Authorized in AD. (yes I can do it via powershell after, but dang it I want DSC to do it!)

    • FoxDeploy September 1, 2015 / 8:41 am

      Hmm, I’ll have to investigate this. It *definitely* will hand out IP addresses, I’m certain of that, at least it does in my testing.

      For times where you just need to run some commands in PowerShell, you can use the Script resource to run a script or a cmdlet or two (like Add-DhcpServerInDC)

      • Antonio January 9, 2016 / 4:35 pm

        I am assuming the state = active authorized the dhcp server

        • FoxDeploy January 9, 2016 / 4:59 pm

          Don’t know why, but I’ve sometimes had to manually authorize the server when I use this config. Just a heads up!

  2. John Flayn February 19, 2016 / 4:58 pm

    New version of the xDhcp module has a xDhcpServerAuthorization resource resource to ensure its authorized

    • FoxDeploy February 19, 2016 / 5:06 pm

      awesome! I need to revisit this and I’ll update accordingly. Do you have a twitter/blog you’d like me to shout out?

      • dave April 12, 2016 / 4:06 pm

        Did you ever get this working? I found the new xDhcpServerAuthorization resource in the latest xDhcp module but I’m not exactly sure how to implement it in the config.

        • Brian Sprogø June 3, 2017 / 5:29 am

          I know this is an old post, but I had the same question and got it fixed….

          xDhcpServerAuthorization LocalServerActivation {
          Ensure = ‘Present’
          DependsOn = ‘[xADDomain]FirstDS’, ‘[WindowsFeature]DHCP’
          }

          I make it depend on the creation of the AD and installation of the DHCP itself.

          Hope this helps others out.

Have a code issue? Share your code by going to Gist.github.com and pasting your code there, then post the link here!

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s