Zoho Banner September 2011

Archive for the ‘Active Directory’ Category

Another short blog posting (brevity is obviously my thing for 2014).

I occasionally come across environments in which Strict Replication Consistency is not enabled.  This is invariably because these environment have forests that were created with Windows 2000 server, but which have subsequently been upgraded.  If you need to know more about Strict Replication Consitency and why it is important for your AD environment, I don’t plan to bore you with the details here as this topic is well covered elsewhere.  The best article I have found on the topic is this one.

http://blogs.technet.com/b/askds/archive/2010/02/15/strict-replication-consistency-myth-versus-reality.aspx

The article makes the essential point that if the environment does not have SRC enabled then you need to do two things:

  1. Ensure the required registry key is configured on each DC.  The quickest method to achieve this is using Repadmin as follows: repadmin /regkey * +strict
  2. Ensure any new DCs promoted within the forest automatically have SRC enabled by creating an operational GUID (actually a Container object in the Configuration Partition).  There are several ways to create the object, but as you know, I’m a fan of Powershell, so here’s the code to do it:

 

# Strict Consistency - add operational GUID
$cnc = (get-adrootdse).configurationnamingcontext
$path = "CN=Operations,CN=ForestUpdates," + $cnc
$obj = "94fdebc6-8eeb-4640-80de-ec52b9ca17fa"
New-ADObject -Name $obj -Type container -Path $path -OtherAttributes @{showInAdvancedViewOnly="TRUE"}

Enjoy!

Today’s blog entry is short and sweet.  You want to quickly find out whether the AD Recycle Bin feature is enabled or not.   There are a few ways to do this, but this is a quick Powershell method.

 

# Is the AD Recycle Bin enabled in my forest?
Import-Module ActiveDirectory
If ((Get-ADOptionalFeature -Identity "Recycle Bin Feature").EnabledScopes) {
    write-host "AD Recycle Bin is enabled"
    } # end if
Else {
    write-host "AD Recyle Bin is not yet enabled"
} # end else

I quite regularly come across Active Directory environments where users have been mistakenly added to groups protected by the AdminSDHolder and subsequently removed when the mistake has been realised.  This process creates “orphans” because the AdminSDHolder process doesn’t tidy up after itself.  Here’s what happens:

  1. User added to group protected by the AdminSDHolder (e.g. Account Operators)
  2. The AdminSDHolder process (actually a thread within LSASS.EXE on the PDC Emulator) sets the adminCount attribute value to 1 on the user object and replaces the user’s security descriptor with that of the AdminSDHolder container object.
  3. User is then removed from Account Operators.
  4. The adminCount value of 1 is not cleared and the security descriptor is not changed (i.e. remains the same as that of the AdminSDHolder).

It doesn’t make sense to leave these orphans as they are.  For one, it plays havoc with any delegation model that is in place.  It also makes it difficult to determine what objects are actually protected.  For example, searching for objects that have an adminCount of 1 will potentially give you misleading results.

So what can you do about it?  One option is to manually look at each object to determine whether it is genuinely a protected object and then clear the adminCount value and re-set the inheritance flag for any objects no longer protected.  This is likely to be incredibly time consuming as you will need to factor in nested group membership into your investigation.  Another option is to run a script that clears the adminCount value and resets the inheritance flag for *all* protected objects.  Any objects that should genuinely be protected will be re-protected (I just made that word up) when the AdminSDHolder next cycles (within 1 hour by default).

The second option sounds like the clear winner.  There are some small risks that you should be aware of with this approach.  Firstly, there might be some malware “lurking” in your environment that will take the opportunity to compromise privileged accounts when they are in an unprotected state (even for a short period).  Secondly, re-setting the inheritance flag on objects might cause unforeseen problems.  For example, a user object might have had the inheritance flag unchecked prior to being protected by the AdminSDHolder.

Basically, there is no silver bullet here.  Personally, I think the small risk associated with the scripted option generally outweighs the negative impact of AdminSDHolder orphans.  Here’s the script that I use:

#########################################################
#
# Name: Cleanup-AdminSDHolder.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 28/08/2013
# Comment: PowerShell 2.0 script to re-set inheritance
# flag for objects no longer protected by the 
# AdminSDHolder
#
########################################################### 

# Import the AD module
Import-Module ActiveDirectory

# Find objects that appear to be protected in AD
$probjs = Get-ADObject -LDAPFilter "(admincount=1)"
$bcount = $probjs.count
if ($bcount) {
    write-host "Protected object count before change is $bcount"
} # end if
else {
    write-host "No objects are currently protected - nothing to do"
    exit
} # end else

