The Experts Conference 2009 (TEC’09)

Earlier this year, I wrote about presenting at Connections’08 in this article. That went so well, I’ve also applied (and been accepted) to speak at another conference – The Experts Conference (TEC).

Up through 2008, TEC was known as DEC (the Directory Experts Conference) and it focused exclusively on Active Directory (AD) and Identity Management (IdM). It was definitely the conference to go to for gurus in AD and IdM and it has a huge representation from the Microsoft Directory Services Product Team.

Beginning in 2009, DEC is adding another track on Exchange Server. Originally, there was some discussion about running two separate conferences side-by-side: DEC and GEEC (Great Experts Exchange Conference), but eventually the decision was made to rename the conference and run two tracks: one on Directory Services and one on Exchange Server.

I am privileged to be one of the Exchange Server speakers at the inauguration of TEC. Originally presented by NetPro (for seven years) and now presented by Quest (who purchased NetPro in the second half of 2008), the conference is still being organized and hosted by Gil Kirkpatrick (a long-time Directory Services MVP).

The American presentation of the conference is in Las Vegas, NV; March 22 – 25, 2009. The European presentation of the conference is in Berlin, Germany; September 14 – 16, 2009.

For the American Exchange Server agenda, please click here.

For the bios of all the Exchange Server speakers (including me!), please click here.

For the abstracts of all the Exchange Server sessions, please click here.

It is the goal of TEC’2009 for the Exchange Server presentations to be as high quality and as technical as those they have always had for Directory Services. Thus, if you want in-depth Exchange Server knowledge from some true experts – TEC’2009 is the place to be. In tight economic times, you have to carefully pick and choose which conferences and technical events you want to attend. TEC’2009 should be your #1 choice. As you can see from the American agenda and biographies, there is a very strong representation from the Exchange Server product team as well as from the Directory Services product team.

I hope that you will join me at TEC’2009. It is a worthwhile investment for you and your company.

Until next time…

As always, if there are items you would like me to talk about, please drop me a line and let me know!


Follow me on twitter: @EssentialExch

Exchange Connections – Fall 2008

Next week, in Las Vegas, Nevada is the semiannual Connections conference. The Connections conference is a technical conference covering SQL Connections, Windows Connections, Exchange Connections, etc. There are lots of individual tracks, both for IT Pros and Devs.

I’ll be speaking next week at the conference, delivering three Exchange presentations:

EXC10: Exchange 2007 and Windows 2008: Backups the Easy Way (75 minutes)
In this presentation I’ll show you how to use the native Windows tools present in Windows 2008 to make Exchange 2007 backups AND to restore them. I’ll cover some theory, some philosophy, and lots of PowerShell.

EXC11: SMB Exchange Operations (60 minutes)
In this presentation I’ll discuss so key factors of Exchange day-to-day operations that affect the Small Business

EXC12: Building an Exchange Test Environment in a Hurry (75 minutes)
In this presentation I’ll discuss some of ways in which you can quickly generate a virtualized Exchange test environment. After all, all the time you spend building, is less time you can spend testing.

You can see the Event Schedule here and general conference information here.

Please come say “hi”. Even better – attend my presentations!

Until next time…

As always, if there are items you would like me to talk about, please drop me a line and let me know!


Follow me on twitter: @EssentialExch

adminCount, adminSDHolder, SDProp and you!

Quick Synopsis

Ever had the permissions on a user object keep changing and you don't know why? Well, this article tells you why and how to fix it.

If you just want to know how to fix it, page down to the Resolution section, and skip the Technical Explanation.

Technical Explanation

One of the many protection mechanisms built into Active Directory is known by several names: adminCount, adminSDHolder, or SDProp. The first two, adminCount and adminSDHolder, are directly tied to Active Directory. adminCount is an attribute that is set on each object affected by this protection mechanism. adminSDHolder is the reference object that all other critical objects are compared to.

The adminSDHolder object, which stands for Administrative Security Descriptor Holder, exists in each domain. That is, in a multi-domain forest, there is an adminSDHolder object in each of the domains in the forest. The object is located at CN=adminSDHolder, CN=System, DC=example, DC=com. There are a number of access control entries (ACEs) on the adminSDHolder object. Those ACEs are the proper ACEs for any object that can be defined as a critical object.

A critical object is a security principal which is either a very specific principal, or a member of a critical group. Security principals are currently limited to users, groups, computers, or inetorgpersons.

Security Description Propagator (SDProp) is the task that runs within LSASS.EXE which actually enforces the protection mechanism. SDProp performs other tasks as well (including replicating security descriptors from one domain controller to another), but in this case we are interested only in its adminSDHolder functions.

The purpose behind the SDProp mechanism is to stop inappropriate changes from being made to critical objects.

For example, assume the user SubAdmin is delegated full-control privileges over an OU named SubOU. If, under whatever circumstance, the Administrator user for the domain were to be moved under that OU, and then if normal inheritance rules applied to the Administrator user, the SubAdmin user could make whatever changes they wished to that user – including changing the Administrator password. However, the SDProp process prevents that.

Permission inheritance is disabled for all critical objects, and they only have the ACEs applied to them that are present on the adminSDHolder object.

When a critical object is processed by SDProp, it not only checks and resets the ACEs on the object, it also sets another attribute: adminCount. If SDProp has ever processed a security principal, that object will have adminCount set equal to 1 AND inheritance will be disabled.

This can cause problems in a number of environments. This is primarily because critical objects in an OU will not receive delegated permissions for that OU. A number of applications depend on that functionality (such as Cisco Unity and Blackberry Enterprise Server).

The critical objects which are users are:

  • Administrator
  • krbtgt

