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

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

Powershell_logo-137x137Description

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.

  2. Kevin C.
    June 16, 2013 at 6:33 pm | #3

    Hi Pat, I’m pretty sure I know the answer to this, but could you clarify the permissions needed to run your script?

    One more thing. A Get-AdminUser version would be nice for discovery of such accounts.

    Overall, great job and just what the doctor ordered!

    • Pat Richard
      June 19, 2013 at 8:16 pm | #4

      I *believe* it needs to be a Domain Admin account to change AdminCount.

      Interesting idea on Get-AdminUser.

  3. June 18, 2013 at 6:13 pm | #5

    Thanks for the script. Question though… Can your script be easily edited to handle groups that need to be reset as well?

    • Pat Richard
      June 19, 2013 at 8:15 pm | #6

      No at this time.

  4. PB
    September 5, 2013 at 1:00 pm | #7

    I cannot get this script run in Server 2012. I’ve tried 32 and 64-bit Powershell v3 and v2. I run as domain administrator. Anyone advise on what I am missing here?

    • Googler
      May 12, 2014 at 5:50 pm | #8

      For anyone like me who already has a script to enable inheritance but can’t get this one to clear the admincount.

      Get-AdUser -LDAPFilter “(admincount=1)” | Set-AdObject -clear admincount

      • Pat Richard
        May 12, 2014 at 6:07 pm | #9

        That’s a pretty overreaching LDAP filter. I can’t think of a reason you’d want to clear all users. They’ll just get reset again in an hour.

  5. September 8, 2013 at 1:23 pm | #10

    Unfortunately I still see a lot of Windows 2003 (and even Windows 2000) out there, a lot of it supporting legacy applications that were never updated to run on newer OS’s….

    Or they do not want to spend the money to upgrade, that is until it is too late & they have been bitten by a exploit/disaster/HW failure of some sort, then the mad scramble to upgrade.

  1. September 17, 2013 at 7:40 pm | #1

Leave a Reply