Reorganize repo: compartmentalize scripts by client/project

Move 150+ scripts from root and scripts/ into client/project directories:
- clients/dataforth/scripts/ (110 files: AD2, sync, SSH, DB, DOS scripts)
- clients/bg-builders/scripts/ (14 files: Lesley mgmt, Exchange, termination)
- clients/internal-infrastructure/scripts/ (10 files: GDAP, Gitea, backups)
- projects/msp-tools/scripts/ (9 files: CIPP, MSP onboarding, Datto)
- projects/gururmm-agent/scripts/ (3 files: API test, JWT, record counts)
- clients/glaztech/scripts/ (1 file: CentraStage removal)

Also reorganized:
- VPN scripts → infrastructure/vpn-configs/
- Retrieved API/JS files → api/
- Forum posts → projects/community-forum/forum-posts/
- SSH docs → clients/internal-infrastructure/docs/
- NWTOC/CTONW docs → projects/wrightstown-smarthome/docs/
- ACG website files → projects/internal/acg-website-2025/
- Dataforth docs → clients/dataforth/docs/
- schema-retrieved.sql → docs/database/

Deleted 24 tmp_*.ps1 one-off debug scripts (preserved in git history).
Root reduced from 220+ files to 62 items (docs + directories only).

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
2026-03-20 17:15:07 -07:00
parent 98ea867d2c
commit 5cbd49ce24
207 changed files with 49 additions and 547 deletions

View File

@@ -1,37 +0,0 @@
# BG Builders - Assign Exchange Administrator role to Claude-MSP-Access service principal
# Required for Exchange Online app-only auth (Set-Mailbox, litigation hold, etc.)
# Run from interactive PowerShell as sysadmin@bgbuildersllc.com
$tenantId = "ededa4fb-f6eb-4398-851d-5eb3e11fab27"
$spId = "9c04bb74-c2d0-4d83-ab54-9c43a9daaa23" # Claude-MSP-Access SP in BG Builders
$exoRoleId = "87706939-e519-4028-a73e-a6a7f04b4a20" # Exchange Administrator
Write-Output "Connecting to Graph..."
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Identity.DirectoryManagement
Connect-MgGraph -TenantId $tenantId -Scopes 'RoleManagement.ReadWrite.Directory' -NoWelcome
Write-Output "[OK] Connected"
Write-Output "Assigning Exchange Administrator to Claude-MSP-Access..."
$body = @{
"@odata.id" = "https://graph.microsoft.com/v1.0/servicePrincipals/$spId"
}
New-MgDirectoryRoleMemberByRef -DirectoryRoleId $exoRoleId -BodyParameter $body
Write-Output "[OK] Exchange Administrator role assigned"
# Now set litigation hold on Lesley
Write-Output "`nConnecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected"
Write-Output "Setting litigation hold on Lesley's mailbox..."
Set-Mailbox -Identity "lesley@bgbuildersllc.com" -LitigationHoldEnabled $true -LitigationHoldDuration Unlimited
Write-Output "[OK] Litigation hold enabled"
Write-Output "`nVerifying..."
Get-Mailbox -Identity "lesley@bgbuildersllc.com" | Format-List DisplayName,LitigationHoldEnabled,LitigationHoldDuration
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-MgGraph
Write-Output "[OK] Done"

View File

@@ -1,81 +0,0 @@
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
Import-Module Microsoft.Graph.Groups
Import-Module Microsoft.Graph.Sites
$tenantId = "ededa4fb-f6eb-4398-851d-5eb3e11fab27"
$lesleyUPN = "lesley@bgbuildersllc.com"
Write-Output "========================================="
Write-Output " BG Builders - Lesley Roth Ownership Audit"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
Connect-MgGraph -TenantId $tenantId -Scopes 'User.Read.All','Group.Read.All','Sites.Read.All','TeamSettings.Read.All' -NoWelcome
$lesley = Get-MgUser -UserId $lesleyUPN -Property Id,DisplayName
Write-Output "[OK] Lesley ID: $($lesley.Id)"
# --- Check Teams/M365 Group ownership ---
Write-Output "`n--- Teams / M365 Group Ownership ---"
$ownedGroups = Get-MgUserOwnedObject -UserId $lesley.Id -All
if ($ownedGroups) {
foreach ($obj in $ownedGroups) {
$group = Get-MgGroup -GroupId $obj.Id -Property DisplayName,GroupTypes,Mail -ErrorAction SilentlyContinue
if ($group) {
$isTeam = $group.GroupTypes -contains "Unified"
$type = if ($isTeam) { "M365 Group/Team" } else { "Group" }
Write-Output " [OWNER] $type : $($group.DisplayName) ($($group.Mail))"
# Check if sole owner
$owners = Get-MgGroupOwner -GroupId $obj.Id -All
if ($owners.Count -le 1) {
Write-Output " [WARNING] SOLE OWNER - needs transfer before termination"
} else {
Write-Output " [OK] Has $($owners.Count) owners total"
}
}
}
} else {
Write-Output " [INFO] Lesley does not own any groups or teams"
}
# --- Check group memberships ---
Write-Output "`n--- Group / Team Memberships ---"
$memberships = Get-MgUserMemberOf -UserId $lesley.Id -All
foreach ($mem in $memberships) {
$group = Get-MgGroup -GroupId $mem.Id -Property DisplayName,GroupTypes,Mail -ErrorAction SilentlyContinue
if ($group) {
$isTeam = $group.GroupTypes -contains "Unified"
$type = if ($isTeam) { "M365 Group/Team" } else { "Security/DL Group" }
Write-Output " [MEMBER] $type : $($group.DisplayName) ($($group.Mail))"
}
}
# --- Check SharePoint site ownership ---
Write-Output "`n--- SharePoint Sites ---"
try {
$sites = Get-MgSite -Search "*" -All -Property DisplayName,WebUrl 2>$null
if ($sites) {
foreach ($site in $sites) {
try {
$sitePermissions = Get-MgSitePermission -SiteId $site.Id -ErrorAction SilentlyContinue 2>$null
} catch {
# Fall through - permissions API may not be available on all sites
}
Write-Output " [SITE] $($site.DisplayName) - $($site.WebUrl)"
}
}
} catch {
Write-Output " [INFO] Could not enumerate SharePoint sites (may need SharePoint admin role)"
}
# --- Check distribution group membership via Exchange ---
Write-Output "`n--- Distribution List Memberships (requires Exchange connection) ---"
Write-Output " [INFO] Run separately via Exchange Online to check DL memberships"
Write-Output "`n========================================="
Write-Output " Audit Complete"
Write-Output "========================================="
Disconnect-MgGraph

View File

@@ -1,11 +0,0 @@
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
Connect-MgGraph -TenantId 'ededa4fb-f6eb-4398-851d-5eb3e11fab27' -Scopes 'User.Read.All' -NoWelcome
# List all users to find Leslie
$allUsers = Get-MgUser -All -Property DisplayName,Mail,UserPrincipalName,AccountEnabled,Id
Write-Output "--- All Users in Tenant ---"
$allUsers | Format-Table DisplayName,Mail,UserPrincipalName,AccountEnabled -AutoSize
Disconnect-MgGraph

View File

@@ -1,102 +0,0 @@
# BG Builders - Disable Lesley Roth + Wipe Email from Device
# Employee: Lesley Roth (lesley@bgbuildersllc.com)
# Date: 2026-03-09
# Actions:
# 1. Block sign-in
# 2. Revoke all sessions
# 3. Reset password
# 4. Wipe email data from mobile devices (selective wipe + EAS wipe)
$ErrorActionPreference = "Stop"
$tenantId = "ededa4fb-f6eb-4398-851d-5eb3e11fab27"
$lesleyUPN = "lesley@bgbuildersllc.com"
Write-Output "========================================="
Write-Output " BG Builders - Disable Lesley Roth"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- STEP 1: Connect to Microsoft Graph ---
Write-Output "`n[STEP 1] Connecting to Microsoft Graph..."
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
Import-Module Microsoft.Graph.Users.Actions
Connect-MgGraph -TenantId $tenantId -Scopes 'User.ReadWrite.All','Directory.ReadWrite.All','DeviceManagementManagedDevices.ReadWrite.All','DeviceManagementManagedDevices.PrivilegedOperations.All' -NoWelcome
Write-Output "[OK] Connected to Graph"
$lesley = Get-MgUser -UserId $lesleyUPN -Property Id,DisplayName,AccountEnabled,AssignedLicenses
Write-Output "[INFO] Current state: AccountEnabled=$($lesley.AccountEnabled)"
# --- STEP 2: Block sign-in ---
Write-Output "`n[STEP 2] Blocking sign-in..."
Update-MgUser -UserId $lesley.Id -AccountEnabled:$false
Write-Output "[OK] Sign-in blocked"
# --- STEP 3: Revoke all sessions ---
Write-Output "`n[STEP 3] Revoking all active sessions..."
Revoke-MgUserSignInSession -UserId $lesley.Id
Write-Output "[OK] All sessions revoked"
# --- STEP 4: Reset password ---
Write-Output "`n[STEP 4] Resetting password..."
$newPassword = -join ((65..90) + (97..122) + (48..57) + (33,35,36,37,38) | Get-Random -Count 24 | ForEach-Object {[char]$_})
$params = @{
passwordProfile = @{
forceChangePasswordNextSignIn = $true
password = $newPassword
}
}
Update-MgUser -UserId $lesley.Id -BodyParameter $params
Write-Output "[OK] Password reset to random value"
# --- STEP 5: Wipe email from devices (Intune managed) ---
Write-Output "`n[STEP 5] Checking for Intune-managed devices..."
Import-Module Microsoft.Graph.DeviceManagement
$devices = Get-MgDeviceManagementManagedDevice -Filter "userPrincipalName eq '$lesleyUPN'" 2>$null
if ($devices) {
foreach ($device in $devices) {
Write-Output " Found: $($device.DeviceName) ($($device.OperatingSystem)) - ID: $($device.Id)"
Write-Output " Initiating selective wipe (company data only)..."
Invoke-MgRetireDeviceManagementManagedDevice -ManagedDeviceId $device.Id
Write-Output " [OK] Selective wipe queued for $($device.DeviceName)"
}
} else {
Write-Output "[INFO] No Intune-managed devices found"
}
# --- STEP 6: Wipe email from devices (Exchange ActiveSync) ---
Write-Output "`n[STEP 6] Connecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected to Exchange Online"
Write-Output "Checking for ActiveSync devices..."
$easDevices = Get-MobileDevice -Mailbox $lesleyUPN 2>$null
if ($easDevices) {
foreach ($eas in $easDevices) {
Write-Output " Found EAS device: $($eas.FriendlyName) ($($eas.DeviceOS))"
Clear-MobileDevice -Identity $eas.Identity -AccountOnly -Confirm:$false
Write-Output " [OK] Account-only wipe initiated for $($eas.FriendlyName)"
}
Write-Output "[OK] All EAS devices queued for account wipe"
} else {
Write-Output "[INFO] No EAS mobile devices found"
}
# --- DONE ---
Write-Output "`n========================================="
Write-Output " DISABLE + DEVICE WIPE COMPLETE"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
Write-Output ""
Write-Output "Summary:"
Write-Output " [OK] Sign-in blocked"
Write-Output " [OK] Sessions revoked"
Write-Output " [OK] Password reset"
Write-Output " [OK] Device email wipe initiated (Intune + EAS)"
Write-Output ""
Write-Output "[INFO] Mailbox is still accessible - run full termination script"
Write-Output " when ready to convert to shared, remove license, etc."
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-MgGraph

View File

@@ -1,33 +0,0 @@
# BG Builders - Lesley Exchange steps (run from interactive PowerShell)
# Adds Shelly as delegate + enables litigation hold
$lesleyUPN = "lesley@bgbuildersllc.com"
$shellyUPN = "Shelly@bgbuildersllc.com"
Write-Output "Connecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected"
# Add Shelly as delegate
Write-Output "`nAdding Shelly as delegate..."
Add-MailboxPermission -Identity $lesleyUPN -User $shellyUPN -AccessRights FullAccess -AutoMapping $true
Write-Output "[OK] Shelly granted FullAccess"
Add-RecipientPermission -Identity $lesleyUPN -Trustee $shellyUPN -AccessRights SendAs -Confirm:$false
Write-Output "[OK] Shelly granted SendAs"
# Enable litigation hold
Write-Output "`nEnabling litigation hold..."
Set-Mailbox -Identity $lesleyUPN -LitigationHoldEnabled $true -LitigationHoldDuration Unlimited
Write-Output "[OK] Litigation hold enabled"
# Verify
Write-Output "`nVerifying permissions..."
Get-MailboxPermission -Identity $lesleyUPN | Where-Object { $_.User -notlike "NT AUTHORITY*" -and $_.User -notlike "S-1-*" } | Format-Table User,AccessRights -AutoSize
Write-Output "`nVerifying litigation hold..."
Get-Mailbox -Identity $lesleyUPN | Format-List LitigationHoldEnabled,LitigationHoldDuration
Disconnect-ExchangeOnline -Confirm:$false
Write-Output "[OK] Done"

View File

@@ -1,83 +0,0 @@
# BG Builders - Check and fix inbox rules on lesley shared mailbox
# Run from interactive PowerShell
$lesleyUPN = "lesley@bgbuildersllc.com"
Write-Output "Connecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected"
# Check inbox rules
Write-Output "`n=== INBOX RULES ==="
$rules = Get-InboxRule -Mailbox $lesleyUPN -IncludeHidden
if ($rules) {
foreach ($rule in $rules) {
Write-Output " Rule: $($rule.Name) | Enabled: $($rule.Enabled) | Priority: $($rule.Priority)"
Write-Output " Description: $($rule.Description)"
Write-Output " MoveToFolder: $($rule.MoveToFolder)"
Write-Output " DeleteMessage: $($rule.DeleteMessage)"
Write-Output " SoftDeleteMessage: $($rule.SoftDeleteMessage)"
Write-Output ""
}
# Disable any rules that delete messages
foreach ($rule in $rules) {
if ($rule.DeleteMessage -or $rule.SoftDeleteMessage -or $rule.MoveToFolder -match "Deleted") {
Write-Output "[ALERT] Removing problematic rule: $($rule.Name)"
Remove-InboxRule -Mailbox $lesleyUPN -Identity $rule.Identity -Confirm:$false
Write-Output "[OK] Removed"
}
}
} else {
Write-Output " [OK] No inbox rules found"
}
# Check sweep rules
Write-Output "`n=== SWEEP RULES ==="
try {
$sweep = Get-SweepRule -Mailbox $lesleyUPN
if ($sweep) {
foreach ($s in $sweep) {
Write-Output " Rule: $($s.Name) | Enabled: $($s.Enabled)"
Write-Output " SourceFolder: $($s.SourceFolder)"
Write-Output " DestFolder: $($s.DestFolder)"
Write-Output " KeepLatest: $($s.KeepLatest)"
Write-Output ""
}
# Remove sweep rules
foreach ($s in $sweep) {
Write-Output "[ALERT] Removing sweep rule: $($s.Name)"
Remove-SweepRule -Identity $s.Identity -Mailbox $lesleyUPN -Confirm:$false
Write-Output "[OK] Removed"
}
} else {
Write-Output " [OK] No sweep rules found"
}
} catch {
Write-Output " [INFO] Sweep rules not available: $_"
}
# Check mailbox type and forwarding
Write-Output "`n=== MAILBOX STATUS ==="
$mb = Get-Mailbox -Identity $lesleyUPN
Write-Output " Type: $($mb.RecipientTypeDetails)"
Write-Output " Forwarding: $($mb.ForwardingAddress)"
Write-Output " ForwardingSMTP: $($mb.ForwardingSmtpAddress)"
Write-Output " DeliverToMailboxAndForward: $($mb.DeliverToMailboxAndForward)"
Write-Output " HiddenFromGAL: $($mb.HiddenFromAddressListsEnabled)"
Write-Output " LitigationHold: $($mb.LitigationHoldEnabled)"
# Check transport rules affecting this mailbox
Write-Output "`n=== TRANSPORT RULES ==="
$transport = Get-TransportRule | Where-Object { $_.State -eq "Enabled" }
if ($transport) {
foreach ($t in $transport) {
Write-Output " Rule: $($t.Name) | Priority: $($t.Priority)"
}
} else {
Write-Output " [OK] No transport rules"
}
Disconnect-ExchangeOnline -Confirm:$false
Write-Output "`n[OK] Done"

