Someone on the /r/msp reddit, and a Slack that I frequent asked if it is possible to create an “all users” distribution group with PowerShell, and keep it up to date. I figured to spend some time on it.
To achieve a list that is always up to date, we can use Dynamic Distribution groups. Dynamic groups allow you to add specific users based on their properties. for example; if a user has a full mailbox, it will be added. You can make these queries as complex as you want.
Our script uses the Secure Application Model to create a couple of new dynamic distribution groups; a single one that contains all users called “AllCompanyUsers” and one per domain that the client has. The domain group only contains people that use that domain’s email address. For example; Cybedrain.com@cyberdrain.com contains John, Hank, and Bob. It does not contain Janet because she uses @Janetdrain.com as an e-mail.
The script
$ApplicationId = 'APPLICATIONID' $ApplicationSecret = 'APPLICATIONSECRET' | Convertto-SecureString -AsPlainText -Force $TenantID = 'YOUURTENANTID' $RefreshToken = 'Freakishly long refreshtoken' $ExchangeRefreshToken = 'Freakishly long refresh' $UPN = "UPN-Of-User-Generating-Tokens" $credential = New-Object System.Management.Automation.PSCredential($ApplicationId, $ApplicationSecret) $aadGraphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.windows.net/.default' -ServicePrincipal -Tenant $tenantID $graphToken = New-PartnerAccessToken -ApplicationId $ApplicationId -Credential $credential -RefreshToken $refreshToken -Scopes 'https://graph.microsoft.com/.default' -ServicePrincipal -Tenant $tenantID Connect-MsolService -AdGraphAccessToken $aadGraphToken.AccessToken -MsGraphAccessToken $graphToken.AccessToken $customers = Get-MsolPartnerContract -All foreach ($customer in $customers) { $token = New-PartnerAccessToken -ApplicationId 'a0c73c16-a7e3-4564-9a95-2bdf47383716'-RefreshToken $ExchangeRefreshToken -Scopes 'https://outlook.office365.com/.default' -Tenant $customer.TenantId $tokenValue = ConvertTo-SecureString "Bearer $($token.AccessToken)" -AsPlainText -Force $credential = New-Object System.Management.Automation.PSCredential($upn, $tokenValue) $customerId = $customer.DefaultDomainName $session = New-PSSession -ConfigurationName Microsoft.Exchange -ConnectionUri "https://ps.outlook.com/powershell-liveid?DelegatedOrg=$($customerId)&BasicAuthToOAuthConversion=true" -Credential $credential -Authentication Basic -AllowRedirection Import-PSSession $session -AllowClobber -DisableNameChecking -CommandName "Get-DynamicDistributionGroup","New-DynamicDistributionGroup","Set-DynamicDistributionGroup" write-host "Logged into tenant $($customer.defaultdomainname)" -ForegroundColor Green write-host "Checking if all users list exist, if not, creating them." -ForegroundColor Green $ExisitingAllUserList = Get-DynamicDistributionGroup -anr "AllCompanyUsers" if (!$ExisitingAllUserList) { write-host "Creating AllCompanyUsers group" -ForegroundColor Green New-DynamicDistributionGroup -Name "AllCompanyUsers" -RecipientFilter "(RecipientType -eq 'UserMailbox')" | out-null Get-DynamicDistributionGroup -anr "AllCompanyUsers" | Set-DynamicDistributionGroup -RequireSenderAuthenticationEnabled $False -HiddenFromAddressListsEnabled $true | out-null } write-host "Checking all domains, and creating a list for each domain." -ForegroundColor Green $Domains = Get-MsolDomain -TenantId $customer.TenantId foreach ($Domain in $domains.name) { write-host "Checking domain $($Domain) creating if it does not exist." -ForegroundColor Green $ExisitingDomainList = Get-DynamicDistributionGroup -anr $Domain if (!$ExisitingDomainList) { write-host " Creating $domain list" -ForegroundColor Green New-DynamicDistributionGroup -Name "$domain" -RecipientFilter "(RecipientType -eq 'UserMailbox') -and (EmailAddresses -like '$Domain')" | out-null Get-DynamicDistributionGroup -anr "$Domain" | Set-DynamicDistributionGroup -RequireSenderAuthenticationEnabled $False -HiddenFromAddressListsEnabled $true | out-null } } Remove-PSSession $session }
So, that’s it! as always, Happy PowerShelling!
Should the GET / SET on dynamic groups not be in the IF statement ?
IF is for create when it does not exists, then updates.
But as the GET/SET is in the IF, it does not updates the list if it exists .. 🙂
Am I Wrong ?
Yes you’re wrong. 🙂 The list only needs to be created once, its a dynamic list so never requires an update, you’ll only need to set it up once.
Pingback: ICYMI: PowerShell Week of 29-May-2020 | PowerShell.org
AAD P1 license is required for all dynamic group members?
Yes.