# Change to the AD drive
cd AD:

# Loop through protected objets to set inheritance flag
# and clear the adminCount value
foreach ($probj in $probjs) {
    $dn = $probj.distinguishedname
    $acl = get-acl $dn
    if ($acl.AreAccessRulesProtected) {
        write-host "$dn has inheritance blocked - we will remove the block"
        $acl.SetAccessRuleProtection($false, $false);
        set-acl -aclobject $acl $dn
        # We need to clear the adminCount attribute too
        Set-ADObject -Identity $dn -Clear adminCount
    } # end if
} # end foreach    

# Count the number of protected objects
$acount = (Get-ADObject -LDAPFilter "(admincount=1)").count
if ($acount) {
    write-host "Protected object count after change is $acount"
} # end if
else {
    write-host "No objects are currently protected"
} # end else

Please leave a comment if you have any thoughts on how to improve the script, or if you are aware of a better method of handling AdminSDHolder orphans.

You can download a copy of the script here: Cleanup-AdminSDHolder

 

Back in March 2010 when Powershell and I were on somewhat less friendly terms, I wrote an OU shadow script to populate group membership based on the contents of an OU. Since then, Powershell and I now at least acknowledge eachother when we pass in the corridor and I have updated the script with some improvements.

One common use for the script is populating group memberships for use with Fine-Grained Password Policy (FGPP).

Please leave a comment if you see any scope for improvement.  You can download a copy of the script here: OUBasedGroupMembership ps1

#########################################################
#
# Name: OUBasedGroupMembership.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 03/09/2013
# Comment: PowerShell 2.0 script to
# manage group membership based on OU contents
#
#########################################################

# Import the AD module
ipmo ActiveDirectory

# Define arrays to be used for matching
$arrou = @()
$arrgp = @()

# Domain controller to be used
$dc = (Get-ADRootDSE).dnshostname
write-host "Using DC $dc for all AD reads/writes"

# Specify the OU where the accounts are located
$OUdn = "OU=Admin Accounts,OU=AD Administration,DC=contoso,DC=com"
$OuUsrs = Get-ADUser -Filter * -SearchBase $oudn -Server $dc

# Specify the group to use
$grp = "de42112f-81d2-4849-900c-d6907c77d3f5" # "Service Accounts"
$grpusers = Get-ADGroupMember -Identity $grp -Server $dc

# Build arrays using the DN attribute value
$OuUsrs | % {$arrou += $_.distinguishedname}
$grpusers | % {$arrgp += $_.distinguishedname}

# Add to group membership (new user in OU)
foreach ($usr in $arrou) {
    if ($arrgp -contains $usr) {
        write-host "User $usr is a member of the group"
    }
    else {
        write-host "User $usr is not a member of the group - adding..."
        #Add-ADGroupMember -Identity $grp -Members $usr -Server $dc
    } # end else
    Remove-Variable -ErrorAction SilentlyContinue -Name usr    
} # end foreach

write-host "`n"

# Remove from group membership (no longer in OU or has been manually added to group)
# The assumption here is that the OU is authoritative for the group's membership
foreach ($mem in $arrgp) {
    if ($arrou -contains $mem) {
        write-host "User $mem is located in the OU.  Nothing to do"
    } # end if
    else {
        write-host "User $mem is not present in the OU.  Removing from membership..."
        #Remove-ADGroupMember -Identity $grp -Members $mem -Server $dc -Confirm:$false
    } # end else
    Remove-Variable -ErrorAction SilentlyContinue -Name mem
} # end foreach

I’ve recently been looking at Microsoft’s Security Compliance Manager 3.0.  SCM allows provides a rich set of server-role-based security baselines for deployment using either GPO or SCCM.  This latest version includes baselines for Windows Server 2012. 

After deploying the “WS2012 Domain Controller Security Compliance 1.0″ baseline settings via GPO into my lab environment I found RDP sessions to my Windows Server 2012 DCs to be horrendously slow – almost to the point of not being able to do anything.

My on-line searches for the cause revealed nothing official from Microsoft, but I did find some references to one specific setting being the probable cause.  The setting is “Use FIPS compliant algorithms for encryption, hashing, and signing” set to Enabled.

Computer Config->Policies->Windows Settings->Security Settings->Local Policies->Security Options->System Cryptography->Use FIPS compliant algorithms for encryption, hashing, and signing

After setting the value to Disabled and updating Group Policy on the DCs my RDP sessions returned immediately to normal speed.

I hope this information helps others who might come across the same behaviour.

 

