Zoho Banner September 2011

Archive for the ‘Active Directory’ Category

I came across a weird error the other day while running Exchange Server 2013 CU6 setup with the /PrepareAD switch.  The error (from the Exchange setup logs) was this:

[12/02/2014 01:14:16.0727] [2] [ERROR] Could not find the Exchange Mailbox Administrators Universal Security Group through its well-known GUID 29a962c2-91d6-4ab7-9e06-8728f8f842ea.  Please make sure that Setup /prepareAD has been run.

I sat there scratching my head for a while because what (wtf?) is the Exchange Mailbox Administrators group and what does it have to do with Exchange 2013.  Anyway, after a journey of discovery, here’s what I found out.

For some time, Exchange has used an attribute named otherWellKnownObjects on the Exchange container in the Configuration partition of AD to store information about the location of certain Exchange objects, including the default groups.  One of these entries corresponds to the Organization Management group (as shown below).

attribute values

The strange-looking string next to the DN for the Organization Management group (C262A929D691B74A9E068728F8F842EA) is a Hex representation of a GUID.  To get to the string representation I found a handy function called Convert-OctetStringToGuid.  The result was as follows:

convert hex

The resulting GUID string (29a962c2-91d6-4ab7-9e06-8728f8f842ea) matches that shown in the original error.  So, basically the setup error was saying that it couldn’t find the Organization Management group.  The guff about the Exchange Mailbox Administrators group must be a legacy piece of code referencing an earlier version.  Once I had the new information I had a look to see if the group actually existed (it did).  I then concluded that maybe AD replication hadn’t finished by the time setup got to looking for the group.  I then made the executive decision to run setup with the /PrepareAD switch again.  Lo and behold it finished successfully.

I thought this write-up might help if you find yourself in the same boat.

A question came up in the forums today about how to use the AD Powershell cmdlets to find objects with attribute values that contain a single space. It’s a good question and relevant because often your results can be skewed by such values when searching for attributes that are not NULL (a space character is not a NULL). Anyway, here’s an example of how to do it using the LDAPFilter.

Get-ADUser -LDAPFilter "(telephonenumber=\20)"

The “\” is the standard escape character for use in LDAP searches and “20″ is the HEX representation of the space character.

The filter should also work with other LDAP clients (e.g. LDP.EXE).

It’s sometimes interesting to know how old your AD forest is and when the various domains were created.  I recently came across a really useful TechNet Blog with a Powershell snippet to do just this.  My version shown below just has some slightly different formatting.

# How old is the forest?
Get-ADObject -SearchBase (Get-ADForest).PartitionsContainer `
-LDAPFilter "(&(objectClass=crossRef)(systemFlags=3))" `
-pr dnsRoot, nETBIOSName, whenCreated | Sort whenCreated `
| select @{e={($_.DNSRoot)};l=”DomainFQDN”}, `
nETBIOSName, @{e={(get-date $_.whencreated -format dd/MM/yyyy)};l=”whenCreated”} `
| ft -AutoSize

The output should look something like this:

check-forestage

So how old is your forest?

If you haven’t heard that extended support for Windows XP ended earlier this year you’ve clearly been in a coma.  There are a number of well-publicised methods for finding out whether you still have XP machines in your environment.  Here is my own humble (and spectacularly over engineered) Powershell offering.

 

#########################################################
#
# Name: Find-XPStillActive.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 23/09/2014
# Comment: PowerShell 2.0 script to find active
# Windows XP computer accounts
#
#########################################################

## Define global variables
# Export file for storing results
$expfile = "c:\xp_still_active.csv"
# Define the header row for the CSV (we will create our own)
$header = "`"name`",`"os`",`"sp`",`"lastlogondate`""
# Consider any account logged on in the last x days to be active
$days = 60
$Today = Get-date
$SubtractDays = New-Object System.TimeSpan $days, 0, 0, 0, 0
$StartDate = $Today.Subtract($SubtractDays)
$startdate = $startdate.ToFiletime()
# LDAP filter settings
$filter = "(&(lastlogontimestamp>=$startDate)(operatingsystem=Windows XP*))"

