Last active
February 18, 2025 13:21
-
-
Save mbrenig/39e51f31ec60c0fbe78b5b1a0dfc7c40 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env -S uv run | |
# /// script | |
# dependencies = [ | |
# "azure-identity==1.20.0", | |
# "requests==2.32.3", | |
# ] | |
# requires-python = ">=3.9" | |
# /// | |
# Quick member list script for Azure AD groups using Azure Identity and raw HTTP requests. | |
# | |
# Usage: | |
# 1) Open Azure CLI | |
# 2) Run `pip install uv` | |
# 3) Run the script with the group's object ID, e.g.: | |
# | |
# uv run https://gist.githubusercontent.com/mbrenig/39e51f31ec60c0fbe78b5b1a0dfc7c40/raw/ced864a1326d3ad3a98839e15136a1090ea350b1/listmembers.py <group_id> | |
# | |
from azure.identity import DefaultAzureCredential | |
import requests | |
import argparse | |
GRAPH_ENDPOINT = "https://graph.microsoft.com/v1.0" | |
def parse_arguments(): | |
parser = argparse.ArgumentParser(description="Retrieve members of an Azure AD group.") | |
parser.add_argument("group_id", help="The ID of the Azure AD group.") | |
return parser.parse_args() | |
def get_group_members(group_id: str, access_token: str): | |
""" | |
Retrieve all members of a Security Group using raw HTTP requests with a Bearer token. | |
Manually handle pagination using @odata.nextLink. | |
""" | |
members = [] | |
url = f"{GRAPH_ENDPOINT}/groups/{group_id}/members?$select=displayName,userPrincipalName,onPremisesExtensionAttributes" | |
headers = { | |
"Authorization": f"Bearer {access_token}", | |
"Accept": "application/json" | |
} | |
while url: | |
response = requests.get(url, headers=headers) | |
response.raise_for_status() # Raise HTTPError if the request failed | |
data = response.json() | |
members_page = data.get("value", []) | |
members.extend(members_page) | |
# Check if we have a nextLink for more pages | |
next_link = data.get("@odata.nextLink") | |
url = next_link if next_link else None | |
return members | |
def main(): | |
args = parse_arguments() | |
# 1) Acquire a token from your existing Azure CLI login | |
credential = DefaultAzureCredential() | |
# The Graph permission scope is "https://graph.microsoft.com/.default" | |
token_object = credential.get_token("https://graph.microsoft.com/.default") | |
access_token = token_object.token | |
# 2) Retrieve the group members | |
members = get_group_members(args.group_id, access_token) | |
# 3) Print results | |
print(f"Found {len(members)} members in group {args.group_id}:") | |
for ix, member in enumerate(members, start=1): | |
type = member.get("@odata.type", "") | |
display_name = member.get("displayName", "No DisplayName") | |
upn = member.get("userPrincipalName", "") | |
onprem = member.get("onPremisesExtensionAttributes", {}) | |
ea12 = onprem.get("extensionAttribute11", "") | |
ea11 = onprem.get("extensionAttribute11", "") | |
ea10 = onprem.get("extensionAttribute10", "") | |
print(f"{ix},{display_name},{upn},{ea10},{ea11},{ea12},{type}") | |
if __name__ == "__main__": | |
main() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment