Home > .net, active directory, adsi, groups, howto, network management, powershell, scripting > Modifying Group Memberships with Powershell, Part I

Modifying Group Memberships with Powershell, Part I

I recently had to spend hours figuring out how to properly modify Active Directory group memberships using Powershell. Some of the .Net methods have not yet been implemented, so I had to get a bit tricky with it. I could find the various bits of information I needed in various places, so I hope that collecting them here in one place is of some use to others.

The scenario was that I needed to disable user accounts in a Windows Server 2003 Active Directory environment running with Exchange 2007. We have a fairly customized, hosted Exchange environment, and so disabling a user is not just a simple matter and right-clicking and disabling the account in Active Directory Users and Computers (ADUC); we have a 2-page doc for the process to catch everything from removing group memberships to setting up email forwarding or restrictions, changing dial-in permissions, changing NTFS permissions on profile directories, etc.

Anyway, I had already dabbled in modifying group memberships in our user creation script (still a bit clunky, but it gets the job done) by copying group memberships from a template account. It goes something like this (please note that several of these commands require the Exchange 2007 snap-in for Powershell, and some also the Powershell Community Extensions snap-in):


$templaccn = Get-Mailbox | Where-Object { $_.name -match [template account name] }
$newuser = Get-User [new user name]
$filterid = ( Get-User $templaccn.name ).identity
$groups = Get-Group -filter { Members -eq $filterid }
$groups | Foreach-Object {
$groupdn = $_.DistinguishedName
$fqgroup = [ADSI]("LDAP://$groupdn")
$membercheck = ($fqgroup.member | Where-Object { $_ -eq $newuser})
if ( $membercheck.length -ge 1)
{
Write-Host "User is already a member of" $_.name "`b. No group addition made. `n"
}
else
{
$fqgroup.member.add("$newuserdn")
$fqgroup.setinfo()
}
}

So here’s the run down:

The opening Get-Mailbox line uses one of the Exchange 2007 snap-ins to get the mailbox object for our template account and saves it to the $templaccn variable; substitute [template account name] with the name of your template account. I also set the $newuser variable to the name of the user who’s group membership we will be modifying. This is just because the script is used for user creation, so you might want to change the variable name to something like $user or $moduser; just be sure to change the variable throughout your code!

The next two lines are used in conjunction with each other to find all groups of which the template account is a member. You could also replace these two lines with Get-Group | Where-Object { $_.Members -match $templaccn }, but that first collects ALL the groups in your environment and then runs them through a filter of Where-Object. I have found the filterid way to be much quicker.

For each group, we then first save the distinguished name to the $groupdn variable, then use the Powershell ADSI wrapper to store its full ADSI object as $fqgroup. I usually prefix fq to variables for full ADSI objecs to denote their type, but you can obviously use something like adObj whatever convention you like. The member property for the group is a multi-valued property that contains the groups members, so using Where-Object we effectively set a value to $membercheck only if our user is a member of that group. As I was using this to create new users, this was probably not completely necessary, but it was good practice anyway.

The if statement there just throws out that the user is already a member of the group if $membercheck had any value set, otherwise it proceeds to adding the user to the group.

We then use the add() method of the member property of the ADSI object for our group, supplying our user’s distinguished name as an argument, and use setInfo() to apply the changes to the ADSI object.

Now, the reason this was tough to do in the first place, and why I ended up later having so much trouble with removing group memberships and making other modifications, is because the $fqgroup ADSI object does not display any methods! You can read all the properties you want, but for some reason the Powershell design team thought it would be a good idea to hide the methods, even though they are there. If you don’t believe me, try this:

$domroot = [adsi]''

distinguishedName
-----------------
{DC=i-worx,DC=ca}

Try just typing $domroot. It should return something like:

[PS] C:\>$domroot

distinguishedName
-----------------
{DC=test,DC=local}

Alright, now try using Get-Member to get some info on this ADSI object: $domroot | Get-Member

All of those seem to be Properties, right, with no methods? Hmm… For more info on this, check out Benp’s Basic Guide to Managing Active Directory Objects with PowerShell as well as “Invisible” methods for ADSI? from the Pathological Scripter.

Anyway, all this to show that it doesn’t seem to be as straightforward as we might have hoped.

So, that seems to have covered adding users to groups…now what if I want to remove a user’s group memberships? Part II of this post will cover that…

