-
Notifications
You must be signed in to change notification settings - Fork 0
/
runbook-dynamicgroup-mfa.ps1
159 lines (139 loc) · 7.78 KB
/
runbook-dynamicgroup-mfa.ps1
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
<#PSScriptInfo
.VERSION 0.4
.GUID 21da31c8-4f69-419d-8a3f-f16168b8f3ae
.AUTHOR Dominik Gilgen
.COMPANYNAME Dominik Gilgen (Personal)
.COPYRIGHT 2023 Dominik Gilgen. All rights reserved.
.LICENSEURI https://github.com/M365-Consultant/EntraID-MFA-DynamicGroup/blob/main/LICENSE
.PROJECTURI https://github.com/M365-Consultant/EntraID-MFA-DynamicGroup
.TAGS AzureAD EntraID MFA ConditionalAccess DynamicGroup Runbook
.RELEASENOTES
This script now supports email reporting, which requires the permission 'Mail.Send' and the Graph-Module 'Microsoft.Graph.Users.Actions'.
Instead of variables it is now using parameters for the input.
#>
<#
.DESCRIPTION
Azure Runbook - Dynamic Group - MFA State
This script is designed for an Azure Runbook to assign users to two Azure AD groups based on their MFA capability (capable / non-capable).
Before running the runbook, you need to set up an automation account with a managed identity.
The managed identity requires the following Graph Permissions:
- User.Read.All
- Group.ReadWrite.All
- UserAuthenticationMethod.Read.All
- Mail.Send
The script requires the following modules:
- Microsoft.Graph.Authentication
- Microsoft.Graph.Groups
- Microsoft.Graph.Identity.SignIns
- Microsoft.Graph.Users
- Microsoft.Graph.Users.Actions
There are a few parameters which must be set for a job run:
- $groupid_capable -> The Object-ID of a EntraID (AzureAD) group where MFA capable uers's should be assigned
- $groupid_noncapable -> The Object-ID of a EntraID (AzureAD) group where MFA NON-capable uers's should be assigned
- $mailMode -> This controls the mail behavior. Enter the mode you want without using '
'always' - sends a mail on every run
'changes' - sends a mail only if there were any changes
'disabled' - never send a mail
- $mailSender -> The mail-alias from which the mail will be send (can be a user-account or a shared-mailbox)
- $mailRecipients -> The recipient(s) of the mail (internal or external). If you want more than one recipient, you can separate them with the character ; in between.
#>
Param
(
[Parameter (Mandatory= $true)]
[String] $groupid_capable = "Enter Group-ID for MFA capable",
[Parameter (Mandatory= $true)]
[String] $groupid_noncapable = "Enter Group-ID for MFA non-capable",
[Parameter (Mandatory= $false)]
[String] $mailMode,
[Parameter (Mandatory= $false)]
[String] $mailSender,
[Parameter (Mandatory= $false)]
[String] $mailRecipients
)
#Connect to Microsoft Graph using a Managed Identity
Connect-MgGraph -Identity
#Preparing necessary variables
$users = get-mguser -All
$members_capable = Get-MgGroupMember -GroupId $groupid_capable -All
$members_noncapable = Get-MgGroupMember -GroupId $groupid_noncapable -All
$groupname_capable = Get-MgGroup -GroupId $groupid_capable
$groupname_noncapable = Get-MgGroup -GroupId $groupid_noncapable
#Preparing mail content
$mailContentHeader = "<p>The Azure runbook for dynamic group based on the user's MFA state has been executed.</p><p>Those are the changes from this run:</p>"
$mailContentChanges = "<ul>"
#Running the MFA state check for every user and assign them to correct groups
foreach ($user in $users) {
$mfa = Get-MgUserAuthenticationMethod -UserId $user.UserPrincipalName -All | Where-Object {$_.AdditionalProperties."@odata.type" -ne "#microsoft.graph.passwordAuthenticationMethod"}
if ($mfa.Count -gt 0) {
if ($members_capable.Id -notcontains $user.Id){
New-MgGroupMember -GroupId $groupid_capable -DirectoryObjectId $user.Id
$output = $user.UserPrincipalName + " added to '" + $groupname_capable.DisplayName + "'. User-ID: " + $user.Id
Write-Output $output
$outputMail = "<li>" + $user.UserPrincipalName + " <font color='green'>added</font> to '" + $groupname_capable.DisplayName + "'. <font color='grey'>(User-ID: " + $user.Id + ")</font></li>"
$mailContentChanges += $outputMail
}
if ($members_noncapable.Id -contains $user.Id){
Remove-MgGroupMemberByRef -GroupId $groupid_noncapable -DirectoryObjectId $user.Id
$output = $user.UserPrincipalName + " removed from '" + $groupname_noncapable.DisplayName + "'. User-ID: " + $user.Id
$outputMail = "<li>" + $user.UserPrincipalName + " <font color='orange'>removed</font> from '" + $groupname_noncapable.DisplayName + "'. <font color='grey'>(User-ID: " + $user.Id + ")</font></li>"
Write-Output $output
$mailContentChanges += $outputMail
}
}
else{
if($members_noncapable.Id -notcontains $user.Id){
New-MgGroupMember -GroupId $groupid_noncapable -DirectoryObjectId $user.Id
$output = $user.UserPrincipalName + " added to '" + $groupname_noncapable.DisplayName + "'. User-ID: " + $user.Id
$outputMail = "<li>" + $user.UserPrincipalName + " <font color='green'>added</font> to '" + $groupname_noncapable.DisplayName + "'. <font color='grey'>(User-ID: " + $user.Id + ")</font></li>"
Write-Output $output
$mailContentChanges += $outputMail
}
if($members_capable.Id -contains $user.Id){
Remove-MgGroupMemberByRef -GroupId $groupid_capable -DirectoryObjectId $user.Id
$output = $user.UserPrincipalName + " removed from '" + $groupname_capable.DisplayName + "' because this account has become non-capable! User-ID: " + $user.Id
$outputMail = "<li><font color='red'><b>WARNING: </b></font>" + $user.UserPrincipalName + " <font color='orange'>removed</font> from '" + $groupname_capable.DisplayName + "' because this account has become non-capable! <font color='grey'>(User-ID: " + $user.Id + ")</font></li>"
Write-Warning $output
$mailContentChanges += $outputMail
}
}
}
if ($mailContentChanges -eq "<ul>"){
$mailContentChanges = "<b>No changes made.</b>"
Write-Output "No changes made."
}
else { $mailContentChanges += "</ul>" }
# Sendmail
function runbookSendMail {
$mailRecipientsArray = $mailRecipients.Split(";")
$mailSubject = "Azure Runbook Report: Dynamic Group MFA State"
$mailContentFooter = "<br><br><p style='color: grey'>You can find additional details in the job history of this runbook.<br>Job finished at (UTC) " + (Get-Date).ToUniversalTime() + "<br>Job ID:"+ $PSPrivateMetadata.JobId.Guid + "</p>"
$mailContent = $mailContentHeader + $mailContentChanges + $mailContentFooter
$params = @{
Message = @{
Subject = $mailSubject
Body = @{
ContentType = "html"
Content = $mailContent
}
ToRecipients = @(
foreach ($recipient in $mailRecipientsArray) {
@{
EmailAddress = @{
Address = $recipient
}
}
}
)
}
SaveToSentItems = "false"
}
Send-MgUserMail -UserId $mailSender -BodyParameter $params
Write-Output "Mail has been sent."
}
if ($mailMode -eq "always" -and $mailSender -and $mailRecipients) { runbookSendMail }
elseif ($mailMode -eq "changes" -and $mailSender -and $mailRecipients -and ($mailContentChanges -ne "<b>No changes made.</b>")) { runbookSendMail }
elseif ($mailMode -eq "changes" -and $mailSender -and $mailRecipients) { Write-Output "No mail sent, because there are no changes and mailmode is set to 'changes'." }
elseif ($mailMode -eq "disabled"){ Write-Output "Mail function is disabled." }
else { Write-Warning "Mail settings are missing or incorrect" }
#Disconnect from Microsoft Graph within Azure Automation
Disconnect-MgGraph