Skip to content

Overview

Calvindd2f edited this page Jan 14, 2026 · 1 revision

Overview

Relevant source files

The following files were used as context for generating this wiki page:

OfficeScrubC2R is a PowerShell module that wraps a native C# library (OfficeScrubNative.dll) to perform deep cleanup of Microsoft Office Click-to-Run installations. The module serves as a replacement for Microsoft's legacy OffScrubC2R.vbs (v2.19) with 10-50x performance improvements through compiled code and direct Windows API access.

What Problem Does It Solve?

Office Click-to-Run installations occasionally fail to uninstall through standard Windows mechanisms (Programs and Features, ODT uninstall, or setup.exe /uninstall). When this occurs, residual registry keys, files, Windows Installer metadata, and COM registrations prevent clean reinstallation. OfficeScrubC2R provides forensic-level cleanup across eight Windows subsystems: Registry (HKLM/HKCU/HKCR with WOW64 support), File System (with locked file handling), Processes, Services, Windows Installer metadata, COM Type Libraries, Software Protection Platform (SPP/OSPP), and Shell Integration.

Why Does It Exist?

Microsoft's original VBScript solution (OffScrubC2R.vbs) suffers from performance limitations inherent to interpreted scripting and COM automation. The PowerShell/C# hybrid architecture achieves dramatic performance gains through:

  • Compiled C# Code: Native OfficeScrubNative.dll replaces interpreted VBScript
  • Direct Win32 APIs: P/Invoke to advapi32.dll, kernel32.dll, shell32.dll bypasses COM overhead
  • Parallel Processing: Multi-threaded operations via Task.Run() and Task.WaitAll()
  • Optimized Data Structures: HashSet<string> for O(1) lookups vs. linear array scans
  • Static Caching: Reduced repetitive API calls in registry enumeration

Sources: README.md:1-14, OfficeScrubC2R.psd1:24-26, docs/memory-bank/product.md:1-11

Capabilities and Scope

The system targets Office 2013, 2016, 2019, and Office 365 Click-to-Run installations on Windows 7 SP1 through Windows 11 (both x86 and x64 architectures).

Core Cleanup Operations

Subsystem Implemented By Key Operations
Registry RegistryHelper Recursive key deletion across HKLM, HKCU, HKCR with WOW64 dual-path access (KEY_WOW64_64KEY, KEY_WOW64_32KEY)
File System FileHelper Directory deletion with cmd.exe rd /s /q optimization; locked file handling via MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT)
Processes ProcessHelper Parallel process termination via Task.Run(); GetProcessesUsingPath() for file lock detection
Windows Installer WindowsInstallerHelper Product/Component/UpgradeCode cleanup using GUID transformation (GetExpandedGuid, GetCompressedGuid, GetDecodedGuid)
COM Type Libraries TypeLibHelper Unregister type libraries from HKCR\TypeLib and HKCR\Interface
SPP/OSPP Licensing LicenseHelper Clear Office Software Protection Platform tokens (optional via -KeepLicense parameter)
Shell Integration ShellHelper Remove published components, taskbar pins, start menu items using Shell.Application COM object
Services ServiceHelper Delete Office-related Windows services via WMI

Sources: docs/memory-bank/product.md:14-24, OfficeScrubC2R.psd1:58-64

System Architecture

OfficeScrubC2R implements a two-layer hybrid architecture: a PowerShell wrapper layer for user interaction and a native C# library for performance-critical operations.

Architecture Overview

graph TB
    subgraph PowerShell["PowerShell Module Layer"]
        PSM["OfficeScrubC2R.psm1"]
        PSD1["OfficeScrubC2R.psd1"]
    end
    
    subgraph Native["Native C# Layer (OfficeScrubNative.dll)"]
        ORCH["OfficeScrubOrchestrator"]
        
        subgraph Helpers["Helper Classes"]
            REG["RegistryHelper"]
            FILE["FileHelper"]
            PROC["ProcessHelper"]
            WI["WindowsInstallerHelper"]
            TL["TypeLibHelper"]
            LIC["LicenseHelper"]
            SVC["ServiceHelper"]
            SH["ShellHelper"]
            GUID["GuidHelper"]
        end
    end
    
    subgraph Win32["Windows APIs"]
        ADVAPI["advapi32.dll<br/>RegOpenKeyEx<br/>RegDeleteKeyEx"]
        KERNEL["kernel32.dll<br/>MoveFileEx<br/>TerminateProcess"]
        SHELL["shell32.dll<br/>Shell.Application"]
    end
    
    PSM --> ORCH
    PSD1 --> PSM
    
    ORCH --> REG
    ORCH --> FILE
    ORCH --> PROC
    ORCH --> WI
    ORCH --> TL
    ORCH --> LIC
    ORCH --> SVC
    ORCH --> SH
    ORCH --> GUID
    
    REG --> ADVAPI
    FILE --> KERNEL
    PROC --> KERNEL
    SH --> SHELL
