Yeah, I was afraid Suppoer was going to say that there was nothing prepared for this kind of request, but I did anticipate that answer.
So... I wrote a script:
function Convert-AdsLargeIntegerToInt64($adsLargeInt) {
return ($adsLargeInt.HighPart * [math]::Pow(2, 32)) + $adsLargeInt.LowPart
}
function IsValidReport($report, $excludedMask) {
try {
$rawValue = $report.Get("msExchRecipientTypeDetails")
$recipientType = Convert-AdsLargeIntegerToInt64 $rawValue
return (($recipientType -band (-bnot $excludedMask)) -ne 0)
} catch {
# If the property is missing, assume it's a valid user
return $true
}
}
$dryRun = $true
$excludedMask = 4 + 16 + 32 + 2147483648 + 8589934592 + 17179869184 + 34359738368
$hasValidReports = $false
# === Step 1: Get direct reports ===
$directReports = @()
try {
$directReports = $Context.TargetObject.GetEx("directReports")
} catch {
if ($dryRun) {
$Context.LogMessage("%userPrincipalName% has no direct reports (property not set)", "Information")
}
}
if ($directReports.Count -eq 0) {
if ($dryRun) {
$Context.LogMessage("%userPrincipalName% has no direct reports", "Information")
}
} else {
foreach ($reportDN in $directReports) {
try {
$report = $Context.BindToObjectByDN($reportDN)
$reportName = $report.Get("name")
if ($dryRun) {
try {
$rawValue = $report.Get("msExchRecipientTypeDetails")
$recipientType = Convert-AdsLargeIntegerToInt64 $rawValue
$Context.LogMessage("Report: $reportName | recipientType: $recipientType", "Information")
} catch {
$Context.LogMessage("Report: $reportName | recipientType: <not set>", "Information")
}
}
if (IsValidReport $report $excludedMask) {
if ($dryRun) {
$Context.LogMessage("Report: $reportName is a valid report (not excluded)", "Information")
}
$hasValidReports = $true
break
} elseif ($dryRun) {
$Context.LogMessage("Report: $reportName is excluded", "Information")
}
} catch {
$Context.LogMessage("Failed to bind to report: $reportDN", "Warning")
}
}
}
# === Step 2: Group membership management ===
$groupDN = "CN=YourGroupName,OU=Groups,DC=yourdomain,DC=com"
$group = $Context.BindToObjectByDN($groupDN)
$userDN = $Context.TargetObject.Get("distinguishedName")
$userPath = "LDAP://$userDN"
$isMember = $group.IsMember($userPath)
if ($hasValidReports -and -not $isMember) {
if ($dryRun) {
$Context.LogMessage("[Dry Run] Would add %userPrincipalName% to the group.", "Information")
} else {
$group.Add("Adaxes://$userDN")
$Context.LogMessage("Added %userPrincipalName% to the group.", "Information")
}
} elseif (-not $hasValidReports -and $isMember) {
if ($dryRun) {
$Context.LogMessage("[Dry Run] Would remove %userPrincipalName% from the group.", "Information")
} else {
$group.Remove("Adaxes://$userDN")
$Context.LogMessage("Removed %userPrincipalName% from the group.", "Information")
}
}
I would love any feedback on it, and feel free to include it in the Script Repository!