# Architecture

**Analysis Date:** 2026-04-02

## Pattern Overview

**Overall:** Monolithic PowerShell Application with WinForms UI and Async Runspace Pattern

**Key Characteristics:**
- Single-file PowerShell script (6408 lines) serving as entry point
- Native WinForms GUI (no external UI framework dependencies)
- Asynchronous operations via dedicated PowerShell runspaces to prevent UI blocking
- Hashtable-based state management for inter-runspace communication
- PnP.PowerShell module for all SharePoint Online interactions
- Profile and template persistence via JSON files
- Region-based code organization for logical grouping

## Layers

**Presentation Layer (GUI):**
- Purpose: User interface and interaction handling
- Location: `Sharepoint_ToolBox.ps1` lines 2990-3844 (GUI setup) + event handlers
- Contains: WinForms controls, dialogs, input validation, visual updates
- Depends on: Shared helpers, Settings layer
- Used by: Event handlers, runspace callbacks via synchronized hashtable

**Application Layer (Business Logic):**
- Purpose: Core operations for each feature (permissions, storage, templates, search, duplicates)
- Location: `Sharepoint_ToolBox.ps1` multiple regions:
  - Permissions: lines 1784-2001
  - Storage: lines 2002-2110
  - File Search: lines 2112-2233
  - Duplicates: lines 2235-2408
  - Templates: lines 475-1360
  - Transfer/Bulk: lines 2410-3000
- Contains: PnP API calls, data aggregation, report generation
- Depends on: PnP.PowerShell module, Presentation feedback
- Used by: Event handlers via runspaces, HTML/CSV export functions

**Data Access Layer:**
- Purpose: File I/O, persistence, caching
- Location: `Sharepoint_ToolBox.ps1` dedicated regions:
  - Profile Management: lines 48-127
  - Settings: lines 129-154
  - Template Management: lines 475-533
- Contains: JSON serialization/deserialization, profile CRUD, settings management
- Depends on: File system access
- Used by: Application layer, GUI initialization

**Export & Reporting Layer:**
- Purpose: Transform data to CSV and interactive HTML
- Location: `Sharepoint_ToolBox.ps1`:
  - Permissions HTML: lines 1361-1617
  - Storage HTML: lines 1619-1784
  - Search HTML: lines 2112-2233
  - Duplicates HTML: lines 2235-2408
  - Transfer HTML: lines 2412-2547
- Contains: HTML template generation, JavaScript for interactivity, CSV formatting
- Depends on: Application layer data, System.Drawing for styling
- Used by: Feature implementations for export operations

**Integration Layer:**
- Purpose: External service communication (SharePoint, PnP.PowerShell)
- Location: `Sharepoint_ToolBox.ps1` PnP function regions
- Contains: Connect-PnPOnline, Get-PnP* cmdlets, authentication handling
- Depends on: PnP.PowerShell module, credentials from user input
- Used by: Application layer operations

**Utilities & Helpers:**
- Purpose: Cross-cutting formatting, UI helpers, internationalization
- Location: `Sharepoint_ToolBox.ps1`:
  - Shared Helpers: lines 4-46
  - Internationalization: lines 2732-2989
  - UI Control Factories: lines 3119-3146
- Contains: Write-Log, Format-Bytes, EscHtml, T() translator, control builders
- Depends on: System.Windows.Forms, language JSON file
- Used by: All other layers

## Data Flow

**Permissions Report Generation:**

1. User selects site(s) and report options in GUI (Permissions tab)
2. Click "Générer le rapport" triggers event handler at line 4068+
3. Validation via `Validate-Inputs` (line 30)
4. GUI triggers runspace via `Start-Job` with user parameters
5. Runspace calls `Generate-PnPSitePermissionRpt` (line 1852)
6. `Generate-PnPSitePermissionRpt` connects to SharePoint via `Connect-PnPOnline` (line 1864)
7. Recursive permission scanning:
   - `Get-PnPWebPermission` (line 1944) for site/webs
   - `Get-PnPListPermission` (line 1912) for lists and libraries
   - `Get-PnPFolderPermission` (line 1882) for folders (if enabled)
   - `Get-PnPPermissions` (line 1786) extracts individual role assignments
8. Results accumulated in `$script:AllPermissions` array
9. Export based on format choice:
   - CSV: `Merge-PermissionRows` (line 1363) then `Export-Csv`
   - HTML: `Export-PermissionsToHTML` (line 1389) generates interactive report
