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:
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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"
|
||||
@@ -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 ""
|
||||
@@ -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"
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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)
|
||||
@@ -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
|
||||
@@ -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 ""
|
||||
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
@@ -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."
|
||||
@@ -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
|
||||
@@ -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}")
|
||||
@@ -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 $_ }
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
|
||||
@@ -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
27
scripts/extract_batch.py
Normal 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
|
||||
@@ -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
|
||||
5375
scripts/perms.json
5375
scripts/perms.json
File diff suppressed because it is too large
Load Diff
639
scripts/sam.json
639
scripts/sam.json
@@ -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"
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user