Examples/Build-ADCS.ps1



configuration CreateADDomainWithCS
{ 
   param 
   ( 
        [Parameter(Mandatory)]
        [String]$DomainName,

        [Parameter(Mandatory)]
        [System.Management.Automation.PSCredential]$AdminCreds,

        [Int]$RetryCount = 60,
        [Int]$RetryIntervalSec = 5
    ) 
    
    Import-DscResource -ModuleName PSDesiredStateConfiguration
    Import-DscResource -ModuleName xActiveDirectory -ModuleVersion 2.17.0.0
    Import-DscResource -ModuleName xAdcsDeployment -ModuleVersion 1.4.0.0
    Import-DscResource -ModuleName ADCSTemplate -ModuleVersion 1.0.1.0
    
    [System.Management.Automation.PSCredential]$DomainCreds = New-Object System.Management.Automation.PSCredential ("$DomainName\$($AdminCreds.UserName)", $AdminCreds.Password)

    Node $AllNodes.NodeName
    {
        LocalConfigurationManager
        {
            ActionAfterReboot = 'ContinueConfiguration'
            ConfigurationMode = 'ApplyOnly'
            RebootNodeIfNeeded = $true
            AllowModuleOverWrite = $true
        }

        WindowsFeature ADDSInstall 
        { 
            Ensure = 'Present'
            Name = 'AD-Domain-Services'
        }  

        WindowsFeature ADDSPowerShell
        { 
            Ensure = 'Present' 
            Name = 'RSAT-AD-PowerShell'
        }

        # Optional GUI tools
        WindowsFeature ADDSTools
        { 
            Ensure = 'Present' 
            Name = 'RSAT-ADDS'
        }

        xADDomain FirstDS 
        {
            DomainName = $DomainName
            DomainAdministratorCredential = $DomainCreds
            SafemodeAdministratorPassword = $DomainCreds
            DomainNetbiosName = ($DomainName -split '\.')[0]
            DependsOn = "[WindowsFeature]ADDSInstall"
        }
<#
        #This resource is broken as of 2.17.0.0.
        #See Script resource alternative below.
        #Revert to using this resource when it is fixed.

        xWaitForADDomain DscForestWait
        {
            DomainName = $DomainName
            DomainUserCredential = $DomainCreds
            RetryCount = $RetryCount
            RetryIntervalSec = $RetryIntervalSec
            DependsOn = "[xADDomain]FirstDS"
        }
#>


        Script xWaitForADDomain_Alternative
        {
            GetScript = {
                Return @{
                    Result = [string]$(([ADSI]"LDAP://$Using:DomainName").distinguishedName)
                }
            }
            TestScript = {
                $DN = "DC=$($Using:DomainName -replace '\.',',DC=')"
                $FoundDomain = $false
                For ($i=1;$i -le $Using:RetryCount;$i++) {
                    If (([ADSI]"LDAP://$DN").distinguishedName -eq $DN) {
                        $FoundDomain = $true
                        Write-Verbose "Found domain $($Using:DomainName)."
                        break
                    } Else {
                        Write-Verbose "Could not find domain $($Using:DomainName). Attempt $i/$($Using:RetryCount). Sleeping $($Using:RetryIntervalSec) seconds..."
                        Start-Sleep -Seconds $Using:RetryIntervalSec
                    }
                }
                Return $FoundDomain
            }
            SetScript = {
                Write-Verbose 'Cannot continue. Domain not found.'
                Throw "Could not find domain $($Using:DomainName)."
            }
        }

        xADRecycleBin RecycleBin
        {
           EnterpriseAdministratorCredential = $DomainCreds
           ForestFQDN = $DomainName
           #DependsOn = '[xWaitForADDomain]DscForestWait'
           DependsOn = '[Script]xWaitForADDomain_Alternative'
        }


        ### OUs ###
        $DomainRoot = "DC=$($DomainName -replace '\.',',DC=')"
        $DependsOn_OU = @()

        ForEach ($RootOU in $ConfigurationData.NonNodeData.RootOUs) {

            xADOrganizationalUnit "OU_$RootOU"
            {
                Name = $RootOU
                Path = $DomainRoot
                ProtectedFromAccidentalDeletion = $true
                Description = "OU for $RootOU"
                Credential = $DomainCred
                Ensure = 'Present'
                DependsOn = '[xADRecycleBin]RecycleBin'
            }

            ForEach ($ChildOU in $ConfigurationData.NonNodeData.ChildOUs) {
                
                xADOrganizationalUnit "OU_$($RootOU)_$ChildOU"
                {
                    Name = $ChildOU
                    Path = "OU=$RootOU,$DomainRoot"
                    ProtectedFromAccidentalDeletion = $true
                    Credential = $DomainCred
                    Ensure = 'Present'
                    DependsOn = "[xADOrganizationalUnit]OU_$RootOU"
                }

                $DependsOn_OU += "[xADOrganizationalUnit]OU_$($RootOU)_$ChildOU"
            }

        }


        ### USERS ###
        # Use PasswordAuthentication = 'Negotiate' to avoid the password verification failure once ADCS is installed.
        # https://github.com/PowerShell/xActiveDirectory/issues/61
        $DependsOn_User = @()
        $Users = $ConfigurationData.NonNodeData.UserData | ConvertFrom-CSV
        ForEach ($User in $Users) {

            xADUser "NewADUser_$($User.UserName)"
            {
                DomainName = $DomainName
                Ensure = 'Present'
                UserName = $User.UserName
                Path = "OU=Users,OU=$($User.Dept),$DomainRoot"
                Enabled = $true
                PasswordAuthentication = 'Negotiate'
                Password = New-Object -TypeName PSCredential -ArgumentList 'JustPassword', (ConvertTo-SecureString -String $User.Password -AsPlainText -Force)
                DependsOn = $DependsOn_OU
            }
            $DependsOn_User += "[xADUser]NewADUser_$($User.UserName)"
        }

        ### GROUPS ###
        ForEach ($RootOU in $ConfigurationData.NonNodeData.RootOUs) {
            xADGroup "NewADGroup_$RootOU"
            {
                GroupName = "G_$RootOU"
                GroupScope = 'Global'
                Description = "Global group for $RootOU"
                Category = 'Security'
                Members = ($Users | Where-Object {$_.Dept -eq $RootOU}).UserName
                Path = "OU=Groups,OU=$RootOU,$DomainRoot"
                Ensure = 'Present'
                DependsOn = $DependsOn_User
            }
        }


        WindowsFeature ADCS-Cert-Authority
        {
            Ensure = 'Present'
            Name = 'ADCS-Cert-Authority'
            DependsOn = '[xADRecycleBin]RecycleBin'
        }

        WindowsFeature ADCS-Web-Enrollment
        {
            Ensure = 'Present'
            Name = 'ADCS-Web-Enrollment'
            DependsOn = '[xADRecycleBin]RecycleBin'
        }

        WindowsFeature RSAT-ADCS
        {
            Ensure = 'Present'
            Name = 'RSAT-ADCS'
            DependsOn = '[xADRecycleBin]RecycleBin'
        }

        xADCSCertificationAuthority ADCS
        {
            Ensure = 'Present'
            Credential = $DomainCreds
            CAType = 'EnterpriseRootCA'
            DependsOn = '[WindowsFeature]ADCS-Cert-Authority'              
        }

        xADCSWebEnrollment CertSrv
        {
            IsSingleInstance = 'Yes'
            Ensure = 'Present'
            Credential = $DomainCreds
            DependsOn = '[xADCSCertificationAuthority]ADCS'
        }

        ADCSTemplate PSDSCEncryptionTemplate
        {
            Ensure = 'Present'
            DisplayName = 'PSCMS'
            JSON = $ConfigurationData.NonNodeData.JSON_PSCMS
            Publish = $true
            Identity = "$DomainName\Domain Computers", "$DomainName\Domain Controllers"
            AutoEnroll = $true
            PsDscRunAsCredential = $DomainCreds
            DependsOn = '[xADCSWebEnrollment]CertSrv'
        }

        ADCSTemplate TaniumTemplate
        {
            Ensure = 'Present'
            DisplayName = 'Tanium'
            JSON = $ConfigurationData.NonNodeData.JSON_Tanium
            Publish = $true
            Identity = "$DomainName\Domain Computers"
            AutoEnroll = $false
            PsDscRunAsCredential = $DomainCreds
            DependsOn = '[xADCSWebEnrollment]CertSrv'
        }

    }
}