View File

@@ -1,62 +0,0 @@
=========================================
LESLEY ROTH - 72-HOUR MAIL ACTIVITY REPORT
Generated: 2026-03-09 09:30:46
Window: 2026-03-06 09:30 to 2026-03-09 09:30
=========================================
=========================================
SENT MESSAGES (0 total)
=========================================
[NONE] No sent messages in the last 72 hours
=========================================
RECEIVED MESSAGES (5 total)
=========================================
Date: 2026-03-09 09:53:49
From: Gallagher.NoReply@Vertafore.com
Subject: Coyote Landing - 23-09001.Coyote - Enrollment Status Report From AJG - 03/09/2026 - By Contractor Name (All Tier)
Status: Delivered
---
Date: 2026-03-09 09:22:52
From: Gallagher.NoReply@Vertafore.com
Subject: Coyote Landing - 23-09001.Coyote - Enrollment Status Report From AJG - 03/09/2026 - By Contractor Name (First Tier)
Status: Delivered
---
Date: 2026-03-09 08:32:29
From: Gallagher.NoReply@Vertafore.com
Subject: Coyote Landing / EmpirePaving-BGBuild-23-09001.Coyote / Missing/Incomplete Insurance Cost Worksheet
Status: Delivered
---
Date: 2026-03-09 08:17:05
From: Gallagher.NoReply@Vertafore.com
Subject: Coyote Landing / EmpirePaving-BGBuild-23-09001.Coyote / Enrollment Incomplete
Status: Delivered
---
Date: 2026-03-06 22:09:29
From: notifications@s.usa.experian.com
Subject: Lesley, your Experian account info recently changed.
Status: Delivered
---
=========================================
DELETED ITEMS (0 total)
=========================================
[NONE] No deleted items in the last 72 hours
=========================================
INBOX RULES
=========================================
[NONE] No inbox rules configured
=========================================
FORWARDING CONFIGURATION
=========================================
ForwardingAddress:
ForwardingSmtpAddress:
DeliverToMailboxAndForward: False
[OK] No forwarding configured

View File

@@ -1,150 +0,0 @@
# BG Builders - Lesley Roth 72-Hour Mail Activity Report
# Pulls sent mail (message trace) and deleted items (mailbox audit log)
# Date: 2026-03-09
$ErrorActionPreference = "Stop"
$lesleyUPN = "lesley@bgbuildersllc.com"
$startDate = (Get-Date).AddHours(-72)
$endDate = Get-Date
$reportPath = "D:\ClaudeTools\scripts\bgb-lesley-mail-report-$(Get-Date -Format 'yyyyMMdd').txt"
Write-Output "========================================="
Write-Output " BG Builders - Lesley Roth Mail Report"
Write-Output " 72-Hour Window: $($startDate.ToString('yyyy-MM-dd HH:mm')) to $($endDate.ToString('yyyy-MM-dd HH:mm'))"
Write-Output "========================================="
# --- Connect to Exchange Online ---
Write-Output "`n[STEP 1] Connecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected"
# Start building report
$report = @()
$report += "========================================="
$report += " LESLEY ROTH - 72-HOUR MAIL ACTIVITY REPORT"
$report += " Generated: $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
$report += " Window: $($startDate.ToString('yyyy-MM-dd HH:mm')) to $($endDate.ToString('yyyy-MM-dd HH:mm'))"
$report += "========================================="
# --- SENT MAIL (Message Trace) ---
Write-Output "`n[STEP 2] Pulling sent mail via message trace..."
$sentMessages = Get-MessageTraceV2 -SenderAddress $lesleyUPN -StartDate $startDate -EndDate $endDate
$report += ""
$report += "=========================================`n SENT MESSAGES ($($sentMessages.Count) total)`n========================================="
if ($sentMessages.Count -gt 0) {
$sentMessages | Sort-Object Received -Descending | ForEach-Object {
$report += ""
$report += " Date: $($_.Received.ToString('yyyy-MM-dd HH:mm:ss'))"
$report += " To: $($_.RecipientAddress)"
$report += " Subject: $($_.Subject)"
$report += " Status: $($_.Status)"
$report += " Size: $([math]::Round($_.Size / 1KB, 1)) KB"
$report += " MsgID: $($_.MessageId)"
$report += " ---"
}
} else {
$report += " [NONE] No sent messages in the last 72 hours"
}
Write-Output "[OK] Found $($sentMessages.Count) sent messages"
# --- RECEIVED MAIL (Message Trace) ---
Write-Output "`n[STEP 3] Pulling received mail via message trace..."
$receivedMessages = Get-MessageTraceV2 -RecipientAddress $lesleyUPN -StartDate $startDate -EndDate $endDate
$report += ""
$report += "=========================================`n RECEIVED MESSAGES ($($receivedMessages.Count) total)`n========================================="
if ($receivedMessages.Count -gt 0) {
$receivedMessages | Sort-Object Received -Descending | ForEach-Object {
$report += ""
$report += " Date: $($_.Received.ToString('yyyy-MM-dd HH:mm:ss'))"
$report += " From: $($_.SenderAddress)"
$report += " Subject: $($_.Subject)"
$report += " Status: $($_.Status)"
$report += " ---"
}
} else {
$report += " [NONE] No received messages in the last 72 hours"
}
Write-Output "[OK] Found $($receivedMessages.Count) received messages"
# --- DELETED ITEMS (Mailbox Audit Log) ---
Write-Output "`n[STEP 4] Pulling deleted items via mailbox audit log..."
# Use Search-UnifiedAuditLog (Search-MailboxAuditLog deprecated Jan 2026)
$deleteOps = "SoftDelete","HardDelete","MoveToDeletedItems"
$deletedItems = Search-UnifiedAuditLog -UserIds $lesleyUPN -Operations ($deleteOps -join ",") -StartDate $startDate -EndDate $endDate -ResultSize 5000
$report += ""
$report += "=========================================`n DELETED ITEMS ($($deletedItems.Count) total)`n========================================="
if ($deletedItems.Count -gt 0) {
$deletedItems | Sort-Object CreationDate -Descending | ForEach-Object {
$auditData = $_.AuditData | ConvertFrom-Json
$report += ""
$report += " Date: $($_.CreationDate)"
$report += " Operation: $($_.Operations)"
$report += " User: $($_.UserIds)"
$report += " Subject: $($auditData.AffectedItems.Subject -join '; ')"
$report += " Folder: $($auditData.Folder.Path)"
$report += " Client: $($auditData.ClientInfoString)"
$report += " ---"
}
} else {
$report += " [NONE] No deleted items in the last 72 hours"
}
Write-Output "[OK] Found $($deletedItems.Count) deleted items"
# --- INBOX RULES (check for forwarding/auto-delete) ---
Write-Output "`n[STEP 5] Checking inbox rules..."
$rules = Get-InboxRule -Mailbox $lesleyUPN 2>$null
$report += ""
$report += "=========================================`n INBOX RULES`n========================================="
if ($rules) {
foreach ($rule in $rules) {
$report += ""
$report += " Name: $($rule.Name)"
$report += " Enabled: $($rule.Enabled)"
$report += " Priority: $($rule.Priority)"
if ($rule.ForwardTo) { $report += " ForwardTo: $($rule.ForwardTo -join '; ')" }
if ($rule.RedirectTo) { $report += " RedirectTo: $($rule.RedirectTo -join '; ')" }
if ($rule.DeleteMessage) { $report += " [WARNING] Auto-delete enabled" }
$report += " ---"
}
} else {
$report += " [NONE] No inbox rules configured"
}
Write-Output "[OK] Rules checked"
# --- FORWARDING CONFIG ---
Write-Output "`n[STEP 6] Checking forwarding configuration..."
$mbx = Get-Mailbox -Identity $lesleyUPN | Select-Object ForwardingAddress,ForwardingSmtpAddress,DeliverToMailboxAndForward
$report += ""
$report += "=========================================`n FORWARDING CONFIGURATION`n========================================="
$report += " ForwardingAddress: $($mbx.ForwardingAddress)"
$report += " ForwardingSmtpAddress: $($mbx.ForwardingSmtpAddress)"
$report += " DeliverToMailboxAndForward: $($mbx.DeliverToMailboxAndForward)"
if ($mbx.ForwardingAddress -or $mbx.ForwardingSmtpAddress) {
$report += " [WARNING] Active forwarding detected!"
} else {
$report += " [OK] No forwarding configured"
}
# --- Write report to file ---
$report | Out-File -FilePath $reportPath -Encoding UTF8
Write-Output "`n========================================="
Write-Output " REPORT SAVED"
Write-Output " $reportPath"
Write-Output "========================================="
# Also output to console
Write-Output "`n--- REPORT CONTENTS ---"
$report | ForEach-Object { Write-Output $_ }
Disconnect-ExchangeOnline -Confirm:$false
Write-Output "`n[OK] Done"

View File

@@ -1,193 +0,0 @@
#Requires -Modules ExchangeOnlineManagement
<#
.SYNOPSIS
BG Builders - Lesley Roth: Recover deleted items (last 10 days) and review inbox rules
.DESCRIPTION
1. Connects to Exchange Online as sysadmin@bgbuildersllc.com
2. Recovers all soft-deleted items from Lesley's mailbox (last 10 days)
3. Lists all inbox rules on the account
.NOTES
Run in PowerShell 7 (pwsh) for best compatibility
Tenant: bgbuildersllc.com / sonorangreenllc.onmicrosoft.com
Target: lesley@bgbuildersllc.com
#>
$ErrorActionPreference = 'Stop'
$targetUser = 'lesley@bgbuildersllc.com'
# ── Connect to Exchange Online ──────────────────────────────────────
Write-Host "`n=== Connecting to Exchange Online ===" -ForegroundColor Cyan
try {
$session = Get-ConnectionInformation -ErrorAction SilentlyContinue
if (-not $session -or $session.State -ne 'Connected') {
Connect-ExchangeOnline -UserPrincipalName sysadmin@bgbuildersllc.com -ShowBanner:$false
} else {
Write-Host "Already connected to Exchange Online" -ForegroundColor Green
}
} catch {
Write-Host "Connecting fresh..." -ForegroundColor Yellow
Connect-ExchangeOnline -UserPrincipalName sysadmin@bgbuildersllc.com -ShowBanner:$false
}
# ── Part 1: Review Inbox Rules ──────────────────────────────────────
Write-Host "`n=== INBOX RULES for $targetUser ===" -ForegroundColor Cyan
try {
$rules = Get-InboxRule -Mailbox $targetUser -IncludeHidden
if ($rules) {
Write-Host "`nFound $($rules.Count) rule(s):" -ForegroundColor Yellow
foreach ($rule in $rules) {
Write-Host "`n--- Rule: $($rule.Name) ---" -ForegroundColor White
Write-Host " Enabled: $($rule.Enabled)"
Write-Host " Priority: $($rule.Priority)"
Write-Host " Description: $($rule.Description)"
if ($rule.ForwardTo) {
Write-Host " ** FORWARD TO: $($rule.ForwardTo)" -ForegroundColor Red
}
if ($rule.ForwardAsAttachmentTo) {
Write-Host " ** FWD ATTACH: $($rule.ForwardAsAttachmentTo)" -ForegroundColor Red
}
if ($rule.RedirectTo) {
Write-Host " ** REDIRECT TO: $($rule.RedirectTo)" -ForegroundColor Red
}
if ($rule.DeleteMessage) {
Write-Host " ** DELETE MSG: True" -ForegroundColor Red
}
if ($rule.MoveToFolder) {
Write-Host " Move To: $($rule.MoveToFolder)"
}
if ($rule.From) {
Write-Host " From: $($rule.From)"
}
if ($rule.SubjectContainsWords) {
Write-Host " Subject Words: $($rule.SubjectContainsWords -join ', ')"
}
if ($rule.BodyContainsWords) {
Write-Host " Body Words: $($rule.BodyContainsWords -join ', ')"
}
}
} else {
Write-Host "No inbox rules found." -ForegroundColor Green
}
} catch {
Write-Host "Error getting inbox rules: $_" -ForegroundColor Red
}
# ── Check forwarding configuration ──────────────────────────────────
Write-Host "`n=== FORWARDING CONFIG for $targetUser ===" -ForegroundColor Cyan
try {
$mbx = Get-Mailbox -Identity $targetUser
if ($mbx.ForwardingAddress) {
Write-Host " ForwardingAddress: $($mbx.ForwardingAddress)" -ForegroundColor Red
} else {
Write-Host " ForwardingAddress: (none)" -ForegroundColor Green
}
if ($mbx.ForwardingSmtpAddress) {
Write-Host " ForwardingSmtpAddress: $($mbx.ForwardingSmtpAddress)" -ForegroundColor Red
} else {
Write-Host " ForwardingSmtpAddress: (none)" -ForegroundColor Green
}
Write-Host " DeliverToMailboxAndForward: $($mbx.DeliverToMailboxAndForward)"
} catch {
Write-Host "Error getting forwarding config: $_" -ForegroundColor Red
}
# ── Part 2: Recover Deleted Items (last 10 days) ───────────────────
Write-Host "`n=== RECOVERING DELETED ITEMS (last 10 days) ===" -ForegroundColor Cyan
Write-Host "Target: $targetUser" -ForegroundColor White
$startDate = (Get-Date).AddDays(-10)
$endDate = Get-Date
$dateRange = "$($startDate.ToString('yyyy-MM-dd'))..$($endDate.ToString('yyyy-MM-dd'))"
# Step 1: Try Get-RecoverableItems (requires Mailbox Import Export role)
Write-Host "`n--- Method 1: Get-RecoverableItems ---" -ForegroundColor White
try {
Write-Host "Scanning recoverable items from $dateRange..."
$preview = Get-RecoverableItems -Identity $targetUser -FilterStartTime $startDate -FilterEndTime $endDate -FilterItemType All
if ($preview) {
Write-Host "Found $($preview.Count) recoverable item(s):" -ForegroundColor Yellow
$preview | Group-Object ItemClass | ForEach-Object { Write-Host " $($_.Name): $($_.Count) items" }
$preview | Select-Object -First 20 | ForEach-Object {
$subj = if ($_.Subject) { $_.Subject } else { "(no subject)" }
Write-Host " [$($_.LastModifiedTime.ToString('MM/dd HH:mm'))] $subj"
}
Write-Host "`nRestoring all $($preview.Count) items..." -ForegroundColor Yellow
Restore-RecoverableItems -Identity $targetUser -FilterStartTime $startDate -FilterEndTime $endDate -FilterItemType All -Confirm:$false
Write-Host "Recovery complete!" -ForegroundColor Green
} else {
Write-Host "No recoverable items found." -ForegroundColor Green
}
} catch {
Write-Host "Get-RecoverableItems not available (needs Mailbox Import Export role)." -ForegroundColor Yellow
Write-Host "Falling back to Compliance Search..." -ForegroundColor Yellow
# Step 2: Connect to Security & Compliance and run a content search
Write-Host "`n--- Method 2: Compliance Search (eDiscovery) ---" -ForegroundColor White
try {
Connect-IPPSSession -UserPrincipalName sysadmin@bgbuildersllc.com -ShowBanner:$false
Write-Host "Connected to Security & Compliance Center." -ForegroundColor Green
$searchName = "LesleyRecovery_$(Get-Date -Format 'yyyyMMdd_HHmmss')"
$kql = "received>=$($startDate.ToString('yyyy-MM-dd')) AND received<=$($endDate.ToString('yyyy-MM-dd'))"
Write-Host "Creating compliance search: $searchName"
Write-Host " KQL: $kql"
Write-Host " Mailbox: $targetUser"
New-ComplianceSearch -Name $searchName `
-ExchangeLocation $targetUser `
-ContentMatchQuery $kql `
-Description "Recover deleted items for Lesley Roth - last 10 days" |
Out-Null
Write-Host "Starting search..." -ForegroundColor Yellow
Start-ComplianceSearch -Identity $searchName
# Poll for completion (max 5 minutes)
$maxWait = 300
$elapsed = 0
do {
Start-Sleep -Seconds 10
$elapsed += 10
$status = (Get-ComplianceSearch -Identity $searchName).Status
Write-Host " Status: $status ($elapsed sec)"
} while ($status -ne 'Completed' -and $elapsed -lt $maxWait)
$result = Get-ComplianceSearch -Identity $searchName
Write-Host "`nSearch Results:" -ForegroundColor Cyan
Write-Host " Status: $($result.Status)"
Write-Host " Items Found: $($result.Items)"
Write-Host " Size: $($result.Size)"
Write-Host " Success Results: $($result.SuccessResults)"
if ($result.Items -gt 0) {
Write-Host "`nItems found! To restore them:" -ForegroundColor Yellow
Write-Host " Option A: Use the Microsoft Purview portal > Content Search > '$searchName' > Export/Restore"
Write-Host " Option B: Run New-ComplianceSearchAction -SearchName '$searchName' -Purge -PurgeType SoftDelete"
Write-Host " (This moves items - for restore, use the Purview portal export instead)"
Write-Host "`n Purview URL: https://compliance.microsoft.com/contentsearchv2" -ForegroundColor Cyan
} else {
Write-Host "`nNo deleted items found in date range." -ForegroundColor Green
Write-Host "(Litigation hold preserves items in-place - they may still be in the mailbox)"
}
} catch {
Write-Host "Compliance search also failed: $_" -ForegroundColor Red
Write-Host "`nManual recovery options:" -ForegroundColor Yellow
Write-Host " 1. Outlook > Deleted Items > 'Recover items recently removed from this folder'"
Write-Host " (Log in as Barry/Shelly who have FullAccess)"
Write-Host " 2. CIPP > Mailbox Restore"
Write-Host " 3. Microsoft Purview portal > eDiscovery > Content Search"
Write-Host " URL: https://compliance.microsoft.com/contentsearchv2"
}
}
Write-Host "`n=== DONE ===" -ForegroundColor Cyan
Write-Host "Summary:"
Write-Host " - Inbox rules reviewed"
Write-Host " - Forwarding config checked"
Write-Host " - Deleted item recovery attempted"
Write-Host ""