Loading

Layer 1: PowerShell Module

The module OfficeScrubC2R.psm1:1-157 provides five exported functions:

  • Import-OfficeScrubNative - Loads OfficeScrubNative.dll from the module directory
  • New-OfficeScrubOrchestrator - Creates an OfficeScrubOrchestrator instance with system bitness detection
  • Test-OfficeC2RPath - Validates Click-to-Run installation paths
  • Test-OfficeProductScope - Determines if a product code should be removed
  • Get-OfficeScrubHelpers - Exposes helper class instances for direct use

Layer 2: Native C# Library

OfficeScrubNative.dll contains the OfficeScrubOrchestrator class (central coordinator) and eight specialized helper classes. Each helper encapsulates operations for a specific Windows subsystem with direct P/Invoke to Win32 APIs. The GuidHelper class provides static utility methods for Windows Installer GUID transformations.

For detailed architecture documentation, see Architecture.

Sources: OfficeScrubC2R.psm1:1-157, OfficeScrubC2R.psd1:1-157, README.md:3-34, docs/memory-bank/guidelines.md:44-67

Performance Improvements

The native C# implementation delivers 10-50x performance gains over the original VBScript through five optimization strategies:

Optimization Implementation Benefit
Compiled Code C# compiled to MSIL vs. interpreted VBScript Eliminates script parsing overhead
Direct Win32 APIs P/Invoke to advapi32.dll, kernel32.dll vs. COM automation Removes COM marshaling layer
HashSet Collections HashSet<string> with StringComparer.OrdinalIgnoreCase O(1) lookups vs. O(n) array scans
Parallel Processing Task.Run() for process termination Multi-core utilization
Optimized Algorithms cmd.exe rd /s /q for directories 15x faster than recursive .NET deletion

Typical Performance

Operation VBScript Time Native C# Time Improvement
Registry enumeration (5000+ keys) ~10 seconds ~0.3 seconds 30x
File deletion (large directories) ~15 seconds ~1 second 15x
Complete Office removal 5-10 minutes 30-60 seconds 10-50x

For detailed performance architecture, see Performance Architecture.

Sources: docs/memory-bank/product.md:8-11, README.md:1-4

Module File Structure

The PowerShell Gallery package contains six primary files:

File Purpose Key Contents
OfficeScrubC2R.psd1 Module manifest Metadata, version 3.0.0, FunctionsToExport, FileList, PowerShell Gallery tags
OfficeScrubC2R.psm1 Root module Five exported functions, DLL loading logic
OfficeScrubNative.dll Compiled native library OfficeScrubOrchestrator class, 8 helper classes, GuidHelper static class
OfficeScrubC2R-Native.cs C# source code Reference implementation for OfficeScrubNative.dll (3,803 lines)
direct_conversion.cs Legacy reference Direct VBScript-to-C# conversion showing implementation lineage
docs/source/OfficeScrubC2R.vbs Original VBScript Microsoft's original implementation (v2.19)

Build Process

The OfficeScrubNative.dll is pre-compiled for .NET Framework 4.5+ using csc.exe. A separate .NET Core 7+ build exists for PowerShell 7 compatibility. The build script build.ps1 handles compilation for both targets.

Sources: OfficeScrubC2R.psd1:82-91, README.md:5-13, README.md:47-66

Execution Workflow

The system implements a three-stage cleanup pipeline. The PowerShell module orchestrates workflow and logging while delegating performance-critical operations to the native C# library.

Simplified Cleanup Pipeline