$configData = @{
    AllNodes = @(
        @{
            Nodename = "localhost"
            PSDscAllowPlainTextPassword = $true
            PSDscAllowDomainUser = $true
            Credential = $cred
        }
    )
    NonNodeData = @{
        
        UserData = @'
UserName,Password,Dept
TaniumAdmin,P@ssw0rd,Tanium
TaniumService,P@ssw0rd,Tanium
'@

        RootOUs = 'Tanium'
        ChildOUs = 'Users','Groups'

        JSON_PSCMS = @'
{
    "name": "PowerShellCMS",
    "displayName": "PowerShellCMS",
    "objectClass": "pKICertificateTemplate",
    "flags": 131680,
    "revision": 100,
    "msPKI-Cert-Template-OID": "1.3.6.1.4.1.311.21.8.14606814.4579994.15679635.15482926.4928991.141.63412935.14964662",
    "msPKI-Certificate-Application-Policy": [
                                                 "1.3.6.1.4.1.311.80.1"
                                             ],
    "msPKI-Certificate-Name-Flag": 268435456,
    "msPKI-Enrollment-Flag": 32,
    "msPKI-Minimal-Key-Size": 2048,
    "msPKI-Private-Key-Flag": 16842752,
    "msPKI-RA-Signature": 0,
    "msPKI-Template-Minor-Revision": 1,
    "msPKI-Template-Schema-Version": 2,
    "pKICriticalExtensions": [
                                  "2.5.29.15"
                              ],
    "pKIDefaultCSPs": [
                           "1,Microsoft RSA SChannel Cryptographic Provider"
                       ],
    "pKIDefaultKeySpec": 1,
    "pKIExpirationPeriod": [
                                0,
                                128,
                                114,
                                14,
                                93,
                                194,
                                253,
                                255
                            ],
    "pKIExtendedKeyUsage": [
                                "1.3.6.1.4.1.311.80.1"
                            ],
    "pKIKeyUsage": [
                        32
                    ],
    "pKIMaxIssuingDepth": 0,
    "pKIOverlapPeriod": [
                             0,
                             128,
                             166,
                             10,
                             255,
                             222,
                             255,
                             255
                         ]
}
'@


        JSON_Tanium = @'
{
    "name": "Tanium",
    "displayName": "Tanium",
    "objectClass": "pKICertificateTemplate",
    "flags": 131649,
    "revision": 100,
    "msPKI-Cert-Template-OID": "1.3.6.1.4.1.311.21.8.14606814.4579994.15679635.15482926.4928991.141.13175610.2217120",
    "msPKI-Certificate-Application-Policy": [
                                                 "1.3.6.1.5.5.7.3.1",
                                                 "1.3.6.1.5.5.7.3.2"
                                             ],
    "msPKI-Certificate-Name-Flag": 1,
    "msPKI-Enrollment-Flag": 0,
    "msPKI-Minimal-Key-Size": 2048,
    "msPKI-Private-Key-Flag": 16842768,
    "msPKI-RA-Signature": 0,
    "msPKI-Template-Minor-Revision": 2,
    "msPKI-Template-Schema-Version": 2,
    "pKICriticalExtensions": [
                                  "2.5.29.7",
                                  "2.5.29.15"
                              ],
    "pKIDefaultKeySpec": 1,
    "pKIExpirationPeriod": [
                                0,
                                128,
                                114,
                                14,
                                93,
                                194,
                                253,
                                255
                            ],
    "pKIExtendedKeyUsage": [
                                "1.3.6.1.5.5.7.3.1",
                                "1.3.6.1.5.5.7.3.2"
                            ],
    "pKIKeyUsage": [
                        160,
                        0
                    ],
    "pKIMaxIssuingDepth": 0,
    "pKIOverlapPeriod": [
                             0,
                             128,
                             166,
                             10,
                             255,
                             222,
                             255,
                             255
                         ]
}
'@

    }
}