View File

@@ -1,71 +0,0 @@
# BG Builders - Verify Lesley Device Wipe Status
$ErrorActionPreference = "Stop"
$tenantId = "ededa4fb-f6eb-4398-851d-5eb3e11fab27"
$lesleyUPN = "lesley@bgbuildersllc.com"
Write-Output "========================================="
Write-Output " Verify Device Wipe - Lesley Roth"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- Check Intune Managed Devices ---
Write-Output "`n[CHECK 1] Intune Managed Devices..."
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.DeviceManagement
Connect-MgGraph -TenantId $tenantId -Scopes 'DeviceManagementManagedDevices.Read.All' -NoWelcome
Write-Output "[OK] Connected to Graph"
$devices = Get-MgDeviceManagementManagedDevice -Filter "userPrincipalName eq '$lesleyUPN'" 2>$null
if ($devices) {
foreach ($d in $devices) {
Write-Output ""
Write-Output " Device: $($d.DeviceName)"
Write-Output " OS: $($d.OperatingSystem) $($d.OsVersion)"
Write-Output " Compliance: $($d.ComplianceState)"
Write-Output " Management State: $($d.ManagementState)"
Write-Output " Last Sync: $($d.LastSyncDateTime)"
Write-Output " Device Action: $($d.DeviceActionResults | ForEach-Object { "$($_.ActionName): $($_.ActionState)" })"
}
} else {
Write-Output " [INFO] No Intune-managed devices found for $lesleyUPN"
}
Disconnect-MgGraph
# --- Check EAS Devices ---
Write-Output "`n[CHECK 2] Exchange ActiveSync Devices..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected to Exchange Online"
$easDevices = Get-MobileDevice -Mailbox $lesleyUPN 2>$null
if ($easDevices) {
foreach ($eas in $easDevices) {
$stats = Get-MobileDeviceStatistics -Identity $eas.Identity 2>$null
Write-Output ""
Write-Output " Device: $($eas.FriendlyName)"
Write-Output " Type: $($eas.DeviceType)"
Write-Output " OS: $($eas.DeviceOS)"
Write-Output " Access State: $($eas.DeviceAccessState)"
Write-Output " First Sync: $($eas.FirstSyncTime)"
if ($stats) {
Write-Output " Last Sync: $($stats.LastSuccessSync)"
Write-Output " Wipe Status: $($stats.DeviceWipeSentTime)"
Write-Output " Wipe Ack: $($stats.DeviceWipeAckTime)"
Write-Output " Status: $($stats.Status)"
}
}
} else {
Write-Output " [INFO] No EAS devices found for $lesleyUPN"
}
# --- Check account status ---
Write-Output "`n[CHECK 3] Account Status..."
$mbx = Get-Mailbox -Identity $lesleyUPN -ErrorAction SilentlyContinue
if ($mbx) {
Write-Output " Mailbox Type: $($mbx.RecipientTypeDetails)"
Write-Output " Litigation Hold: $($mbx.LitigationHoldEnabled)"
}
Disconnect-ExchangeOnline -Confirm:$false
Write-Output "`n[OK] Verification complete"

View File

@@ -1,119 +0,0 @@
# BG Builders - Re-enable Lesley Roth + Add Shelly Delegate
# lesley@bgbuildersllc.com - was terminated 2026-02-27
# Actions:
# 1. Unblock sign-in
# 2. Reassign license
# 3. Add Shelly@bgbuildersllc.com as delegate (FullAccess + SendAs)
# 4. Enable litigation hold (prevent email deletion)
$ErrorActionPreference = "Stop"
$tenantId = "ededa4fb-f6eb-4398-851d-5eb3e11fab27"
$lesleyUPN = "lesley@bgbuildersllc.com"
$shellyUPN = "Shelly@bgbuildersllc.com"
Write-Output "========================================="
Write-Output " BG Builders - Re-enable Lesley Roth"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- STEP 1: Connect to Microsoft Graph ---
Write-Output "`n[STEP 1] Connecting to Microsoft Graph..."
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
Connect-MgGraph -TenantId $tenantId -Scopes 'User.ReadWrite.All','Organization.Read.All' -NoWelcome
Write-Output "[OK] Connected to Graph"
$lesley = Get-MgUser -UserId $lesleyUPN -Property Id,DisplayName,AccountEnabled,AssignedLicenses
Write-Output "[INFO] Lesley current state: AccountEnabled=$($lesley.AccountEnabled)"
# --- STEP 2: Unblock sign-in ---
Write-Output "`n[STEP 2] Unblocking sign-in..."
Update-MgUser -UserId $lesley.Id -AccountEnabled:$true
Write-Output "[OK] Sign-in unblocked for Lesley Roth"
# --- STEP 3: Reassign license ---
Write-Output "`n[STEP 3] Reassigning license..."
# List available SKUs to find the right one
$skus = Get-MgSubscribedSku -All
Write-Output "Available licenses:"
foreach ($sku in $skus) {
$available = $sku.PrepaidUnits.Enabled - $sku.ConsumedUnits
Write-Output " $($sku.SkuPartNumber) - $available available of $($sku.PrepaidUnits.Enabled) total"
}
# Assign Exchange Online Plan 1 (EXCHANGESTANDARD) - cheapest option for mailbox access
$exoPlan = $skus | Where-Object { $_.SkuPartNumber -eq "EXCHANGESTANDARD" }
if ($exoPlan) {
$availableCount = $exoPlan.PrepaidUnits.Enabled - $exoPlan.ConsumedUnits
if ($availableCount -gt 0) {
Set-MgUserLicense -UserId $lesley.Id -AddLicenses @(@{SkuId = $exoPlan.SkuId}) -RemoveLicenses @()
Write-Output "[OK] Assigned Exchange Online Plan 1 ($availableCount were available)"
} else {
Write-Output "[WARNING] No Exchange Online Plan 1 licenses available, trying Business Standard..."
$bizStd = $skus | Where-Object { $_.SkuPartNumber -eq "O365_BUSINESS_PREMIUM" }
if ($bizStd) {
$availableCount = $bizStd.PrepaidUnits.Enabled - $bizStd.ConsumedUnits
if ($availableCount -gt 0) {
Set-MgUserLicense -UserId $lesley.Id -AddLicenses @(@{SkuId = $bizStd.SkuId}) -RemoveLicenses @()
Write-Output "[OK] Assigned M365 Business Standard ($availableCount were available)"
} else {
Write-Output "[ERROR] No available licenses of either type - assign manually"
}
}
}
} else {
Write-Output "[WARNING] EXCHANGESTANDARD SKU not found, trying Business Standard..."
$bizStd = $skus | Where-Object { $_.SkuPartNumber -eq "O365_BUSINESS_PREMIUM" }
if ($bizStd) {
$availableCount = $bizStd.PrepaidUnits.Enabled - $bizStd.ConsumedUnits
if ($availableCount -gt 0) {
Set-MgUserLicense -UserId $lesley.Id -AddLicenses @(@{SkuId = $bizStd.SkuId}) -RemoveLicenses @()
Write-Output "[OK] Assigned M365 Business Standard ($availableCount were available)"
} else {
Write-Output "[ERROR] No available licenses - assign manually"
}
}
}
# --- STEP 4: Connect to Exchange Online ---
Write-Output "`n[STEP 4] Connecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected to Exchange Online"
# --- STEP 5: Add Shelly as delegate ---
Write-Output "`n[STEP 5] Adding Shelly as delegate on Lesley's mailbox..."
Add-MailboxPermission -Identity $lesleyUPN -User $shellyUPN -AccessRights FullAccess -AutoMapping $true
Write-Output "[OK] Shelly granted FullAccess (auto-mapped)"
Add-RecipientPermission -Identity $lesleyUPN -Trustee $shellyUPN -AccessRights SendAs -Confirm:$false
Write-Output "[OK] Shelly granted SendAs"
# --- STEP 6: Enable litigation hold ---
Write-Output "`n[STEP 6] Enabling litigation hold (prevent email deletion)..."
Set-Mailbox -Identity $lesleyUPN -LitigationHoldEnabled $true -LitigationHoldDuration Unlimited
Write-Output "[OK] Litigation hold enabled - emails cannot be permanently deleted"
# --- STEP 7: Verify ---
Write-Output "`n[STEP 7] Verifying permissions..."
$perms = Get-MailboxPermission -Identity $lesleyUPN | Where-Object { $_.User -notlike "NT AUTHORITY*" -and $_.User -notlike "S-1-*" }
Write-Output "Current mailbox permissions:"
foreach ($p in $perms) {
Write-Output " $($p.User) - $($p.AccessRights -join ', ')"
}
# --- DONE ---
Write-Output "`n========================================="
Write-Output " COMPLETE"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
Write-Output ""
Write-Output "Summary:"
Write-Output " [OK] Lesley sign-in re-enabled"
Write-Output " [OK] License reassigned"
Write-Output " [OK] Shelly has FullAccess + SendAs on Lesley's mailbox"
Write-Output " [OK] Litigation hold enabled - no email can be permanently deleted"
Write-Output " [INFO] Barry still has access from termination script"
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-MgGraph

View File

@@ -1,166 +0,0 @@
# BG Builders - Employee Termination Script
# Employee: Lesley Roth (lesley@bgbuildersllc.com)
# Scheduled: 2026-02-27 12:00 PM MST
# Actions:
# 1. Block sign-in
# 2. Revoke all sessions
# 3. Reset password
# 4. Selective wipe company data from mobile devices
# 5. Convert mailbox to shared
# 6. Grant Barry full access + send-as on shared mailbox
# 7. Remove from Employees group
# 8. Hide from GAL
# 9. Grant Barry OneDrive access
# 10. Remove license
$ErrorActionPreference = "Stop"
$tenantId = "ededa4fb-f6eb-4398-851d-5eb3e11fab27"
$lesleyUPN = "lesley@bgbuildersllc.com"
$barryUPN = "barry@bgbuildersllc.com"
Write-Output "========================================="
Write-Output " BG Builders - Lesley Roth Termination"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- STEP 1: Connect to Microsoft Graph ---
Write-Output "`n[STEP 1] Connecting to Microsoft Graph..."
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
Import-Module Microsoft.Graph.Users.Actions
Import-Module Microsoft.Graph.Identity.DirectoryManagement
Connect-MgGraph -TenantId $tenantId -Scopes 'User.ReadWrite.All','Directory.ReadWrite.All','Group.ReadWrite.All','DeviceManagementManagedDevices.ReadWrite.All','DeviceManagementManagedDevices.PrivilegedOperations.All' -NoWelcome
Write-Output "[OK] Connected to Graph"
# Get user IDs
$lesley = Get-MgUser -UserId $lesleyUPN -Property Id,DisplayName,AccountEnabled,AssignedLicenses
$barry = Get-MgUser -UserId $barryUPN -Property Id,DisplayName
Write-Output "[OK] Lesley ID: $($lesley.Id)"
Write-Output "[OK] Barry ID: $($barry.Id)"
# --- STEP 2: Block sign-in ---
Write-Output "`n[STEP 2] Blocking sign-in..."
Update-MgUser -UserId $lesley.Id -AccountEnabled:$false
Write-Output "[OK] Sign-in blocked"
# --- STEP 3: Revoke all sessions ---
Write-Output "`n[STEP 3] Revoking all active sessions..."
Revoke-MgUserSignInSession -UserId $lesley.Id
Write-Output "[OK] All sessions revoked"
# --- STEP 4: Reset password ---
Write-Output "`n[STEP 4] Resetting password..."
$newPassword = -join ((65..90) + (97..122) + (48..57) + (33,35,36,37,38) | Get-Random -Count 24 | ForEach-Object {[char]$_})
$params = @{
passwordProfile = @{
forceChangePasswordNextSignIn = $true
password = $newPassword
}
}
Update-MgUser -UserId $lesley.Id -BodyParameter $params
Write-Output "[OK] Password reset (stored securely - not displayed)"
# --- STEP 5: Selective wipe company data from mobile devices ---
Write-Output "`n[STEP 5] Checking for managed mobile devices..."
Import-Module Microsoft.Graph.DeviceManagement
$devices = Get-MgDeviceManagementManagedDevice -Filter "userPrincipalName eq '$lesleyUPN'" 2>$null
if ($devices) {
foreach ($device in $devices) {
Write-Output " Found device: $($device.DeviceName) ($($device.OperatingSystem)) - ID: $($device.Id)"
Write-Output " Initiating selective wipe (company data only)..."
# Retire = selective wipe (removes company data, leaves personal data)
Invoke-MgRetireDeviceManagementManagedDevice -ManagedDeviceId $device.Id
Write-Output " [OK] Selective wipe initiated for $($device.DeviceName)"
}
Write-Output "[OK] All managed devices queued for selective wipe"
} else {
Write-Output "[INFO] No Intune-managed devices found"
Write-Output "[INFO] Checking for EAS (Exchange ActiveSync) devices..."
}
# --- STEP 6: Connect to Exchange Online and convert mailbox ---
Write-Output "`n[STEP 6] Connecting to Exchange Online..."
Import-Module ExchangeOnlineManagement
Connect-ExchangeOnline -UserPrincipalName "sysadmin@bgbuildersllc.com" -ShowBanner:$false
Write-Output "[OK] Connected to Exchange Online"
# Check for ActiveSync devices and wipe company data
$easDevices = Get-MobileDevice -Mailbox $lesleyUPN 2>$null
if ($easDevices) {
foreach ($eas in $easDevices) {
Write-Output " Found EAS device: $($eas.FriendlyName) ($($eas.DeviceOS))"
# AccountOnly wipe - removes only the M365 account, not personal data
Clear-MobileDevice -Identity $eas.Identity -AccountOnly -Confirm:$false
Write-Output " [OK] Account-only wipe initiated for $($eas.FriendlyName)"
}
Write-Output "[OK] All EAS devices queued for account wipe"
} else {
Write-Output "[INFO] No EAS mobile devices found"
}
Write-Output "`n[STEP 6a] Converting mailbox to shared..."
Set-Mailbox -Identity $lesleyUPN -Type Shared
Write-Output "[OK] Mailbox converted to shared"
# --- STEP 7: Grant Barry full access and send-as ---
Write-Output "`n[STEP 7] Granting Barry full access to shared mailbox..."
Add-MailboxPermission -Identity $lesleyUPN -User $barryUPN -AccessRights FullAccess -AutoMapping $true
Write-Output "[OK] Full access granted"
Write-Output "Granting Barry send-as permission..."
Add-RecipientPermission -Identity $lesleyUPN -Trustee $barryUPN -AccessRights SendAs -Confirm:$false
Write-Output "[OK] Send-as granted"
# --- STEP 8: Remove from Employees group ---
Write-Output "`n[STEP 8] Removing from Employees group..."
$employeesGroup = Get-MgGroup -Filter "displayName eq 'Employees'" | Select-Object -First 1
if ($employeesGroup) {
Remove-MgGroupMemberByRef -GroupId $employeesGroup.Id -DirectoryObjectId $lesley.Id -ErrorAction SilentlyContinue
Write-Output "[OK] Removed from Employees group ($($employeesGroup.Id))"
} else {
Write-Output "[WARNING] Employees group not found"
}
# --- STEP 9: Hide from GAL ---
Write-Output "`n[STEP 9] Hiding shared mailbox from Global Address List..."
Set-Mailbox -Identity $lesleyUPN -HiddenFromAddressListsEnabled $true
Write-Output "[OK] Hidden from GAL"
# --- STEP 10: Remove license ---
Write-Output "`n[STEP 10] Removing licenses..."
$licenses = $lesley.AssignedLicenses
if ($licenses.Count -gt 0) {
$licenseIds = $licenses | ForEach-Object { $_.SkuId }
Set-MgUserLicense -UserId $lesley.Id -AddLicenses @() -RemoveLicenses $licenseIds
Write-Output "[OK] Removed $($licenseIds.Count) license(s)"
} else {
Write-Output "[INFO] No licenses assigned"
}
# --- STEP 11: Grant Barry OneDrive access ---
Write-Output "`n[STEP 11] Granting Barry access to Lesley's OneDrive..."
# Note: OneDrive access delegation requires SharePoint admin or may need manual step
Write-Output "[WARNING] OneDrive access must be granted via M365 Admin Center:"
Write-Output " Admin Center > Users > Lesley Roth > OneDrive tab > Create link to files"
Write-Output " Or: SharePoint Admin > User Profiles > Manage User Profiles > Lesley Roth > Manage site collection owners > Add Barry"
# --- DONE ---
Write-Output "`n========================================="
Write-Output " TERMINATION COMPLETE"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
Write-Output ""
Write-Output "Summary:"
Write-Output " [OK] Sign-in blocked"
Write-Output " [OK] Sessions revoked"
Write-Output " [OK] Password reset"
Write-Output " [OK] Mobile devices - selective wipe initiated"
Write-Output " [OK] Mailbox converted to shared"
Write-Output " [OK] Barry has full access + send-as"
Write-Output " [OK] Removed from Employees group"
Write-Output " [OK] Hidden from GAL"
Write-Output " [OK] Licenses removed"
Write-Output " [WARNING] OneDrive access - manual step required"
Disconnect-ExchangeOnline -Confirm:$false
Disconnect-MgGraph

View File

@@ -1,2 +0,0 @@
@echo off
powershell.exe -ExecutionPolicy Bypass -File "D:\ClaudeTools\scripts\bgb-terminate-lesley.ps1" > "D:\ClaudeTools\scripts\bgb-terminate-lesley.log" 2>&1

View File

@@ -1,16 +0,0 @@
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Users
# Connect with interactive browser auth
Connect-MgGraph -TenantId 'ededa4fb-f6eb-4398-851d-5eb3e11fab27' -Scopes 'User.Read.All','User.ReadWrite.All','Directory.ReadWrite.All' -NoWelcome
# Find both users
$leslie = Get-MgUser -Filter "startsWith(displayName,'Leslie') or startsWith(mail,'leslie')" -Property DisplayName,Mail,UserPrincipalName,AccountEnabled,Id
$barry = Get-MgUser -Filter "startsWith(displayName,'Barry') or startsWith(mail,'barry')" -Property DisplayName,Mail,UserPrincipalName,AccountEnabled,Id
Write-Output '--- Leslie ---'
$leslie | Format-List DisplayName,Mail,UserPrincipalName,AccountEnabled,Id
Write-Output '--- Barry ---'
$barry | Format-List DisplayName,Mail,UserPrincipalName,AccountEnabled,Id
Disconnect-MgGraph

View File

@@ -1,98 +0,0 @@
#!/usr/bin/env python3
"""
Check record counts in all ClaudeTools database tables
"""
import sys
from sqlalchemy import create_engine, text, inspect
# Database connection
DATABASE_URL = "mysql+pymysql://claudetools:CT_e8fcd5a3952030a79ed6debae6c954ed@172.16.3.30:3306/claudetools?charset=utf8mb4"
def get_table_counts():
"""Get row counts for all tables"""
engine = create_engine(DATABASE_URL)
with engine.connect() as conn:
# Get all table names
inspector = inspect(engine)
tables = inspector.get_table_names()
print("=" * 70)
print("ClaudeTools Database Record Counts")
print("=" * 70)
print(f"Database: claudetools @ 172.16.3.30:3306")
print(f"Total Tables: {len(tables)}")
print("=" * 70)
print()
# Count rows in each table
counts = {}
total_records = 0
for table in sorted(tables):
result = conn.execute(text(f"SELECT COUNT(*) FROM `{table}`"))
count = result.scalar()
counts[table] = count
total_records += count
# Group by category
categories = {
'Core': ['machines', 'clients', 'projects', 'sessions', 'tags'],
'MSP Work': ['work_items', 'tasks', 'billable_time', 'work_item_files'],
'Infrastructure': ['sites', 'infrastructure', 'services', 'networks', 'firewall_rules', 'm365_tenants', 'm365_licenses'],
'Credentials': ['credentials', 'credential_audit_logs', 'security_incidents'],
'Context Recall': ['conversation_contexts', 'context_snippets', 'project_states', 'decision_logs'],
'Learning': ['command_runs', 'file_changes', 'problem_solutions', 'failure_patterns', 'environmental_insights'],
'Integrations': ['msp_integrations', 'backup_jobs', 'backup_reports'],
'Junction': ['session_tags', 'session_work_items', 'client_contacts', 'project_repositories']
}
# Print by category
for category, table_list in categories.items():
category_tables = [t for t in table_list if t in counts]
if not category_tables:
continue
print(f"{category}:")
print("-" * 70)
category_total = 0
for table in category_tables:
count = counts[table]
category_total += count
status = "[OK]" if count > 0 else " "
print(f" {status} {table:.<50} {count:>10,}")
print(f" {'Subtotal':.<50} {category_total:>10,}")
print()
# Print any uncategorized tables
all_categorized = set()
for table_list in categories.values():
all_categorized.update(table_list)
uncategorized = [t for t in counts.keys() if t not in all_categorized]
if uncategorized:
print("Other Tables:")
print("-" * 70)
for table in uncategorized:
count = counts[table]
status = "[OK]" if count > 0 else " "
print(f" {status} {table:.<50} {count:>10,}")
print()
# Print summary
print("=" * 70)
print(f"TOTAL RECORDS: {total_records:,}")
print(f"Tables with data: {sum(1 for c in counts.values() if c > 0)}/{len(tables)}")
print("=" * 70)
return counts, total_records
if __name__ == "__main__":
try:
counts, total = get_table_counts()
sys.exit(0)
except Exception as e:
print(f"ERROR: {e}", file=sys.stderr)
import traceback
traceback.print_exc()
sys.exit(1)

View File

@@ -1,27 +0,0 @@
@echo off
REM Check current status of ClaudeTools API on RMM server
echo ============================================================
echo ClaudeTools API Status Check
echo ============================================================
echo.
echo [1] API Service Status:
plink guru@172.16.3.30 "sudo systemctl status claudetools-api --no-pager | head -15"
echo.
echo [2] Current Code Version (checking for search_term parameter):
plink guru@172.16.3.30 "grep -c 'search_term.*Query' /opt/claudetools/api/routers/conversation_contexts.py"
echo (0 = OLD CODE, 1+ = NEW CODE)
echo.
echo [3] File Last Modified:
plink guru@172.16.3.30 "ls -lh /opt/claudetools/api/routers/conversation_contexts.py"
echo.
echo [4] API Response Format:
python -c "import requests; jwt='eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiJpbXBvcnQtc2NyaXB0Iiwic2NvcGVzIjpbImFkbWluIiwiaW1wb3J0Il0sImV4cCI6MTc3MTI3NTEyOX0.-DJF50tq0MaNwVQBdO7cGYNuO5pQuXte-tTj5DpHi2U'; r=requests.get('http://172.16.3.30:8001/api/conversation-contexts/recall', headers={'Authorization': f'Bearer {jwt}'}, params={'limit': 1}); print(f'Response keys: {list(r.json().keys())}'); print('Format: NEW' if 'contexts' in r.json() else 'Format: OLD')"
echo.
echo ============================================================
pause

View File

@@ -1,141 +0,0 @@
# CIPP - Add Claude-MSP-Access as Auto-Consent App Template
# This adds Claude's app to CIPP so it gets automatically consented
# when you add new tenants via CIPP.
#
# Uses the CIPP API (ClaudeCipp2 credentials)
$ErrorActionPreference = "Stop"
$cippUrl = "https://cippcanvb.azurewebsites.net"
$cippTenantId = "ce61461e-81a0-4c84-bb4a-7b354a9a356d"
$cippClientId = "420cb849-542d-4374-9cb2-3d8ae0e1835b"
$cippClientSecret = "MOn8Q~otmxJPLvmL~_aCVTV8Va4t4~SrYrukGbJT"
$cippScope = "api://420cb849-542d-4374-9cb2-3d8ae0e1835b/.default"
$claudeAppId = "fabb3421-8b34-484b-bc17-e46de9703418"
Write-Output "========================================="
Write-Output " CIPP - Add Claude-MSP-Access Template"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- STEP 1: Get CIPP API token ---
Write-Output "`n[STEP 1] Getting CIPP API token..."
$tokenBody = @{
client_id = $cippClientId
client_secret = $cippClientSecret
scope = $cippScope
grant_type = "client_credentials"
}
$tokenResponse = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$cippTenantId/oauth2/v2.0/token" -Method POST -Body $tokenBody
$token = $tokenResponse.access_token
Write-Output "[OK] Got CIPP API token"
$headers = @{
"Authorization" = "Bearer $token"
"Content-Type" = "application/json"
}
# --- STEP 2: Check existing app approval templates ---
Write-Output "`n[STEP 2] Checking existing app approval templates..."
try {
$existing = Invoke-RestMethod -Uri "$cippUrl/api/ExecAppPermissionTemplate" -Headers $headers -Method GET
Write-Output "[INFO] Found $($existing.Count) existing template(s)"
foreach ($tmpl in $existing) {
Write-Output " - $($tmpl.displayName) ($($tmpl.appId))"
}
} catch {
Write-Output "[INFO] No existing templates or endpoint returned error: $($_.Exception.Message)"
}
# --- STEP 3: Add Claude-MSP-Access as app template ---
Write-Output "`n[STEP 3] Adding Claude-MSP-Access app template..."
# Application permissions Claude needs consented in each customer tenant
$appPermissions = @(
"User.ReadWrite.All",
"Directory.ReadWrite.All",
"Mail.ReadWrite",
"MailboxSettings.ReadWrite",
"AuditLog.Read.All",
"Application.ReadWrite.All",
"DelegatedPermissionGrant.ReadWrite.All",
"Group.ReadWrite.All",
"GroupMember.ReadWrite.All",
"SecurityEvents.ReadWrite.All",
"SecurityEvents.Read.All",
"SecurityIncident.ReadWrite.All",
"AppRoleAssignment.ReadWrite.All",
"UserAuthenticationMethod.ReadWrite.All",
"Organization.ReadWrite.All",
"Domain.Read.All",
"Policy.Read.All",
"Policy.ReadWrite.ConditionalAccess",
"Policy.ReadWrite.AuthenticationMethod",
"Policy.ReadWrite.AuthenticationFlows",
"Policy.ReadWrite.ApplicationConfiguration",
"Policy.ReadWrite.ConsentRequest",
"Policy.ReadWrite.CrossTenantAccess",
"Reports.Read.All",
"ReportSettings.ReadWrite.All",
"Device.ReadWrite.All",
"DeviceManagementApps.ReadWrite.All",
"DeviceManagementConfiguration.ReadWrite.All",
"DeviceManagementManagedDevices.ReadWrite.All",
"DeviceManagementManagedDevices.PrivilegedOperations.All",
"DeviceManagementRBAC.ReadWrite.All",
"DeviceManagementServiceConfig.ReadWrite.All",
"CrossTenantInformation.ReadBasic.All",
"Channel.Create",
"Channel.ReadBasic.All",
"ChannelMember.ReadWrite.All",
"Files.ReadWrite.All",
"Group.Create",
"InformationProtectionPolicy.Read.All",
"Place.Read.All",
"PrivilegedAccess.ReadWrite.AzureADGroup",
"SharePointTenantSettings.ReadWrite.All",
"Sites.FullControl.All",
"TeamMember.ReadWrite.All",
"TeamMember.ReadWriteNonOwnerRole.All",
"TeamsTelephoneNumber.ReadWrite.All"
)
$templateBody = @{
AppId = $claudeAppId
displayName = "Claude-MSP-Access (AI Investigation & Remediation)"
Permissions = $appPermissions
} | ConvertTo-Json -Depth 5
try {
$result = Invoke-RestMethod -Uri "$cippUrl/api/ExecAppPermissionTemplate" -Headers $headers -Method POST -Body $templateBody
Write-Output "[OK] Template added: $($result | ConvertTo-Json -Compress)"
} catch {
$errBody = $_.ErrorDetails.Message
Write-Output "[WARNING] API response: $errBody"
Write-Output "[INFO] If the endpoint doesn't support POST, you can add the template manually:"
Write-Output " CIPP > Settings > Application Approval > Add Application"
Write-Output " App ID: $claudeAppId"
Write-Output " Name: Claude-MSP-Access (AI Investigation & Remediation)"
Write-Output ""
Write-Output "Or use the CIPP UI to navigate to:"
Write-Output " Tenant Administration > Application Approval"
Write-Output " Click 'Add App' and enter the App ID above"
}
# --- STEP 4: Summary ---
Write-Output "`n========================================="
Write-Output " TEMPLATE SETUP SUMMARY"
Write-Output "========================================="
Write-Output ""
Write-Output "App ID: $claudeAppId"
Write-Output "Name: Claude-MSP-Access (AI Investigation & Remediation)"
Write-Output "Perms: $($appPermissions.Count) application permissions"
Write-Output ""
Write-Output "What happens now:"
Write-Output " 1. When you add a new tenant in CIPP, Claude's app gets auto-consented"
Write-Output " 2. For existing tenants, run CPV Refresh in CIPP to push the permissions"
Write-Output " 3. The admin consent URL also works as a manual fallback:"
Write-Output ""
Write-Output " https://login.microsoftonline.com/common/adminconsent?client_id=$claudeAppId&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient"
Write-Output ""

View File