10. Output file path returned to UI via synchronized hashtable
11. User can open report via `btnPermOpen` click handler

**Storage Metrics Scan:**

1. User selects storage options and sites
2. Click "Générer les métriques" triggers runspace job
3. Job calls `Get-SiteStorageMetrics` (line 2004)
4. Per-site or per-library scanning:
   - Connect to web via `Connect-PnPOnline`
   - `Get-PnPList` retrieves document libraries (if per-library mode)
   - `Get-PnPFolderStorageMetric` for library/root metrics
   - `Collect-FolderStorage` (recursive nested function) walks folder tree to configured depth
5. Results accumulate in `$script:storageResults` with hierarchy intact
6. HTML or CSV export writes report file
7. File path communicated back to UI

**Site Picker (Browse Sites):**

1. User clicks "Voir les sites" button
2. `Show-SitePicker` dialog opens (line 212)
3. User clicks "Charger les sites" button
4. Dialog initializes `$script:_pkl` state hashtable (line 315)
5. Runspace spawned in `btnLoad.Add_Click` (line 395)
6. Runspace connects to admin site and retrieves all sites via `Get-PnPTenantSite`
7. Results queued back to UI via synchronized `$script:_pkl.Sync` hashtable
8. Timer polls `$script:_pkl.Sync` and updates ListView asynchronously
9. User filters by text, sorts columns, checks/unchecks sites
10. Returns selected site URLs in `$script:SelectedSites` array

**File Search:**

1. User enters search criteria (extensions, regex, date ranges, etc.)
2. Click "Lancer la recherche" triggers runspace
3. Runspace uses PnP Search API (KQL) with filters:
   - File extension filters via `fileExtension:ext1` OR syntax
   - Date range filters via `Created >= date`
   - Regex applied client-side after retrieval
4. Results paginated and accumulated
5. Exported to CSV or HTML with interactive filtering/sorting

**Duplicate Detection:**

1. User chooses file or folder mode and comparison criteria
2. Click "Lancer le scan" triggers runspace
3. File duplicates: Search API with filename-based grouping
4. Folder duplicates: Enumerate all folders, compare attributes (size, dates, subfolder/file counts)
5. Results grouped by match criteria
6. HTML export shows grouped duplicates with visual indicators (green/orange for matching/differing fields)

**Template Capture & Apply:**

1. Capture mode: `Show-TemplateManager` dialog (line 542)
   - User selects "Capture from site"
   - Runspace scans site structure via `Get-PnPList`, `Get-PnPFolderItem`, `Get-PnPWebPermission`
   - Captures libraries, folders, permission groups, site logo, title
   - Persisted to `Sharepoint_Templates.json`
2. Apply mode: User selects template and target site
   - Runspace creates lists/libraries via `New-PnPList`
   - Replicates folder structure via `New-PnPFolder`
   - Applies permission groups if selected
   - Logs creation results

**State Management:**

- `$script:` variables hold state across runspace calls (profiles, sites, results, settings)
- Synchronized hashtables (`$script:_pkl`, `$script:_sync`) enable runspace-to-UI communication
- Timer at line 3850-3870 polls synchronized hashtable and updates GUI with progress/results
- Event handlers trigger jobs but don't block waiting for completion (asynchronous pattern)

## Key Abstractions

**Runspace Encapsulation:**

- Purpose: Execute long-running SharePoint operations without freezing GUI
- Pattern: `$job = Start-Job -ScriptBlock { ... } -RunspacePool $rsPool`
- Example: `Start-NextStorageScan` (line 4536) manages storage scan runspace jobs
- Trade-off: Requires careful state management via shared hashtables; no direct closures

**Hashtable-Based State:**

- Purpose: Share mutable state between main runspace and job runspaces
- Pattern: `$sync = @{ Data = @(); Status = "Running" }` passed to job
- Example: `$script:_pkl` (line 315) manages site picker state across checkbox events
- Benefit: Avoids closure complexity; timer can poll changes safely

**Dialog Modal Isolation:**

- Purpose: Site picker and template manager as isolated UI contexts
- Pattern: `Show-SitePicker` and `Show-TemplateManager` create self-contained `Form` objects
- State stored in `$script:_pkl` and `$script:_tpl` respectively
- Returns result arrays (selected sites, template data) to main form

**Language Translation System:**

- Purpose: Internationalization without external dependencies
- Pattern: `T("key")` function (line 2908) looks up keys in `$script:LangDict` hashtable
- Source: `lang/fr.json` contains French translations; English is hardcoded
- Used throughout: All UI labels, buttons, messages use `T()` for localization