#Install-Module -Name xAdcsDeployment, xActiveDirectory -Force
#Get-DscResource | Sort-Object ModuleName, Version, Name

md C:\ADCS -ErrorAction SilentlyContinue
cd C:\ADCS

$cred = New-Object -TypeName PSCredential -ArgumentList 'Administrator', (ConvertTo-SecureString -String 'Passw0rd' -AsPlainText -Force)

CreateADDomainWithCS -ConfigurationData $configData -DomainName 'goatee.lab' -AdminCreds $cred

Set-DscLocalConfigurationManager -Path .\CreateADDomainWithCS -Verbose
Start-DscConfiguration -Path .\CreateADDomainWithCS -Force -Verbose -Wait


break


#region CERT REQUEST/INSTALL ##################################################

dir Cert:\LocalMachine\My
dir Cert:\LocalMachine\My | Select-Object Thumbprint,Subject,@{name='KeyUsage';expression={$_.Extensions.KeyUsages}} | fl *

certutil -pulse

$Req = @{
    Template          = 'PSCMS'
    Url               = 'ldap:'
    CertStoreLocation = 'Cert:\LocalMachine\My'
}
Get-Certificate @Req

dir Cert:\LocalMachine\My | Select-Object Thumbprint,Subject,@{name='KeyUsage';expression={$_.Extensions.KeyUsages}} | fl *

$DocEncrCert = (dir Cert:\LocalMachine\My -DocumentEncryptionCert)[-1]
Protect-CmsMessage -To $DocEncrCert -Content "Encrypted with my new cert from the new template!"

#endregion ####################################################################