@@ -1,640 +0,0 @@
{
"requiredResourceAccess": [
{
"resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2",
"resourceAccess": [
{
"id": "594c1fb6-4f81-4475-ae41-0c394909246c",
"type": "Scope"
}
]
},
{
"resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85",
"resourceAccess": [
{
"id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9",
"type": "Role"
},
{
"id": "b0afded3-3588-46d8-8b3d-9842eff778da",
"type": "Role"
},
{
"id": "5e1e9171-754d-478c-812c-f1755a9a4c2d",
"type": "Role"
},
{
"id": "f3a65bd4-b703-46df-8f7e-0174fea562aa",
"type": "Role"
},
{
"id": "59a6b24b-4225-4393-8165-ebaec5f55d7a",
"type": "Role"
},
{
"id": "35930dcf-aceb-4bd1-b99a-8ffed403c974",
"type": "Role"
},
{
"id": "cac88765-0581-4025-9725-5ebc13f729ee",
"type": "Role"
},
{
"id": "1138cb37-bd11-4084-a2b7-9f71582aeddb",
"type": "Role"
},
{
"id": "78145de6-330d-4800-a6ce-494ff2d33d07",
"type": "Role"
},
{
"id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4",
"type": "Role"
},
{
"id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c",
"type": "Role"
},
{
"id": "243333ab-4d21-40cb-a475-36241daa0842",
"type": "Role"
},
{
"id": "e330c4f0-4170-414e-a55a-2f022ec2b57b",
"type": "Role"
},
{
"id": "9255e99d-faf5-445e-bbf7-cb71482737c4",
"type": "Role"
},
{
"id": "8b9d79d0-ad75-4566-8619-f7500ecfcebe",
"type": "Scope"
},
{
"id": "5ac13192-7ace-4fcf-b828-1a26f28068ee",
"type": "Role"
},
{
"id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7",
"type": "Role"
},
{
"id": "dbb9058a-0e50-45d7-ae91-66909b5d4664",
"type": "Role"
},
{
"id": "75359482-378d-4052-8f01-80520e7db3cd",
"type": "Role"
},
{
"id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f",
"type": "Role"
},
{
"id": "62a82d76-70ea-41e2-9197-370581804d09",
"type": "Role"
},
{
"id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695",
"type": "Role"
},
{
"id": "19da66cb-0fb0-4390-b071-ebc76a349482",
"type": "Role"
},
{
"id": "6931bccd-447a-43d1-b442-00a195474933",
"type": "Role"
},
{
"id": "292d869f-3427-49a8-9dab-8c70152b74e9",
"type": "Role"
},
{
"id": "2cb92fee-97a3-4034-8702-24a6f5d0d1e9",
"type": "Role"
},
{
"id": "b6890674-9dd5-4e42-bb15-5af07f541ae1",
"type": "Role"
},
{
"id": "913b9306-0ce1-42b8-9137-6a7df690a760",
"type": "Role"
},
{
"id": "246dd0d5-5bd0-4def-940b-0421030a5b68",
"type": "Role"
},
{
"id": "be74164b-cff1-491c-8741-e671cb536e13",
"type": "Role"
},
{
"id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec",
"type": "Role"
},
{
"id": "29c18626-4985-4dcd-85c0-193eef327366",
"type": "Role"
},
{
"id": "01c0a623-fc9b-48e9-b794-0756f8e8f067",
"type": "Role"
},
{
"id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9",
"type": "Role"
},
{
"id": "338163d7-f101-4c92-94ba-ca46fe52447c",
"type": "Role"
},
{
"id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e",
"type": "Role"
},
{
"id": "230c1aed-a721-4c5d-9cb4-a90514e508ef",
"type": "Role"
},
{
"id": "2a60023f-3219-47ad-baa4-40e17cd02a1d",
"type": "Role"
},
{
"id": "025d3225-3f02-4882-b4c0-cd5b541a4e80",
"type": "Role"
},
{
"id": "04c55753-2244-4c25-87fc-704ab82a4f69",
"type": "Role"
},
{
"id": "bf394140-e372-4bf9-a898-299cfc7564e5",
"type": "Role"
},
{
"id": "34bf0e97-1971-4929-b999-9e2442d941d7",
"type": "Role"
},
{
"id": "19b94e34-907c-4f43-bde9-38b1909ed408",
"type": "Role"
},
{
"id": "a82116e5-55eb-4c41-a434-62fe8a61c773",
"type": "Role"
},
{
"id": "0121dc95-1b9f-4aed-8bac-58c5ac466691",
"type": "Role"
},
{
"id": "4437522e-9a86-4a41-a7da-e380edd4a97d",
"type": "Role"
},
{
"id": "741f803b-c850-494e-b5df-cde7c675a1ca",
"type": "Role"
},
{
"id": "50483e42-d915-4231-9639-7fdb7fd190e5",
"type": "Role"
},
{
"id": "bdfbf15f-ee85-4955-8675-146e8e5296b5",
"type": "Scope"
},
{
"id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64",
"type": "Scope"
},
{
"id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20",
"type": "Scope"
},
{
"id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30",
"type": "Scope"
},
{
"id": "101147cf-4178-4455-9d58-02b5c164e759",
"type": "Scope"
},
{
"id": "cc83893a-e232-4723-b5af-bd0b01bcfe65",
"type": "Scope"
},
{
"id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87",
"type": "Scope"
},
{
"id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075",
"type": "Scope"
},
{
"id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11",
"type": "Scope"
},
{
"id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53",
"type": "Scope"
},
{
"id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8",
"type": "Scope"
},
{
"id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4",
"type": "Scope"
},
{
"id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378",
"type": "Scope"
},
{
"id": "f3bfad56-966e-4590-a536-82ecf548ac1e",
"type": "Scope"
},
{
"id": "885f682f-a990-4bad-a642-36736a74b0c7",
"type": "Scope"
},
{
"id": "41ce6ca6-6826-4807-84f1-1c82854f7ee5",
"type": "Scope"
},
{
"id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804",
"type": "Scope"
},
{
"id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd",
"type": "Scope"
},
{
"id": "951183d1-1a61-466f-a6d1-1fde911bfd95",
"type": "Scope"
},
{
"id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9",
"type": "Scope"
},
{
"id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af",
"type": "Scope"
},
{
"id": "0883f392-0a7a-443d-8c76-16a6d39c7b63",
"type": "Scope"
},
{
"id": "3404d2bf-2b13-457e-a330-c24615765193",
"type": "Scope"
},
{
"id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3",
"type": "Scope"
},
{
"id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d",
"type": "Scope"
},
{
"id": "662ed50a-ac44-4eef-ad86-62eed9be2a29",
"type": "Scope"
},
{
"id": "0e263e50-5827-48a4-b97c-d940288653c7",
"type": "Scope"
},
{
"id": "c5366453-9fb0-48a5-a156-24f0c49a4b84",
"type": "Scope"
},
{
"id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311",
"type": "Scope"
},
{
"id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0",
"type": "Scope"
},
{
"id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e",
"type": "Scope"
},
{
"id": "9e4862a5-b68f-479e-848a-4e07e25c9916",
"type": "Scope"
},
{
"id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515",
"type": "Scope"
},
{
"id": "e0a7cdbb-08b0-4697-8264-0069786e9674",
"type": "Scope"
},
{
"id": "e383f46e-2787-4529-855e-0e479a3ffac0",
"type": "Scope"
},
{
"id": "a367ab51-6b49-43bf-a716-a1fb06d2a174",
"type": "Scope"
},
{
"id": "818c620a-27a9-40bd-a6a5-d96f7d610b4b",
"type": "Scope"
},
{
"id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be",
"type": "Scope"
},
{
"id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
"type": "Scope"
},
{
"id": "37f7f235-527c-4136-accd-4a02d197296e",
"type": "Scope"
},
{
"id": "46ca0847-7e6b-426e-9775-ea810a948356",
"type": "Scope"
},
{
"id": "346c19ff-3fb2-4e81-87a0-bac9e33990c1",
"type": "Scope"
},
{
"id": "e67e6727-c080-415e-b521-e3f35d5248e9",
"type": "Scope"
},
{
"id": "4c06a06a-098a-4063-868e-5dfee3827264",
"type": "Scope"
},
{
"id": "572fea84-0151-49b2-9301-11cb16974376",
"type": "Scope"
},
{
"id": "b27add92-efb2-4f16-84f5-8108ba77985c",
"type": "Scope"
},
{
"id": "edb72de9-4252-4d03-a925-451deef99db7",
"type": "Scope"
},
{
"id": "7e823077-d88e-468f-a337-e18f1f0e6c7c",
"type": "Scope"
},
{
"id": "edd3c878-b384-41fd-95ad-e7407dd775be",
"type": "Scope"
},
{
"id": "ad902697-1014-4ef5-81ef-2b4301988e8c",
"type": "Scope"
},
{
"id": "4d135e65-66b8-41a8-9f8b-081452c91774",
"type": "Scope"
},
{
"id": "40b534c3-9552-4550-901b-23879c90bcf9",
"type": "Scope"
},
{
"id": "a8ead177-1889-4546-9387-f25e658e2a79",
"type": "Scope"
},
{
"id": "a84a9652-ffd3-496e-a991-22ba5529156a",
"type": "Scope"
},
{
"id": "14dad69e-099b-42c9-810b-d002981feec1",
"type": "Scope"
},
{
"id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c",
"type": "Scope"
},
{
"id": "b955410e-7715-4a88-a940-dfd551018df3",
"type": "Scope"
},
{
"id": "d01b97e9-cbc0-49fe-810a-750afd5527a3",
"type": "Scope"
},
{
"id": "dc38509c-b87d-4da0-bd92-6bec988bac4a",
"type": "Scope"
},
{
"id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc",
"type": "Scope"
},
{
"id": "128ca929-1a19-45e6-a3b8-435ec44a36ba",
"type": "Scope"
},
{
"id": "55896846-df78-47a7-aa94-8d3d4442ca7f",
"type": "Scope"
},
{
"id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b",
"type": "Scope"
},
{
"id": "aa07f155-3612-49b8-a147-6c590df35536",
"type": "Scope"
},
{
"id": "89fe6a52-be36-487e-b7d8-d061c450a026",
"type": "Scope"
},
{
"id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0",
"type": "Scope"
},
{
"id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4",
"type": "Scope"
},
{
"id": "4a06efd2-f825-4e34-813e-82a57b03d1ee",
"type": "Scope"
},
{
"id": "2104a4db-3a2f-4ea0-9dba-143d457dc666",
"type": "Scope"
},
{
"id": "0e755559-83fb-4b44-91d0-4cc721b9323e",
"type": "Scope"
},
{
"id": "39d65650-9d3e-4223-80db-a335590d027e",
"type": "Scope"
},
{
"id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e",
"type": "Scope"
},
{
"id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9",
"type": "Scope"
},
{
"id": "cac97e40-6730-457d-ad8d-4852fddab7ad",
"type": "Scope"
},
{
"id": "73e75199-7c3e-41bb-9357-167164dbb415",
"type": "Scope"
},
{
"id": "637d7bec-b31e-4deb-acc9-24275642a2c9",
"type": "Scope"
},
{
"id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4",
"type": "Scope"
},
{
"id": "48971fc1-70d7-4245-af77-0beb29b53ee2",
"type": "Scope"
},
{
"id": "b7887744-6746-4312-813d-72daeaee7e2d",
"type": "Scope"
},
{
"id": "424b07a8-1209-4d17-9fe4-9018a93a1024",
"type": "Scope"
},
{
"id": "0a42382f-155c-4eb1-9bdc-21548ccaa387",
"type": "Role"
},
{
"id": "2d9bd318-b883-40be-9df7-63ec4fcdc424",
"type": "Role"
},
{
"id": "c8948c23-e66b-42db-83fd-770b71ab78d2",
"type": "Role"
},
{
"id": "a94a502d-0281-4d15-8cd2-682ac9362c4c",
"type": "Role"
},
{
"id": "e2a3a72e-5f79-4c64-b1b1-878b674786c9",
"type": "Role"
},
{
"id": "06b708a9-e830-4db3-a914-8e69da51d44f",
"type": "Role"
},
{
"id": "d903a879-88e0-4c09-b0c9-82f6a1333f84",
"type": "Role"
},
{
"id": "8e8e4742-1d95-4f68-9d56-6ee75648c72a",
"type": "Role"
}
]
},
{
"resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd",
"resourceAccess": [
{
"id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "dc50a0fb-09a3-484d-be87-e023b12c6440",
"type": "Role"
},
{
"id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99",
"type": "Role"
},
{
"id": "f9156939-25cd-4ba8-abfe-7fabcf003749",
"type": "Role"
},
{
"id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c",
"type": "Scope"
},
{
"id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415",
"type": "Scope"
},
{
"id": "2e83d72d-8895-4b66-9eea-abb43449ab8b",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000003-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0",
"type": "Scope"
}
]
},
{
"resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239",
"resourceAccess": [
{
"id": "e60370c1-e451-437e-aa6e-d76df38e5f15",
"type": "Scope"
}
]
},
{
"resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92",
"resourceAccess": [
{
"id": "41269fc5-d04d-4bfd-bce7-43a51cea049a",
"type": "Role"
},
{
"id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe",
"type": "Scope"
}
]
}
]
}

View File

