So, I have a site that has no cool admin tools that can dynamically update group memberships with staff reporting to a manager. This occasionally comes up as they wish to send emails to all employees in their orgs.

I’ve hashed together a powershell that will take care of this problem, and I think its pretty cool.

As you can tell, it prompts for the manager and group you wish to upgrade. I hope it helps someone.

ztest



#####################
#  Update Group Member based on Manager ID
#  V.01.  Gregory Van Den Ham
#  5 April 2016
#####################
#  Function -Get-ADDirectReports from lazywinadmin  (lines 14-127)
#
#  Utilizing the Description field "(E)" for employee tag in the user ad account to add to distribution list.
#
#  Note:  use group "ztest" to test in your.domain.
######################


function Get-ADDirectReports
{
	<#
	.SYNOPSIS
		This function retrieve the directreports property from the IdentitySpecified.
		Optionally you can specify the Recurse parameter to find all the indirect
		users reporting to the specify account (Identity).
	
	.DESCRIPTION
		This function retrieve the directreports property from the IdentitySpecified.
		Optionally you can specify the Recurse parameter to find all the indirect
		users reporting to the specify account (Identity).
	
	.NOTES
		Francois-Xavier Cat
		www.lazywinadmin.com
		@lazywinadm
	
		VERSION HISTORY
		1.0 2014/10/05 Initial Version
	
	.PARAMETER Identity
		Specify the account to inspect
	
	.PARAMETER Recurse
		Specify that you want to retrieve all the indirect users under the account
	
	.EXAMPLE
		Get-ADDirectReports -Identity Test_director
	
Name                SamAccountName      Mail                Manager
----                --------------      ----                -------
test_managerB       test_managerB       test_managerB@la... test_director
test_managerA       test_managerA       test_managerA@la... test_director
		
	.EXAMPLE
		Get-ADDirectReports -Identity Test_director -Recurse
	
Name                SamAccountName      Mail                Manager
----                --------------      ----                -------
test_managerB       test_managerB       test_managerB@la... test_director
test_userB1         test_userB1         test_userB1@lazy... test_managerB
test_userB2         test_userB2         test_userB2@lazy... test_managerB
test_managerA       test_managerA       test_managerA@la... test_director
test_userA2         test_userA2         test_userA2@lazy... test_managerA
test_userA1         test_userA1         test_userA1@lazy... test_managerA
	
	#>
	[CmdletBinding()]
	PARAM (
		[Parameter(Mandatory)]
		[String[]]$Identity,
		[Switch]$Recurse
	)
	BEGIN
	{
		TRY
		{
			IF (-not (Get-Module -Name ActiveDirectory)) { Import-Module -Name ActiveDirectory -ErrorAction 'Stop' -Verbose:$false }
		}
		CATCH
		{
			Write-Verbose -Message "[BEGIN] Something wrong happened"
			Write-Verbose -Message $Error[0].Exception.Message
		}
	}
	PROCESS
	{
		foreach ($Account in $Identity)
		{
			TRY
			{
				IF ($PSBoundParameters['Recurse'])
				{
					# Get the DirectReports
					Write-Verbose -Message "[PROCESS] Account: $Account (Recursive)"
					Get-Aduser -identity $Account -Properties directreports |
					ForEach-Object -Process {
						$_.directreports | ForEach-Object -Process {
							# Output the current object with the properties Name, SamAccountName, Mail and Manager
							Get-ADUser -Identity $PSItem -Properties mail, manager | Select-Object -Property Name, SamAccountName, Mail, @{ Name = "Manager"; Expression = { (Get-Aduser -identity $psitem.manager).samaccountname } }
							# Gather DirectReports under the current object and so on...
							Get-ADDirectReports -Identity $PSItem -Recurse
						}
					}
				}#IF($PSBoundParameters['Recurse'])
				IF (-not ($PSBoundParameters['Recurse']))
				{
					Write-Verbose -Message "[PROCESS] Account: $Account"
					# Get the DirectReports
					Get-Aduser -identity $Account -Properties directreports | Select-Object -ExpandProperty directReports |
					Get-ADUser -Properties mail, manager | Select-Object -Property Name, SamAccountName, Mail, @{ Name = "Manager"; Expression = { (Get-Aduser -identity $psitem.manager).samaccountname } }
				}#IF (-not($PSBoundParameters['Recurse']))
			}#TRY
			CATCH
			{
				Write-Verbose -Message "[PROCESS] Something wrong happened"
				Write-Verbose -Message $Error[0].Exception.Message
			}
		}
	}
	END
	{
		Remove-Module -Name ActiveDirectory -ErrorAction 'SilentlyContinue' -Verbose:$false | Out-Null
	}
}