**HTML Export Templates:**

- Purpose: Dynamically generate interactive HTML reports with embedded JavaScript
- Pattern: String templates with `@"` heredoc syntax containing HTML/CSS/JS
- Examples:
  - `Export-PermissionsToHTML` (line 1389): Responsive table, collapsible groups, copy-to-clipboard
  - `Export-StorageToHTML` (line 1621): Tree visualization, sorting, filtering
  - `Export-DuplicatesToHTML` (line 2235): Grouped duplicates with visual indicators
- Benefit: No external libraries; reports are self-contained single-file HTML

## Entry Points

**Main GUI Form:**
- Location: `Sharepoint_ToolBox.ps1` line 2992
- Triggers: Script execution via `.ps1` file or PowerShell IDE
- Responsibilities:
  - Initialize WinForms components (form, controls, menus)
  - Load and populate profiles/settings from JSON
  - Register event handlers for all buttons and controls
  - Run main event loop `[void]$form.ShowDialog()`

**Feature Event Handlers:**
- Location: Various in lines 4068+ (Event Handlers region)
- Examples:
  - `btnPermRun.Add_Click` → Permissions report generation
  - `btnStorRun.Add_Click` → Storage metrics scan
  - `btnSearchRun.Add_Click` → File search
  - `btnDupRun.Add_Click` → Duplicate detection
- Pattern: Validate inputs, start runspace job, launch progress animation, register cleanup callback

**Background Runspaces:**
- Entry: `Start-Job -ScriptBlock { Generate-PnPSitePermissionRpt ... }`
- Execution: PnP cmdlets execute within runspace's isolated context
- Completion: Job completion callback writes results to synchronized hashtable; timer detects and updates UI

**Language Switch:**
- Location: Menu → Language submenu (line 3011+)
- Handler: `Switch-AppLanguage` (line 4167)
- Updates: All UI labels via `Update-UILanguage` (line 2951)

## Error Handling

**Strategy:** Try/Catch with graceful degradation; errors logged to UI RichTextBox

**Patterns:**

1. **Runspace Error Handling:**
   ```powershell
   try { $result = Get-PnPList }
   catch { Write-Log "Error: $($_.Exception.Message)" "Red" }
   ```

2. **Connection Validation:**
   - `Validate-Inputs` (line 30) checks required fields before operation
   - `Connect-PnPOnline` fails if credentials invalid; caught and logged

3. **File I/O Protection:**
   ```powershell
   if (Test-Path $path) {
       try { $data = Get-Content $path -Raw | ConvertFrom-Json }
       catch {} # Silently ignore JSON parse errors
   }
   ```

4. **UI Update Safety:**
   - `Write-Log` checks `if ($script:LogBox -and !$script:LogBox.IsDisposed)` before updating
   - Prevents access to disposed UI objects after form close

5. **Missing Configuration Handling:**
   - Settings default to English + current directory if file missing
   - Profiles default to empty array if file missing
   - Templates default to empty if file corrupted

## Cross-Cutting Concerns

**Logging:**
- Framework: `Write-Log` function (line 6)
- Pattern: Writes colored messages to RichTextBox + host console
- Usage: All operations log status (connecting, scanning, exporting)
- Timestamps: `Get-Date -Format 'HH:mm:ss'` prefixes each message

**Validation:**
- Entry point: `Validate-Inputs` (line 30) checks ClientID and Site URL
- Pattern: Early return if missing; user sees MessageBox with missing field hint
- Localization: Error messages use `T()` function for i18n

**Authentication:**
- Method: Interactive browser login via `Connect-PnPOnline -Interactive`
- Pattern: PnP module opens browser for Azure AD consent; token cached within session
- Credential scope: Per site connection; multiple connections supported (for multi-site operations)
- Token management: Automatic via PnP.PowerShell; no manual handling

**Asynchronous Progress:**
- Animation: `Start-ProgressAnim` (line 3845) flashes "Running..." in status label
- Polling: Timer at line 3850-3870 checks `$job.State` and synchronized hashtable every 300ms
- Cleanup: `Stop-ProgressAnim` (line 3850) stops animation when job completes

**UI Responsiveness:**
- Pattern: `[System.Windows.Forms.Application]::DoEvents()` called during long operations
- Benefit: Allows UI events (button clicks, close) to process while waiting
- Cost: Runspace jobs recommended for truly long operations (>5 second operations)

---

*Architecture analysis: 2026-04-02*
