Skip to main content

Manage Shadow Group Membership - Powershell Function

Manage Shadow Group Membership - PowerShell Function
I looked at a quick script to update a shadow group here, and then thought, this would make a good function. I have used my function template (refer to that post if you want to know more about how to format a function), to build up a reusable script to update group membership based on user and computer object location in AD.

A traditional shadow group is all members of an OU. In my mind, there are a few assumptions to this statement. Being that you have taken the time to create an OU, put objects in it, and created a group to mirror those objects, you probably have only 1 type of object (i.e. user) and they are all similar in some respect (i.e. same office location). This function takes that in mind and only updates groups with users or computers - not other groups etc.

Moving away from the traditional meaning of shadow group, I have added (for my own benefit as I required the functionality) a parameter to change the searchscope from OneLevel (only objects from the OU specified) to subtree (all objects in the tree below the OU specified). Also, by default the function will get all users and computers (name -like *). If you add the -name parameter you can also filter by name, i.e. comp* (all users and computers that start with comp)

As with PowerShell v2 functions you can use get-help, copy and paste the following code in PowerShell, and then run get-help Update-ShadowGroup -detailed to see the examples I have added.


A couple of new commands (for me anyway) I have used here is write-error within  try - catch.  When a group or OU name is passed to the function, I try to get both the OU and the group.  If the catch grabs an error, it outputs the write-error cmdlet making the function look a bit more professional. 

Please send any comments!

function Update-ShadowGroup {
<#
.SYNOPSIS
   Updates a shadow group membership based on the user or computer objects within an ou
.DESCRIPTION
   Better description
.NOTES
   Function Name : Update-ShadowGroup
   Author : Adam Stone
   Requires : PowerShell V2 with AD management pack
.LINK
   http://adadmin.blogspot.com/
.EXAMPLE
   Simple usage
   PS C:\> Update-ShadowGroup -ou "OU=ShadowOU,OU=Test,DC=domain,DC=com" -group shadowgroup
.EXAMPLE
   Simple usage
   PS C:\> Update-ShadowGroup "OU=ShadowOU,OU=Test,DC=domain,DC=com" shadowgroup
.EXAMPLE
   Specify SearchScope
   PS C:\> Update-ShadowGroup "OU=ShadowOU,OU=Test,DC=domain,DC=com" shadowgroup -searchscope Subtree
.EXAMPLE
   Specify name filter
   PS C:\> Update-ShadowGroup "OU=ShadowOU,OU=Test,DC=domain,DC=com" shadowgroup -name srv*
.PARAMETER OU
   DN of the OU - required
.PARAMETER Group
   Name of the Group - required
.PARAMETER Name
   Search pattern to match for the object name
.PARAMETER SearchScope
   Can be either "Base" "OneLevel" or "Subtree" - default OneLevel
#>
param (
   [Parameter(Position=0, Mandatory=$true,HelpMessage="Enter the DN of the OU (eg ou=test,dc=domain,dc=com)")]
   [string] $ou = ""
   ,
   [Parameter(Position=1, Mandatory=$true,HelpMessage="Enter the name of the group (eg group1)")]
   [string] $Group = ""
   ,
   [Parameter(Mandatory=$false)]
   #valadate the input against defined set of attributes
   [string] $name = "*"
   ,
   [Parameter(Mandatory=$false)]
   #valadate the input against defined set of attributes
   [validateset("Base","OneLevel","Subtree")]
   [string] $searchscope = "OneLevel"
)
#the processes the function will complete
process {
   try{
      $getOU = Get-ADOrganizationalUnit $ou
   }
   catch {
      write-error -message "OU $ou does not exist" -RecommendedAction "Make sure the OU is spelt correctly and try again" ;break
   }
   try{
      $getgroup = get-adgroup $group
   }
   catch {
      write-error -message "Group $group does not exist" -RecommendedAction "Make sure the Group name is spelt correctly and try again" ;break
   }
   $objects = $(get-adobject -SearchBase $OU -SearchScope $searchscope -filter {((ObjectCategory -eq "user") -or (ObjectCategory -eq "computer")) -and (name -like $name)})
   $groupmembers = Get-ADGroupMember -Identity $Group
   If ($objects -eq $null -and $groupmembers -eq $null){break}
   If ($objects -eq $null){remove-adgroupmember -identity $group -member $groupmembers -confirm:$false;write-host "$OU was empty, all objects removed"}
   If ($groupmembers -eq $null){
add-adgroupmember -identity $group -member $objects;write-host "$group was empty, all objects added"
   }Else{
      switch (Compare-Object -ReferenceObject $groupmembers -DifferenceObject $objects -property name){
         {$_.SideIndicator -eq "=>"} {add-adgroupmember -identity $group -member $(get-adobject -LDAPFilter "(name=$($_.name)*)"); write-host "$($_.name) added to $group"}
         {$_.SideIndicator -eq "<="} {remove-adgroupmember -identity $group -member $(get-adobject -LDAPFilter "(name=$($_.name)*)") -confirm:$false; write-host "$($_.name) removed to $group"}
      }
   }
}

}#end function


Comments

  1. I would like to make this automated by task manager where the OU and subtree get added to an group. suggestions?

    ReplyDelete
    Replies
    1. This is precisely the way i use this function. Some of the things to consider...

      You will need an account to run the task with that has permission to update the group membership of the shadow groups, nothing more as all accounts have read only access to AD.

      It is best to run this sort of task on a server, preferably not a domain controller. If you do this, the account will need the ability to start a scheduled task. This can be achieved by adding them to the Admin group, but normally (depending on OS version) adding them to allow this account to start as a batch is good enough.

      hopefully this helps!

      cheers

      Delete

Post a Comment

Popular posts from this blog

Enable Powershell Remoting (WinRM) via Group Policy

I have been doing some testing on enabling WinRM via group policy, being that WinRM is the service that Powershell v2 sets up it remoting capabilities. Here are the GPO settings that you need to configure WinRM .... set the winrm service to auto start Computer Configuration \ Policies \ Windows Settings \ Security Settings \ System Services Windows Remote Management (WS-Management)  set Startup Mode to Automatic start the service incorporated in to the above - you may need a restart. create a winrm listener Computer Configuration / Policies / Administrative Templates / Windows Components / Windows Remote Management (WinRM) / WinRM Service / Allow automatic configuration of listeners IPv4 filter: * * is listen on all addresses, or if you only want a particular IP address to respond use an iprange eg 10.1.1.1-10.1.1.254 - don't forget that this IP range has to be valid for all hosts that fall in the scope of the GPO you are creating.  You can use 10.1.1.1 -

Assigning Permissions - AGDLP

AGDLP It seems I have been mildly distracted away from the title of this blog site.   It does say AD Admin, but I seem to have been taken away by file system stuff.   I have to say, it has all been worthwhile, but it’s probably time I got back to the real heart of what I do. There are probably a million permission assigning advice pages, but I thought I would put another one out there after referring to AGDLP in my last post. So, what is this all about – AGDLP.   Well, it is something I learned in my MCSE 2003 studies and has become ingrained into my ideals since.   As a contractor, I get to move job often.   This enables me to forge opinions on how to configure things in a domain, and more importantly how NOT to configure things. AGDLP is definitely on the to do list…for anyone in any size domain or forest, as it follows some very basic principals.   I will explain these whilst I go through what AGDPL stands for. A A is for account.   It is the securit

PowerShell 3 behavioural change

It's taken me way too long to get into PowerShell 3, I guess opportunity hasn't shown it's self until now and so, here, my V3 journey begins. I was asked to debug a script that would run fine in PS v2 and not in v3.  The issue was a that a variable length was being checked and was failing in v3.  This is why... In v2 if a variable is undefined , this test returns false PS C:\windows\system32> $var.length -eq 0 False In v3 the same test returns true.... PS C:\windows\system32> $var.length -eq 0 True Not a biggie, but as in this case, a script has broken so something to consider! cheers Adam