<#
# Find all direct user reporting to Test_director
Get-ADDirectReports -Identity Test_director

# Find all Indirect user reporting to Test_director
Get-ADDirectReports -Identity Test_director -Recurse
#>

###
### Start Greg's Update Script
###

#
#Set Defaults
#

$updatelist =""
$updatearray=@()
$samname=""
$currentdate = get-date -Format "dd-MMM-yyyy-HH-MM";

#
#Prompt Questions
#

Write-Host "Update Group Based on Manager ID"
Write-Host "`n`n"
Write-Host "This tool was initiated On $currentdate by $((Get-Item env:\username).Value) on computer $((Get-Item env:\Computername).Value)" 
Write-Host "`n`n"

#
#  Script to walk org and create groups based on managerid field - walking recrusively
#  Need to block 3rd party consultants from showing in field.
#

$managername = Read-Host 'What is the manager''s ID that you wish to enumerate?'
$groupname = Read-Host 'What is the group name we''re targeting to update?'
Write-Host "`n`n"
Write-Host "One momemt while this tool runs ...."
Write-Host "`n`n"

#
# Get Current AD Group Membership and Save off
#

$filepath = "PreUpdate-$groupname $currentdate.csv"
Get-ADGroupMember -Identity "$groupname" | Export-Csv "$filepath" -NoTypeInformation
Write-Host "Saving Backup of $groupname to $filepath `n`n"
Write-Host "Enumerating accounts, one momemt .... `n`n"
#
# Get AD Manager / Employee List and put into $updatelist variable
# I'm looking for an (E) in account description to validate its an employee, you could set this to look for anything
#

$addirectreports = Get-ADDirectReports -Identity $managername -Recurse | select SamAccountName

foreach ($samaccountname in $addirectreports) {
    #Debugline:Write-Host "in foreach" + $samaccountname;
    $samname =" ";
    $samname = $samaccountname.samaccountname;
    #Debugline:write-host "samname= " $samname;
    $contractorflag = Get-ADUser $samname -Properties description | select description;
    #check for null description
        if (!$contractorflag.description) { 
            $contractorflag.description = 'No Data in AD for Description';
        }    
    #Debugline:write-host "Description for Contractor Flag:" $contractorflag
    if ($contractorflag.description.Contains("(E)")){
        #Debugline:Write-Host "Employee Check Passed";
        $updatelist += $samname +",";
        $updatearray += $samname;
        #Debugline:Write-Host "samname was=" $samname " and current updatelist value is= " $updatelist; 
    }
    else {
    #Debugline:Write-Host "Not an Employee";
    }

}

#
#Add Manager back into Grouplist and list group to screen.
#

$updatelist += $managername;
$updatearray += $managername;

Write-Host "New Group Members will be: `n"
Write-Host "$updatelist `n`n"


#
# Update Group Membership...  technically, i don't need the array to load in, but its more fun this way.  i could just use the -members $updatelist instead.
#

$updategroup = Read-Host 'Update group now? (y/n)?';

if ($updategroup -eq "y") {
    Write-Host "`n`nUpdating $groupname ....`n`n";
    #Set commands - clear group membership and import $updatelist.
    $groupuserstoclear = Get-ADGroupMember -Identity $groupname
    #Loop through all the members of the group and remove them.
    foreach ($usertoclear in $groupuserstoclear){
        Remove-ADGroupMember $groupname -Member $usertoclear -Confirm:$False;
    }
    #add back group members from $updatelist
    foreach ($username in $updatearray){
        Write-Host "Adding $username to $groupname.";
        Add-ADGroupMember -Identity $groupname -Members $username;  
    }
    #write out new group list to csv
}
else {
Write-Host "No Updates Made!"
}
Write-Host "`n`nThanks for using Greg's Script"