Monday 29 April 2013

Adding Audit Rules (SACLs) to Active Directory Objects

As part of the work I'm currently doing with Active Directory, my customer requires auditing of user, group and computer object deletions.  The group policy setting "Audit Directory Service Changes" enables the required auditing at an audit policy level, but the system access control lists (SACLs) for the objects don't include deletions by default.  I needed a way to configure all user, group and computer objects in the domain to include such a SACL entry.

Firstly, what are SACLs?  SACLs identify the users and groups that you want to audit when they successfully access or fail to access an object and can be configured not only to include the user or group you are interested in, but also the type of access.  The following screen grab shows the default auditing configured at the root of a new Windows Server 2012 Active Directory domain.


Default auditing on the root of a W2K12 Active Directory



I wanted to configure the SACLs as a task sequence action during the System Center Configuration Manager OSD task sequence I have developed for my customer, so I turned to Windows PowerShell.  After running my script, the auditing configured at the root of the domain looks like this:


Auditing on the root of the domain after the script has run


This is the script I came up with:



#------------------------------------------------------
# | File : ADDSAuditSettings.ps1                                        
# |                                            
# | Purpose : Configures extra auditing (SACLs) at for the
# | new domain
# |
# | Usage : PowerShell.exe -FILE .\ADDSAuditSettings.ps1 
#------------------------------------------------------
# |                                         
# | Author:          JustAnotherTechnicalBlog
# | Creation Date:   26 April 2013
# |
# |
# | Maintenance History                                            
# | ------------------- 
# | 
# | Version:  1.00  2013-04-26  Initial Version  JustAnotherTechnicalBlog
# |
# |
#------------------------------------------------------


# Clear the error variable
#------------------------------------------------------
$error.clear()


# Import the ActiveDirectory PowerShell Module if required
#------------------------------------------------------
if (-not (Get-Module ActiveDirectory))
  {
   Import-Module ActiveDirectory
  }

