September 25, 2017

Concise ShadowGroup Powershell Scripts

sync icon

The definition of a shadowgroup is simply the synchronization of members in an Active Directory OU to the memberships of an Active Directory Group.

Thanks goes to David K. Sutton for his post at ravingroo.com.

One caveat of his concise script was that Get-ADGroupMember, by default, has a limit of 5000 objects returned. Other internet sources reported an easy workaround by using the member property of the get-adgroup cmdlet.

So I present to you modified versions of a concise ShadowGroup powershell script. One no-frills version, and another with email support.

$OU="OU=TheOUName,DC=yourdomain,DC=com"
$ShadowGroup="CN=ShadowGroupName,OU=TheOUName,DC=yourdomain,DC=com"
Import-Module ActiveDirectory
(Get-ADGroup -Identity $ShadowGroup -properties members).Members | Get-ADUser | Where-Object {$_.distinguishedName –NotMatch $OU} | ForEach-Object {Remove-ADPrincipalGroupMembership –Identity $_ –MemberOf $ShadowGroup –Confirm:$false}
Get-ADUser –SearchBase $OU –SearchScope OneLevel –LDAPFilter "(!memberOf=$ShadowGroup)" | ForEach-Object {Add-ADPrincipalGroupMembership –Identity $_ –MemberOf $ShadowGroup}
$OU="OU=TheOUName,DC=yourdomain,DC=com"
$ShadowGroup="CN=ShadowGroupName,OU=TheOUName,DC=yourdomain,DC=com"
$WhatIf=$true #set $true for testing and $false for action
Import-Module ActiveDirectory
Write-Host "Removing non-existent members"
#$RemoveMembers = (Get-ADGroupMember -Identity $ShadowGroup | Where-Object {$_.distinguishedName -NotMatch $OU}) #Fails for more than 5000
$RemoveMembers = ((Get-ADGroup -Identity $ShadowGroup -properties members).Members | Get-ADUser | Where-Object {$_.distinguishedName -NotMatch $OU}) #workaround for 5000 limit
$RemoveMembers | ForEach-Object {Write-Host -NoNewline $_.SamAccountName ": " ; Remove-ADPrincipalGroupMembership -Identity $_ -MemberOf $ShadowGroup -Confirm:$false -WhatIf:$WhatIf -Verbose}
Write-Host "Adding members"
$AddMembers=(Get-ADUser -SearchBase $OU -SearchScope OneLevel -LDAPFilter "(!memberOf=$ShadowGroup)")
$AddMembers | ForEach-Object {Write-Host -NoNewline $_.SamAccountName ": " ; Add-ADPrincipalGroupMembership -Identity $_ -MemberOf $ShadowGroup -WhatIf:$WhatIf -Verbose}
# Emailing
if ($RemoveMembers -or $AddMembers) {
$adminEmailAddr="admin1@yourdomain.com","admin2@yourdomain.com"
$smtpServer="mailserver.yourdomain.com"
$from = "$env:COMPUTERNAME <noreply@yourdomain.com>"
$subject = "Automated script: ShadowGroup: "+($ShadowGroup -split ',*..=')[1]
$body="The following shadows applied between: <br>"
$body+="OU: $OU <br>"
$body+="Group: $ShadowGroup <br><br>"
if ($WhatIf) { $body+="TESTING ONLY<br><br>"}
foreach ($rm in $RemoveMembers) {
$sName=$rm.SamAccountName
$body+="Removed $sName <br>"
}
if ($RemoveMembers) {$body+="<br>"}
foreach ($am in $AddMembers) {
$sName=$am.SamAccountName
$body+="Added $sName <br>"
}
$body+="<br>"
Write-host "Emailing $adminEmailAddr"
$textEncoding = [System.Text.Encoding]::UTF8
try {
Send-Mailmessage -smtpServer $smtpServer -from $from -to $adminEmailAddr -subject $subject -body $body -bodyasHTML -priority High -Encoding $textEncoding -ErrorAction Stop -ErrorVariable err
} catch {
write-host "Error: Failed to email $adminEmailAddr via $smtpServer"
} finally {
if ($err.Count -eq 0) {
write-host "Successfully emailed $adminEmailAddr"
}
}
} else {
Write-Host "Nothing to email."
}
~~~