@@ -1,188 +0,0 @@
# Claude-MSP-Access - Automated Tenant Onboarding
# Onboards a customer tenant with full Claude + CIPP permissions
# No manual intervention required after initial admin consent
#
# Usage: .\claude-msp-onboard-tenant.ps1 -TenantDomain "sonorangreenllc.com"
#
# Prerequisites: Admin consent URL must be clicked first by customer/sysadmin:
# https://login.microsoftonline.com/common/adminconsent?client_id=fabb3421-8b34-484b-bc17-e46de9703418&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient
#
# What this script does after consent:
# 1. Finds the Claude-MSP-Access service principal in the customer tenant
# 2. Activates Exchange Administrator directory role (if not active)
# 3. Assigns Exchange Administrator to Claude's SP (via CIPP Graph proxy)
# 4. Verifies all access: Graph, Exchange, Mail, Security, Intune
param(
[Parameter(Mandatory=$true)]
[string]$TenantDomain
)
$ErrorActionPreference = "Stop"
# --- Credentials ---
$cippUrl = "https://cippcanvb.azurewebsites.net"
$cippTenantId = "ce61461e-81a0-4c84-bb4a-7b354a9a356d"
$cippClientId = "420cb849-542d-4374-9cb2-3d8ae0e1835b"
$cippSecret = "MOn8Q~otmxJPLvmL~_aCVTV8Va4t4~SrYrukGbJT"
$claudeAppId = "fabb3421-8b34-484b-bc17-e46de9703418"
$claudeSecret = "~QJ8Q~NyQSs4OcGqHZyPrA2CVnq9KBfKiimntbMO"
Write-Output "========================================="
Write-Output " Claude-MSP-Access - Tenant Onboarding"
Write-Output " Tenant: $TenantDomain"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- STEP 1: Get CIPP API token ---
Write-Output "`n[STEP 1] Getting CIPP API token..."
$tokenBody = @{
client_id = $cippClientId
client_secret = $cippSecret
scope = "api://$cippClientId/.default"
grant_type = "client_credentials"
}
$cippToken = (Invoke-RestMethod -Uri "https://login.microsoftonline.com/$cippTenantId/oauth2/v2.0/token" -Method POST -Body $tokenBody).access_token
$cippHeaders = @{ "Authorization" = "Bearer $cippToken" }
Write-Output "[OK] CIPP token acquired"
# --- STEP 2: Find Claude SP in customer tenant via CIPP ---
Write-Output "`n[STEP 2] Finding Claude-MSP-Access service principal..."
$spFilter = [uri]::EscapeDataString("appId eq '$claudeAppId'")
$spResult = Invoke-RestMethod -Uri "$cippUrl/api/ListGraphRequest?TenantFilter=$TenantDomain&Endpoint=servicePrincipals&`$filter=$spFilter" -Headers $cippHeaders
$sp = $spResult.Results | Select-Object -First 1
if (-not $sp) {
Write-Output "[ERROR] Claude-MSP-Access SP not found in $TenantDomain"
Write-Output "[INFO] Has admin consent been completed? Use this URL:"
Write-Output " https://login.microsoftonline.com/common/adminconsent?client_id=$claudeAppId&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient"
exit 1
}
$spId = $sp.id
Write-Output "[OK] Found SP: $($sp.displayName) (ID: $spId)"
# --- STEP 3: Get Exchange Administrator role ID ---
Write-Output "`n[STEP 3] Finding Exchange Administrator role..."
$rolesResult = Invoke-RestMethod -Uri "$cippUrl/api/ListGraphRequest?TenantFilter=$TenantDomain&Endpoint=directoryRoles" -Headers $cippHeaders
$exoRole = $rolesResult.Results | Where-Object { $_.displayName -eq "Exchange Administrator" }
if (-not $exoRole) {
Write-Output "[INFO] Exchange Admin role not activated, activating from template..."
# Exchange Administrator role template ID is always 29232cdf-9323-42fd-ade2-1d097af3e4de
$activateBody = [uri]::EscapeDataString((@{ roleTemplateId = "29232cdf-9323-42fd-ade2-1d097af3e4de" } | ConvertTo-Json -Compress))
$activateResult = Invoke-RestMethod -Uri "$cippUrl/api/ListGraphRequest?TenantFilter=$TenantDomain&Endpoint=directoryRoles&type=POST&body=$activateBody" -Headers $cippHeaders
# Re-fetch roles
$rolesResult = Invoke-RestMethod -Uri "$cippUrl/api/ListGraphRequest?TenantFilter=$TenantDomain&Endpoint=directoryRoles" -Headers $cippHeaders
$exoRole = $rolesResult.Results | Where-Object { $_.displayName -eq "Exchange Administrator" }
}
if (-not $exoRole) {
Write-Output "[ERROR] Could not find or activate Exchange Administrator role"
exit 1
}
$exoRoleId = $exoRole.id
Write-Output "[OK] Exchange Admin role: $exoRoleId"
# --- STEP 4: Assign Exchange Administrator to Claude SP ---
Write-Output "`n[STEP 4] Assigning Exchange Administrator role..."
$assignEndpoint = [uri]::EscapeDataString("directoryRoles/$exoRoleId/members/`$ref")
$assignBody = [uri]::EscapeDataString((@{ "@odata.id" = "https://graph.microsoft.com/v1.0/servicePrincipals/$spId" } | ConvertTo-Json -Compress))
try {
$assignResult = Invoke-RestMethod -Uri "$cippUrl/api/ListGraphRequest?TenantFilter=$TenantDomain&Endpoint=$assignEndpoint&type=POST&body=$assignBody" -Headers $cippHeaders
if ($assignResult.Results.CippStatus -eq "Good") {
Write-Output "[OK] Exchange Administrator assigned to Claude-MSP-Access"
} else {
Write-Output "[INFO] Assignment result: $($assignResult.Results | ConvertTo-Json -Compress)"
}
} catch {
$errMsg = $_.Exception.Message
if ($errMsg -match "already exist") {
Write-Output "[OK] Exchange Administrator already assigned"
} else {
Write-Output "[WARNING] Role assignment: $errMsg"
}
}
# --- STEP 5: Verify Claude API access ---
Write-Output "`n[STEP 5] Verifying Claude-MSP-Access API connectivity..."
# Get tenant ID from CIPP
$selectFields = [uri]::EscapeDataString("id,displayName")
$orgResult = Invoke-RestMethod -Uri "$cippUrl/api/ListGraphRequest?TenantFilter=$TenantDomain&Endpoint=organization&`$select=$selectFields" -Headers $cippHeaders
$customerTenantId = $orgResult.Results[0].id
Write-Output "[INFO] Tenant ID: $customerTenantId"
# Get Claude token for this tenant
$claudeTokenBody = @{
client_id = $claudeAppId
client_secret = $claudeSecret
scope = "https://graph.microsoft.com/.default"
grant_type = "client_credentials"
}
try {
$claudeToken = (Invoke-RestMethod -Uri "https://login.microsoftonline.com/$customerTenantId/oauth2/v2.0/token" -Method POST -Body $claudeTokenBody).access_token
Write-Output "[OK] Claude Graph token acquired"
} catch {
Write-Output "[ERROR] Could not get Claude token - admin consent may not be complete"
Write-Output " $($_.Exception.Message)"
exit 1
}
$claudeHeaders = @{ "Authorization" = "Bearer $claudeToken"; "Content-Type" = "application/json" }
# Test endpoints
$tests = @(
@{ Name = "Users"; Uri = "https://graph.microsoft.com/v1.0/users?`$top=1&`$select=displayName" },
@{ Name = "Security"; Uri = "https://graph.microsoft.com/v1.0/security/alerts?`$top=1" },
@{ Name = "AuditLogs"; Uri = "https://graph.microsoft.com/v1.0/auditLogs/signIns?`$top=1" },
@{ Name = "Policies"; Uri = "https://graph.microsoft.com/v1.0/identity/conditionalAccess/policies" },
@{ Name = "Devices"; Uri = "https://graph.microsoft.com/v1.0/deviceManagement/managedDevices?`$top=1" }
)
foreach ($test in $tests) {
try {
$r = Invoke-RestMethod -Uri $test.Uri -Headers $claudeHeaders -ErrorAction Stop
Write-Output " [OK] $($test.Name)"
} catch {
$code = $_.Exception.Response.StatusCode.value__
Write-Output " [FAIL] $($test.Name): HTTP $code"
}
}
# Test Exchange Online REST
Write-Output "`n Testing Exchange Online REST API..."
try {
$exoTokenBody = @{
client_id = $claudeAppId
client_secret = $claudeSecret
scope = "https://outlook.office365.com/.default"
grant_type = "client_credentials"
}
$exoToken = (Invoke-RestMethod -Uri "https://login.microsoftonline.com/$customerTenantId/oauth2/v2.0/token" -Method POST -Body $exoTokenBody).access_token
$exoHeaders = @{ "Authorization" = "Bearer $exoToken"; "Content-Type" = "application/json" }
$invokeUrl = "https://outlook.office365.com/adminapi/beta/$customerTenantId/InvokeCommand"
$getMailbox = @{
CmdletInput = @{
CmdletName = "Get-Mailbox"
Parameters = @{ ResultSize = "1" }
}
} | ConvertTo-Json -Depth 5
$r = Invoke-RestMethod -Uri $invokeUrl -Headers $exoHeaders -Method POST -Body $getMailbox -ErrorAction Stop
Write-Output " [OK] Exchange Online (Get-Mailbox)"
} catch {
Write-Output " [FAIL] Exchange Online: $($_.Exception.Message)"
}
# --- DONE ---
Write-Output "`n========================================="
Write-Output " ONBOARDING COMPLETE: $TenantDomain"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
Write-Output ""
Write-Output "Claude-MSP-Access is fully operational for this tenant."
Write-Output "Capabilities: User mgmt, mail access, security alerts,"
Write-Output "audit logs, conditional access, Intune, Exchange admin,"
Write-Output "litigation hold, and all CIPP SAM operations."

View File

@@ -1,93 +0,0 @@
# Claude-MSP-Access - Update App Registration with Combined CIPP + Investigation Permissions
# App ID: fabb3421-8b34-484b-bc17-e46de9703418
# Partner Tenant: ce61461e-81a0-4c84-bb4a-7b354a9a356d
#
# This script updates the app registration to include:
# - All CIPP SAM required permissions (Graph, Exchange, SharePoint, Intune, PowerBI, Partner Center)
# - Claude investigation extras (Mail.ReadWrite, SecurityEvents.ReadWrite.All, etc.)
#
# After running this, the admin consent URL will grant everything in one click.
$ErrorActionPreference = "Stop"
$tenantId = "ce61461e-81a0-4c84-bb4a-7b354a9a356d"
$appId = "fabb3421-8b34-484b-bc17-e46de9703418"
Write-Output "========================================="
Write-Output " Claude-MSP-Access - Permission Update"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
# --- STEP 1: Connect to Graph ---
Write-Output "`n[STEP 1] Connecting to Microsoft Graph..."
Import-Module Microsoft.Graph.Authentication
Import-Module Microsoft.Graph.Applications
Connect-MgGraph -TenantId $tenantId -Scopes 'Application.ReadWrite.All' -NoWelcome
Write-Output "[OK] Connected to Graph"
# --- STEP 2: Get current app registration ---
Write-Output "`n[STEP 2] Reading current app registration..."
$app = Get-MgApplication -Filter "appId eq '$appId'"
if (-not $app) {
Write-Output "[ERROR] App not found: $appId"
exit 1
}
Write-Output "[OK] Found: $($app.DisplayName) (Object ID: $($app.Id))"
$currentPerms = ($app.RequiredResourceAccess | ForEach-Object { $_.ResourceAccess }).Count
Write-Output "[INFO] Current permission count: $currentPerms"
# --- STEP 3: Load combined manifest ---
Write-Output "`n[STEP 3] Loading combined permission manifest..."
$manifestPath = Join-Path $PSScriptRoot "claude-msp-combined-manifest.json"
$manifest = Get-Content $manifestPath -Raw | ConvertFrom-Json
# Build the requiredResourceAccess array
$resourceAccess = @()
foreach ($resource in $manifest.requiredResourceAccess) {
$accessList = @()
foreach ($access in $resource.resourceAccess) {
$accessList += @{
Id = $access.id
Type = $access.type
}
}
$resourceAccess += @{
ResourceAppId = $resource.resourceAppId
ResourceAccess = $accessList
}
}
$newPerms = ($manifest.requiredResourceAccess | ForEach-Object { $_.resourceAccess }).Count
Write-Output "[INFO] New permission count: $newPerms"
# --- STEP 4: Update app registration ---
Write-Output "`n[STEP 4] Updating app registration..."
Update-MgApplication -ApplicationId $app.Id -RequiredResourceAccess $resourceAccess
Write-Output "[OK] App registration updated with combined permissions"
# --- STEP 5: Verify ---
Write-Output "`n[STEP 5] Verifying update..."
$updated = Get-MgApplication -ApplicationId $app.Id
$updatedPerms = ($updated.RequiredResourceAccess | ForEach-Object { $_.ResourceAccess }).Count
Write-Output "[OK] Verified: $updatedPerms permissions across $($updated.RequiredResourceAccess.Count) resource APIs"
# --- STEP 6: Show admin consent URL ---
Write-Output "`n[STEP 6] Admin consent URL (use this to onboard tenants):"
Write-Output ""
Write-Output " https://login.microsoftonline.com/common/adminconsent?client_id=$appId&redirect_uri=https://login.microsoftonline.com/common/oauth2/nativeclient"
Write-Output ""
Write-Output "[INFO] This single URL now grants ALL permissions:"
Write-Output " - Microsoft Graph (application + delegated)"
Write-Output " - Exchange Online (ManageAsApp + Calendars + Mailbox)"
Write-Output " - SharePoint Online (FullControl)"
Write-Output " - Intune (user_impersonation)"
Write-Output " - PowerBI (Vulnerability.Read)"
Write-Output " - Partner Center (user_impersonation)"
Write-Output " - Office Management API (ActivityFeed.Read)"
Write-Output " - Claude investigation extras (Mail.ReadWrite, SecurityEvents.ReadWrite.All)"
Write-Output "`n========================================="
Write-Output " UPDATE COMPLETE"
Write-Output " $(Get-Date -Format 'yyyy-MM-dd HH:mm:ss')"
Write-Output "========================================="
Disconnect-MgGraph

View File

@@ -1,28 +0,0 @@
#!/usr/bin/env python3
"""
Create a JWT token for ClaudeTools API access
"""
import jwt
from datetime import datetime, timedelta, timezone
# Get the JWT secret from the RMM server's .env file
# This should match what's in /opt/claudetools/.env on 172.16.3.30
JWT_SECRET = "NdwgH6jsGR1WfPdUwR3u9i1NwNx3QthhLHBsRCfFxcg="
# Create token data
data = {
"sub": "import-script",
"scopes": ["admin", "import"],
"exp": datetime.now(timezone.utc) + timedelta(days=30)
}
# Create token
token = jwt.encode(data, JWT_SECRET, algorithm="HS256")
print(f"New JWT Token:")
print(token)
print()
print(f"Expires: {data['exp']}")
print()
print("Add this to .claude/context-recall-config.env:")
print(f"JWT_TOKEN={token}")

View File

@@ -1,68 +0,0 @@
Write-Output "=== HKCU Excel Addins ==="
$path = "HKCU:\Software\Microsoft\Office\Excel\Addins"
if (Test-Path $path) {
Get-ChildItem $path | ForEach-Object {
Write-Output "`n Key: $($_.PSChildName)"
Get-ItemProperty $_.PSPath | Format-List
}
} else {
Write-Output " Path not found"
}
Write-Output "`n=== HKCU Word Addins ==="
$path = "HKCU:\Software\Microsoft\Office\Word\Addins"
if (Test-Path $path) {
Get-ChildItem $path | ForEach-Object {
Write-Output "`n Key: $($_.PSChildName)"
Get-ItemProperty $_.PSPath | Format-List
}
} else {
Write-Output " Path not found"
}
Write-Output "`n=== HKCU PowerPoint Addins ==="
$path = "HKCU:\Software\Microsoft\Office\PowerPoint\Addins"
if (Test-Path $path) {
Get-ChildItem $path | ForEach-Object {
Write-Output "`n Key: $($_.PSChildName)"
Get-ItemProperty $_.PSPath | Format-List
}
} else {
Write-Output " Path not found"
}
Write-Output "`n=== HKLM Excel Addins ==="
$path = "HKLM:\Software\Microsoft\Office\Excel\Addins"
if (Test-Path $path) {
Get-ChildItem $path | ForEach-Object {
Write-Output "`n Key: $($_.PSChildName)"
Get-ItemProperty $_.PSPath | Format-List
}
} else {
Write-Output " Path not found"
}
Write-Output "`n=== HKLM WOW6432 Excel Addins ==="
$path = "HKLM:\Software\WOW6432Node\Microsoft\Office\Excel\Addins"
if (Test-Path $path) {
Get-ChildItem $path | ForEach-Object {
Write-Output "`n Key: $($_.PSChildName)"
Get-ItemProperty $_.PSPath | Format-List
}
} else {
Write-Output " Path not found"
}
Write-Output "`n=== Search for any Datto/SmartBadge registry entries ==="
$results = reg query "HKCU\Software\Microsoft\Office" /s /f "Datto" 2>&1
$results | ForEach-Object { Write-Output $_ }
$results2 = reg query "HKLM\Software\Microsoft\Office" /s /f "Datto" 2>&1
$results2 | ForEach-Object { Write-Output $_ }
$results3 = reg query "HKLM\Software\WOW6432Node\Microsoft\Office" /s /f "SmartBadge" 2>&1
$results3 | ForEach-Object { Write-Output $_ }
Write-Output "`n=== SmartBadge DLL registration (CLSID) ==="
$results4 = reg query "HKLM\Software\Classes\CLSID" /s /f "SmartBadge" 2>&1
$results4 | Select-Object -First 20 | ForEach-Object { Write-Output $_ }
$results5 = reg query "HKCU\Software\Classes\CLSID" /s /f "SmartBadge" 2>&1
$results5 | Select-Object -First 20 | ForEach-Object { Write-Output $_ }

View File

@@ -1,100 +0,0 @@
Windows Registry Editor Version 5.00
; Datto SmartBadge Add-in Registration for 64-bit Office
; Generated from working installation reference
; === Excel Add-ins ===
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim_CC]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
; === Word Add-ins ===
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Word\Addins\Datto.SmartBadgeShim]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Word\Addins\Datto.SmartBadgeShim_CC]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
; === PowerPoint Add-ins ===
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\PowerPoint\Addins\Datto.SmartBadgeShim]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\PowerPoint\Addins\Datto.SmartBadgeShim_CC]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
; === WOW6432Node (32-bit compatibility layer) ===
[HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Office\Excel\Addins\Datto.SmartBadgeShim_CC]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Office\Word\Addins\Datto.SmartBadgeShim]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Office\Word\Addins\Datto.SmartBadgeShim_CC]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Office\PowerPoint\Addins\Datto.SmartBadgeShim]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\WOW6432Node\Microsoft\Office\PowerPoint\Addins\Datto.SmartBadgeShim_CC]
"FriendlyName"="Datto SmartBadge"
"Description"="SmartBadge for Microsoft Office applications."
"LoadBehavior"=dword:00000003
; === COM CLSID Registration (64-bit shim DLL) ===
[HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{2B96EDC1-FDF3-47E1-B177-F205E7B98DF4}]
@="Datto.SmartBadgeShim"
[HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{2B96EDC1-FDF3-47E1-B177-F205E7B98DF4}\InprocServer32]
@="C:\\Program Files\\Datto\\Workplace Desktop\\SmartBadge\\DattoSmartBadgeShim_x64.dll"
"ThreadingModel"="Both"
[HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{2B96EDC1-FDF3-47E1-B177-F205E7B98DF4}\ProgID]
@="Datto.SmartBadgeShim"
[HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{3C639243-95A2-400D-B4B4-4384DA7F61D3}]
@="Datto.SmartBadgeShim_CC"
[HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{3C639243-95A2-400D-B4B4-4384DA7F61D3}\InprocServer32]
@="C:\\Program Files\\Datto\\Workplace2\\SmartBadge\\DattoSmartBadgeShim_x64.dll"
"ThreadingModel"="Both"
[HKEY_LOCAL_MACHINE\Software\Classes\CLSID\{3C639243-95A2-400D-B4B4-4384DA7F61D3}\ProgID]
@="Datto.SmartBadgeShim_CC"
; === Outlook Plugin (if needed) ===
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Outlook\Addins\Datto.OutlookPluginShim]
"FriendlyName"="Datto Outlook Plugin"
"Description"="Datto add-in for Microsoft Outlook."
"LoadBehavior"=dword:00000003
[HKEY_LOCAL_MACHINE\Software\Microsoft\Office\Outlook\Addins\Datto.OutlookPluginShim_CC]
"FriendlyName"="Datto Outlook Plugin"
"Description"="Datto add-in for Microsoft Outlook."
"LoadBehavior"=dword:00000003

View File

@@ -1,27 +0,0 @@
Import-Module Posh-SSH
$secPassword = ConvertTo-SecureString 'Paper123!@#' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('INTRANET\sysadmin', $secPassword)
$session = New-SSHSession -ComputerName 192.168.0.6 -Credential $cred -AcceptKey -Force -ConnectionTimeout 30
Write-Output "[OK] Connected to AD2"
$portCheck = @'
powershell -Command "foreach ($p in @(22,445,3389,5985)) { $t = New-Object System.Net.Sockets.TcpClient; $r = $t.BeginConnect('192.168.0.149', $p, $null, $null); $w = $r.AsyncWaitHandle.WaitOne(2000, $false); if ($w -and $t.Connected) { Write-Output \"$p : Open\"; $t.Close() } else { Write-Output \"$p : Closed\"; $t.Close() } }"
'@
Write-Output "`n=== Port Check 192.168.0.149 ==="
$result = Invoke-SSHCommand -SessionId $session.SessionId -Command $portCheck -TimeOut 30
Write-Output $result.Output
# If 445 is open, try PsExec-style via SMB to check creds
# If 5985 not open, try enabling WinRM via scheduled task
$cmd = @'
powershell -Command "Invoke-Command -ComputerName DESKTOP-Q33I5H1 -Credential (New-Object PSCredential('INTRANET\sysadmin',(ConvertTo-SecureString 'Paper123!@#' -AsPlainText -Force))) -ScriptBlock { cmdkey /list } -ErrorAction SilentlyContinue 2>&1"
'@
Write-Output "`n=== WinRM attempt ==="
$r2 = Invoke-SSHCommand -SessionId $session.SessionId -Command $cmd -TimeOut 30
Write-Output $r2.Output
if ($r2.Error) { Write-Output $r2.Error }
Remove-SSHSession -SessionId $session.SessionId | Out-Null

View File

@@ -1,62 +0,0 @@
$secPassword = ConvertTo-SecureString 'Paper123!@#' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('INTRANET\sysadmin', $secPassword)
# Query lockout events from AD1 via AD2 (same subnet hop)
Invoke-Command -ComputerName 192.168.0.6 -Credential $cred -Authentication Negotiate -ScriptBlock {
# Query AD1's event log from AD2 (both on same subnet)
Write-Output "=== Lockout Events (4740) from AD1 ==="
try {
$lockouts = Get-WinEvent -ComputerName AD1 -FilterHashtable @{LogName='Security'; Id=4740; StartTime=(Get-Date).AddDays(-7)} -ErrorAction Stop |
Where-Object { $_.Properties[0].Value -eq 'jlohr' } |
Select-Object -First 30
foreach ($e in $lockouts) {
Write-Output "$($e.TimeCreated) | Caller: $($e.Properties[1].Value)"
}
if (-not $lockouts) { Write-Output " None found" }
} catch { Write-Output " ERROR: $_" }
Write-Output "`n=== Kerberos Failures (4771) from AD1 ==="
try {
$k = Get-WinEvent -ComputerName AD1 -FilterHashtable @{LogName='Security'; Id=4771; StartTime=(Get-Date).AddDays(-3)} -ErrorAction Stop |
Where-Object { $_.Properties[0].Value -eq 'jlohr' } |
Select-Object -First 30
foreach ($e in $k) {
Write-Output "$($e.TimeCreated) | IP: $($e.Properties[6].Value) | Status: $($e.Properties[4].Value)"
}
if (-not $k) { Write-Output " None found" }
} catch { Write-Output " ERROR: $_" }
Write-Output "`n=== NTLM Failures (4776) from AD1 ==="
try {
$n = Get-WinEvent -ComputerName AD1 -FilterHashtable @{LogName='Security'; Id=4776; StartTime=(Get-Date).AddDays(-3)} -ErrorAction Stop |
Where-Object { $_.Properties[1].Value -eq 'jlohr' -and $_.Properties[2].Value -ne 0 } |
Select-Object -First 30
foreach ($e in $n) {
Write-Output "$($e.TimeCreated) | Workstation: $($e.Properties[0].Value) | Error: $($e.Properties[2].Value)"
}
if (-not $n) { Write-Output " None found" }
} catch { Write-Output " ERROR: $_" }
Write-Output "`n=== Logon Failures (4625) from AD1 ==="
try {
$f = Get-WinEvent -ComputerName AD1 -FilterHashtable @{LogName='Security'; Id=4625; StartTime=(Get-Date).AddDays(-3)} -ErrorAction Stop |
Where-Object { $_.Properties[5].Value -eq 'jlohr' } |
Select-Object -First 30
foreach ($e in $f) {
Write-Output "$($e.TimeCreated) | Source: $($e.Properties[13].Value) ($($e.Properties[19].Value)) | Type: $($e.Properties[10].Value) | Reason: $($e.Properties[8].Value)"
}
if (-not $f) { Write-Output " None found" }
} catch { Write-Output " ERROR: $_" }
# Also check AD2's own logs
Write-Output "`n=== Lockout Events (4740) from AD2 ==="
try {
$l2 = Get-WinEvent -FilterHashtable @{LogName='Security'; Id=4740; StartTime=(Get-Date).AddDays(-7)} -ErrorAction Stop |
Where-Object { $_.Properties[0].Value -eq 'jlohr' } |
Select-Object -First 30
foreach ($e in $l2) {
Write-Output "$($e.TimeCreated) | Caller: $($e.Properties[1].Value)"
}
if (-not $l2) { Write-Output " None found" }
} catch { Write-Output " ERROR: $_" }
} -ErrorAction Stop

View File

@@ -1,27 +0,0 @@
$secPassword = ConvertTo-SecureString 'Paper123!@#' -AsPlainText -Force
$cred = New-Object System.Management.Automation.PSCredential('INTRANET\sysadmin', $secPassword)
Write-Output "Testing Negotiate auth..."
try {
$result = Invoke-Command -ComputerName 192.168.0.27 -Credential $cred -Authentication Negotiate -ScriptBlock { hostname } -ErrorAction Stop
Write-Output "[OK] Negotiate: $result"
} catch {
Write-Output "[FAIL] Negotiate: $_"
}
Write-Output "`nTesting Default auth..."
try {
$result = Invoke-Command -ComputerName 192.168.0.27 -Credential $cred -ScriptBlock { hostname } -ErrorAction Stop
Write-Output "[OK] Default: $result"
} catch {
Write-Output "[FAIL] Default: $_"
}
Write-Output "`nTesting with SessionOption..."
try {
$so = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
$result = Invoke-Command -ComputerName 192.168.0.27 -Credential $cred -Authentication Negotiate -SessionOption $so -ScriptBlock { hostname } -ErrorAction Stop
Write-Output "[OK] SessionOption: $result"
} catch {
Write-Output "[FAIL] SessionOption: $_"
}

27
scripts/extract_batch.py Normal file
View File

@@ -0,0 +1,27 @@
import json
import sys
# Read and extract batch file content
jsonl_file = r'D:\ClaudeTools\imported-conversations\general-work\claude-general\5e058595-cbe5-4373-94ea-728e103504f5.jsonl'
with open(jsonl_file, 'r', encoding='utf-8') as f:
for line_num, line in enumerate(f, 1):
try:
data = json.loads(line)
if 'content' in data:
content_items = data.get('content', [])
for item in content_items:
if isinstance(item, dict) and item.get('type') == 'text':
text = item.get('text', '')
# Look for batch file code
if '@ECHO OFF' in text and ('UPDATE' in text or 'STARTNET' in text or 'AUTOEXEC' in text):
# Find code blocks
if '```' in text:
parts = text.split('```')
for i, p in enumerate(parts):
if '@ECHO OFF' in p or 'REM' in p[:100]:
print(f"=== LINE {line_num}, BLOCK {i} ===")
print(p[:3000])
print("\n" + "="*50 + "\n")
except Exception as e:
pass

View File

@@ -1,183 +0,0 @@
# Fix error logging in Copy-ToNAS function in AD2 Sync-FromNAS.ps1
# Target: 192.168.0.6 (AD2)
# Script: C:\Shares\test\scripts\Sync-FromNAS.ps1
param(
[string]$ComputerName = "192.168.0.6",
[string]$Username = "INTRANET\sysadmin",
[string]$Password = "Paper123!@#",
[string]$ScriptPath = "C:\Shares\test\scripts\Sync-FromNAS.ps1"
)
# Create credential object
$securePassword = ConvertTo-SecureString $Password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential($Username, $securePassword)
Write-Host "[INFO] Connecting to AD2 ($ComputerName) to fix error logging..." -ForegroundColor Cyan
try {
# Execute remote script block
$result = Invoke-Command -ComputerName $ComputerName -Credential $credential -ScriptBlock {
param($ScriptPath)
$output = @{
Success = $false
Message = ""
Before = ""
After = ""
BackupPath = ""
}
# Check if script exists
if (-not (Test-Path $ScriptPath)) {
$output.Message = "Script not found at $ScriptPath"
return $output
}
# Create backup with timestamp
$timestamp = Get-Date -Format "yyyyMMdd_HHmmss"
$backupPath = "$ScriptPath.backup_$timestamp"
try {
Copy-Item -Path $ScriptPath -Destination $backupPath -Force
$output.BackupPath = $backupPath
} catch {
$output.Message = "Failed to create backup: $_"
return $output
}
# Read script content
$content = Get-Content -Path $ScriptPath -Raw
$output.Before = $content
# Find and replace the error logging section
# Original pattern (lines 90-91):
# if ($LASTEXITCODE -ne 0) { Write-Log " SCP ERROR (exit ): $result" }
$originalPattern = '\s*if\s*\(\$LASTEXITCODE\s+-ne\s+0\)\s*\{\s*Write-Log\s+"[^"]*SCP ERROR[^"]*"\s*\}'
$replacement = @"
if (`$LASTEXITCODE -ne 0) {
`$errorMsg = `$result | Out-String
Write-Log " SCP PUSH ERROR (exit `$LASTEXITCODE): `$errorMsg"
}
"@
# Perform replacement
$newContent = $content -replace $originalPattern, $replacement
# Verify something changed
if ($newContent -eq $content) {
# Try alternative pattern match
if ($content -match 'Write-Log\s+"[^"]*SCP ERROR[^"]*exit\s*\)[^"]*"\s*\}') {
# Pattern found but not replaced, try more specific replacement
$lines = $content -split "`r?`n"
$newLines = @()
$i = 0
$replaced = $false
while ($i -lt $lines.Count) {
$line = $lines[$i]
# Look for the error logging line in Copy-ToNAS function
if ($line -match '^\s*if\s*\(\$LASTEXITCODE\s+-ne\s+0\)\s*\{.*SCP ERROR.*\}') {
# Replace this line with multi-line version
$indent = ($line -replace '^(\s*).*', '$1')
$newLines += "$indent`if (`$LASTEXITCODE -ne 0) {"
$newLines += "$indent `$errorMsg = `$result | Out-String"
$newLines += "$indent Write-Log `" SCP PUSH ERROR (exit `$LASTEXITCODE): `$errorMsg`""
$newLines += "$indent}"
$replaced = $true
} else {
$newLines += $line
}
$i++
}
if ($replaced) {
$newContent = $newLines -join "`r`n"
} else {
$output.Message = "Could not find the exact error logging pattern to replace"
return $output
}
} else {
$output.Message = "Could not find the error logging pattern in the script"
return $output
}
}
$output.After = $newContent
# Write updated content
try {
Set-Content -Path $ScriptPath -Value $newContent -Force
$output.Success = $true
$output.Message = "Successfully updated error logging in Copy-ToNAS function"
} catch {
$output.Message = "Failed to write updated script: $_"
# Restore backup
Copy-Item -Path $backupPath -Destination $ScriptPath -Force
return $output
}
# Verify syntax by attempting to parse
try {
$errors = $null
$null = [System.Management.Automation.PSParser]::Tokenize($newContent, [ref]$errors)
if ($errors) {
$output.Message = "Syntax validation found errors: $($errors -join '; ')"
$output.Success = $false
# Restore backup
Copy-Item -Path $backupPath -Destination $ScriptPath -Force
}
} catch {
$output.Message = "Syntax validation failed: $_"
$output.Success = $false
# Restore backup
Copy-Item -Path $backupPath -Destination $ScriptPath -Force
}
return $output
} -ArgumentList $ScriptPath
# Display results
if ($result.Success) {
Write-Host "`n[SUCCESS] $($result.Message)" -ForegroundColor Green
Write-Host "[INFO] Backup created at: $($result.BackupPath)" -ForegroundColor Cyan
# Show before/after comparison
Write-Host "`n--- BEFORE ---" -ForegroundColor Yellow
$beforeLines = $result.Before -split "`r?`n"
$startLine = 0
for ($i = 0; $i -lt $beforeLines.Count; $i++) {
if ($beforeLines[$i] -match 'if\s*\(\$LASTEXITCODE\s+-ne\s+0\).*SCP ERROR') {
$startLine = [Math]::Max(0, $i - 2)
break
}
}
$beforeLines[$startLine..([Math]::Min($startLine + 5, $beforeLines.Count - 1))] | ForEach-Object { Write-Host $_ }
Write-Host "`n--- AFTER ---" -ForegroundColor Green
$afterLines = $result.After -split "`r?`n"
$startLine = 0
for ($i = 0; $i -lt $afterLines.Count; $i++) {
if ($afterLines[$i] -match 'if\s*\(\$LASTEXITCODE\s+-ne\s+0\).*\{' -and $afterLines[$i + 1] -match 'errorMsg') {
$startLine = [Math]::Max(0, $i - 2)
break
}
}
$afterLines[$startLine..([Math]::Min($startLine + 7, $afterLines.Count - 1))] | ForEach-Object { Write-Host $_ }
Write-Host "`n[OK] Error logging fix applied successfully" -ForegroundColor Green
} else {
Write-Host "`n[ERROR] $($result.Message)" -ForegroundColor Red
exit 1
}
} catch {
Write-Host "`n[ERROR] Failed to connect or execute on AD2: $_" -ForegroundColor Red
Write-Host "Error Details: $($_.Exception.Message)" -ForegroundColor Red
exit 1
}
Write-Host "`n[COMPLETE] AD2 error logging fix completed" -ForegroundColor Cyan

File diff suppressed because it is too large Load Diff

View File

@@ -1,639 +0,0 @@
{
"isFallbackPublicClient": true,
"signInAudience": "AzureADMultipleOrgs",
"displayName": "CIPP-SAM",
"web": {
"redirectUris": [
"https://login.microsoftonline.com/common/oauth2/nativeclient",
"https://localhost",
"http://localhost",
"http://localhost:8400"
]
},
"servicePrincipalLockConfiguration": {
"isEnabled": true,
"allProperties": true
},
"requiredResourceAccess": [
{
"resourceAppId": "c5393580-f805-4401-95e8-94b7a6ef2fc2",
"resourceAccess": [
{
"id": "594c1fb6-4f81-4475-ae41-0c394909246c",
"type": "Scope"
}
]
},
{
"resourceAppId": "aeb86249-8ea3-49e2-900b-54cc8e308f85",
"resourceAccess": [
{
"id": "fc946a4f-bc4d-413b-a090-b2c86113ec4f",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000003-0000-0000-c000-000000000000",
"resourceAccess": [
{
"id": "1bfefb4e-e0b5-418b-a88f-73c46d2cc8e9",
"type": "Role"
},
{
"id": "b0afded3-3588-46d8-8b3d-9842eff778da",
"type": "Role"
},
{
"id": "5e1e9171-754d-478c-812c-f1755a9a4c2d",
"type": "Role"
},
{
"id": "f3a65bd4-b703-46df-8f7e-0174fea562aa",
"type": "Role"
},
{
"id": "59a6b24b-4225-4393-8165-ebaec5f55d7a",
"type": "Role"
},
{
"id": "35930dcf-aceb-4bd1-b99a-8ffed403c974",
"type": "Role"
},
{
"id": "cac88765-0581-4025-9725-5ebc13f729ee",
"type": "Role"
},
{
"id": "1138cb37-bd11-4084-a2b7-9f71582aeddb",
"type": "Role"
},
{
"id": "78145de6-330d-4800-a6ce-494ff2d33d07",
"type": "Role"
},
{
"id": "9241abd9-d0e6-425a-bd4f-47ba86e767a4",
"type": "Role"
},
{
"id": "5b07b0dd-2377-4e44-a38d-703f09a0dc3c",
"type": "Role"
},
{
"id": "243333ab-4d21-40cb-a475-36241daa0842",
"type": "Role"
},
{
"id": "e330c4f0-4170-414e-a55a-2f022ec2b57b",
"type": "Role"
},
{
"id": "9255e99d-faf5-445e-bbf7-cb71482737c4",
"type": "Role"
},
{
"id": "8b9d79d0-ad75-4566-8619-f7500ecfcebe",
"type": "Scope"
},
{
"id": "5ac13192-7ace-4fcf-b828-1a26f28068ee",
"type": "Role"
},
{
"id": "19dbc75e-c2e2-444c-a770-ec69d8559fc7",
"type": "Role"
},
{
"id": "dbb9058a-0e50-45d7-ae91-66909b5d4664",
"type": "Role"
},
{
"id": "75359482-378d-4052-8f01-80520e7db3cd",
"type": "Role"
},
{
"id": "bf7b1a76-6e77-406b-b258-bf5c7720e98f",
"type": "Role"
},
{
"id": "62a82d76-70ea-41e2-9197-370581804d09",
"type": "Role"
},
{
"id": "dbaae8cf-10b5-4b86-a4a1-f871c94c6695",
"type": "Role"
},
{
"id": "19da66cb-0fb0-4390-b071-ebc76a349482",
"type": "Role"
},
{
"id": "6931bccd-447a-43d1-b442-00a195474933",
"type": "Role"
},
{
"id": "292d869f-3427-49a8-9dab-8c70152b74e9",
"type": "Role"
},
{
"id": "2cb92fee-97a3-4034-8702-24a6f5d0d1e9",
"type": "Role"
},
{
"id": "b6890674-9dd5-4e42-bb15-5af07f541ae1",
"type": "Role"
},
{
"id": "913b9306-0ce1-42b8-9137-6a7df690a760",
"type": "Role"
},
{
"id": "246dd0d5-5bd0-4def-940b-0421030a5b68",
"type": "Role"
},
{
"id": "be74164b-cff1-491c-8741-e671cb536e13",
"type": "Role"
},
{
"id": "25f85f3c-f66c-4205-8cd5-de92dd7f0cec",
"type": "Role"
},
{
"id": "29c18626-4985-4dcd-85c0-193eef327366",
"type": "Role"
},
{
"id": "01c0a623-fc9b-48e9-b794-0756f8e8f067",
"type": "Role"
},
{
"id": "999f8c63-0a38-4f1b-91fd-ed1947bdd1a9",
"type": "Role"
},
{
"id": "338163d7-f101-4c92-94ba-ca46fe52447c",
"type": "Role"
},
{
"id": "2f6817f8-7b12-4f0f-bc18-eeaf60705a9e",
"type": "Role"
},
{
"id": "230c1aed-a721-4c5d-9cb4-a90514e508ef",
"type": "Role"
},
{
"id": "2a60023f-3219-47ad-baa4-40e17cd02a1d",
"type": "Role"
},
{
"id": "025d3225-3f02-4882-b4c0-cd5b541a4e80",
"type": "Role"
},
{
"id": "04c55753-2244-4c25-87fc-704ab82a4f69",
"type": "Role"
},
{
"id": "bf394140-e372-4bf9-a898-299cfc7564e5",
"type": "Role"
},
{
"id": "34bf0e97-1971-4929-b999-9e2442d941d7",
"type": "Role"
},
{
"id": "19b94e34-907c-4f43-bde9-38b1909ed408",
"type": "Role"
},
{
"id": "a82116e5-55eb-4c41-a434-62fe8a61c773",
"type": "Role"
},
{
"id": "0121dc95-1b9f-4aed-8bac-58c5ac466691",
"type": "Role"
},
{
"id": "4437522e-9a86-4a41-a7da-e380edd4a97d",
"type": "Role"
},
{
"id": "741f803b-c850-494e-b5df-cde7c675a1ca",
"type": "Role"
},
{
"id": "50483e42-d915-4231-9639-7fdb7fd190e5",
"type": "Role"
},
{
"id": "bdfbf15f-ee85-4955-8675-146e8e5296b5",
"type": "Scope"
},
{
"id": "84bccea3-f856-4a8a-967b-dbe0a3d53a64",
"type": "Scope"
},
{
"id": "e4c9e354-4dc5-45b8-9e7c-e1393b0b1a20",
"type": "Scope"
},
{
"id": "b27a61ec-b99c-4d6a-b126-c4375d08ae30",
"type": "Scope"
},
{
"id": "101147cf-4178-4455-9d58-02b5c164e759",
"type": "Scope"
},
{
"id": "cc83893a-e232-4723-b5af-bd0b01bcfe65",
"type": "Scope"
},
{
"id": "9d8982ae-4365-4f57-95e9-d6032a4c0b87",
"type": "Scope"
},
{
"id": "2eadaff8-0bce-4198-a6b9-2cfc35a30075",
"type": "Scope"
},
{
"id": "0c3e411a-ce45-4cd1-8f30-f99a3efa7b11",
"type": "Scope"
},
{
"id": "2b61aa8a-6d36-4b2f-ac7b-f29867937c53",
"type": "Scope"
},
{
"id": "767156cb-16ae-4d10-8f8b-41b657c8c8c8",
"type": "Scope"
},
{
"id": "ebf0f66e-9fb1-49e4-a278-222f76911cf4",
"type": "Scope"
},
{
"id": "d649fb7c-72b4-4eec-b2b4-b15acf79e378",
"type": "Scope"
},
{
"id": "f3bfad56-966e-4590-a536-82ecf548ac1e",
"type": "Scope"
},
{
"id": "885f682f-a990-4bad-a642-36736a74b0c7",
"type": "Scope"
},
{
"id": "41ce6ca6-6826-4807-84f1-1c82854f7ee5",
"type": "Scope"
},
{
"id": "bac3b9c2-b516-4ef4-bd3b-c2ef73d8d804",
"type": "Scope"
},
{
"id": "11d4cd79-5ba5-460f-803f-e22c8ab85ccd",
"type": "Scope"
},
{
"id": "951183d1-1a61-466f-a6d1-1fde911bfd95",
"type": "Scope"
},
{
"id": "280b3b69-0437-44b1-bc20-3b2fca1ee3e9",
"type": "Scope"
},
{
"id": "7b3f05d5-f68c-4b8d-8c59-a2ecd12f24af",
"type": "Scope"
},
{
"id": "0883f392-0a7a-443d-8c76-16a6d39c7b63",
"type": "Scope"
},
{
"id": "3404d2bf-2b13-457e-a330-c24615765193",
"type": "Scope"
},
{
"id": "44642bfe-8385-4adc-8fc6-fe3cb2c375c3",
"type": "Scope"
},
{
"id": "0c5e8a55-87a6-4556-93ab-adc52c4d862d",
"type": "Scope"
},
{
"id": "662ed50a-ac44-4eef-ad86-62eed9be2a29",
"type": "Scope"
},
{
"id": "0e263e50-5827-48a4-b97c-d940288653c7",
"type": "Scope"
},
{
"id": "c5366453-9fb0-48a5-a156-24f0c49a4b84",
"type": "Scope"
},
{
"id": "2f9ee017-59c1-4f1d-9472-bd5529a7b311",
"type": "Scope"
},
{
"id": "4e46008b-f24c-477d-8fff-7bb4ec7aafe0",
"type": "Scope"
},
{
"id": "f81125ac-d3b7-4573-a3b2-7099cc39df9e",
"type": "Scope"
},
{
"id": "9e4862a5-b68f-479e-848a-4e07e25c9916",
"type": "Scope"
},
{
"id": "bb6f654c-d7fd-4ae3-85c3-fc380934f515",
"type": "Scope"
},
{
"id": "e0a7cdbb-08b0-4697-8264-0069786e9674",
"type": "Scope"
},
{
"id": "e383f46e-2787-4529-855e-0e479a3ffac0",
"type": "Scope"
},
{
"id": "a367ab51-6b49-43bf-a716-a1fb06d2a174",
"type": "Scope"
},
{
"id": "818c620a-27a9-40bd-a6a5-d96f7d610b4b",
"type": "Scope"
},
{
"id": "f6a3db3e-f7e8-4ed2-a414-557c8c9830be",
"type": "Scope"
},
{
"id": "7427e0e9-2fba-42fe-b0c0-848c9e6a8182",
"type": "Scope"
},
{
"id": "37f7f235-527c-4136-accd-4a02d197296e",
"type": "Scope"
},
{
"id": "46ca0847-7e6b-426e-9775-ea810a948356",
"type": "Scope"
},
{
"id": "346c19ff-3fb2-4e81-87a0-bac9e33990c1",
"type": "Scope"
},
{
"id": "e67e6727-c080-415e-b521-e3f35d5248e9",
"type": "Scope"
},
{
"id": "4c06a06a-098a-4063-868e-5dfee3827264",
"type": "Scope"
},
{
"id": "572fea84-0151-49b2-9301-11cb16974376",
"type": "Scope"
},
{
"id": "b27add92-efb2-4f16-84f5-8108ba77985c",
"type": "Scope"
},
{
"id": "edb72de9-4252-4d03-a925-451deef99db7",
"type": "Scope"
},
{
"id": "7e823077-d88e-468f-a337-e18f1f0e6c7c",
"type": "Scope"
},
{
"id": "edd3c878-b384-41fd-95ad-e7407dd775be",
"type": "Scope"
},
{
"id": "ad902697-1014-4ef5-81ef-2b4301988e8c",
"type": "Scope"
},
{
"id": "4d135e65-66b8-41a8-9f8b-081452c91774",
"type": "Scope"
},
{
"id": "40b534c3-9552-4550-901b-23879c90bcf9",
"type": "Scope"
},
{
"id": "a8ead177-1889-4546-9387-f25e658e2a79",
"type": "Scope"
},
{
"id": "a84a9652-ffd3-496e-a991-22ba5529156a",
"type": "Scope"
},
{
"id": "14dad69e-099b-42c9-810b-d002981feec1",
"type": "Scope"
},
{
"id": "02e97553-ed7b-43d0-ab3c-f8bace0d040c",
"type": "Scope"
},
{
"id": "b955410e-7715-4a88-a940-dfd551018df3",
"type": "Scope"
},
{
"id": "d01b97e9-cbc0-49fe-810a-750afd5527a3",
"type": "Scope"
},
{
"id": "dc38509c-b87d-4da0-bd92-6bec988bac4a",
"type": "Scope"
},
{
"id": "6aedf524-7e1c-45a7-bd76-ded8cab8d0fc",
"type": "Scope"
},
{
"id": "128ca929-1a19-45e6-a3b8-435ec44a36ba",
"type": "Scope"
},
{
"id": "55896846-df78-47a7-aa94-8d3d4442ca7f",
"type": "Scope"
},
{
"id": "eda39fa6-f8cf-4c3c-a909-432c683e4c9b",
"type": "Scope"
},
{
"id": "aa07f155-3612-49b8-a147-6c590df35536",
"type": "Scope"
},
{
"id": "89fe6a52-be36-487e-b7d8-d061c450a026",
"type": "Scope"
},
{
"id": "7825d5d6-6049-4ce7-bdf6-3b8d53f4bcd0",
"type": "Scope"
},
{
"id": "485be79e-c497-4b35-9400-0e3fa7f2a5d4",
"type": "Scope"
},
{
"id": "4a06efd2-f825-4e34-813e-82a57b03d1ee",
"type": "Scope"
},
{
"id": "2104a4db-3a2f-4ea0-9dba-143d457dc666",
"type": "Scope"
},
{
"id": "0e755559-83fb-4b44-91d0-4cc721b9323e",
"type": "Scope"
},
{
"id": "39d65650-9d3e-4223-80db-a335590d027e",
"type": "Scope"
},
{
"id": "a9ff19c2-f369-4a95-9a25-ba9d460efc8e",
"type": "Scope"
},
{
"id": "b98bfd41-87c6-45cc-b104-e2de4f0dafb9",
"type": "Scope"
},
{
"id": "cac97e40-6730-457d-ad8d-4852fddab7ad",
"type": "Scope"
},
{
"id": "73e75199-7c3e-41bb-9357-167164dbb415",
"type": "Scope"
},
{
"id": "637d7bec-b31e-4deb-acc9-24275642a2c9",
"type": "Scope"
},
{
"id": "204e0828-b5ca-4ad8-b9f3-f32a958e7cc4",
"type": "Scope"
},
{
"id": "48971fc1-70d7-4245-af77-0beb29b53ee2",
"type": "Scope"
},
{
"id": "b7887744-6746-4312-813d-72daeaee7e2d",
"type": "Scope"
},
{
"id": "424b07a8-1209-4d17-9fe4-9018a93a1024",
"type": "Scope"
},
{
"id": "0a42382f-155c-4eb1-9bdc-21548ccaa387",
"type": "Role"
},
{
"id": "2d9bd318-b883-40be-9df7-63ec4fcdc424",
"type": "Role"
},
{
"id": "c8948c23-e66b-42db-83fd-770b71ab78d2",
"type": "Role"
},
{
"id": "a94a502d-0281-4d15-8cd2-682ac9362c4c",
"type": "Role"
}
]
},
{
"resourceAppId": "fa3d9a0c-3fb0-42cc-9193-47c7ecd2edbd",
"resourceAccess": [
{
"id": "1cebfa2a-fb4d-419e-b5f9-839b4383e05a",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000002-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "dc50a0fb-09a3-484d-be87-e023b12c6440",
"type": "Role"
},
{
"id": "ef54d2bf-783f-4e0f-bca1-3210c0444d99",
"type": "Role"
},
{
"id": "f9156939-25cd-4ba8-abfe-7fabcf003749",
"type": "Role"
},
{
"id": "ab4f2b77-0b06-4fc1-a9de-02113fc2ab7c",
"type": "Scope"
},
{
"id": "bbd1ca91-75e0-4814-ad94-9c5dbbae3415",
"type": "Scope"
},
{
"id": "2e83d72d-8895-4b66-9eea-abb43449ab8b",
"type": "Scope"
}
]
},
{
"resourceAppId": "00000003-0000-0ff1-ce00-000000000000",
"resourceAccess": [
{
"id": "56680e0d-d2a3-4ae1-80d8-3c4f2100e3d0",
"type": "Scope"
}
]
},
{
"resourceAppId": "48ac35b8-9aa8-4d74-927d-1f4a14a0b239",
"resourceAccess": [
{
"id": "e60370c1-e451-437e-aa6e-d76df38e5f15",
"type": "Scope"
}
]
},
{
"resourceAppId": "fc780465-2017-40d4-a0c5-307022471b92",
"resourceAccess": [
{
"id": "41269fc5-d04d-4bfd-bce7-43a51cea049a",
"type": "Role"
},
{
"id": "63a677ce-818c-4409-9d12-5c6d2e2a6bfe",
"type": "Scope"
}
]
}
]
}