Have you ever considered running BitLocker to encrypt the drives within a Virtual Machine running on, e.g. Hyper-V or VMWare? On the face of it, it seems a sensible thing to do, especially considering how portable VHDX and VMDK files are. Despite the process of enabling BitLocker for VMs being described online, you should be aware that it is not actually supported.

The Microsoft support statement is here:

Can I use BitLocker within a virtual machine operating environment?

BitLocker is not supported for use within a virtual machine. Do not run BitLocker Drive Encryption within a virtual machine. You can use BitLocker in the virtual machine management operating system to protect volumes that contain configuration files, virtual hard disks, and snapshots.

Source: http://technet.microsoft.com/en-us/library/hh831507.aspx

The VMWare support statement follows logically from Microsoft’s:

As the operating system vendor does not support this configuration, it is unsupported by VMware in a Player, Workstation, Fusion or ESX/ESXi virtual machine.

Source: http://kb.vmware.com/selfservice/microsites/search.do?language=en_US&cmd=displayKC&externalId=2036142

In the context of Active Directory Domain Controllers, Microsoft makes the following recommendations for securing virtual domain controllers:

If you implement virtual domain controllers, you should ensure that domain controllers run on separate physical hosts than other virtual machines in the environment. Even if you use a third-party virtualization platform, consider deploying virtual domain controllers on Hyper-V Server in Windows Server 2012 or Windows Server 2008 R2, which provides a minimal attack surface and can be managed with the domain controllers it hosts rather than being managed with the rest of the virtualization hosts. If you implement System Center Virtual Machine Manager (SCVMM) for management of your virtualization infrastructure, you can delegate administration for the physical hosts on which domain controller virtual machines reside and the domain controllers themselves to authorized administrators. You should also consider separating the storage of virtual domain controllers to prevent storage administrators from accessing the virtual machine files.

Source: Best Practices for Securing Active Directory

It will be interesting to see whether Microsoft change their support statement in future versions of Windows.  I’ve not seen anything in Windows Server 2012 R2 to indicate a change, so it might be a while yet.

Occasionally, I have a need to merge the attributes of one AD user into another.  This requirement is typically the result of a migration where some users have had accounts informally created in the target environment in advance of the formal migration process.  In other words, a user ends up with two accounts and needs to merge the authoritative attribute values from one of user object to another.   The Powershell script below shows an example of how selected attributes on one object can be replaced with those from another object.  

#########################################################
#
# Name: Merge-UserAttributes.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 12/06/2013
# Comment: PowerShell 2.0 script to copy a fixed set of
# attributes from one user object to another
#
#########################################################

# Import the AD module
ipmo activedirectory

#### Function to test the existence of an AD user
function Test-ADUser() {
   [CmdletBinding(ConfirmImpact="Low")]
   Param (
      [Parameter(Mandatory=$true,
                 Position=0,
                 ValueFromPipeline=$true,
                 HelpMessage="Identity of the AD object to verify if exists or not."
                )]
      [Object] $Identity
   )
   trap [Exception] {
      return $false
   }
   $auxObject = Get-ADUser -Identity $Identity -Server $dc
   return $true
}
####

#### Global variables
$dc = (Get-ADDomainController).hostname

# Create an array of the attributes we want to copy
$atts2copy = @("ipphone","mobile","facsimileTelephoneNumber",
"telephonenumber","streetAddress","st","l","c","physicalDeliveryOfficeName",
"description","department","postofficebox","thumbnailPhoto","manager")

# Users to merge 
$source = "User1"
$target = "User2"

write-host "Working on source target pair: $source --> $target"
if ( (Test-ADUser $source) -and (Test-ADUser $target) ) { $greenlight = $true }
if ($greenlight) {
    $srcatts = Get-ADUser -Identity $source -pr * -Server $dc
    # Create a hashtable to store the attributes
    $replaceHashTable = New-Object HashTable
    # Add the attributes one-by-one to the hashtable
    foreach ($att2copy in $atts2copy){
        $attvalue = $srcatts.$att2copy
        if ($attvalue) {
            if ( ($attvalue.gettype()).name -eq "ADPropertyValueCollection") {
                # We have a collection which need to convert to an array
                # otherwise the set-aduser cmdlet doesn't set the value
                $attarray = @($attvalue)
                $replaceHashTable.Add($att2copy,$attarray)
            } # end if
            else {
                $replaceHashTable.Add($att2copy,$attvalue)
            } # end else
        } # end if
        Remove-Variable -ErrorAction SilentlyContinue -Name att2copy
        Remove-Variable -ErrorAction SilentlyContinue -Name attvalue
        Remove-Variable -ErrorAction SilentlyContinue -Name attarray
    } #end foreach
    # Set the attributes on the target user
    write-host "Setting attributes on target"
    $replaceHashTable
    Set-ADUser -Identity $target -Replace $replaceHashTable -Server $dc
    } # end if
Else {
    Write-Host "No match found for either $source or $target - please check CSV"
} # end else
Remove-Variable -ErrorAction SilentlyContinue -Name source
Remove-Variable -ErrorAction SilentlyContinue -Name target
Remove-Variable -ErrorAction SilentlyContinue -Name greenlight
Remove-Variable -ErrorAction SilentlyContinue -Name srceatts
$replaceHashTable = @{}

Another scenario where this script might be useful is merging attributes from an AD Snapshot (taken with NTDSUtil) into a “live” object, e.g. following the corruption of attribute values in the production environment.  In this case you would need to modify or remove the test for the existence of the user objects.

You can download a copy of the script here: Merge-UserAttributes

Quite often I see customers that need to use generic attributes to populate user, group or contact objects with certain values that do not appear in the default AD schema.  Most of these customers have Microsoft Exchange and tend to use the extension attributes that are delivered as part of the Exchange AD schema extensions.  This is all well and good, but there are some downsides with using the Exchange extensions.  In particular, the attribute values associated with the Exchange extension attributes are cleared when an object is either mail(or mailbox)-enabled or mail(or mailbox)-disabled.  Exchange effectively “owns” the values for these attributes and does not expect them to be used for anything other than Exchange use.

Armed with this knowledge, what are you supposed to do if you want to use some “spare” schema attributes for general use?  Well, within the AD default schema you don’t have a great deal of choice available.   Your best option is to extend the schema with some custom attributes of your own.  Custom schema extensions are no longer considered the scary beast they once were.  Schema conflicts are rare nowadays and can be handled by defuncting the offending schema class objects as required.

If you plan to add some classes and attributes to the schema you can choose appropriate, non-conflicting names and simply get on  with it.  This is fine if you know the attributes will be used indefinitely, but want if you simply want some generic attributes whose values you will populate for a short period (e.g. a project or a migration) and then re-use for some other purpose?  In that case you could extend your schema with some generic custom attributes – similar to those introduced by Exchange.

The attached LDF file is a schema extension that includes 10 generic string attributes (genericExtensionAttribute1-10).  These are included in custom auxiliary classes (Generic-User, Generic-Group and Generic-Contact) that are then linked to their corresponding classes from the default AD schema (User, Group and Contact).  The attributes have a maximum length of 128 characters (rangeUpper). 

To add the schema extensions, use LDIFDE running from a Administrator command prompt.  The account you use must be a member of the Schema Admins group.

Shortly after the schema update has completed, you will see the new attributes available for population on User, Group and Contact objects.

Feel free to use these extensions as-is (but don’t blame me if anything breaks!).  The OIDs used for the attributes and classes are derived from a parent that has been assigned to me by IANA.  You can obviously modify the LDF to change the names (e.g. if they conflict with anything in your schema) or the OID (e.g. if you have your own).  In any case you will need to replace the forest distinguished name in the LDF file (DC=contoso,DC=com) with your own.  Be sure to test this in your lab environment before you go ahead in production.

The LDF file is available here: Schema_Extensions

Enjoy!

I often see my customers running things other than Active Directory Domain Services (ADDS) on Domain Controllers.  These can range from the relatively innocuous (KMS) to the downright ludicrous (Exchange).  Until now, I haven’t been able to point to anything official from Microsoft to state that this is not a good idea.  Anyway, fellow Directory Services MVP Joe “Won’t Leave The Shire” Richards recently found this guidance in the new Best Practices for Securing Active Directory:

Domain controllers should be treated as critical infrastructure components, secured more stringently and configured more rigidly than file, print, and application servers. Domain controllers should not run any software that is not required for the domain controller to function or doesn’t protect the domain controller against attacks.

Source: http://www.microsoft.com/en-us/download/details.aspx?id=38785

Something I’ve noticed in the on-line forums is that people are still advising others to use NTDSUTIL to perform a metadata cleanup to remove references to Domain Controllers that have been removed from AD without using DCPROMO (e.g. following a DC failure where demotion was not possible).  Since Windows Server 2008 it has been possible to perform the metadata cleanup simpy by deleting the Domain Controller object using Active Directory Users and Computers.

A full explanation is provided here:

http://technet.microsoft.com/pt-pt/library/cc816907(v=ws.10).aspx