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-Object name

and we can look at groups, too, using

Get-ADgroup -LDAPFilter "(admincount=1)" | Select-Object 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, Skype for Business MVP
	    Email/Blog/Twitter	: pat@innervation.com 	https://www.ucunleashed.com @patrichard
	    Dedicated Post			: https://www.ucunleashed.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     
	    
Function: Set-AdminUser – Clear AdminCount and Enable Security Inheritance
.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

Donations

I’ve never been one to really solicit donations for my work. My offerings are created because *I* need to solve a problem, and once I do, it makes sense to offer the results of my work to the public. I mean, let’s face it: I can’t be the only one with that particular issue, right? Quite often, to my surprise, I’m asked why I don’t have a “donate” button so people can donate a few bucks. I’ve never really put much thought into it. But those inquiries are coming more often now, so I’m yielding to them. If you’d like to donate, you can send a few bucks via PayPal at https://www.paypal.me/PatRichard. Money collected from that will go to the costs of my website (hosting and domain names), as well as to my home lab.

Download

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

Categories: PowerShell Tags: ,
  1. Juan
    October 25th, 2012 at 12:09 | #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 25th, 2012 at 12:13 | #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 16th, 2013 at 18:33 | #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 19th, 2013 at 20:16 | #4

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

      Interesting idea on Get-AdminUser.

  3. June 18th, 2013 at 18:13 | #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 19th, 2013 at 20:15 | #6

      No at this time.

  4. PB
    September 5th, 2013 at 13:00 | #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 12th, 2014 at 17:50 | #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 12th, 2014 at 18:07 | #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 8th, 2013 at 13:23 | #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.

  6. ICT Department
    February 10th, 2015 at 19:18 | #11

    This might be helpful to reset users within an OU
    get-Aduser -searchbase “ou=Department, ou=users,dc=domain,dc-com” -filter * |set-adobject -clear admincount

  7. Anurag
    September 22nd, 2015 at 01:59 | #12

    Awesome Script!! Was wondering why it resets the admincount of krbtgt account back to 0? By default it was 1 and I never touched the account to modify it’s group membership

    • Pat Richard
      September 22nd, 2015 at 10:03 | #13

      The only way it sets that account back to 0 is if you specify that account.

  8. Timur
    October 14th, 2015 at 05:37 | #14

    Hello Pat. Great script, looks like something exactly what I need. But I have question: where can I set OU for target users or this script applied through whole domain? Thank you in advance for you answer.

    • Pat Richard
      October 14th, 2015 at 09:07 | #15

      This does just the specified user. Regardless of where that user is in the OU hierarchy.

  9. Tony Auby
    February 16th, 2016 at 17:31 | #16

    One comment above stated that this would get reset in an hour. I take that to mean, if a user remains in BUILTIN\Administrators group (Domain Admins, etc.), that the AdminCount will get reset back to 1 and Inheritance will get unchecked again. This is the behavior I have observed, just want to know if what I’m seeing is by design.

    • Pat Richard
      February 16th, 2016 at 19:26 | #17

      That is by design.

  10. soder
    January 7th, 2017 at 12:49 | #18

    I am not sure if its intentional or a bug, but the username refers to some “Exchange receive connector” in the script…

  11. January 7th, 2017 at 18:33 | #19

    @soder
    Looks like when I moved the content to the new domain, some of the code got mangled. Just pasted it in again. Let me know if you have any other issues.

  12. Tom
    March 9th, 2017 at 13:25 | #20

    I’m in the middle of an Exchange 07 > 2013 migration and have hit this issue.. Company has over 100 users with this..

    I’m no coding expert at all so weary of running this, especially on a customers environment..

    Is it really just a copy / paste with no modifying of the code?

    Thanks for your time!

  13. Tom
    March 9th, 2017 at 16:03 | #22

    So I downloaded the script.. Ran the following:

    .\Set-AdminUser.ps1 jdoe

    I get no return data after running it and the admin flag is still 1..

    What am I doing wrong? Thanks so much

  14. Tom
    March 9th, 2017 at 22:02 | #23

    Also, I tried it on a Windows 2012 R2 server and a Windows 2008 R2 server… Ran powershell as admin and logged in as a domain admin..

    Each time I ran .\Set-AdminUser.ps1 jdoe and nothing happens.. No errors, no messages at all, and the attribute doesn’t clear..

    Any help would be appreciated as I have over 150 accounts that need this done.

    Thanks again!

  15. aron morgulis
    April 16th, 2021 at 13:29 | #24

    @Tom

    Tom:

    Whatever did you do?

    Thank you

  16. Dwayne
    August 16th, 2021 at 21:01 | #25

    The Write-Verbose cmdlet writes text to the verbose message stream in PowerShell. Typically, the verbose message stream is used to deliver more in depth information about command processing.

    By default, the verbose message stream is not displayed.

    This is why you saw not output.

    at the call add -verbose to see it

  1. September 17th, 2013 at 19:40 | #1
  2. December 23rd, 2015 at 11:57 | #2
  3. March 10th, 2017 at 17:00 | #3