import urllib.request, urllib.parse, json, sys CIPP_URL = "https://cippcanvb.azurewebsites.net" CIPP_TENANT = "ce61461e-81a0-4c84-bb4a-7b354a9a356d" CIPP_CLIENT = "420cb849-542d-4374-9cb2-3d8ae0e1835b" CIPP_SECRET = "MOn8Q~otmxJPLvmL~_aCVTV8Va4t4~SrYrukGbJT" CLAUDE_APP = "fabb3421-8b34-484b-bc17-e46de9703418" CLAUDE_SECRET = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO" TENANT = "bardach.net" TENANT_ID = "dd4a82e8-85a3-44ac-8800-07945ab4d95f" def get_token(tenant_id, client_id, client_secret, scope): data = urllib.parse.urlencode({ 'client_id': client_id, 'client_secret': client_secret, 'scope': scope, 'grant_type': 'client_credentials' }).encode() req = urllib.request.Request(f"https://login.microsoftonline.com/{tenant_id}/oauth2/v2.0/token", data=data, method='POST') with urllib.request.urlopen(req) as resp: return json.loads(resp.read())['access_token'] # Get Exchange token for bardach.net print("[STEP 1] Getting Exchange token...") try: exo_token = get_token(TENANT_ID, CLAUDE_APP, CLAUDE_SECRET, "https://outlook.office365.com/.default") print("[OK] Exchange token acquired") except Exception as e: print(f"[ERROR] {e}") sys.exit(1) # Run Get-MailboxFolderStatistics to find contact folders including deleted print("\n[STEP 2] Getting mailbox folder statistics (contacts scope)...") invoke_url = f"https://outlook.office365.com/adminapi/beta/{TENANT_ID}/InvokeCommand" headers = {'Authorization': f'Bearer {exo_token}', 'Content-Type': 'application/json'} cmd = json.dumps({ "CmdletInput": { "CmdletName": "Get-MailboxFolderStatistics", "Parameters": { "Identity": "barbara@bardach.net", "FolderScope": "Contacts" } } }).encode() try: req = urllib.request.Request(invoke_url, data=cmd, headers=headers, method='POST') with urllib.request.urlopen(req) as resp: result = json.loads(resp.read()) for item in result.get('value', []): name = item.get('Name', '?') count = item.get('ItemsInFolder', '?') folder_type = item.get('FolderType', '?') size = item.get('FolderSize', '?') print(f" {name}: {count} items ({folder_type})") except urllib.error.HTTPError as e: body = e.read().decode() print(f"[ERROR] HTTP {e.code}: {body[:500]}") except Exception as e: print(f"[ERROR] {e}") # Also check RecoverableItems scope print("\n[STEP 3] Getting mailbox folder statistics (RecoverableItems scope)...") cmd2 = json.dumps({ "CmdletInput": { "CmdletName": "Get-MailboxFolderStatistics", "Parameters": { "Identity": "barbara@bardach.net", "FolderScope": "RecoverableItems" } } }).encode() try: req2 = urllib.request.Request(invoke_url, data=cmd2, headers=headers, method='POST') with urllib.request.urlopen(req2) as resp2: result2 = json.loads(resp2.read()) for item in result2.get('value', []): name = item.get('Name', '?') count = item.get('ItemsInFolder', '?') size = item.get('FolderSize', '?') folder_type = item.get('FolderType', '?') print(f" {name}: {count} items ({folder_type}) - {size}") except urllib.error.HTTPError as e: body = e.read().decode() print(f"[ERROR] HTTP {e.code}: {body[:500]}") except Exception as e: print(f"[ERROR] {e}") # Also get ALL folder stats to see everything print("\n[STEP 4] Getting ALL mailbox folder statistics...") cmd3 = json.dumps({ "CmdletInput": { "CmdletName": "Get-MailboxFolderStatistics", "Parameters": { "Identity": "barbara@bardach.net" } } }).encode() try: req3 = urllib.request.Request(invoke_url, data=cmd3, headers=headers, method='POST') with urllib.request.urlopen(req3) as resp3: result3 = json.loads(resp3.read()) # Filter for anything contact-related contact_folders = [] for item in result3.get('value', []): name = item.get('Name', '?') folder_type = item.get('FolderType', '?') count = item.get('ItemsInFolder', 0) container_class = item.get('ContainerClass', '?') if 'contact' in name.lower() or 'contact' in str(folder_type).lower() or 'contact' in str(container_class).lower() or count > 100: contact_folders.append(item) print(f" {name}: {count} items (type={folder_type}, class={container_class})") if not contact_folders: print(" No contact-related folders found in full stats") # Show all folders with items print("\n All folders with >0 items:") for item in result3.get('value', []): count = item.get('ItemsInFolder', 0) if count > 0: name = item.get('Name', '?') folder_type = item.get('FolderType', '?') print(f" {name}: {count} items ({folder_type})") except urllib.error.HTTPError as e: body = e.read().decode() print(f"[ERROR] HTTP {e.code}: {body[:500]}") except Exception as e: print(f"[ERROR] {e}")