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-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/ .LINKFunction: 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
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*.
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.
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!
I *believe* it needs to be a Domain Admin account to change AdminCount.
Interesting idea on Get-AdminUser.
Thanks for the script. Question though… Can your script be easily edited to handle groups that need to be reset as well?
No at this time.
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?
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
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.
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.
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
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
The only way it sets that account back to 0 is if you specify that account.
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.
This does just the specified user. Regardless of where that user is in the OU hierarchy.
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.
That is by design.
I am not sure if its intentional or a bug, but the username refers to some “Exchange receive connector” in the script…
@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.
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!
Yep – that simple
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
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!
@Tom
Tom:
Whatever did you do?
Thank you
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