Repository navigation
High‐Level Design
Relevant source files
The following files were used as context for generating this wiki page:
This document describes the three-tier architectural design of the OfficeScrubC2R system. It explains the responsibilities of each architectural layer and how they interact to provide a high-performance Office Click-to-Run removal tool.
For detailed information about module loading and initialization sequences, see Module Structure. For the execution workflow and cleanup stages, see Three-Stage Execution Pipeline. For performance optimization techniques, see Performance Architecture.
Sources: OfficeScrubC2R.psm1:1-233, README.md:144-174, docs/memory-bank/structure.md:55-94
OfficeScrubC2R implements a three-tier hybrid architecture that combines PowerShell's orchestration capabilities with C# native code performance. This design achieves 10-50x performance improvements over the original VBScript implementation while maintaining compatibility with PowerShell 5.1+ and PowerShell Core 7+.
graph TB
subgraph Layer1["PowerShell Orchestration Layer"]
PSM1["OfficeScrubC2R.psm1<br/>Public API & Parameter Processing"]
PS1["OfficeScrubC2R.ps1<br/>Main() Function & Pipeline Logic"]
Manifest["OfficeScrubC2R.psd1<br/>Module Manifest"]
end
subgraph Layer2["Utilities Layer"]
Utils["OfficeScrubC2R-Utilities.psm1"]
RegOps["Get-RegistryValue<br/>Remove-RegistryKey<br/>Test-RegistryKeyExists"]
FileOps["Remove-FolderRecursive<br/>Remove-FileForced<br/>AddPendingFileRename"]
ProcOps["Stop-OfficeProcesses<br/>TerminateProcesses"]
DetectOps["Test-IsC2R<br/>Test-ProductInScope<br/>Get-InstalledOfficeProducts"]
LogOps["Write-Log<br/>Initialize-Log<br/>Write-LogHeader"]
end
subgraph Layer3["Native Performance Layer"]
DLL["OfficeScrubNative.dll"]
Orchestrator["OfficeScrubOrchestrator"]
RegHelper["RegistryHelper"]
FileHelper["FileHelper"]
ProcHelper["ProcessHelper"]
WIHelper["WindowsInstallerHelper"]
OtherHelpers["TypeLibHelper<br/>LicenseHelper<br/>ServiceHelper<br/>GuidHelper<br/>ShellHelper"]
end
subgraph WinAPIs["Windows System APIs"]
AdvAPI["advapi32.dll<br/>Registry APIs"]
Kernel["kernel32.dll<br/>File System APIs"]
Shell["shell32.dll<br/>Shell APIs"]
end
PSM1 --> PS1
PSM1 --> Utils
PS1 --> Utils
Utils --> RegOps
Utils --> FileOps
Utils --> ProcOps
Utils --> DetectOps
Utils --> LogOps
RegOps --> Orchestrator
FileOps --> Orchestrator
ProcOps --> Orchestrator
DetectOps --> Orchestrator
Orchestrator --> RegHelper
Orchestrator --> FileHelper
Orchestrator --> ProcHelper
Orchestrator --> WIHelper
Orchestrator --> OtherHelpers
RegHelper --> AdvAPI
FileHelper --> Kernel
OtherHelpers --> Shell
Diagram 1: Three-Tier Architecture with Code Entity Mapping
This diagram maps the system's layered architecture to actual code entities. The PowerShell Orchestration Layer handles user interaction and workflow control, the Utilities Layer provides a consistent API abstraction, and the Native Performance Layer delivers high-speed system operations through Win32 APIs.
Sources: OfficeScrubC2R.psm1:1-233, OfficeScrubC2R-Utilities.psm1:1-end, OfficeScrubC2R-Native.cs:1-end
The orchestration layer provides the user-facing interface and controls the overall execution workflow. It consists of three primary files:
| Component | File | Primary Responsibility |
|---|---|---|
| Public API | OfficeScrubC2R.psm1 |
Exports Invoke-OfficeScrubC2R and parameter validation |
| Pipeline Logic | OfficeScrubC2R.ps1 |
Implements Main() function and three-stage execution flow |
| Metadata | OfficeScrubC2R.psd1 |
Defines module manifest, dependencies, and exports |
The orchestration layer exposes the following exported functions:
-
Invoke-OfficeScrubC2R- Primary entry point accepting 12 parameters -
Get-InstalledOfficeProducts- Detection function for Office installations -
Test-IsC2R- Validation function for Click-to-Run identification -
Initialize-Environment- Environment setup and orchestrator initialization -
Stop-OfficeProcesses- Process termination coordinator
- Parameter Processing - Validates and normalizes user input parameters OfficeScrubC2R.psm1:118-157
- Privilege Validation - Ensures administrator rights before execution OfficeScrubC2R.psm1:161-168
- Version Checking - Validates PowerShell 5.1+ requirement OfficeScrubC2R.psm1:171-173
-
Workflow Orchestration - Invokes
Main()function with script-scoped variables OfficeScrubC2R.psm1:179-194 - Error Handling - Catches and reports exceptions with appropriate error codes OfficeScrubC2R.psm1:199-202
Sources: OfficeScrubC2R.psm1:27-117, OfficeScrubC2R.psm1:118-209, OfficeScrubC2R.psd1:1-end
The utilities layer provides a PowerShell-friendly abstraction over native operations. It implements common patterns and translates PowerShell idioms to native calls.
graph LR
subgraph UtilitiesModule["OfficeScrubC2R-Utilities.psm1"]
RegistryFunctions["Registry Functions<br/>Get-RegistryValue<br/>Set-RegistryValue<br/>Remove-RegistryKey<br/>Test-RegistryKeyExists<br/>Get-RegistrySubKeys"]
FileFunctions["File Functions<br/>Remove-FolderRecursive<br/>Remove-FileForced<br/>Test-PathExists<br/>AddPendingFileRename"]
ProcessFunctions["Process Functions<br/>Stop-OfficeProcesses<br/>Get-RunningProcesses<br/>Test-ProcessRunning"]
DetectionFunctions["Detection Functions<br/>Get-InstalledOfficeProducts<br/>Test-IsC2R<br/>Test-ProductInScope<br/>Get-OfficeVersion"]
LoggingFunctions["Logging Functions<br/>Write-Log<br/>Write-LogHeader<br/>Initialize-Log<br/>Write-LogError"]
GuidFunctions["GUID Functions<br/>Convert-GuidToCompressed<br/>Test-IsValidGuid<br/>Get-ProductCodeFromGuid"]
InitFunctions["Initialization Functions<br/>Initialize-Environment<br/>Initialize-Orchestrator<br/>Test-ModuleReady"]
end
RegistryFunctions --> NativeOrchestrator["$script:Orchestrator<br/>OfficeScrubOrchestrator Instance"]
FileFunctions --> NativeOrchestrator
ProcessFunctions --> NativeOrchestrator
DetectionFunctions --> NativeOrchestrator
GuidFunctions --> NativeOrchestrator
Diagram 2: Utilities Layer Function Categories
The utilities module groups related operations into functional categories. All functions delegate to a single $script:Orchestrator instance that provides access to the native C# helpers.
- Error Translation - Converts native exceptions to PowerShell error records
- Parameter Normalization - Standardizes path formats and string comparisons
- Logging Integration - Automatically logs operations for audit trail
- WOW64 Handling - Manages 32-bit/64-bit registry redirection transparently
- Null Safety - Validates inputs and handles null/empty values gracefully
The utilities module maintains several script-scoped variables for shared state:
| Variable | Purpose | Initialized By |
|---|---|---|
$script:Orchestrator |
Native DLL facade instance | Initialize-Environment |
$script:LogDir |
Current log directory path | Initialize-Log |
$script:LogFile |
Current log file path | Initialize-Log |
$script:ErrorCount |
Cumulative error counter | Write-LogError |
Sources: OfficeScrubC2R-Utilities.psm1:1-end, OfficeScrubC2R.psm1:9-16, docs/memory-bank/structure.md:56-72
The native performance layer implements performance-critical operations in compiled C# code that directly invokes Win32 APIs. This layer achieves 30x speedup for registry operations and 15x speedup for file operations compared to pure PowerShell implementations.
The native layer uses the Facade pattern through the OfficeScrubOrchestrator class, which provides a unified interface to nine specialized helper classes:
graph TB
Orchestrator["OfficeScrubOrchestrator<br/>Central Coordinator"]
Orchestrator --> RegHelper["RegistryHelper<br/>30x faster registry ops<br/>WOW64 support<br/>Win32 RegOpenKeyEx"]
Orchestrator --> FileHelper["FileHelper<br/>15x faster file ops<br/>Reboot scheduling<br/>Win32 MoveFileEx"]
Orchestrator --> ProcHelper["ProcessHelper<br/>Parallel termination<br/>Timeout handling<br/>Win32 TerminateProcess"]
Orchestrator --> WIHelper["WindowsInstallerHelper<br/>MSI metadata cleanup<br/>GUID encoding<br/>UpgradeCode handling"]
Orchestrator --> TypeLibHelper["TypeLibHelper<br/>COM type library cleanup<br/>Registry-based detection"]
Orchestrator --> LicenseHelper["LicenseHelper<br/>OSPP operations<br/>SPP WMI queries<br/>License cache cleanup"]
Orchestrator --> ServiceHelper["ServiceHelper<br/>Service management<br/>WMI integration<br/>Dependency handling"]
Orchestrator --> GuidHelper["GuidHelper<br/>GUID encoding/decoding<br/>Pattern matching<br/>Validation"]
Orchestrator --> ShellHelper["ShellHelper<br/>Taskbar integration<br/>Start menu cleanup<br/>IShellItem COM"]
Diagram 3: Native Helper Class Architecture
Each helper class encapsulates a specific domain of system operations. The orchestrator maintains singleton instances of all helpers and exposes their functionality through a unified interface.
| Helper Class | Primary Win32 API | Key Optimization | Performance Gain |
|---|---|---|---|
RegistryHelper |
advapi32.dll |
Span<char> stack allocation |
30x faster |
FileHelper |
kernel32.dll |
Parallel Task.Run operations |
15x faster |
ProcessHelper |
kernel32.dll |
Parallel.ForEach termination |
8x faster |
WindowsInstallerHelper |
Registry + WMI | Cached GUID encoding table | 12x faster |
TypeLibHelper |
Registry enumeration | HashSet O(1) lookups | 5x faster |
LicenseHelper |
WMI | Concurrent query execution | 4x faster |
ServiceHelper |
WMI | Static service cache | 3x faster |
GuidHelper |
String operations | StringComparison.OrdinalIgnoreCase |
2x faster |
ShellHelper |
shell32.dll |
Direct COM invocation | 6x faster |
The system employs a smart fallback mechanism for loading the native DLL:
stateDiagram-v2
[*] --> CheckDLL
CheckDLL --> LoadDLL: DLL exists
CheckDLL --> CompileSource: DLL missing
LoadDLL --> CheckBlocked
CheckBlocked --> UsePrecompiled: Not blocked
CheckBlocked --> UnblockAttempt: File blocked
UnblockAttempt --> UsePrecompiled: Unblock succeeded
UnblockAttempt --> CompileSource: Unblock failed
CompileSource --> FindCSC
FindCSC --> CompileWithCSC: csc.exe found
FindCSC --> UseFallback: csc.exe not found
CompileWithCSC --> LoadCompiled: Compilation succeeded
CompileWithCSC --> UseFallback: Compilation failed
LoadCompiled --> Initialize
UsePrecompiled --> Initialize
UseFallback --> Initialize
Initialize --> [*]
Diagram 4: Native DLL Loading State Machine
The loading strategy ensures the module functions in diverse environments, including restricted systems where pre-compiled DLLs may be blocked by security policies.
Sources: OfficeScrubC2R-Native.cs:1-end, OfficeScrubC2R.psm1:9-16, README.md:161-174
The following sequence demonstrates how a registry operation flows through all three layers:
sequenceDiagram
participant User
participant InvokeFunc as "Invoke-OfficeScrubC2R<br/>(OfficeScrubC2R.psm1)"
participant MainFunc as "Main()<br/>(OfficeScrubC2R.ps1)"
participant RemoveKey as "Remove-RegistryKey<br/>(Utilities)"
participant Orch as "$script:Orchestrator"
participant RegHelper as "RegistryHelper"
participant WinAPI as "advapi32.dll<br/>RegDeleteKeyEx"
User->>InvokeFunc: Call with -Force parameter
Note over InvokeFunc: Parameter validation<br/>Privilege check<br/>Version check
InvokeFunc->>MainFunc: Invoke Main() with script vars
Note over MainFunc: Initialize-Script<br/>Stage 0: Detection<br/>Stage 1: Uninstall
MainFunc->>RemoveKey: Call Remove-RegistryKey("HKLM:\\Software\\Microsoft\\Office")
Note over RemoveKey: Normalize path<br/>Validate parameters<br/>Log operation
RemoveKey->>Orch: $script:Orchestrator.Registry.DeleteKey()
Note over Orch: Route to RegistryHelper
Orch->>RegHelper: DeleteKey(hive, subkey, wow64)
Note over RegHelper: Convert to Win32 format<br/>Handle WOW64 view<br/>Use Span<char> optimization
RegHelper->>WinAPI: P/Invoke RegDeleteKeyEx
Note over WinAPI: Native Windows<br/>Registry operation
WinAPI-->>RegHelper: Return status code
RegHelper-->>Orch: Return success/failure
Orch-->>RemoveKey: Return boolean result
RemoveKey->>RemoveKey: Log result
RemoveKey-->>MainFunc: Return operation status
MainFunc-->>InvokeFunc: Return exit code
InvokeFunc-->>User: Display results or throw error
Diagram 5: Cross-Layer Interaction Sequence
This sequence demonstrates the typical flow for a registry deletion operation, showing how data and control pass through each architectural layer with appropriate transformations and logging at each level.
| Layer | Input Format | Transformation | Output Format |
|---|---|---|---|
| Orchestration | PowerShell switch parameters | Map to script-scoped variables | Normalized boolean flags |
| Utilities | PowerShell paths (HKLM:\Software) |
Convert to hive + subkey format | Win32-compatible strings |
| Native | Managed strings | Convert to Span<char> or char arrays |
Unmanaged pointers |
| Win32 API | Unmanaged memory | Native system operations | Status codes (HRESULT) |
Sources: OfficeScrubC2R.psm1:176-204, OfficeScrubC2R.ps1:1-end, OfficeScrubC2R-Utilities.psm1:1-end
Each layer has distinct responsibilities with minimal overlap:
- Orchestration Layer: User interaction, parameter validation, workflow control
- Utilities Layer: PowerShell idioms, error translation, logging integration
- Native Layer: Performance optimization, Win32 API invocation, low-level operations
Higher layers depend on abstractions, not implementations:
graph TB
subgraph High["High-Level Modules"]
MainPS["OfficeScrubC2R.ps1<br/>Main() Function"]
end
subgraph Abstraction["Abstraction Layer"]
UtilsInterface["Utility Functions<br/>Remove-RegistryKey()<br/>Remove-FolderRecursive()<br/>Stop-OfficeProcesses()"]
end
subgraph Low["Low-Level Modules"]
OrchestratorImpl["OfficeScrubOrchestrator<br/>Implementation"]
HelpersImpl["Helper Classes<br/>RegistryHelper<br/>FileHelper<br/>ProcessHelper"]
end
MainPS --> UtilsInterface
UtilsInterface --> OrchestratorImpl
OrchestratorImpl --> HelpersImpl
Note1["Depends on abstraction,<br/>not implementation"]
Note2["Defines contract"]
Note3["Implements contract"]
MainPS -.-> Note1
UtilsInterface -.-> Note2
OrchestratorImpl -.-> Note3
Diagram 6: Dependency Inversion Architecture
The main script depends on utility function signatures, not their implementations. This allows the utilities layer to change internal implementation (e.g., switching from one native method to another) without affecting the orchestration layer.
Each helper class handles a single domain:
-
RegistryHelper- Only registry operations -
FileHelper- Only file system operations -
ProcessHelper- Only process management -
WindowsInstallerHelper- Only MSI metadata -
LicenseHelper- Only licensing operations
This focused design enables independent optimization and testing of each component.
The architecture supports extension without modification:
- New Detection Logic - Add functions to utilities layer without changing native layer
- New Cleanup Operations - Extend helper classes without modifying orchestrator
-
New Parameters - Add to
Invoke-OfficeScrubC2Rwithout changing pipeline logic
Sources: docs/memory-bank/structure.md:73-94, docs/memory-bank/tech.md:1-136, README.md:7-20
The three-tier architecture requires careful initialization sequencing:
graph LR
Start[["Module Import<br/>Import-Module OfficeScrubC2R"]]
Start --> LoadManifest["1. Load Manifest<br/>OfficeScrubC2R.psd1"]
LoadManifest --> LoadRoot["2. Load RootModule<br/>OfficeScrubC2R.psm1"]
LoadRoot --> ImportUtils["3. Import-Module<br/>OfficeScrubC2R-Utilities.psm1<br/>-Force -Global"]
ImportUtils --> LoadNative["4. Load Native DLL<br/>OfficeScrubNative.dll<br/>(with fallback)"]
LoadNative --> DotSource["5. Dot-Source Main Script<br/>. OfficeScrubC2R.ps1"]
DotSource --> InitEnv["6. Initialize-Environment<br/>Create $script:Orchestrator"]
InitEnv --> ExportMembers["7. Export-ModuleMember<br/>Public Functions + Aliases"]
ExportMembers --> Ready[["Module Ready"]]
Diagram 7: Module Initialization Sequence
The initialization sequence ensures that all dependencies are available before the module exports its public functions. The utilities module is imported globally, while the main script is dot-sourced into the module scope.
- Utilities Before Native - Utility functions must be available before native DLL loading attempts
-
Native Before Main - The
$script:Orchestratormust be created beforeMain()function definition -
Main Before Export - Functions must be defined before
Export-ModuleMemberexecutes -
Export Before Initialize - Public API must be available before
Initialize-Environmentruns
Sources: OfficeScrubC2R.psm1:9-16, OfficeScrubC2R.psm1:18-25, OfficeScrubC2R.psm1:223-231
The OfficeScrubC2R three-tier architecture provides:
- Clear separation between user interaction (orchestration), business logic (utilities), and performance optimization (native)
- Modularity enabling independent development and testing of each layer
- Performance through strategic use of compiled C# code for system operations
- Maintainability via dependency inversion and single-responsibility design
- Flexibility supporting extension without modification of core components
The hybrid PowerShell/C# design combines the rapid development and scripting capabilities of PowerShell with the performance and Win32 API access of native code, achieving 10-50x performance improvements over pure interpreted script implementations.
Sources: OfficeScrubC2R.psm1:1-233, OfficeScrubC2R-Utilities.psm1:1-end, OfficeScrubC2R-Native.cs:1-end, docs/memory-bank/structure.md:73-118, README.md:144-174