flowchart TD
    Start["Import-Module<br/>OfficeScrubC2R"] --> Load["Import-OfficeScrubNative"]
    Load --> Create["New-OfficeScrubOrchestrator"]
    
    Create --> Detect["Detection Phase<br/>Test-OfficeC2RPath<br/>Test-OfficeProductScope"]
    
    Detect --> Stage1["Stage 1: Uninstall<br/>- OSPP License Clear<br/>- Process Termination<br/>- ODT/MSI Uninstall"]
    
    Stage1 --> Stage2["Stage 2: Registry Cleanup<br/>- RegistryHelper.DeleteKey()<br/>- WOW64 dual-path access<br/>- MSI metadata removal"]
    
    Stage2 --> Stage3["Stage 3: File System Cleanup<br/>- FileHelper.DeleteDirectory()<br/>- Service deletion<br/>- MoveFileEx() for locked files"]
    
    Stage3 --> Reboot{Pending<br/>Reboot?}
    Reboot -->|Yes| Schedule["PendingFileRenameOperations<br/>Registry Entry"]
    Reboot -->|No| Exit["Exit"]
    Schedule --> Exit
Loading

Stage Implementation

  • Stage 1 (Uninstall): Clears SPP licenses via LicenseHelper, terminates processes via ProcessHelper.TerminateProcesses(), attempts graceful uninstall via ODT Configuration.xml or msiexec.exe
  • Stage 2 (Registry): Removes registry keys via RegistryHelper with recursive deletion and WOW64 support, cleans Windows Installer metadata via WindowsInstallerHelper
  • Stage 3 (File System): Deletes installation directories via FileHelper.DeleteDirectory() with cmd.exe rd /s /q optimization, schedules locked files via MoveFileEx(MOVEFILE_DELAY_UNTIL_REBOOT)

For detailed pipeline documentation, see Three-Stage Execution Pipeline.

Sources: README.md:18-34, docs/memory-bank/product.md:14-24

System Requirements

Component Minimum Version Notes
Windows 7 SP1 Windows 10/11 recommended
PowerShell 5.1 Compatible with PowerShell Core 7+
.NET Framework 4.5 Required for OfficeScrubNative.dll (Windows PowerShell)
.NET SDK 7.0 Required for PowerShell Core compilation
Privileges Administrator Mandatory for registry and file operations
Architecture x86, x64 WOW64 registry redirection automatically handled

PowerShell Edition Compatibility

The module supports both Windows PowerShell 5.1 (Desktop edition) and PowerShell Core 7+ (Core edition). The native DLL has two compilation targets:

  • .NET Framework 4.5 - Used by Windows PowerShell 5.1
  • .NET 7.0 - Used by PowerShell Core 7+

The Import-OfficeScrubNative function automatically selects the appropriate DLL based on the PowerShell edition ($PSVersionTable.PSEdition).

Sources: OfficeScrubC2R.psd1:9, OfficeScrubC2R.psd1:29-32, README.md:52-66, docs/memory-bank/product.md:58-64

Version History and Critical Fixes

Current Version: 2.19.2

The current release (v2.19.2) addresses a critical packaging issue in v2.19.1 where the main script file OfficeScrubC2R.ps1 was not included in the PowerShell Gallery package due to an incomplete FileList in the module manifest. This resulted in a non-functional module. Version 2.19.2 corrects the FileList to include all required script files.

Critical fix from v2.19.1 (also in v2.19.2): The Initialize-Environment function now executes automatically on module import, ensuring the $script:LogDir variable and OfficeScrubOrchestrator instance are properly initialized before any operations begin. This resolves null reference errors that occurred when functions like Test-IsC2R were called before manual environment initialization.

Sources: docs/CHANGELOG.md:8-33

Performance Evolution

Version 2.2.0 introduced the optimization strategies that achieve 10-50x performance improvements: Span<char> usage for memory efficiency, HashSet-based collections for O(1) lookups, static caching in registry operations, parallel processing for independent tasks, and StringComparison.OrdinalIgnoreCase for faster string comparisons.

Sources: docs/CHANGELOG.md:44-103


For detailed usage instructions and parameters, see User Guide.
For architectural deep-dives into each component, see Architecture.
For development and contribution guidelines, see Developer Guide.

Clone this wiki locally