Home > PowerShell > Function: Set-AdminUser – Clear AdminCount and Enable Security Inheritance

Function: Set-AdminUser – Clear AdminCount and Enable Security Inheritance

Description

While migrating some users during a Lync migration, I needed to disable users for Lync in one forest, and enable them in another. I ran into a problem where many users in the legacy forest had adminCount set to 1, and security inheritance disabled. The problem is that my account didn’t have rights to disable them in Lync, and I was getting an access denied error. This is common when the user is/was a member of a protected group. I won’t go into the background of adminCount, as it’s well documented.

I knew that as the migration progressed, we would identify more users where this was the case. So I wanted to find a better way of dealing with these. There are several ways of finding users with adminCount set using PowerShell, including

([adsisearcher]"(AdminCount=1)").findall()

and using the ActiveDirectory PowerShell module via

Get-ADuser -LDAPFilter "(admincount=1)" | select name

and we can look at groups, too, using

Get-ADgroup -LDAPFilter "(admincount=1)" | select name

Turns out that many of the users (1000+) were no longer members of protected groups, what’s often referred to as Orphaned AdminSD Objects. So we could clear adminCount and enable security inheritance. But doing this manually on 1000+ users isn’t something that any of us wanted to spend time doing.

We can clear adminCount with a one-liner:

Get-AdUser [user name] | Set-AdObject -clear adminCount

But that doesn’t take care of security inheritance, which is the real culprit in my issue. We can use dsacls:

$User = [ADSI] $_.Path
dsacls $User.distinguishedName /p:n

Unfortunately, this involves multiple steps in native PowerShell. So, a function was born.

Set-AdminUser takes input from either the $UserName parameter, or via the pipeline, and clears adminCount, then enables security inheritance. It can process a single user or multiple, such as with the output of Get-ADGroupMember.

Syntax

Set-AdminUser [[-UserName] ] [-WhatIf] [-Confirm] []

Examples

Set-AdminUser [user name]
Get-AdGroupMember [group name] | Set-AdminUser

Code

Here is the function to copy. You can also download it in the download section below.

function Set-AdminUser	{  
	<# 
	.SYNOPSIS
			Clears adminCount, and enables inherited security on a user account.

	.DESCRIPTION
			Clears adminCount, and enables inherited security on a user account.

	.NOTES
	    Version    	      	: v1.0
	    Wish list						: 
	    Rights Required			: UserAdministrator
	    Sched Task Req'd		: No
	    Lync Version				: N/A
	    Lync Version				: N/A
	    Author       				: Pat Richard, Exchange MVP
	    Email/Blog/Twitter	: pat@innervation.com 	http://www.ehloworld.com @patrichard
	    Dedicated Post			: http://www.ehloworld.com/1621
	    Disclaimer   				: You running this script means you won't blame me if this breaks your stuff.
	    Info Stolen from 		: http://serverfault.com/questions/304627/powershell-script-to-find-ad-users-with-admincount-0
													: http://morgansimonsen.wordpress.com/2012/01/26/adminsdholder-protected-groups-sdprop-and-moving-mailboxes-in-exchange/

	.LINK     

http://www.ehloworld.com/1621

	.INPUTS
			You can pipeline input to this command		

	.PARAMETER UserName
			Create the scheduled task to run the script daily. It does NOT create the required Exchange receive connector.

	.EXAMPLE 
			Set-AdminUser -UserName [user name]

			Description
			-----------
			Clears the adminCount of the specified user, and enabled inherited security

	.EXAMPLE 
			Get-AdGroupMember [group name] | Set-AdminUser

			Description
			-----------
			Clears the adminCount of all group members, and enabled inherited security

	#>
	#Requires -Version 2.0	

	[CmdletBinding(SupportsShouldProcess = $True)]
	param (
		[Parameter(ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $True, Mandatory = $False)]
	  [ValidateNotNullOrEmpty()]
		[string]$UserName
	)
	Begin{
		## allows inheritance 
		[bool]$isProtected = $false
		## preserves inherited rules 
		[bool]$PreserveInheritance = $true
	}
	Process{
		[string]$dn = (Get-ADUser $UserName).DistinguishedName
		Set-AdObject -identity $dn -clear adminCount
		$user = [ADSI]"LDAP://$dn"
		$acl = $user.objectSecurity
		Write-Verbose $dn
		Write-Verbose "Original permissions blocked:"
		Write-Verbose $acl.AreAccessRulesProtected
		if ($acl.AreAccessRulesProtected){
			$acl.SetAccessRuleProtection($isProtected,$PreserveInheritance)
			$inherited = $acl.AreAccessRulesProtected
			$user.commitchanges()
			Write-Verbose "Updated permissions blocked:"
			Write-Verbose $acl.AreAccessRulesProtected
		}
	}
	End{
		remove-variable acl
		remove-variable UserName
		remove-variable isProtected
		remove-variable PreserveInheritance
		remove-variable dn
		remove-variable user
	}
} # end function Set-AdminUser

Download

v1.0 – 10-20-2012 Set-AdminUser.v1.0.zip

Categories: PowerShell Tags: ,
  1. Juan
    October 25, 2012 at 12:09 pm | #1

    Great script. If I can make a recommendation, I’d add a version for those still on Windows 2003 domains that could use the Quest ActiveRoles Shell. Replacing the set-ad* commands with set-QAD*.

    • Pat Richard
      October 25, 2012 at 12:13 pm | #2

      The problem is that that would require a third party solution (Quest ActiveRoles) be installed. My scripts don’t typically require something like that, as mine are created with the goal that someone could come into another orgs environment and use the scripts without additional work. Plus, many of my scripts are based around an idea I have, and a desire to figure out how to do it natively in PowerShell.

      Plus – 2003? Really? That’s getting pretty outdated.

  1. No trackbacks yet.

Leave a Reply