The script adds/removes users from Microsoft 365 (Office 365) distribution, security and unified groups based on the business units the users are members of. To run the script, create a scheduled task configured for the Domain-DNS object type and add a managed domain to the Activity Scope of the task.
Parameter:
- $unitDNsToGroupNames - Maps distinguished names (DNs) of the Business Units a user needs to be a member of to be added to Microsoft 365 (Office 365) distribution/security/unified groups with names of the groups that correspond to each Business Unit. A Business Unit can have one or more associated Microsoft 365 (Office 365) groups. For information on how to get DN of a directory object, see Get the DN of an Active Directory Object.
Distribution and mail-enabled security groups
PowerShell
$unitDNsToGroupNames = @{
"CN=My Unit1,CN=Business Units,CN=Configuration Objects,CN=Adaxes Configuration,CN=Adaxes" = @("MyGroup1", "MyGroup2");
"CN=My Unit2,CN=Business Units,CN=Configuration Objects,CN=Adaxes Configuration,CN=Adaxes" = @("MyGroup3");
} # TODO: modify me
function UpdateGroupMembership($groupName, $memberIDs, $operation)
{
foreach ($memberID in $memberIDs)
{
switch ($operation)
{
"Add"
{
try
{
Add-DistributionGroupMember $groupName -Member $memberID -BypassSecurityGroupManagerCheck -ErrorAction Stop
}
catch
{
$Context.LogMessage("An error occurred when adding the user to $groupName group. Error: " + $_.Exception.Message, "Warning")
}
}
"Remove"
{
try
{
Remove-DistributionGroupMember $groupName -Member $memberID -ErrorAction Stop -BypassSecurityGroupManagerCheck -Confirm:$False
}
catch
{
$Context.LogMessage("An error occurred when removing the user from $groupName group. Error: " + $_.Exception.Message, "Warning")
}
}
}
}
}
$groupNamesToUserIDs = @{}
foreach ($dn in $unitDNsToGroupNames.Keys)
{
$unit = $Context.BindToObjectByDN($dn)
$members = $unit.Members()
$groupNames = $unitDNsToGroupNames[$dn]
foreach ($groupName in $groupNames)
{
if ($groupNamesToUserIDs.ContainsKey($groupName))
{
continue
}
$groupNamesToUserIDs.Add($groupName, (New-Object System.Collections.Generic.HashSet[System.String]))
}
for ($i = 0; $i -lt $members.Count; $i++)
{
$member = $members.GetObject($i)
try
{
$objectId = ([Guid]$member.Get("adm-O365ObjectId")).ToString()
}
catch
{
continue
}
$groupNames | %%{ [void]$groupNamesToUserIDs[$_].Add($objectId) }
}
}
try
{
# Connect to Exchange Online
$session = $Context.CloudServices.CreateExchangeOnlinePSSession()
Import-PSSession $session -AllowClobber -DisableNameChecking -CommandName "Get-DistributionGroupMember", "Add-DistributionGroupMember", "Remove-DistributionGroupMember"
foreach ($groupName in $groupNamesToUserIDs.Keys)
{
# Get current members
$members = Get-DistributionGroupMember $groupName
$currentMembers = New-Object System.Collections.Generic.HashSet[System.String]
$members | %%{[void]$currentMembers.Add($_.ExternalDirectoryObjectId)}
# Get users to Add
$membersToAdd = $groupNamesToUserIDs[$groupName]
# Get users to Remove
$membersToRemove = New-Object System.Collections.Generic.HashSet[System.String]
$members | %%{ [void]$membersToRemove.Add($_.ExternalDirectoryObjectId) }
$membersToRemove.ExceptWith($membersToAdd)
# Exclude members already added to group
$membersToAdd.ExceptWith($currentMembers)
# Add users to group
UpdateGroupMembership $groupName $membersToAdd "Add"
# Remove users from group
UpdateGroupMembership $groupName $membersToRemove "Remove"
}
}
finally
{
# Release resources
if ($session) { Remove-PSSession $session }
}
Unified groups and security groups that are not mail-enabled
For the script to work, install Azure Active Directory PowerShell for Graph module on the computer where Adaxes service is running.
PowerShell
$unitDNsToGroupNames = @{
"CN=My Unit1,CN=Business Units,CN=Configuration Objects,CN=Adaxes Configuration,CN=Adaxes" = @("MyGroup1", "MyGroup2");
"CN=My Unit2,CN=Business Units,CN=Configuration Objects,CN=Adaxes Configuration,CN=Adaxes" = @("MyGroup3");
} # TODO: modify me
function UpdateGroupMembership($groupID, $memberIDs, $operation)
{
foreach ($memberID in $memberIDs)
{
switch ($operation)
{
"Add"
{
try
{
Add-AzureADGroupMember -ObjectId $groupID -RefObjectId $memberID -ErrorAction Stop
}
catch
{
$Context.LogMessage("An error occurred when adding the user to $groupName group. Error: " + $_.Exception.Message, "Warning")
}
}
"Remove"
{
try
{
Remove-AzureADGroupMember -ObjectId $groupID -MemberId $memberID -ErrorAction Stop
}
catch
{
$Context.LogMessage("An error occurred when removing the user from $groupName group. Error: " + $_.Exception.Message, "Warning")
}
}
}
}
}
$groupNamesToUserIDs = @{}
foreach ($dn in $unitDNsToGroupNames.Keys)
{
$unit = $Context.BindToObjectByDN($dn)
$members = $unit.Members()
$groupNames = $unitDNsToGroupNames[$dn]
foreach ($groupName in $groupNames)
{
if ($groupNamesToUserIDs.ContainsKey($groupName))
{
continue
}
$groupNamesToUserIDs.Add($groupName, (New-Object System.Collections.Generic.HashSet[System.String]))
}
for ($i = 0; $i -lt $members.Count; $i++)
{
$member = $members.GetObject($i)
try
{
$objectId = ([Guid]$member.Get("adm-O365ObjectId")).ToString()
}
catch
{
continue
}
$groupNames | %%{ [void]$groupNamesToUserIDs[$_].Add($objectId) }
}
}
# Connect to Azure AD
$token = $Context.CloudServices.GetAzureAuthAccessToken("https://graph.windows.net/")
$tenant = $Context.CloudServices.GetO365Tenant()
$credential = $tenant.GetCredential()
Connect-AzureAD -AccountId $credential.AppId -AadAccessToken $token -TenantId $tenant.TenantId
foreach ($groupName in $groupNamesToUserIDs.Keys)
{
$group = Get-AzureADGroup -Filter "displayName eq '$groupName'"
if ($NULL -eq $group)
{
$Context.LogMessage("$groupName group not found.", "Warning")
continue
}
if ($group.Count -gt 1)
{
$Context.LogMessage("Found more than one group named $groupName.", "Warning")
continue
}
# Get current members
$members = Get-AzureADGroupMember -ObjectId $group.ObjectId
$currentMembers = New-Object System.Collections.Generic.HashSet[System.String]
$members | %%{[void]$currentMembers.Add($_.ObjectId)}
# Get users to Add
$membersToAdd = $groupNamesToUserIDs[$groupName]
# Get users to Remove
$membersToRemove = New-Object System.Collections.Generic.HashSet[System.String]
$members | %%{ [void]$membersToRemove.Add($_.ObjectId) }
$membersToRemove.ExceptWith($membersToAdd)
# Exclude members already added to group
$membersToAdd.ExceptWith($currentMembers)
# Add users to group
UpdateGroupMembership $group.ObjectId $membersToAdd "Add"
# Remove users from group
UpdateGroupMembership $group.ObjectId $membersToRemove "Remove"
}
unfortunately the script doesn't work for me. In the logs it says:
"Cannot process argument transformation on parameter 'Credential'. A command that prompts the user failed because the host program or the command type does not support user interaction. The host was attempting to request confirmation with the following message: Enter your credentials. Stack trace: at <ScriptBlock>, <No file>: line 73"
best regards
Hello Nils,
The error occurs because the account whose credentials were used to register your Office 365 tenant in Adaxes has MFA or conditional access enabled in Office 365. You need to disable both. To check the account:
I am using the "Unified Groups" script and it is working... But, how do I avoid the Owners of each group? I receive an message that before the member is removed, it can only be removed as Member and not as Owner. I would like to use this script focussed only on Members and not Owners.
The Unified Groups script does add/remove only members. Most probably, the message that you face occurs when a member is also specified as the group owner and means that the trustee will be removed only from the members list but will stay as an owner.
An error occurred when adding the user to AllCompany group. Error: We failed to update the group mailbox. Please try again later.
Unfortunately, this is a known issue that sometimes occurs when adding users to groups in Azure AD. The issue is on the side of Azure AD itself and is not related to Adaxes. As per our check, in such cases Microsoft recommends to re-create the groups. For details, have a look at the following thread on Microsoft forums:https://answers.microsoft.com/en-us/msoffice/forum/msoffice_o365admin-mso_dep365-mso_o365b/cant-add-user-to-office365-unified-group/00c55086-1c86-44b5-ac9e-2b8b40d860e0.
I am trying to get this working to add a user to a dist group and I am getting the error "You cannot call a method on a null-valued expression. Stack trace: at <ScriptBlock>, <No file>:line 74" When it tries to connect to exchange online.
$Session = $Context.cloudservices.CreateExchangeOnlinePSSession().
Would someone be able to help with this?
Make sure that your Microsoft 365 tenant is registered in Adaxes using an Azure application. For details, have a look at the following help article:https://www.adaxes.com/help/RegisterAdaxesAsAppMicrosoftAzure.
When running the script, it removes users without an office account. Any way to modify the script to keep those email addresses in the distro without one?
Unfortunately, there is no such possibility.
The error occurs because one of the business unit members is not included into the associated scope of any Microsoft 365 tenant registered in Adaxes. For details on how to view Microsoft 365 tenant for a user, see https://www.adaxes.com/help/LookupTenantForUser.