Repository navigation
Native Library Overview
Relevant source files
The following files were used as context for generating this wiki page:
This document introduces the OfficeScrubNative.dll native library, which provides high-performance system operations through compiled C# code. The library achieves 10-50x performance improvements over pure PowerShell implementations through direct Win32 API calls, parallel processing, and memory-efficient algorithms.
For detailed documentation of individual helper classes, see Helper Classes. For performance optimization techniques, see Performance Optimizations. For Win32 API integration details, see P/Invoke and Win32 APIs.
The native library serves as the performance-critical layer of OfficeScrubC2R, handling operations that would be prohibitively slow in pure PowerShell:
- Registry Operations: 30x faster than PowerShell registry cmdlets through direct Win32 API calls
-
File System Operations: 15x faster with parallel deletion and native
cmd.exeintegration - Process Management: Concurrent termination with proper timeout handling
- Windows Installer Cleanup: Efficient MSI metadata enumeration and GUID decoding
- COM Type Library Cleanup: Automated COM registration cleanup with file validation
- License Management: WMI-based OSPP/SPP operations for Office activation cleanup
- Service Management: Reliable service termination and deletion
- Shell Integration: Taskbar and Start menu unpinning with localization support
The library is distributed as a pre-compiled DLL (OfficeScrubNative.dll) but includes the full C# source code for fallback compilation in environments where pre-compiled binaries are blocked.
Sources: OfficeScrubC2R-Native.cs:1-1408
The OfficeScrubOrchestrator class implements the facade pattern, providing a unified entry point for all native operations. This class instantiates and manages all helper classes, exposing them as public properties.
classDiagram
class OfficeScrubOrchestrator {
+RegistryHelper Registry
+FileHelper Files
+ProcessHelper Processes
+ShellHelper Shell
+WindowsInstallerHelper WindowsInstaller
+TypeLibHelper TypeLib
+LicenseHelper License
+ServiceHelper Services
+bool IsC2RPath(string path)
+bool IsInScope(string productCode)
}
class RegistryHelper {
+bool KeyExists()
+bool DeleteKey()
+string[] EnumerateKeys()
+object GetValue()
}
class FileHelper {
+bool DeleteFile()
+bool DeleteDirectory()
+void ScheduleDeleteOnReboot()
}
class ProcessHelper {
+List~int~ TerminateProcesses()
+bool IsProcessRunning()
}
class WindowsInstallerHelper {
+void CleanupUpgradeCodes()
+void CleanupProducts()
+void CleanupComponents()
}
class TypeLibHelper {
+void CleanupKnownTypeLibs()
}
class LicenseHelper {
+void CleanOSPP()
+void ClearVNextLicenseCache()
}
class ServiceHelper {
+bool DeleteService()
}
class ShellHelper {
+bool UnpinFromTaskbar()
+bool UnpinFromStartMenu()
+void RestartExplorer()
}
class GuidHelper {
+string GetExpandedGuid()
+string GetCompressedGuid()
+bool GetDecodedGuid()
}
OfficeScrubOrchestrator --> RegistryHelper
OfficeScrubOrchestrator --> FileHelper
OfficeScrubOrchestrator --> ProcessHelper
OfficeScrubOrchestrator --> ShellHelper
OfficeScrubOrchestrator --> WindowsInstallerHelper
OfficeScrubOrchestrator --> TypeLibHelper
OfficeScrubOrchestrator --> LicenseHelper
OfficeScrubOrchestrator --> ServiceHelper
WindowsInstallerHelper --> RegistryHelper
WindowsInstallerHelper --> GuidHelper
TypeLibHelper --> RegistryHelper
Figure 1: OfficeScrubOrchestrator Class Hierarchy
The orchestrator is instantiated once during module initialization and stored in the PowerShell module scope for reuse throughout the cleanup process.
Sources: OfficeScrubC2R-Native.cs:1347-1405
All native types are defined in the OfficeScrubNative namespace, organized into logical regions:
| Region | Lines | Purpose |
|---|---|---|
| Enums and Constants | 19-58 |
RegistryHiveType enum and OfficeConstants static class |
| P/Invoke Declarations | 60-167 | Native method signatures and COM interface definitions |
| GUID Utilities | 169-330 | Static GuidHelper class for GUID transformations |
| Registry Operations | 332-617 |
RegistryHelper class with WOW64 support |
| File Operations | 620-768 |
FileHelper class with reboot scheduling |
| Process Operations | 771-859 |
ProcessHelper class with parallel termination |
| Shell Integration | 862-975 |
ShellHelper class for taskbar/Start menu |
| Windows Installer Helper | 978-1129 |
WindowsInstallerHelper class for MSI cleanup |
| TypeLib Helper | 1132-1210 |
TypeLibHelper class for COM cleanup |
| License/SPP Helper | 1213-1274 |
LicenseHelper class for activation cleanup |
| Service Helper | 1277-1344 |
ServiceHelper class for service management |
| Orchestrator | 1347-1407 |
OfficeScrubOrchestrator facade class |
Sources: OfficeScrubC2R-Native.cs:17-1408
The native library provides nine specialized helper classes, each targeting a specific Windows subsystem:
| Helper Class | Primary Responsibility | Key Performance Feature | Lines |
|---|---|---|---|
RegistryHelper |
Registry operations with WOW64 support | HashSet-based deduplication, 30x faster enumeration | 334-616 |
FileHelper |
File and directory deletion with reboot scheduling |
cmd.exe batch deletion, 15x faster |
622-767 |
ProcessHelper |
Process termination and detection | Parallel process termination with Task.Run | 773-858 |
WindowsInstallerHelper |
MSI metadata cleanup (Products, Components, UpgradeCodes) | Compressed GUID decoding, predicate-based filtering | 980-1128 |
TypeLibHelper |
COM type library cleanup | Known TypeLib array, file existence validation | 1134-1209 |
LicenseHelper |
Office license and SPP operations | WMI-based OSPP cleanup, VNext cache deletion | 1215-1273 |
ServiceHelper |
Windows service management | WMI service control with sc.exe fallback |
1279-1343 |
GuidHelper |
GUID encoding/decoding utilities | Static methods for compressed/expanded/decoded GUIDs | 171-328 |
ShellHelper |
Shell integration (taskbar, Start menu) | COM automation with multi-language support | 864-974 |
Sources: OfficeScrubC2R-Native.cs:171-1343
Provides registry operations with automatic WOW64 redirection handling. On 64-bit systems, operations automatically check both native and WOW6432Node locations.
Key Methods:
-
KeyExists(RegistryHiveType hive, string subKey): Check if registry key exists in any view -
DeleteKey(RegistryHiveType hive, string subKey, bool recursive): Delete key from all views -
EnumerateKeys(RegistryHiveType hive, string subKey): List subkeys from both views (deduplicated) -
EnumerateValues(RegistryHiveType hive, string subKey): List values from both views (deduplicated) -
GetValue/SetValue: Read/write registry values with view fallback -
AddPendingFileRenameOperation: Schedule file deletion on reboot via Session Manager
Sources: OfficeScrubC2R-Native.cs:334-616
Handles file system operations with fallback strategies for locked files. Uses cmd.exe for large directory trees for optimal performance.
Key Methods:
-
DeleteFile(string filePath, bool scheduleOnFail): Delete file with attribute reset -
DeleteDirectory(string directoryPath, bool recursive, bool scheduleOnFail): Delete directory usingcmd.exe rdwith .NET fallback -
ScheduleDeleteOnReboot(string filePath): Schedule file deletion viaMoveFileEx -
ScheduleDirectoryDeleteOnReboot(string directoryPath): Recursively schedule directory deletion -
GetPendingDeletes(): Retrieve list of files scheduled for deletion -
IsFileLocked(string filePath): Check if file is locked by another process
Sources: OfficeScrubC2R-Native.cs:622-767
Cleans up Windows Installer metadata for Office products. Requires RegistryHelper instance for registry access.
Key Methods:
-
CleanupUpgradeCodes(Func<string, bool> shouldDelete): Remove UpgradeCode entries matching predicate -
CleanupProducts(Func<string, bool> shouldDelete): Clean Products registry under UserData and Classes -
CleanupComponents(Func<string, bool> shouldDelete): Remove component values matching predicate -
CleanupPublishedComponents(Func<string, bool> shouldDelete): Parse and filter PublishedComponents multi-string values
All methods use GUID helper functions to decode compressed GUIDs (32 characters) and encoded GUIDs (20 characters) from registry keys and values.
Sources: OfficeScrubC2R-Native.cs:980-1128
Static utility class for GUID format transformations used in Windows Installer metadata.
GUID Formats:
-
Expanded:
{XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX}(38 chars, standard format) -
Compressed:
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX(32 chars, byte-reversed segments) -
Encoded:
XXXXXXXXXXXXXXXXXXXX(20 chars, base-85 encoding)
Key Methods:
-
GetExpandedGuid(string compressedGuid): Convert compressed → expanded format -
GetCompressedGuid(string expandedGuid): Convert expanded → compressed format -
GetDecodedGuid(string encodedGuid, out string decodedGuid): Decode base-85 encoded GUID
Sources: OfficeScrubC2R-Native.cs:171-328
The following diagram illustrates how PowerShell functions in the utilities module call into the native library:
sequenceDiagram
participant PS as "PowerShell Function"
participant Script as "$script:orchestrator"
participant Orch as "OfficeScrubOrchestrator"
participant Helper as "RegistryHelper/FileHelper/etc"
participant Win32 as "Win32 APIs"
Note over PS: From OfficeScrubC2R-Utilities.psm1
PS->>Script: Access $script:orchestrator
Script->>Orch: Get helper property
Orch->>Helper: Return helper instance
PS->>Helper: Call helper method
Helper->>Win32: P/Invoke native API
Win32-->>Helper: Return result
Helper-->>PS: Return result
Note over PS,Win32: Example: Remove-RegistryKey
PS->>Script: $script:orchestrator.Registry
Script-->>PS: RegistryHelper instance
PS->>Helper: DeleteKey(hive, subKey, recursive)
Helper->>Win32: RegDeleteKeyEx
Win32-->>Helper: ERROR_SUCCESS
Helper-->>PS: $true
Figure 2: PowerShell to Native Library Call Flow
Sources: OfficeScrubC2R-Native.cs:1347-1405
The PowerShell module creates a single OfficeScrubOrchestrator instance during module initialization and stores it in module scope:
Initialization Pattern (from OfficeScrubC2R.psm1):
# Load native library based on PowerShell edition
$dllPath = if ($PSVersionTable.PSEdition -eq 'Core') {
Join-Path $PSScriptRoot 'OfficeScrubNative.Core.dll'
} else {
Join-Path $PSScriptRoot 'OfficeScrubNative.dll'
}
# Load and instantiate orchestrator
[System.Reflection.Assembly]::LoadFrom($dllPath)
$script:orchestrator = [OfficeScrubNative.OfficeScrubOrchestrator]::new(
[Environment]::Is64BitOperatingSystem
)Helper Access Pattern (from OfficeScrubC2R-Utilities.psm1):
function Remove-RegistryKey {
[CmdletBinding()]
param(
[string]$KeyPath,
[switch]$Recursive
)
$hive = [OfficeScrubNative.RegistryHiveType]::LocalMachine
$script:orchestrator.Registry.DeleteKey($hive, $KeyPath, $Recursive.IsPresent)
}
function Stop-OfficeProcesses {
[CmdletBinding()]
param([string[]]$ProcessNames)
$script:orchestrator.Processes.TerminateProcesses($ProcessNames, 5000)
}
function Test-OfficeC2RPath {
[CmdletBinding()]
param([string]$Path)
$script:orchestrator.IsC2RPath($Path)
}Sources: OfficeScrubC2R-Native.cs:1349-1382, docs/memory-bank/structure.md:110-132
PowerShell code accesses native types through several patterns:
Access Pattern Comparison:
flowchart LR
PSCode["PowerShell Code"] --> Enum["[OfficeScrubNative.RegistryHiveType]<br/>Enum Access"]
PSCode --> Orch["$script:orchestrator.Registry<br/>Helper via Orchestrator"]
PSCode --> Static["[OfficeScrubNative.GuidHelper]<br/>Static Utility Methods"]
PSCode --> Direct["[OfficeScrubNative.RegistryHelper]::new()<br/>Direct Construction"]
Orch --> Helper["RegistryHelper Instance"]
Helper --> Method["DeleteKey() / EnumerateKeys()"]
| Access Pattern | Code Example | Usage Context |
|---|---|---|
| Enum Members | [OfficeScrubNative.RegistryHiveType]::LocalMachine |
Registry hive selection |
| Via Orchestrator | $script:orchestrator.Registry.DeleteKey($hive, $key, $true) |
Preferred: Helper class methods |
| Static Helpers | [OfficeScrubNative.GuidHelper]::GetExpandedGuid($compressed) |
GUID transformation utilities |
| Direct Construction | [OfficeScrubNative.FileHelper]::new() |
Rare: Orchestrator manages instances |
| Constants | [OfficeScrubNative.OfficeConstants]::OFFICE_PROCESSES |
Static data arrays |
Module-Scoped Access (internal to utilities module):
# Helper property accessors
$regHelper = $script:orchestrator.Registry
$fileHelper = $script:orchestrator.Files
$procHelper = $script:orchestrator.Processes
# Validation methods
$isC2R = $script:orchestrator.IsC2RPath($installPath)
$inScope = $script:orchestrator.IsInScope($productGuid)Sources: OfficeScrubC2R-Native.cs:17-1408, OfficeScrubC2R-Native.cs:1349-1405
The OfficeScrubC2R-Native.cs source file supports compilation for two .NET targets:
| Target | Binary Name | Compiler | PowerShell Compatibility |
|---|---|---|---|
| .NET Framework 4.5+ | OfficeScrubNative.dll |
csc.exe | Windows PowerShell 5.1 |
| .NET Core 7+ | OfficeScrubNative.Core.dll |
dotnet build | PowerShell Core 7+ |
Framework Selection Logic:
flowchart LR
PSEdition{"$PSVersionTable.PSEdition"}
PSEdition -->|Desktop| Framework["Load OfficeScrubNative.dll<br/>.NET Framework 4.5+"]
PSEdition -->|Core| NetCore["Load OfficeScrubNative.Core.dll<br/>.NET Core 7+"]
Framework --> Orchestrator["OfficeScrubOrchestrator"]
NetCore --> Orchestrator
Sources: docs/memory-bank/structure.md:111-124, docs/memory-bank/tech.md:17-27
The build.ps1 script compiles both target frameworks:
Compilation Workflow:
flowchart TD
BuildScript["build.ps1"] --> CheckFramework{"Framework<br/>Available?"}
CheckFramework -->|"csc.exe found"| CompileFramework["csc.exe /target:library<br/>/out:OfficeScrubNative.dll<br/>/optimize+<br/>/reference:System.Management.dll"]
CheckFramework -->|"dotnet found"| CompileCore["dotnet build<br/>-c Release<br/>-o OfficeScrubNative.Core.dll"]
CompileFramework --> VerifyFW["Verify-NativeBuild.ps1<br/>Test .NET Framework"]
CompileCore --> VerifyCore["Verify-NativeBuild.ps1<br/>Test .NET Core"]
VerifyFW --> Success["Build Artifacts Ready"]
VerifyCore --> Success
Compiler Configuration (.NET Framework):
# From build.ps1
$cscPath = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
$arguments = @(
"/target:library"
"/out:OfficeScrubNative.dll"
"/optimize+"
"/warn:4"
"/reference:System.Management.dll"
"/reference:Microsoft.CSharp.dll"
"OfficeScrubC2R-Native.cs"
)Compiler Configuration (.NET Core):
# From build.ps1
dotnet build OfficeScrubC2R-Native.cs `
-c Release `
-f net7.0 `
-o ./bin/CoreSources: docs/memory-bank/structure.md:117-124, docs/memory-bank/tech.md:29-55
The module ships with pre-compiled binaries for both targets to provide immediate availability:
flowchart TD
ModuleImport["Import-Module OfficeScrubC2R"] --> CheckEdition{"$PSVersionTable<br/>.PSEdition"}
CheckEdition -->|Desktop| CheckFW{"OfficeScrubNative.dll<br/>exists?"}
CheckEdition -->|Core| CheckCore{"OfficeScrubNative.Core.dll<br/>exists?"}
CheckFW -->|Yes| LoadFW["[System.Reflection.Assembly]<br/>::LoadFrom(dll path)"]
CheckFW -->|No| CompileFW["Add-Type -TypeDefinition<br/>-ReferencedAssemblies"]
CheckCore -->|Yes| LoadCore["[System.Reflection.Assembly]<br/>::LoadFrom(dll path)"]
CheckCore -->|No| CompileCore["Add-Type -TypeDefinition<br/>-ReferencedAssemblies"]
LoadFW --> CreateOrch["new OfficeScrubOrchestrator<br/>$script:orchestrator"]
LoadCore --> CreateOrch
CompileFW --> CreateOrch
CompileCore --> CreateOrch
Sources: docs/memory-bank/structure.md:126-132, docs/memory-bank/tech.md:56-70
If pre-compiled binaries are unavailable, blocked, or incompatible, the module compiles from source:
Add-Type Parameters:
# From OfficeScrubC2R.psm1 (conceptual)
Add-Type -TypeDefinition $sourceCode `
-Language CSharp `
-ReferencedAssemblies @(
'System.Management'
'Microsoft.CSharp'
'System.Core'
) `
-CompilerOptions '/optimize+'Fallback Advantages:
- Works with restrictive execution policies (bypasses DLL blocking)
- Functions even if binaries corrupted or deleted
- Enables source code inspection and verification
- Supports environment-specific modifications
Compilation Performance:
- Initial Compilation: 5-10 seconds (one-time cost)
- Session Caching: Assembly cached for PowerShell session lifetime
- Runtime Performance: Identical to pre-compiled DLL after loading
Sources: docs/memory-bank/tech.md:56-80, OfficeScrubC2R-Native.cs:1-17
Both compilation targets require the same external assemblies:
| Assembly | Purpose | APIs Used |
|---|---|---|
System.Management.dll |
WMI operations | ManagementScope, ManagementObjectSearcher, SelectQuery |
Microsoft.CSharp.dll |
Dynamic binding | CSharpArgumentInfo, CSharpBinderFlags (for Shell.Application COM) |
System.Core.dll |
LINQ extensions | Enumerable.Any, Enumerable.ToArray, Task.Run |
P/Invoke Dependencies (No external DLLs required):
-
kernel32.dll: MoveFileEx, SetFileAttributes, RemoveDirectory -
advapi32.dll: RegOpenKeyEx, RegDeleteKeyEx, RegEnumKeyEx, RegQueryValueEx -
shell32.dll: ILCreateFromPath, SHCreateShellItem, ILFree
Sources: OfficeScrubC2R-Native.cs:1-16, OfficeScrubC2R-Native.cs:60-167, docs/memory-bank/tech.md:82-94
The RegistryHiveType enum provides type-safe registry hive identifiers:
public enum RegistryHiveType
{
ClassesRoot = unchecked((int)0x80000000), // HKEY_CLASSES_ROOT
CurrentUser = unchecked((int)0x80000001), // HKEY_CURRENT_USER
LocalMachine = unchecked((int)0x80000002), // HKEY_LOCAL_MACHINE
Users = unchecked((int)0x80000003) // HKEY_USERS
}These values match the Win32 HKEY predefined key values used in registry API calls.
Sources: OfficeScrubC2R-Native.cs:21-27
The OfficeConstants static class defines Office-specific constants and patterns:
| Constant | Value | Purpose |
|---|---|---|
OFFICE_ID |
"0000000FF1CE}" |
Office product GUID suffix |
PROD_LEN |
13 |
Product code length |
SQUISHED |
20 |
Encoded GUID length |
COMPRESSED |
32 |
Compressed GUID length |
C2R_PATTERNS |
string[] |
Click-to-Run path detection patterns |
OFFICE_PROCESSES |
string[] |
Office process names for termination |
C2R Pattern Detection:
The C2R_PATTERNS array contains 7 path patterns used to identify Click-to-Run installations:
"\ROOT\OFFICE1""Microsoft Office\Root\""\microsoft shared\ClickToRun""\Microsoft Office\PackageManifests""\Microsoft Office\PackageSunrisePolicies""Microsoft Office 15""Microsoft Office 16"
Office Process List:
The OFFICE_PROCESSES array lists 24 Office-related process names that should be terminated during cleanup, including core applications (Word, Excel, PowerPoint, Outlook) and supporting processes (ClickToRun, integrator, firstrun).
Sources: OfficeScrubC2R-Native.cs:29-56
| Operation | Pure PowerShell | Native Library | Speedup |
|---|---|---|---|
| Registry key enumeration (1000 keys) | ~10 seconds | ~0.3 seconds | 30x |
| Recursive directory deletion | ~15 seconds | ~1 second | 15x |
| Process termination (10 processes) | ~2 seconds | ~0.2 seconds | 10x |
| GUID decoding (100 GUIDs) | ~0.5 seconds | ~0.05 seconds | 10x |
| Overall cleanup operation | 5-10 minutes | 30-60 seconds | 10-50x |
The native library employs several performance optimization techniques:
- Direct Win32 API Calls: Bypass .NET registry/file abstractions
- Parallel Processing: Task.Run and Parallel.ForEach for concurrent operations
- Memory Efficiency: Span for string manipulation (zero-copy)
- Smart Caching: Static caching of decode tables and hive keys
- HashSet Lookups: O(1) deduplication vs O(n) array searches
- StringComparison.OrdinalIgnoreCase: 2x faster than culture-aware comparisons
- cmd.exe Integration: Native batch deletion faster than .NET for large trees
For detailed performance analysis, see Performance Optimizations.
Sources: docs/memory-bank/tech.md:85-95, OfficeScrubC2R-Native.cs:1-1408
This native library forms the foundation of OfficeScrubC2R's performance advantages, providing PowerShell with access to highly optimized system operations while maintaining code clarity and maintainability through the facade pattern.