# This fuction takes a schema GUID ID and a security  
# principal and enables a new SACL entry so deletions
# of target object type by the specified security 
# principal will be audited
#------------------------------------------------------
Function AuditDeletions {

  Param (
         [Parameter(Mandatory=$true)]
         [system.guid]$SchemaIDGUID,
         [Security.Principal.NTAccount]$SecurityPrincipal  
        )

  # Get the DN for the current domain
  #------------------------------------------------------
  $dn = (Get-ADDomain).DistinguishedName

  # Get the current ACLs for the root of the domain
  #------------------------------------------------------
  $acl = Get-ACL -Audit -Path AD:\$dn

  # Build the new SACL rule.
  # This rule will enable auditing of succesful deletion 
  # of our target object.  The rule will be inherited 
  # throughout the domain
  #------------------------------------------------------
  $Rule = New-Object System.DirectoryServices.ActiveDirectoryAuditRule `
                     $SecurityPrincipal, `
                     "DeleteChild", `
                     "Success", `
                     $SchemaIDGUID, `
                     "All"

  # Add the new audit rule to the ACL we 
  # opened earlier
  #------------------------------------------------------
  $acl.AddAuditRule($Rule)

  # Commit the new audit rule
  #------------------------------------------------------
  Set-ACL -Path AD:\$dn -AclObject $acl

}


# To work with AD objects we need the relevent schema
# ID GUIDs. variables to hold these:
#------------------------------------------------------
$ComputerSchemaIDGUID = "bf967a86-0de6-11d0-a285-00aa003049e2"
$GroupSchemaIDGUID    = "bf967a9c-0de6-11d0-a285-00aa003049e2"
$UserSchemaIDGUID     = "bf967aba-0de6-11d0-a285-00aa003049e2"


# The AuditDeletions function above requires a security 
# principal.  user/group we want to audit?
#------------------------------------------------------
$who = "Everyone"


# Put the AuditDeletions function to use ....
#------------------------------------------------------
AuditDeletions $ComputerSchemaIDGUID $who
AuditDeletions $GroupSchemaIDGUID $who
AuditDeletions $UserSchemaIDGUID $who


# Basic error handling
#------------------------------------------------------
If ($error)
  {
   Write-Host "Audit setting configurations failed"
   Exit 1003
  }
Else
  {
   Write-Host "Audit setting configurations completed OK"
  }

Tuesday 23 April 2013

Automating Active Directory Setup - Install a Child Domain

In previous posts over the past few weeks I've explained how I've installed the Active Directory Domain Services role and provisioned the first domain controller in a root domain using Configuration Manager OSD task sequences and some Windows PowerShell code. The next thing I need to do is install the first domain controller in a subordinate child domain in the new forest. The child domain will hold all my computing resources and users.

The following script:

  • Installs a new domain controller in a child domain, creating that new domain.
  • Gets the variables you will see in the script from Configuration Manager.
  • Creates the new domain within the previously created forest
  • Ensures DNS delegations are created
#-------------------------------------------------------------------
# | File : NewChildDomain.ps1                                           
# |                                            
# | Purpose : Installs the first Domain Controller in a child domain, 
# |           thus creating the new domain
# |           - Designed to be run from a Configuration Manager OSD 
# |             task sequence
# |           - Designed for Windows Server 2012 environments
# |           - Reboot handled by task sequence
# |
# | Usage : PowerShell.exe -FILE .\NewChildDomain.ps1 
#-------------------------------------------------------------------
# |                                         
# | Author:          JustAnotherTechnicalBlog
# | Creation Date:   23 April 2013
# |
# |
# | Maintenance History                                            
# | ------------------- 
# | 
# | Version:  1.00  2013-04-23  Initial Version  JustAnotherTechnicalBlog
# |
# |
#-------------------------------------------------------------------


# Clear the error variable
#-------------------------------------------------------------------
$error.clear()


# Import the ActiveDirectory PowerShell Module if required
#-------------------------------------------------------------------
if (-not (Get-Module ActiveDirectory))
  {
   Import-Module ActiveDirectory
  }


# Here we get access to the Task Sequence variables
#-------------------------------------------------------------------
$objTSenv = New-Object -COMObject Microsoft.SMS.TSEnvironment


# Grab the data we need from the task sequence variables
#-------------------------------------------------------------------
$strTSNetBIOSName =  $objTSenv.Value("RoleVariable1")
$strTSDomainName  =  $objTSenv.Value("RoleVariable2")
$strTSPrntNBName  =  $objTSenv.Value("RoleVariable3")
$strTSPrntDmnName =  $objTSenv.Value("RoleVariable4")
$strTSPrntDmnAcct = "$strTSPrntNBName\" + $objTSenv.Value("RoleAccount2")
$strTSDNSAccount  = "$strTSPrntNBName\" + $objTSenv.Value("RoleAccount3")


# Convert our password to the data type required by Install-ADDSDomain
#-------------------------------------------------------------------
$secstrSafeModePassword = $objTSenv.Value("RoleAccountPassword1") | `
      ConvertTo-SecureString -asPlainText -Force


# Convert our accounts and passwords strings to the data type required
# by Install-ADDSDomain
#-------------------------------------------------------------------
$secstrDomainPassword = $objTSenv.Value("RoleAccountPassword2") | `
     ConvertTo-SecureString -asPlainText -Force
$DomainCreds = New-Object `
     System.Management.Automation.PSCredential("$strTSPrntDmnAcct",$secstrDomainPassword)

$secstrDNSPassword = $objTSenv.Value("RoleAccountPassword3") | `
     ConvertTo-SecureString -asPlainText -Force
$DNSCreds = New-Object `
     System.Management.Automation.PSCredential("$strTSDNSAccount",$secstrDNSPassword)



# Install our first forest Domain Controller, creating a new forest
#-------------------------------------------------------------------
Install-ADDSDomain `
  -Force `
  -NoRebootOnCompletion `
  -CreateDNSDelegation `
  -DomainType Child `
  -DomainMode Win2012 `
  -ParentDomainName "$strTSPrntDmnName" `
  -NewDomainNetBIOSName "$strTSNetBIOSName" `
  -NewDomainName "$strTSDomainName" `
  -SafeModeAdministratorPassword $secstrSafeModePassword `
  -DNSDelegationCredential $DNSCreds `
  -Credential $DomainCreds



# Basic error handling
#-------------------------------------------------------------------
If ($error)
  {
   Write-Host "Child domain creation failed"
   Exit 1001
  }
Else
  {
   Write-Host "Child domain created successfully"



Task Sequence Snippet:  Active Directory Installation

Installing an Active Directory Child Domain with Windows PowerShell

Monday 15 April 2013

Tip - Using Active Directory Users & Computers to Manage Another Domain

Today a colleague asked me how to connect to our forest root domain from an admin workstation in our child domain when using Active Directory Users & Computers (ADUC).  The forest root domain contains only a small number of servers, and they all have Windows 2012 Standard (Core) installed so no GUI.  What he wanted to do was quickly look at something with ADUC an not mess around with Windows PowerShell.  I thought it would be easy, but it isn't as easy as I thought, I figured it out in the end, but was a bit surprised this isn't built into the GUI tools.

This is what we did.

1.  On the admin workstation (a child domain member) launched an elevated command prompt with an admin level account local to the child domain (and probably would have worked with an admin level account that was only a workstation admin)

2.  Run the following command using credentials from the parent domain:


runas /netonly /user:DOMAIN01\TechGuy "mmc.exe dsa.msc"


This worked a treat and my colleague was able to do what he needed to do.  Is there a better way?

Automating Active Directory Setup - Installing the Active Directory Domain Services Role

I've been working on a OSD task sequence to deploy Active Directory in a Windows 2012 environment for my current customer.  They have many environments in production, and many more in the development, testing and quality assurance environments, so this is something they need to be automated and repeatable.

The screen sot below shows the snippet of a larger task sequence that installs many different roles, features, and applications all in one task sequence.  Variables assigned to the computer object when we provision the computer object in Configuration Manager drive what roles, features and applications get installed.  I'm not going to show how that works here, but it may be something I explain in separate posts at some stage.

The first step to install Active Directory is to install the Active Directory Domain Services role.  The screen shots below show how that is done in the task sequence.  I just use Windows PowerShell to do this with the following command:

#-----------
PowerShell.exe -COMMAND Install-WindowsFeature -Name AD-Domain-Services `
   -IncludeManagementTools

The code above does not create an domain controller. It just installs the Active Directory Domain Services role.  Other steps in the task sequence see the server promoted to be a domain controller.

Including the 'IncludeManagementTools' option sees the appropriate management tools, and Windows PowerShell modules, get installed.  This works on both the standard and core installations of Windows, with the installer being intelligent enough to know what to install base on what edition of Windows Server is being installed.


Task Sequence Snippet:  Active Directory Installation


Installing the Active Directory Domain Services Role with Windows PowerShell

Friday 12 April 2013

Automating Active Directory Setup - Installing the First Domain Controller in a Forest

I'm building a new Active Directory environment based on Windows Server 2012. This is a green-fields site, and the builds are automated using the OSD task sequences available in System Center Configuration Manager 2012. The first server I build in the domain is a domain controller in a place-holder root domain. The following script promotes a server to this be a domain controller and creates the new forest and domain. A previous post explains how I install the Active Directory Domain Services role.


The script below:

  • Installs a new domain controller in a forest root domain, creating that domain.
  • Gets the variables you will see in the script from Configuration Manager.


I will explain how to populate variables in Configuration Manager in a separate post in due course.

#------------------------------------------------------------------------------------
# | File : NewForest.ps1                                           
# |                                            
# | Purpose : Installs the first Domain Controller in a forest, thus creating 
# |           a new forest
# |           - Designed to be run from a Configuration Manager OSD task sequence
# |           - Designed for Windows Server 2012 environments
# |           - Reboot handled by task sequence
# |
# | Usage : PowerShell.exe -FILE .\NewForest.ps1 
#------------------------------------------------------------------------------------
# |                                         
# | Author:          JustAnotherTechnicalBlog
# | Creation Date:   11 April 2013
# |
# |
# | Maintenance History                                            
# | ------------------- 
# | 
# | Version: 1.00 2013-04-12      Initial Version      JustAnotherTechnicalBlog
# |
# |
#------------------------------------------------------------------------------------


# Clear the error variable
#------------------------------------------------------------------------------------

$error.clear()



# Import the ActiveDirectory PowerShell Module if required
#------------------------------------------------------------------------------------

if (-not (Get-Module ActiveDirectory))
  {
   Import-Module ActiveDirectory
  }



# Here we get access to the Task Sequence variables
#------------------------------------------------------------------------------------

$objTSenv = New-Object -COMObject Microsoft.SMS.TSEnvironment



# Grab the data we need from the task sequence variables
#------------------------------------------------------------------------------------

$strTSNetBIOSName         = $objTSenv.Value("RoleVariable1")
$strTSDomainName          = $objTSenv.Value("RoleVariable2")



# Convert our password to the data type required
# by Install-ADDSForest
#------------------------------------------------------------------------------------

$secstrSafeModePassword = $objTSenv.Value("RolePassword1") | `
   ConvertTo-SecureString -asPlainText -Force



# Install our first forest Domain Controller, creating a new forest
#------------------------------------------------------------------------------------

Install-ADDSForest `
  -Force `
  -NoRebootOnCompletion `
  -DomainNetBIOSName "$strTSNetBIOSName" `
  -DomainName "$strTSDomainName" `
  -ForestMode Win2012 `
  -DomainMode Win2012 `
  -SafeModeAdministratorPassword `
        $secstrSafeModePassword



# Very basic error handling ...
#------------------------------------------------------------------------------------

If ($error)
  {
   Write-Host "Forest creation failed"
   Exit 1000
  }
Else
  {
   Write-Host "Forest created successfully"
  }


Task Sequence Snippet:  Active Directory Installation


Installing a new forest with a PowerShell script

Thursday 11 April 2013

I Closed my Command Windows on a Server Core Machine ....

Doh! Doh! Doh!

I keep doing this, and in a Remote Desktop Session! Idiot!!!! You would think I'd learn, but I don't.

How do I get it back, I can't use CTRL-ALT-DEL?

Well, it turns out to be really easy. Just launch Task Manager with CTRL-SHIFT-ESC and then launch a new command window using the run option in Task Manager.

Easy!