Files
Sharepoint-Toolbox/.planning/codebase/ARCHITECTURE.md
Kawa 63cf69f114 docs: map existing codebase
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-02 09:28:40 +02:00

13 KiB

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:

    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:

    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