06
Apr 2016
Update Group Based On Manager ID
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.
#####################
# 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"