The critical objects which are groups are:

  • Enterprise Admins
  • Schema Admins
  • Domain Admins
  • Administrators
  • Account Operators
  • Server Operators
  • Print Operators
  • Backup Operators
  • Cert Publishers

Only the first four were critical objects in Windows 2000. The last five were added with Windows 2003 (and Windows 2000 service pack 4). This explains why the issue was not seen for most companies with Windows 2000 and it only began appearing with the deployment of Windows 2003.

Resolution

The proper workaround is for high-privilege principals (i.e., critical objects) not be used for day-to-day activities. That is, you should not log into your workstations with your account which is a member of any critical group. The Administrator user shouldn't have a Blackberry or a voice-mail account. Etc.

In order to reverse the effect of SDProp on a security principal, you must do three things:

  1. Remove the security principal from the critical group.
  2. Set adminCount equal to zero using ADSIEdit or LDP.
  3. Re-enable inheritance on the object (this can be done from within ADUC, with View -> Advanced, on the security tab or from within ADSIEdit or LDP).

Note that once adminCount is set equal to one, removing the security principal from the critical group will not cause SDProp to reverse its changes. As long as adminCount is equal to one, SDProp will continue to reset permissions on an object. Therefore, the order of the steps listed above is important. Depending on timing, you may be successful at following an alternate order, but you may not always be so lucky.

Until next time…

As always, if there are items you would like me to talk about, please drop me a line and let me know!

Groups and their Membership

I’m working with a new client and this client is a “wholly owned subsidiary” of another company and is getting ready to be spun off as their own company.

One of the things we are doing is configuring their network to be standalone and not part of the corporate Active Directory. That involves creating users, group, moving computers, installing a new Exchange organization, etc. etc.

But sometimes it’s the simple things that bite you…

We’d gotten an export of the OU for the subsidiary out of corporate in a CSV file – every object, every attribute. That was a mess in-and-of itself, but at least all the data was there.

So we started importing the data. And it broke.

Huh? We’d done this before and no problem. What was going on here?

Like I said – the simple things…

This set of users and groups were using embedded groups. Sometimes up to five levels deep. (That is, a group within a group within a group within a group within a group.)

Well, you can’t assign a group membership to a group that doesn’t exist! Seems obvious, in retrospect.

The solution? Go through and harvest all groups FIRST – just create the groups in Active Directory. Then, go back through and assign membership to the groups.

Here is a somewhat sanitized version of the code we used. On the first pass, it creates groups. On the second pass, it will assign membership to the groups. This shows a number of PowerShell techniques in group management – including creating groups, checking for membership in a group, and adding members to a group.

Also note: there are several places where this script could be optimized. But I was more interested in clarity (since, as a consultant, I won’t be there forever!).

I hope you find this useful for your scripts!

set-variable ADS_GROUP_TYPE_DOMAIN_LOCALGROUP 1          
set-variable ADS_GROUP_TYPE_GLOBAL_GROUP      2          
set-variable ADS_GROUP_TYPE_LOCAL_GROUP       4          
set-variable ADS_GROUP_TYPE_UNIVERSAL_GROUP   8          
set-variable ADS_GROUP_TYPE_SECURITY_ENABLED -2147483648 

$groupType = $ADS_GROUP_TYPE_GLOBAL_GROUP –bor $ADS_GROUP_TYPE_SECURITY_ENABLED

$csv = import-csv GroupsOnly.csv
#
# Each line contains the dn, the name, the description if one exists, and the member list
# with the dn of each group member. The member list has each member separated by a semi-colon.
#
foreach ($line in $csv)
{
	$dn = $line.dn
	$adsPath = "LDAP://" + $dn
	$objGroup = [ADSI]$adsPath
	if ($objGroup.Name)
	{
		# the above verifies that the group exists. Note that 
		# ADSI is "smart". It doesn't actually access AD and 
		# fill the property cache until you read an attribute
		# from the object.
		"Exists: " + $line.Name
		if ($line.member.Length -gt 0)
		{
			$i = 0
			$members = $line.member.Split(";")
			$lower   = $dn.ToLower()
			foreach ($member in $members)
			{
				$objMember = [ADSI]("LDAP://" + $member)
				if ($objMember.Name)
				{
					# check to see if member is already in group
					[bool]$already = $false
					$userGroups = $objMember.memberOf.Value
					if ($userGroups)
					{
						foreach ($usergroup in $userGroups)
						{
							if ($userGroup.ToLower() -eq $lower)
							{
								$already = $true
								break
							}
						}
					}
					$objMember = $null
					if ($already)
					{
						"`tAlready in group: $member"
					}
					else
					{
						$objGroup.Add(("LDAP://" + $member))
						if ($?)
						{
							"`tAdded to group: $member"
							$i++
						}
						else
						{
							# should be an error displayed on the PowerShell window
							"`tCouldn't add to group: $member"
						}
					}
				}
				else
				{
					# member specified in CSV doesn't exist in Active Directory
					"`tObject doesn't exist: $member"
				}
			}
			"`tadded $i members"
		}
		else
		{
			# members element of the CSV was empty
			"`tno members specified for group"
		}
		$objGroup = $null
	}
	else 
	{
		"Creating " + $line.Name

		$parent = "LDAP://" + $dn.SubString(1 + $dn.IndexOf(","))
		$object = [ADSI]$parent
		$child  = $object.Create("group", "CN=" + $line.Name)

		$child.Put("groupType",      $groupType)
		$child.Put("sAMAccountName", $line.name)
		$child.Put("name",           $line.name)

		if ($line.description.length -gt 0)
		{
			$child.Put("description",    $line.description)
		}

		$child.SetInfo()
		$child = $null

	}

	sleep -milli 500
}

$csv = $null

Until next time…

As always, if there are items you would like me to talk about, please drop me a line and let me know!


Follow me on twitter: @EssentialExch