Advertisements
  1. 2008-12-09 at 11:50

    To see the methods you need to view the “PSBASE” then you’ll see them. I know, not too intuitive but once you know, you know…

    [PS] C:\>$domRoot.psbase | gm

    TypeName: System.Management.Automation.PSMemberSet

    Name MemberType Definition
    —- ———- ———-
    Disposed Event System.EventHandler Disposed(System.Object, System.EventArgs)
    Close Method System.Void Close()
    CommitChanges Method System.Void CommitChanges()
    CopyTo Method System.DirectoryServices.DirectoryEntry CopyTo(DirectoryEntry newParent), Syste…
    CreateObjRef Method System.Runtime.Remoting.ObjRef CreateObjRef(Type requestedType)
    DeleteTree Method System.Void DeleteTree()
    Dispose Method System.Void Dispose()
    Equals Method System.Boolean Equals(Object obj)
    GetHashCode Method System.Int32 GetHashCode()
    GetLifetimeService Method System.Object GetLifetimeService()
    GetType Method System.Type GetType()
    InitializeLifetimeService Method System.Object InitializeLifetimeService()
    Invoke Method System.Object Invoke(String methodName, Params Object[] args)
    InvokeGet Method System.Object InvokeGet(String propertyName)
    InvokeSet Method System.Void InvokeSet(String propertyName, Params Object[] args)
    MoveTo Method System.Void MoveTo(DirectoryEntry newParent), System.Void MoveTo(DirectoryEntry…
    RefreshCache Method System.Void RefreshCache(), System.Void RefreshCache(String[] propertyNames)
    Rename Method System.Void Rename(String newName)
    ToString Method System.String ToString()
    AuthenticationType Property System.DirectoryServices.AuthenticationTypes AuthenticationType {get;set;}
    Children Property System.DirectoryServices.DirectoryEntries Children {get;}
    Container Property System.ComponentModel.IContainer Container {get;}
    Guid Property System.Guid Guid {get;}
    Name Property System.String Name {get;}
    NativeGuid Property System.String NativeGuid {get;}
    NativeObject Property System.Object NativeObject {get;}
    ObjectSecurity Property System.DirectoryServices.ActiveDirectorySecurity ObjectSecurity {get;set;}
    Options Property System.DirectoryServices.DirectoryEntryConfiguration Options {get;}
    Parent Property System.DirectoryServices.DirectoryEntry Parent {get;}
    Password Property System.String Password {set;}
    Path Property System.String Path {get;set;}
    Properties Property System.DirectoryServices.PropertyCollection Properties {get;}
    SchemaClassName Property System.String SchemaClassName {get;}
    SchemaEntry Property System.DirectoryServices.DirectoryEntry SchemaEntry {get;}
    Site Property System.ComponentModel.ISite Site {get;set;}
    UsePropertyCache Property System.Boolean UsePropertyCache {get;set;}
    Username Property System.String Username {get;set;}

  2. Lance
    2010-04-14 at 08:09

    Thanks a ton for posting that – that code was gold! I was having problems adding a child domain account to a parent domain group…thus my modified version of what you came up is below:

    $AddThisUser = Get-User myuser@childdomain.contoso.com
    $AddThisUserDN = $AddThisUser.DistinguishedName
    $AddToGroup = Get-Group MyGroup
    $AddToGroupDN = $AddToGroup.DistinguishedName
    $AddToGroupADSI = [ADSI](“LDAP://$AddToGroupDN”)
    $AddToGroupADSI.Member.Add(“$AddThisUserdn”)
    $AddToGroupADSI.Setinfo()

    $RemoveFromGroup = Get-Group MyGroup
    $RemoveFromGroupDN = $RemoveFromGroup.DistinguishedName
    $RemoveThisUser = get-user myuser@childdomain.contoso.com
    $RemoveThisUserDN = $RemoveThisUser.DistinguishedName
    $RemoveFromGroupADSI = [adsi]”LDAP://$RemoveFromGroupDN”
    $RemoveFromGroupADSI.Member.Remove($RemoveThisUserDN)
    $RemoveFromGroupADSI.SetInfo()

  3. JC
    2010-04-16 at 13:32

    Where is .Create or .Setinfo under PSBASE ??

  4. 2010-05-02 at 19:13

    @Lance:

    Thanks for that update!

    JaSa

  5. 2010-05-27 at 08:03

    justanothersysadmin.wordpress.com’s done it once again. Incredible article!

  1. No trackbacks yet.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: