Synced files: - Quote wizard frontend (all components, hooks, types, config) - API updates (config, models, routers, schemas, services) - Client work (bg-builders, gurushow) - Scripts (BGB Lesley termination, CIPP, Datto, migration) - Temp files (Bardach contacts, VWP investigation, misc) - Credentials and session logs - Email service, PHP API, session logs Machine: ACG-M-L5090 Timestamp: 2026-03-10 19:11:00 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
135 lines
5.0 KiB
Python
135 lines
5.0 KiB
Python
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}")
|