## Functions
Function Format-ShortDate ($fdate)
{
        if ($fdate) {
            $day = $fdate.day
            $month = $fdate.month
            $year = $fdate.year
            "$day/$month/$year"
        } # end if

} # end function

## Start doing things
# Import the AD module
ipmo ActiveDirectory
# Tidy up any previous copies of the export file 
if (test-path $expfile) {Remove-Item $expfile}
# Add the header row to the export file
Add-Content -Value $header -Path $expfile
# Create an array of computer objects
$active = Get-ADComputer -LDAPFilter $filter -pr *
# loop through the array
foreach ($xp in $active) {
    # Grab the attribute values we need from the AD object
    $nm = $xp.name
    $os = $xp.operatingsystem
    $sp = $xp.operatingsystemservicepack
    $lt = Format-ShortDate $($xp.lastlogondate)
    $row = "`"$nm`",`"$os`",`"$sp`",`"$lt`""
    # Commit the row to the export file
    Add-Content -Value $row -Path $expfile
} # end foreach

## End script

Enjoy!

 

There was in interesting discussion the other day on the ActiveDir.org mailing list. Someone asked how many values can be stored within the proxyAddresses mutlivalued attribute in Active Directory. The responses were reasonably consistent, with most people indicating that in Windows 2000 the number was in the range of approximately 800 to 850 and from Windows 2000 the range is approximately 1200 to 1300.

This begs the question of why we can’t be specific about the number. Well, it comes down to how the data is stored within the Active Directory database (ntds.dit). Most of the attribute data for an individual object is stored within a single row in the Data Table within the database. I say “most” because linked attribute data (e.g. member/memberof, manager/directReports, etc.) is kept in a separate table (the Link Table). The AD schema determines how many attributes are available for a particular object and this obviously varies a lot from forest to forest, as does which of those possible attributes actually have populated values. There are also some overhead requirements that vary. All this combines to make it impossible to determine with any accuracy how many values an individual multivalued, nonlinked attribute can have.

Because I have an enquiring mind (some would say “nosey bastard”), I decided to try and hit the limit in my test lab. I did this by running a Powershell script to keep adding SMTP addresses to the proxyAddresses attribute for a user until an exception was thrown. I got to 1192 before I got the “The administrative limit for this request was exceeded” error (see below).

admin_limit

As Don Hacherl (former dev lead for AD at Microsoft) pointed out to me on the mailing list, the non-linked attribute limit is a limit across all non-linked attributes on the object. So for example, if I had added a telephone number before running the script then I would have only got to 1191 values on proxyAddresses.

Don also made is clear that under normal circumstances you shouldn’t need to be anywhere near the limit. In his words…

“The limit is supposed to be high enough that the only time you’ll hit it is when you have made an architectural error in your schema usage. Asking questions about the exact number of a limit that you have not yet hit is often a warning sign of your burning desire to make an architectural error in the future.”

I found a Powershell script on Experts Exchange that seemed to be useful for detecting errant objects that have a high number of values within an individual multivalued attribute. I’ve hacked with it a bit and have ensured that it now excludes linked values. Here it is for anyone that is interested.

#########################################################
#
# Name: Find-BloatedObjects.ps1
# Author: Tony Murray
# Version: 1.0
# Date: 18/09/2014
# Comment: PowerShell 2.0 script to
# find objects with an unusually large number of values
# within a non-linked multi-valued attribute
# Credit: Parts of the script are from a solution posted by 
# footech on Experts Exchange here:
# http://tinyurl.com/md3cvzn
#
#########################################################

Import-Module ActiveDirectory
$queryCount = 1000 # adjust this if you need to
$snc = (Get-ADRootDSE).SchemaNamingContext
$dnc = (Get-ADRootDSE).DefaultNamingContext
$def = "Microsoft.ActiveDirectory.Management.ADPropertyValueCollection*"
$objs = Get-ADObject -Filter * -Properties * -SearchBase $dnc

ForEach ($obj in $objs) {
    #Write-Output "Looking at object $obj.distinguishedname"
    $ADOprops = $obj | gm -MemberType Property `
    | Where { $_.Definition -like $def } `
    | Select -ExpandProperty Name
        foreach ($prop in $ADOprops) {
            #Write-Output "Looking at property $prop"
            $fl = "(&(objectclass=attributeschema)(ldapdisplayname=$prop))"
            $linked = (Get-ADObject -LDAPFilter $fl -SearchBase $snc -pr linkid).linkid
            #Write-Output $linked
            If (($linked -eq $null) -and (($obj.$prop).count -gt $queryCount)) {
                Write-Output "----------------------------------------------"
                Write-Output "AD Object ""$($obj.DistinguishedName)"""
                Write-Output "has attribute ""$prop"" with a count of $($obj.$prop.count)"
            } # end if
        } # end foreach
} # end foreach

Feedback is, as always, very welcome!

 

When you install a new version of Exchange or apply a Cumulative Update certain AD attributes are updated to reflect the change.  The updates are made in three different directory partitions (also known as naming contexts): Schema, Configuration and Domain.  The following Microsoft TechNet article is a good reference for the different versions and the corresponding attribute values.

http://technet.microsoft.com/en-us/library/bb125224(v=exchg.150).aspx

You can check the values manually….or you could do it the easy way with Powershell.  Here’s a Powershell sample to give you values across the three partitions (assumes a single domain forest):

 

# Exchange Schema Version
$sc = (Get-ADRootDSE).SchemaNamingContext
$ob = "CN=ms-Exch-Schema-Version-Pt," + $sc
(Get-ADObject $ob -pr rangeUpper).rangeUpper

# Exchange Object Version (forest)
$cc = (Get-ADRootDSE).ConfigurationNamingContext
$fl = "(objectClass=msExchOrganizationContainer)"
(Get-ADObject -LDAPFilter $fl -SearchBase $cc -pr objectVersion).objectVersion

# Exchange Object Version (domain) - assumes single domain forest
$dc = (Get-ADRootDSE).DefaultNamingContext
$ob = "CN=Microsoft Exchange System Objects," + $dc
(Get-ADObject $ob -pr objectVersion).objectVersion

The output will looking something similar to screenshot shown below (showing the values for Exchange Server 2013 CU5):

Schema

I had an interesting one recently when submitting a certificate request to a Windows Certificate Authority using certreq.exe.  The error that came back was:

The disposition message is “Error Parsing Request The request subject name is invalid or too long. 0×80094001 (-2146877439)”

I found several links to possible solutions but, as it turns out, the problem in my case was the subject name (specified an X.500 DistinguishedName) was too long.  It seems that the CA limits the subject name field to 64 characters.  Mine was around 80 characters, which is not unusual for a DN.

The workaround is to remove the 64 character limit by running the following command:

certutil -setreg ca\EnforceX500NameLengths 0

The CA service needs to be restarted after running the command.

The Microsoft TechNet article that provides more detail can be found here.

Despite Active Directory having been around for more than 10 years, I still find new implementations proceeding without directory service access auditing enabled.  For me, auditing of who does what, where and when in your directory is crucial information.  I can’t fully fathom why Microsoft doesn’t have it enabled with some sensible defaults out of the box, but maybe that’s just me.  If you download and install Microsoft’s Security Compliance Manager 3.0, the Domain Controller baseline contains good auditing defaults.  Anyway, here is a quick “how to” guide for enabling basic directory service access auditing in Windows Server 2012 R2 Active Directory.

Getting auditing going is done in two key steps.

  1. Configuring Group Policy with the appropriate auditing settings
  2. Configuring the System Access Control List (SACL) at the appropriate level(s) in the directory

Ok, let’s get started with the first item (Group Policy).  For this, you will need a GPO linked to the Domain Controllers OU.  You can either use the Default Domain Controllers Policy or create a new one specifically for auditing.  My preference is to leave the DDCP at its defaults and create a new GPO with the settings.

Before the days of granular auditing settings you would configure your directory service access auditing under:

Computer Configuration->Policies->Windows Settings->Security Settings->Local Policies->Audit Policy

11

These settings belong to the dark days of pre-Windows Server 2008 when only the 9 auditing categories were available.  You don’t want to use this setting.  Instead you want to use the more granular auditing sub-categories introduced first in Windows Server 2008.

The first thing you need to do is enforce the use of the sub-categories in case someone unwittingly turns on the legacy auditing mentioned above.  To do this, enable the following setting:

Computer Configuration->Policies->Windows Settings->Security Settings->Local Policies->Security Options->Audit: Force audit policy subcategory settings….[it goes on a bit, but you get the picture]

13

Now we need to enable auditing for the specific sub-categories we are interested in.  To do this go to:

Computer Configuration->Policies->Windows Settings->Security Settings->Advanced Audit Policy Configuration->Audit Policies->DS Access

… and enable Audit Directory Service Access.  I would also enable Audit Directory Service Changes as that can provide you with complementary audit events, including before and after information for changed attribute values (really very useful).  Success and Failure?  Perhaps, but unless you have firm requirements to capture failure events then  just choosing Success can save the reduce the number of events generated.

14

Right, remember to link your new GPO to the Domain Controllers OU and that’s it for the GPO side of things.  You might be thinking that’s all you need to do, but unless you’ve done part 2 you won’t see the required events generated.

Now you might be interested in just certain parts of your directory, but if you don’t have an obvious place to begin, consider turning on audit records from the top of your domain partition.   To do this, open the Active Directory Administrative Centre (dsac).  Yes, yes, you could use dsa.msc or adsiedit.msc too.

Right-click the top of the domain tree (“contoso” in my case) and bring up the properties.  Under Extensions you will see the Security tab.  From there select Advanced and then choose the Auditing tab.  If you want to be comprehensive, I would select the Everyone security principal, set Type to Success and Applies to: This object and all descendant objects.  For the permissions, again if you want to be comprehensive, set the following:

  • Write all properties
  • Delete
  • Delete subtree
  • Modify permissions
  • Modify owner
  • All validated writes
  • All extended writes
  • Create all child objects
  • Delete all child objects

15

Once you have applied the changes you’re pretty much ready to go.  You should now start to see comprehensive directory access events as well as the before and after values for changed objects.

16

17

One thing you might not be aware of is that there was a bug in the RTM version of Windows Server 2012 R2 which meant that the directory service change information events did not get captured.  Of course, by now you will have your R2 servers fully patched, but just in case you are still running RTM be aware that you will need the download from KB2887595 for the change information to be available.

Bear in mind that, if you have a lot of auditing going on in your security logs on your DCs, the events are going to be overwritten pretty regularly even if you beef up the size of your security event log.  As part of defining your audit strategy you should work out your requirements for storing key events.  There are a number of ways to do that, including leveraging some kind of centralised audit collection system (or SIEM), but that’s beyond the scope of this article.

I fell foul of this one the other day and it took a while to figure out what to do about it. Here’s the scenario:

You deploy a new Group Policy Preferences (GPP) setting to create a folder on a workstation and specify the “Apply once and do not reapply” option. Unsurprisingly, this implies the GPP item will apply only once and will not run again!

gpp1

But what if you have a problem on a specific target computer where the computer thinks it has already applied the GPP setting once? You won’t get the setting to reapply using the traditional gpupdate /force option. Instead you must look in the registry of the affected computer and look for the RunOnce entries. These are located here:

HKEY_CURRENT_USER\Software\Microsoft\Group Policy\Client\RunOnce
HKEY_LOCAL_MACHINE\Software\Microsoft\Group Policy\Client\RunOnce

The registry string values (REG_SZ) shown correspond to the RunOnce settings. Instead of descriptive text these entries have (spectacularly unhelpful) GUID-style names.

gpp4

Ok, so armed with this information, how do you go about identifying the GUID-style name with your GPP setting? Don’t be led down the path of thinking the GUID-style name will match the GUID of your GPO – it doesn’t. That kind of make sense as a single GPO can have multiple GPP settings. The answer lies buried within the XML of the GPP setting. To get to the XML, right-click the GPP item within the GPO Editor and select All Tasks -> Display XML. Once you can see the XML look for the line starting with “FilterRunOnce” line. The value shown next to the “ID” is the one that corresponds to the registry entry.

 

gpp2

 

gpp3

To get the GPP setting to re-apply to the problem workstation, simply delete the relevant string value from the registry and force the policy to re-apply (gpupdate /force).

I had a requirement recently to try and find out where and when a whole lot of mailboxes were hidden from the GAL.  Yes, fingering some poor sucker for the blame is an immensely satisfying task, isn’t it?  I’ve found that an effective way to do this is to query the AD replication metadata for the attribute concerned (in this case ‘msexchhidefromaddresslists’).  The replication metadata will provide you with the date/time for when the attribute value was last changed as well as the name of the DC where the last change was made.  From there you can search the Security Event Log on the DC in question for the audit events corresponding to the change.  This of course assumes that you have Audit Directory Service Changes switched on.

Typically, I would use the excellent Repadmin.exe command line tool to query the replication metadata, e.g. -

Repadmin /showobjmeta MyDC1 “CN=MyUser,OU=User Accounts,DC=contoso,DC=com”

However, in this case someone had already reversed most of the changes (i.e. unhidden the mailboxes) and I needed to query a large number of objects to find some others that were still hidden, hoping that some of them would have a common data/time stamp.  For this the Repadmin.exe would work but would be hopelessly inefficient.  And what (I said to myself) is the best method for performing bulk operations such as this?  Yes, that’s right:  Powershell to the rescue!

After some Googling, I found an excellent code snippet from Powershell MVP Brandon shell that hooks into the underlying .Net class to expose the replication metadata.  His is the clever bit (that’s why he’s paid the big bucks) – I’ve basically just done the wrapper to perform a bulk query and output the results to a CSV file.  Here’s the script for your enjoyment.

 

#########################################################
#
# Name: BulkReportReplicationMetadata.ps1
# Author: Tony Murray
# Version: 2.0
# Date: 27/03/2014
# Comment: PowerShell 2.0 script to find change times
# for an individual AD attribute using replication metadata
# 
# Some bits borrowed from: Get-ADObjectREplicationMetadata.ps1
# Brandon Shell (www.bsonposh.com)
#
#########################################################

# import the AD module
ipmo ActiveDirectory

# Define variables
$domain = (get-addomain).dnsroot # Use the current AD domain
$property = "msexchhidefromaddresslists" # This is the AD attribute we are interested in
$outfile = "c:\csv\outfile.csv" # CSV output file

# Blow away the existing file if it exists
if (test-path $outfile) {remove-item $outfile}

# We will build our own CSV rather than work with export-csv
$header = "samaccountname,modified,dc"
Add-Content -Value $header -Path $outfile

$sb = "OU=Standard User Accounts,DC=contoso,DC=com" # Search base for where our mailbox users live
$fl = "(&(homemdb=*)(msexchhidefromaddresslists=TRUE))" # LDAP filter to find our users
$users = Get-ADUser -LDAPFilter $fl -searchbase $sb

# Loop through our list of users
foreach ($user in $users) {

    $objectDN = $user.distinguishedname # used for finding the replication metadata
    $name = $user.samaccountname # Just for info
    # Sets Context to Domain for System.DirectoryServices.ActiveDirectory.DomainController
    $context = new-object System.DirectoryServices.ActiveDirectory.DirectoryContext("Domain",$domain)
    # .NET Class that returns a Domain Controller for Specified Context
    $dc = [System.DirectoryServices.ActiveDirectory.DomainController]::findOne($context)
    # GetReplicationMetadata returns metadata from the DC for the DN specified.
    $meta = $dc.GetReplicationMetadata($objectDN)
    # Get the last time the attribute value was changed
    $ctime = $meta | %{$_.$Property.LastOriginatingChangeTime}
    # Get the DC that the change was made on
    $dcon = $meta | %{$_.$Property.OriginatingServer}
    # Build the values to write to the output file
    $line =  "`"$name`",`"$ctime`",`"$dcon`""
    # Write the line to the output file
    Add-Content -Value $line -Path $outfile

} # end foreach

The shrewd amongst you would ask why I didn’t query the Exchange (2010 in this case) audit log for this information. The answer is that I did, but couldn’t find the relevant audit entries. The Exchange audit events are only captured if the Exchange tools (EMC/EMS/ECP) were used to perform the change. In my case the changes had been made in bulk, probably using the AD cmdlets.