If you aren’t licensed for and using Conditional Access policies, please do not disable the security defaults feature just because something isn’t working (e.g. scan to email). Microsoft introduced the defaults for a very good reason – they realised that tenants without Azure AD Premium P1 licensing and correctly configured CA policies were wide open to Phishing and Password Spray attacks, via connections to Exchange Online using basic authentication protocols such as POP, IMAP and SMTP.
Connections using basic authentication do not support and therefore bypass MFA. If you disable this setting you are effectively turning off many security features.
Let’s find a solution to these problems and leave our tenant protected ‘by default’.
Here’s how to allow certain things (e.g. Teams meeting room devices and printers) while leaving our tenant secure:
1. Add any external IPs of company locations to Trusted IPs under MFA settings. In most cases you would do this for all company owned office locations.
Now your users and devices will be able to connect without MFA requirement from trusted offices, and you can set up Scan to Email functions to use the account you created.
Righto – time have a cup of tea and reward yourself for not chopping off a leg to fix an itch! 🤣🤣
Hey! I hope you are well.. 🤘 🙂 🤘. This script was a result of the following ponderings:
How to monitor and manage the deletion of Blocked (Disabled) and Guest accounts in Azure AD.
I have a Dynamic group for ‘Blocked (Disabled) users’, but members include valid Shared Mailbox accounts.
What about Guest users… should I just leave them? 🤣
Noooo, I shouldn’t… paying monthly subscriptions it’s important to stay on top of user account maintenance. There are some reports and sorting you can do, and Power BI, Graph etc, but I wanted to script something!! In my usual non-perfect PowerShell way of course, but hey it gets the job done.
The Guest users are easy to group using a Azure AD Dynamic Security group with this Rule Syntax:
(user.userType -eq "Guest") and (user.accountEnabled -eq true)
Sweet! My Blocked (or Disabled) users group is Dynamic as well, using this syntax:
(user.accountEnabled -ne true) and (user.surname -ne "Shared_Mailbox")
I’ve only just added (user.surname -ne “Shared_Mailbox”) – the script sets that attribute when it adds an account to the Shared Mailbox group, so that the accounts are excluded from the Dynamic Bocked Users group. Cool now I can actually review the blocked users knowing my Shared Mailbox accounts are safe!
I could also use Conditional Access policies to increase the security of those accounts!
Here is the script… you need to have an Automation account with credential set up (this can be a Synced AD or cloud account that has ‘Exchange Recipient’ and ‘Group Administrator’ roles assigned. Make sure you have imported the AzureAD and ExchangeOnlineManagement modules into the Automation account, and have created the Azure AD Group (set the group to ‘Assigned’ membership rather than ‘Dynamic’). From Azure AD navigate to Groups, search for your group and click on it. You will be able to copy the Object ID from here:
Enter that for $sharedmailboxgroupid and the ‘Name’ of your Automation account credential as $runbookcredentialname. That’s it – give it a good testing and whack eem into production mate!
(NB – following all relevant change control precedures of course!)
See below the code for how the output looks in the Runbook logs… great for troubleshooting!
See ya! 🍺
# use TLS 1.2
[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12
# Sync shared mailbox accounts with an Azure AD group - Simon Burbery - November 2021
# Update variables with the name of your runbook credential and the Azure AD Object ID displayed on the groups overview page in the AAD portal.
# set variables
$runbookcredentialname = 'svc_runbookcredential'
$sharedmailboxgroupid = '12345678-abcd-4321-0987-665544332211'
# get credential for connections
Try {
$CredAzure = Get-AutomationPSCredential -Name $runbookcredentialname
}
Catch {
Write-Error "Failed to get credential!"
Exit
}
Write-Output "Get automation credential - Success"
# connect Azure AD
Try {
Connect-AzureAD -Credential $CredAzure | Out-Null
}
Catch {
Write-Error "Failed to connect to Azure AD!"
Exit
}
Write-Output "Connect to Azure AD - Success"
# connect EOL
Try {
Connect-ExchangeOnline -Credential $CredAzure
}
Catch {
Write-Error "Failed to connect to EOL!"
Exit
}
Write-Output "Connect to EOL - Success"
# get group name
$groupname = (Get-AzureADGroup -ObjectId $sharedmailboxgroupid).DisplayName
# get all shared mailboxes and group members
Write-Output "Enumerating Shared Mailbox accounts and $groupname membership..."
Try {
$sharedmailboxaccounts = Get-Mailbox -ResultSize Unlimited | Where-Object { $_.RecipientTypeDetails -eq 'SharedMailbox' } | select ExternalDirectoryObjectID,UserPrincipalName
$currentgroupmembers = Get-AzureADGroupMember -All $true -ObjectId $sharedmailboxgroupid | select ObjectID,UserPrincipalName
}
Catch {
Write-Error "Failed to enumerate Shared Mailbox accounts or $groupname membership!"
Exit
}
Write-Output "Enumerate Shared Mailbox accounts and $groupname membership - Success"
# remove any members that are no longer shared mailboxes
Write-Output "Verify $groupname membership..."
Try {
foreach ( $groupmember in $currentgroupmembers ) {
$groupmemberid = $groupmember.ObjectID
$groupmemberupn = $groupmember.UserPrincipalName
$checkmember = ( $sharedmailboxaccounts.ExternalDirectoryObjectId -contains $groupmemberid )
If ( $checkmember -ne 'True' ) {
Write-Output "Shared Mailbox not found - removing $groupmemberupn from $groupname..."
Remove-AzureADGroupMember -ObjectId $sharedmailboxgroupid -MemberId $groupmemberid
Set-AzureADUser -ObjectId $groupmemberid -Surname 'Disabled User'
}
Else {
Write-Output "Shared Mailbox found - skipping $groupmemberupn"
}
}
}
Catch {
Write-Error "Error while removing accounts from group!"
Exit
}
Write-Output "Verify $groupname membership - Success"
# add new shared mailbox accounts to Azure AD group
Write-Output "Checking for new Shared Mailboxes..."
Try {
foreach ( $sharedmailboxaccount in $sharedmailboxaccounts ) {
$sharedmailboxaccountid = $sharedmailboxaccount.ExternalDirectoryObjectId
$sharedmailboxaccountupn = $sharedmailboxaccount.UserPrincipalName
$checkmembersm = ( $currentgroupmembers.ObjectID -contains $sharedmailboxaccountid )
If ( $checkmembersm -ne 'True' ) {
Write-Output "New Shared Mailbox - adding $sharedmailboxaccountupn to $groupname..."
Add-AzureADGroupMember -ObjectId $sharedmailboxgroupid -RefObjectId $sharedmailboxaccountid
Set-AzureADUser -ObjectId $sharedmailboxaccountid -Surname 'Shared_Mailbox'
}
else {
Write-Output "Skipping Shared Mailbox $sharedmailboxaccountupn"
}
}
}
Catch {
Write-Error "Error while adding accounts to group!"
Exit
}
Write-Output "Check for new Shared Mailboxes - Success"
# clean up
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-AzureAD -Confirm:$false
# end
And here is what I really like about using Runbooks – the output from the script is available to go back and look at when failures occur etc. Nice!
UPDATE Feb ’23 – David made me do it – well, he didn’t make me at all really, but I did it anyway 🙂. Check out this new post which uses AzAD and AzureAD cmdlets to get the groups and members email, UPN and ObjectID (catering for different member types and groups with no members):
recent comms…