Skip to content

Instantly share code, notes, and snippets.

@alexmags
Last active February 26, 2022 08:11
Show Gist options
  • Save alexmags/cb69108c65fb38614b6625b4400c98c2 to your computer and use it in GitHub Desktop.
Save alexmags/cb69108c65fb38614b6625b4400c98c2 to your computer and use it in GitHub Desktop.
PowerShell to map AD security group members to Azure AD roles.
# Make code debuggable
$ErrorActionPreference = "Stop"
Set-StrictMode -Version latest
# Enable use of proxy using current credentials
$browser = New-Object System.Net.WebClient
$browser.Proxy.Credentials =[System.Net.CredentialCache]::DefaultNetworkCredentials
# Download PowerShell module if not already installed
function get-moduleIfNotInstalled ($modulename) {
if (!(get-module $modulename -listavailable)) {
write-host "Installing $modulename module into current user scope"
Install-Module -name $modulename -Scope 'CurrentUser' -Confirm:$false -Force -verbose
get-Module -name $modulename -ListAvailable # log the versions of modules availble
}
else {
write-host "$modulename already installed"
}
import-Module -Name $modulename
write-host "$modulename imported"
}
function get-AzureADGroupSafely {
[cmdletbinding()]
param(
[parameter(Mandatory=$True,ValueFromPipeline=$true)]
$SearchString
)
# searchstring returns multiple results if it's a substring
return get-AzureADGroup -SearchString $SearchString | where-object {$_.displayname -eq $SearchString}
}
function Get-RecursiveAzureAdGroupMemberUsers{
[cmdletbinding()]
param(
[parameter(Mandatory=$True,ValueFromPipeline=$true)]
$AzureGroup
)
Begin{
#If(-not(Get-AzureADCurrentSessionInfo)){Connect-AzureAD}
}
Process {
Write-Verbose -Message "Enumerating $($AzureGroup.DisplayName)"
$Members = Get-AzureADGroupMember -ObjectId $AzureGroup.ObjectId -All $true
$UserMembers=@() # initialise array
$UserMembers += $Members | Where-Object{$_.ObjectType -eq 'User'} # might be empty
$nestedGroups=$Members | Where-Object{$_.ObjectType -eq 'Group'}
If($nestedGroups){
Write-Debug "Checking nested group $($nestedGroups.displayname)"
$UserMembers += $nestedGroups | ForEach-Object{ Get-RecursiveAzureAdGroupMemberUsers -AzureGroup $_}
}
}
end {
if ($UserMembers) { Write-Debug "returning $($UserMembers.count) members"}
Return $UserMembers
}
}
function set-AADRoleByAADGroup {
param(
[parameter(Mandatory=$True)]$aadGroupName,
[parameter(Mandatory=$True)]$aadRoleName,
[bool]$removeUsers=$false
)
Write-Output "Security Group $aadGroupName -> $aadRoleName"
# Get Admin role group members
$AdminroleGroupMembers=@()
$AdminroleGroupMembers += get-AzureADGroupSafely -SearchString $aadGroupName | Get-RecursiveAzureAdGroupMemberUsers
$AdminroleGroupMembers = $AdminroleGroupMembers | Sort-Object -Unique
# Get Admin role
$Adminrole = Get-AzureADDirectoryRole | Where-Object {$_.displayName -eq $aadRoleName}
if (!($Adminrole)) {
write-output "Available roles is:"
Get-AzureADDirectoryRole | sort-object -Property Displayname | select DisplayName
throw "Role not found $aadRoleName"
}
# Get existing role members
$AADRoleMembers=@()
$AADRoleMembers+=Get-AzureADDirectoryRoleMember -ObjectId $Adminrole.ObjectId
# compare AAD role members v AAD role security group members
# !! Bug here if Azure AD role has no members, or Security group has no members.!! Dirty fix add 1 member....
if ($AdminroleGroupMembers -and $AADRoleMembers)
{
$differences=Compare-Object -ReferenceObject $AdminroleGroupMembers.ObjectId -DifferenceObject $AADRoleMembers.ObjectId -IncludeEqual
foreach ($diff in $differences){
$userObject=get-azureaduser -ObjectId $diff.inputobject
switch ($diff.SideIndicator)
{
'==' {
write-output "`tOK, $($userObject.displayname) is supposed to have role: $aadRoleName
}
'<=' {
write-output "`##vso[task.logissue type=warning] Adding $($userObject.displayname) to role: $aadRoleName"
Add-AzureADDirectoryRoleMember -ObjectId $Adminrole.ObjectId -RefObjectId $diff.inputobject -Verbose
}
'=>' {
if ($removeUsers -eq $true)
{
write-output "##vso[task.logissue type=warning] Removing $($userObject.displayname) from role: $aadRoleName"
remove-AzureADDirectoryRoleMember -ObjectId $Adminrole.ObjectId -MemberId $diff.inputobject -Verbose
}
else
{
write-output "##vso[task.logissue type=warning] Additional user $($userObject.displayname) in role: $aadRoleName"
}
}
default {
throw "$($diff.inputobject) compare object SideIndicator unexpected!"
}
} #end diff switch
} # end each diff
} # if objects to compare
else
{
if ($AdminroleGroupMembers) # AAD group exists but AAD role has no members
{
foreach ($AdminroleGroupMember in $AdminroleGroupMembers)
{
write-output "`##vso[task.logissue type=warning] Adding $($AdminroleGroupMember.displayname) to role: $aadRoleName"
Add-AzureADDirectoryRoleMember -ObjectId $Adminrole.ObjectId -RefObjectId $AdminroleGroupMember.objectID -Verbose
}
}
}
}
function set-AADGroupByAADGroup {
param(
[parameter(Mandatory=$True)]$sourceGroupname,
[parameter(Mandatory=$True)]$destinationgroupName,
[bool]$removeUsers=$false
)
# Workaround for Service desk access to service desk AAD admin unit role. Copy AD security group to AAD security group
$sourceUsers=get-AzureADGroupSafely -SearchString $sourceGroupname | Get-RecursiveAzureAdGroupMemberUsers | Sort-Object -Descending
$destinationUsers=get-AzureADGroupSafely -SearchString $destinationgroupName | Get-RecursiveAzureAdGroupMemberUsers | Sort-Object -Descending
$differences=Compare-Object -IncludeEqual $sourceUsers.UserPrincipalName -DifferenceObject $destinationUsers.UserPrincipalName
$destinationgroup= get-AzureADGroupSafely -SearchString $destinationgroupName
foreach ($diff in $differences){
$userObject=get-azureaduser -ObjectId $diff.inputobject
switch ($diff.SideIndicator){
'==' {
write-output "`tOK, $($userObject.displayname) is supposed to be in group: $destinationgroupName"
}
'<=' {
write-output "`##vso[task.logissue type=warning] Adding $($userObject.displayname) to group: $destinationgroupName"
Add-AzureADGroupMember -ObjectId $destinationgroup.ObjectId -RefObjectId $userObject.objectid -Verbose
}
'=>' {
if ($removeUsers -eq $true)
{
write-output "##vso[task.logissue type=warning] Removing $($userObject.displayname) from group: $destinationgroupName"
remove-AzureADGroupMember -ObjectId $destinationgroup.ObjectId -MemberId $userObject.objectid -Verbose
}
else
{
write-output "##vso[task.logissue type=warning] Additional user $($userObject.displayname) in role: $aadRoleName"
}
}
default {
throw "$($diff.inputobject) compare object SideIndicator unexpected!"
}
}
}
}
get-moduleIfNotInstalled AzureAD
# Assign group of users a role, kick anyone else out
set-AADRoleByAADGroup -aadGroupName "sec_AADRoleReportsReaders" -aadRoleName "Reports Reader" -removeUsers $true
# Mirror the membership of AD to AAD role
set-AADGroupByAADGroup -sourceGroupname 'GroupA' -destinationgroupName 'GroupB' -removeUsers $true
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment