mirror of
https://dev.azure.com/effectory/Survey%20Software/_git/Cloud%20Engineering
synced 2026-02-27 10:45:02 +01:00
Rewrite group check script to not use AD libs #120605
This commit is contained in:
@@ -30,7 +30,8 @@ function GetEligibleAssignments {
|
||||
[string] $scope
|
||||
)
|
||||
|
||||
$access_token = (Get-AzAccessToken -TenantId "e9792fd7-4044-47e7-a40d-3fba46f1cd09").Token
|
||||
$access_token_secure = (Get-AzAccessToken -TenantId "e9792fd7-4044-47e7-a40d-3fba46f1cd09").Token
|
||||
$access_token = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto([System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($access_token_secure))
|
||||
|
||||
$url = "https://management.azure.com/$scope/providers/Microsoft.Authorization/roleEligibilityScheduleInstances?api-version=2020-10-01&`$filter=atScope()"
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@ else {
|
||||
# .\AzureStoragebloblist.ps1 -subscriptionId "14c2354d-45a9-4e0f-98ff-be58cdbcddc7" -resourcegroupName "ec-measurement" -storageAccountName "stecmeasurementprod"
|
||||
# .\AzureStoragebloblist.ps1 -subscriptionId "2a07dfa7-69ee-4608-b2d5-14124fcccc31" -resourcegroupName "questionnaire-server-weu" -storageAccountName "questionnairedataweu"
|
||||
# .\AzureStoragebloblist.ps1 -subscriptionId "54794e27-b714-4346-81bc-05eae7ccb5a5" -resourcegroupName "question-management-api-weu" -storageAccountName "qmprojectionsweu" -excludedContainers "`$logs","`$blobchangefeed"
|
||||
|
||||
# .\AzureStoragebloblist.ps1 -subscriptionId "7feeb150-9ee0-4aea-992a-5f3a89d933e6" -resourcegroupName "Results" -storageAccountName "myeffectoryresults" -excludedContainers "`$logs","`$blobchangefeed", "attachments", "azure-webjobs-hosts", "azure-webjobs-secrets", "azure-webjobs-dashboard", "azure-webjobs-hosts", "azure-webjobs-secrets", "hierarchydatesettings-leases", "projectcalculations-leases","resultscleanup-applease","resultscleanup-leases","resultsgroupscorecalculator-leases","testhubname-leases"
|
||||
|
||||
class BlobCheck {
|
||||
[string] $SubscriptionId = ""
|
||||
|
||||
@@ -1,112 +0,0 @@
|
||||
# import AD Module
|
||||
Import-Module activedirectory
|
||||
#Set-ExecutionPolicy unrestricted
|
||||
|
||||
#---------------------------
|
||||
#-------- Variable ---------
|
||||
#---------------------------
|
||||
$i=0
|
||||
|
||||
#---------------------------
|
||||
#------- Functions ---------
|
||||
#---------------------------
|
||||
function Get-ADGroupName ([string] $ADDistinguishedName)
|
||||
{
|
||||
$ADGrpName= (Get-ADGroup -Filter "DistinguishedName -eq '$ADDistinguishedName'").SamAccountName
|
||||
return $ADGrpName
|
||||
}
|
||||
|
||||
|
||||
function Get-GroupMemberOf ([string] $ADGroupName)
|
||||
{
|
||||
if ($ADGroupName -eq "# Developer") { return } # prevent recursing
|
||||
|
||||
$ii++; $a=0
|
||||
$Message=""; $Prefix=""
|
||||
$GroupCategory=""; $GroupScope=""; $GroupName=""
|
||||
|
||||
For ($a=0; $a -lt $ii; $a++) {$Prefix = $Prefix + " "}
|
||||
|
||||
$DNs=(Get-ADGroup $ADGroupName -Properties *).MemberOf
|
||||
if ($DNs.count -ne 0)
|
||||
{
|
||||
foreach ($DN in $DNs)
|
||||
{
|
||||
$GroupName = (Get-ADGroupName $DN)
|
||||
$GroupCategory = (Get-ADGroup $GroupName -Properties *).GroupCategory
|
||||
$GroupScope = (Get-ADGroup $GroupName -Properties *).GroupScope
|
||||
|
||||
$Message="$Prefix $ADGroupName => $GroupName [$GroupCategory - $GroupScope]"
|
||||
Write-Output $Message
|
||||
|
||||
Get-GroupMemberOf $GroupName ' '
|
||||
}# End ForEach
|
||||
}# End IF
|
||||
}#End Function
|
||||
|
||||
function Get-UserMemberships ([string] $ADUserSID)
|
||||
{
|
||||
$ADUser = Get-ADUser $ADUserSID -Properties *
|
||||
$ADUserMembers=$ADUser.MemberOf
|
||||
|
||||
$ADUserName = $ADUser.name
|
||||
Write-Host "AD-User: $ADUserName ($ADUserSID)"
|
||||
Write-Output "AD-User: $ADUserName"
|
||||
|
||||
#PrimaryGroup
|
||||
$ADPrimaryGroupDN = (Get-ADUser -Properties * -Filter "SID -eq '$ADUserSID'").PrimaryGroup
|
||||
$ADPrimaryGroupName=(Get-ADGroupName $ADPrimaryGroupDN)
|
||||
$ADGroupCategory=(Get-ADGroup $ADPrimaryGroupName).GroupCategory
|
||||
$ADGroupScope=(Get-ADGroup $ADPrimaryGroupName).GroupScope
|
||||
$Message = "Primary Group: $ADPrimaryGroupName [$ADGroupCategory, $ADGroupScope]"
|
||||
Write-Output $Message
|
||||
|
||||
#Other groups
|
||||
foreach ($ADUserMember in $ADUserMembers)
|
||||
{
|
||||
$i++
|
||||
$ADGroupName = (Get-ADGroupName $ADUserMember)
|
||||
$ADGroupCategory=(Get-ADGroup $ADGroupName).GroupCategory
|
||||
$ADGroupScope=(Get-ADGroup $ADGroupName).GroupScope
|
||||
$Message = "($i) $ADGroupName [$ADGroupCategory, $ADGroupScope]"
|
||||
Write-Output $Message
|
||||
Get-GroupMemberOf $ADGroupName ' '
|
||||
Write-Output " "
|
||||
}
|
||||
}
|
||||
|
||||
function Get-AllMembershipsOfUsers([string] $ADGroupName)
|
||||
{
|
||||
$i=0
|
||||
|
||||
$devadmaccounts = get-adgroupmember -Identity $ADGroupName -Recursive
|
||||
foreach ($devADM in $devadmaccounts)
|
||||
{
|
||||
Get-UserMemberships $devADM.SID
|
||||
Write-Output "======================================================================================================"
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
#-----------------------------------------------------------------
|
||||
Clear-Host
|
||||
|
||||
[string] $ADGroupName
|
||||
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
||||
|
||||
$ADGroupName = "# Developer ADM"
|
||||
Get-AllMembershipsOfUsers $ADGroupName | Out-file "$date Developer ADM.txt"
|
||||
|
||||
$ADGroupName = "Domain Admins"
|
||||
Get-AllMembershipsOfUsers $ADGroupName | Out-file "$date Domain Admins.txt"
|
||||
|
||||
$ADGroupName = "# Developer"
|
||||
Get-AllMembershipsOfUsers $ADGroupName | Out-file "$date Developer.txt"
|
||||
|
||||
$ADGroupName = "# Interne Automatisering Team-Assistent"
|
||||
Get-AllMembershipsOfUsers $ADGroupName | Out-file "$date Interne Automatisering Team-Assistent.txt"
|
||||
|
||||
$ADGroupName = "# Interne Automatisering"
|
||||
Get-AllMembershipsOfUsers $ADGroupName | Out-file "$date Interne Automatisering.txt"
|
||||
|
||||
225
Powershell/Lists/Entra/GroupMemberships.ps1
Normal file
225
Powershell/Lists/Entra/GroupMemberships.ps1
Normal file
@@ -0,0 +1,225 @@
|
||||
param(
|
||||
[Parameter(Mandatory=$true)]
|
||||
[string]$GroupId
|
||||
)
|
||||
|
||||
# GroupMemberships.ps1 -GroupId "# Developer ADM"
|
||||
# GroupMemberships.ps1 -GroupId "Domain Admins"
|
||||
# GroupMemberships.ps1 -GroupId "# Developer"
|
||||
# GroupMemberships.ps1 -GroupId "# Interne Automatisering Team-Assistent"
|
||||
# GroupMemberships.ps1 -GroupId "# Interne Automatisering"
|
||||
|
||||
[string] $date = Get-Date -Format "yyyy-MM-dd HHmm"
|
||||
[string] $OutputPath = ".\$date ($GroupId) group members.csv"
|
||||
[string] $membershipOutputPath = ".\$date ($GroupId) group memberships - parent groups .csv"
|
||||
|
||||
# Connect to Microsoft Graph if not already connected
|
||||
Write-Host "Connecting to Microsoft Graph..."
|
||||
Connect-MgGraph -Scopes "Group.Read.All", "GroupMember.Read.All" -NoWelcome
|
||||
|
||||
# If GroupId is actually a group name, resolve it to the actual GroupId
|
||||
if ($GroupId -notmatch '^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$') {
|
||||
Write-Host "Resolving group name '$GroupId' to GroupId..."
|
||||
try {
|
||||
$group = Get-MgGroup -Filter "displayName eq '$GroupId'" -ErrorAction Stop
|
||||
if ($group) {
|
||||
if ($group.Count -gt 1) {
|
||||
Write-Warning "Multiple groups found with name '$GroupId'. Using the first one."
|
||||
$GroupId = $group[0].Id
|
||||
} else {
|
||||
$GroupId = $group.Id
|
||||
}
|
||||
Write-Host "Resolved to GroupId: $GroupId"
|
||||
} else {
|
||||
Write-Error "Group with name '$GroupId' not found."
|
||||
exit 1
|
||||
}
|
||||
} catch {
|
||||
Write-Error "Error resolving group name: $($_.Exception.Message)"
|
||||
exit 1
|
||||
}
|
||||
}
|
||||
|
||||
# Function to get groups that this group is a member of (reverse membership)
|
||||
function Get-GroupMembershipRecursive {
|
||||
param(
|
||||
[string]$GroupId,
|
||||
[int]$Level = 0,
|
||||
[hashtable]$ProcessedMemberships = @{}
|
||||
)
|
||||
|
||||
# Check for circular reference in membership chain
|
||||
if ($ProcessedMemberships.ContainsKey($GroupId)) {
|
||||
Write-Warning "Circular membership reference detected for group: $GroupId"
|
||||
return @()
|
||||
}
|
||||
|
||||
# Check for maximum depth
|
||||
if ($Level -gt 50) {
|
||||
Write-Warning "Maximum membership recursion depth reached for group: $GroupId"
|
||||
return @()
|
||||
}
|
||||
|
||||
# Mark group as being processed for membership
|
||||
$ProcessedMemberships[$GroupId] = $true
|
||||
$membershipResults = @()
|
||||
|
||||
try {
|
||||
# Get groups that this group is a member of
|
||||
$memberOfGroups = Get-MgGroupMemberOf -GroupId $GroupId -All
|
||||
|
||||
foreach ($parentGroup in $memberOfGroups) {
|
||||
if ($parentGroup.AdditionalProperties['@odata.type'] -eq '#microsoft.graph.group') {
|
||||
$parentGroupDetails = Get-MgGroup -GroupId $parentGroup.Id -Select "DisplayName,Mail,GroupTypes"
|
||||
|
||||
$membershipObject = [PSCustomObject]@{
|
||||
ChildGroupId = $GroupId
|
||||
ParentGroupId = $parentGroup.Id
|
||||
ParentGroupName = $parentGroupDetails.DisplayName
|
||||
ParentGroupType = $parentGroupDetails.GroupTypes -join ","
|
||||
ParentGroupEmail = $parentGroupDetails.Mail
|
||||
MembershipLevel = $Level
|
||||
}
|
||||
|
||||
$membershipResults += $membershipObject
|
||||
|
||||
# Recursively get parent groups of this parent group
|
||||
if ($parentGroup.Id -ne $GroupId) {
|
||||
$nestedMemberships = Get-GroupMembershipRecursive -GroupId $parentGroup.Id -Level ($Level + 1) -ProcessedMemberships $ProcessedMemberships
|
||||
$membershipResults += $nestedMemberships
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Error getting group memberships for $GroupId`: $($_.Exception.Message)"
|
||||
}
|
||||
finally {
|
||||
# Remove from processed memberships when done
|
||||
$ProcessedMemberships.Remove($GroupId)
|
||||
}
|
||||
|
||||
return $membershipResults
|
||||
}
|
||||
|
||||
|
||||
# Initialize collections
|
||||
$groupMembers = @()
|
||||
$processedGroups = @{}
|
||||
$groupStack = @()
|
||||
|
||||
# Function to get group members recursively
|
||||
# This function will handle circular references and maximum recursion depth
|
||||
function Get-GroupMembersRecursive {
|
||||
param(
|
||||
[string]$GroupId,
|
||||
[int]$Level = 0,
|
||||
[string]$ParentGroupName = ""
|
||||
)
|
||||
|
||||
# Check for circular reference
|
||||
if ($processedGroups.ContainsKey($GroupId)) {
|
||||
Write-Warning "Circular reference detected for group: $GroupId"
|
||||
return
|
||||
}
|
||||
|
||||
# Check for stack overflow (max depth)
|
||||
if ($Level -gt 50) {
|
||||
Write-Warning "Maximum recursion depth reached for group: $GroupId"
|
||||
return
|
||||
}
|
||||
|
||||
# Mark group as being processed
|
||||
$processedGroups[$GroupId] = $true
|
||||
$groupStack += $GroupId
|
||||
|
||||
try {
|
||||
# Get the group information
|
||||
$group = Get-MgGroup -GroupId $GroupId -ErrorAction Stop
|
||||
|
||||
# Get group members
|
||||
$members = Get-MgGroupMember -GroupId $GroupId -All
|
||||
|
||||
foreach ($member in $members) {
|
||||
# Create custom object for the result
|
||||
$memberObject = [PSCustomObject]@{
|
||||
ParentGroupId = $GroupId
|
||||
ParentGroupName = $group.DisplayName
|
||||
ParentGroupType = $group.GroupTypes -join ","
|
||||
MemberId = $member.Id
|
||||
MemberType = $member.AdditionalProperties['@odata.type'] -replace '#microsoft.graph.', ''
|
||||
Level = $Level
|
||||
Path = ($groupStack -join " -> ") + " -> " + $member.Id
|
||||
}
|
||||
|
||||
# Get member details based on type
|
||||
switch ($member.AdditionalProperties['@odata.type']) {
|
||||
'#microsoft.graph.user' {
|
||||
$user = Get-MgUser -UserId $member.Id -Select "DisplayName,UserPrincipalName,Mail"
|
||||
$memberObject | Add-Member -NotePropertyName "MemberName" -NotePropertyValue $user.DisplayName
|
||||
$memberObject | Add-Member -NotePropertyName "MemberUPN" -NotePropertyValue $user.UserPrincipalName
|
||||
$memberObject | Add-Member -NotePropertyName "MemberEmail" -NotePropertyValue $user.Mail
|
||||
}
|
||||
'#microsoft.graph.group' {
|
||||
$memberGroup = Get-MgGroup -GroupId $member.Id -Select "DisplayName,Mail,GroupTypes"
|
||||
$memberObject | Add-Member -NotePropertyName "MemberName" -NotePropertyValue $memberGroup.DisplayName
|
||||
$memberObject | Add-Member -NotePropertyName "MemberUPN" -NotePropertyValue ""
|
||||
$memberObject | Add-Member -NotePropertyName "MemberEmail" -NotePropertyValue $memberGroup.Mail
|
||||
$memberObject | Add-Member -NotePropertyName "MemberGroupTypes" -NotePropertyValue ($memberGroup.GroupTypes -join ",")
|
||||
}
|
||||
default {
|
||||
$memberObject | Add-Member -NotePropertyName "MemberName" -NotePropertyValue "Unknown"
|
||||
$memberObject | Add-Member -NotePropertyName "MemberUPN" -NotePropertyValue ""
|
||||
$memberObject | Add-Member -NotePropertyName "MemberEmail" -NotePropertyValue ""
|
||||
}
|
||||
}
|
||||
|
||||
$script:groupMembers += $memberObject
|
||||
|
||||
# If member is a group, recurse into it
|
||||
if ($member.AdditionalProperties['@odata.type'] -eq '#microsoft.graph.group') {
|
||||
# Check if this group is already in the current path to prevent immediate loops
|
||||
if ($member.Id -notin $groupStack) {
|
||||
Get-GroupMembersRecursive -GroupId $member.Id -Level ($Level + 1) -ParentGroupName $group.DisplayName
|
||||
} else {
|
||||
Write-Warning "Immediate circular reference detected. Skipping group: $($memberGroup.DisplayName)"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch {
|
||||
Write-Error "Error processing group $GroupId`: $($_.Exception.Message)"
|
||||
}
|
||||
finally {
|
||||
# Remove from stack and processed groups when done
|
||||
$groupStack = $groupStack[0..($groupStack.Length-2)]
|
||||
$processedGroups.Remove($GroupId)
|
||||
}
|
||||
}
|
||||
|
||||
# Start the recursive process
|
||||
Write-Host "Starting recursive group membership scan for group: $GroupId"
|
||||
Get-GroupMembersRecursive -GroupId $GroupId
|
||||
|
||||
# Export results to CSV
|
||||
if ($groupMembers.Count -gt 0) {
|
||||
$groupMembers | Export-Csv -Path $OutputPath -NoTypeInformation
|
||||
Write-Host "Results exported to: $OutputPath"
|
||||
Write-Host "Total members found: $($groupMembers.Count)"
|
||||
} else {
|
||||
Write-Host "No members found in the specified group."
|
||||
}
|
||||
|
||||
# Get group memberships (groups this group belongs to)
|
||||
Write-Host "Getting group memberships for group: $GroupId"
|
||||
$groupMemberships = Get-GroupMembershipRecursive -GroupId $GroupId
|
||||
|
||||
# Export group memberships to separate CSV if any found
|
||||
if ($groupMemberships.Count -gt 0) {
|
||||
$groupMemberships | Export-Csv -Path $membershipOutputPath -NoTypeInformation
|
||||
Write-Host "Group memberships exported to: $membershipOutputPath"
|
||||
Write-Host "Total parent groups found: $($groupMemberships.Count)"
|
||||
} else {
|
||||
Write-Host "No group memberships found for the specified group."
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user