Repository navigation
Module Structure
Relevant source files
The following files were used as context for generating this wiki page:
This document describes the PowerShell module file organization and component interactions in OfficeScrubC2R. The module implements a lightweight wrapper pattern where PowerShell provides the user interface while delegating all performance-critical operations to the native C# library.
For details on the native C# performance layer that this module wraps, see Native Performance Layer. For information on the orchestrator pattern used to coordinate cleanup operations, see OfficeScrubOrchestrator.
The OfficeScrubC2R module v3.0.0 consists of two primary components with a simplified architecture:
| File | Type | Role |
|---|---|---|
OfficeScrubC2R.psd1 |
Module Manifest | Defines module metadata, version, and exports |
OfficeScrubC2R.psm1 |
Root Module | Lightweight wrapper exposing native DLL functions |
OfficeScrubNative.dll |
Native Assembly | C# library with all cleanup logic |
The module uses a wrapper pattern where the PowerShell layer is intentionally minimal. The module loads the native DLL and exposes five helper functions that create and interact with the OfficeScrubOrchestrator class. This design achieves 10-50x performance improvements by implementing all cleanup operations in compiled C# code with direct Win32 API access.
The repository also includes reference files (OfficeScrubC2R-Native.cs, direct_conversion.cs, docs/source/OfficeScrubC2R.vbs) for documentation and comparison purposes, but these are not loaded by the module.
Sources: OfficeScrubC2R.psd1:1-158, OfficeScrubC2R.psm1:1-99, docs/memory-bank/structure.md:1-133
The manifest defines the module's identity, requirements, and structure:
RootModule = 'OfficeScrubC2R.psm1'
ModuleVersion = '3.0.0'
CompatiblePSEditions = @('Desktop', 'Core')
GUID = 'f8e7c4d1-5a3b-4e2d-9c8f-1b6a4d7e9c3a'
PowerShellVersion = '5.1'
DotNetFrameworkVersion = '4.5'
ProcessorArchitecture = 'None'The manifest establishes version 3.0.0, which represents a major architectural change from previous versions. The module is now a lightweight wrapper focusing on the native DLL rather than script-based implementations. Support for both PowerShell Desktop and Core editions OfficeScrubC2R.psd1:9 ensures compatibility across Windows PowerShell 5.1 and PowerShell 7+.
Sources: OfficeScrubC2R.psd1:3-35
The manifest declares minimal dependencies:
RequiredModules = @()
RequiredAssemblies = @()
NestedModules = @()Unlike typical PowerShell modules, this manifest does not declare OfficeScrubNative.dll in RequiredAssemblies OfficeScrubC2R.psd1:43. The DLL is loaded dynamically by the Import-OfficeScrubNative function to avoid conflicts when the assembly is already loaded in the current AppDomain. This approach provides better control over assembly loading and error handling.
Sources: OfficeScrubC2R.psd1:38-55
The manifest explicitly defines the public API surface:
| Export Type | Count | Members |
|---|---|---|
| Functions | 5 |
Import-OfficeScrubNative, New-OfficeScrubOrchestrator, Test-OfficeC2RPath, Test-OfficeProductScope, Get-OfficeScrubHelpers
|
| Aliases | 0 | None exported |
| Cmdlets | 0 | None (pure PowerShell wrapper) |
| Variables | 0 | None exported |
The explicit export list OfficeScrubC2R.psd1:58-64 ensures only intended functions are visible to module consumers. All five functions are thin wrappers around the native OfficeScrubOrchestrator class and its helper components.
Sources: OfficeScrubC2R.psd1:58-76
The manifest includes both runtime and reference files:
FileList = @(
'OfficeScrubC2R.psd1',
'OfficeScrubC2R.psm1',
'OfficeScrubNative.dll',
'OfficeScrubC2R-Native.cs',
'direct_conversion.cs',
'docs\source\OfficeScrubC2R.vbs',
'LICENSE',
'README.md'
)The FileList OfficeScrubC2R.psd1:82-91 includes the original VBScript implementation (OfficeScrubC2R.vbs) and reference C# conversions (OfficeScrubC2R-Native.cs, direct_conversion.cs) for documentation and comparison purposes. These files are not loaded or executed by the module; they serve as historical reference and demonstrate the evolution from VBScript to optimized C#.
Sources: OfficeScrubC2R.psd1:82-91
The root module is intentionally minimal, containing only wrapper functions that expose the native DLL functionality. The module defines script-level variables and five exported functions:
$script:ModuleRoot = $PSScriptRoot
$script:NativeAssemblyPath = Join-Path $script:ModuleRoot 'OfficeScrubNative.dll'
$script:NativeAssembly = $nullThese script variables OfficeScrubC2R.psm1:6-8 track the module location, DLL path, and loaded assembly reference. The $script:NativeAssembly variable is cached to avoid reloading the assembly if already present in the AppDomain.
Sources: OfficeScrubC2R.psm1:1-9
sequenceDiagram
participant User["User"]
participant Manifest["OfficeScrubC2R.psd1"]
participant RootModule["OfficeScrubC2R.psm1"]
participant NativeDLL["OfficeScrubNative.dll"]
User->>Manifest: "Import-Module OfficeScrubC2R"
Note over Manifest: "Parse manifest v3.0.0<br/>No RequiredAssemblies"
Manifest->>RootModule: "Execute RootModule"
RootModule->>RootModule: "Lines 6-8: Initialize variables<br/>$script:ModuleRoot<br/>$script:NativeAssemblyPath<br/>$script:NativeAssembly"
RootModule->>RootModule: "Lines 10-35: Define<br/>Import-OfficeScrubNative"
RootModule->>RootModule: "Lines 37-46: Define<br/>New-OfficeScrubOrchestrator"
RootModule->>RootModule: "Lines 48-60: Define<br/>Test-OfficeC2RPath"
RootModule->>RootModule: "Lines 62-74: Define<br/>Test-OfficeProductScope"
RootModule->>RootModule: "Lines 76-96: Define<br/>Get-OfficeScrubHelpers"
RootModule->>RootModule: "Line 98: Export-ModuleMember"
Note over RootModule: "Export 5 functions"
RootModule-->>User: "Module ready<br/>DLL not loaded yet"
Note over User,NativeDLL: "DLL loads on first function call"
User->>RootModule: "New-OfficeScrubOrchestrator"
RootModule->>RootModule: "Line 44: Call Import-OfficeScrubNative"
RootModule->>NativeDLL: "Assembly.LoadFrom()"
NativeDLL-->>RootModule: "Assembly loaded"
RootModule->>NativeDLL: "[OfficeScrubNative.OfficeScrubOrchestrator]::new()"
NativeDLL-->>User: "Orchestrator instance"
Module Loading and Lazy Assembly Loading
This diagram shows the loading sequence with lazy DLL loading. Unlike previous versions, the native assembly is not loaded during module import. The DLL loads on the first function call that requires it, typically New-OfficeScrubOrchestrator. This lazy loading pattern improves module import performance and avoids assembly conflicts.
Sources: OfficeScrubC2R.psm1:1-99, OfficeScrubC2R.psd1:1-158
The Import-OfficeScrubNative function implements dynamic assembly loading with caching:
function Import-OfficeScrubNative {
[CmdletBinding()]
param(
[string]$Path = $script:NativeAssemblyPath
)
$resolvedPath = (Resolve-Path -Path $Path -ErrorAction Stop).ProviderPath
if (-not (Test-Path -Path $resolvedPath -PathType Leaf)) {
throw "Native assembly not found at '$resolvedPath'..."
}
if ($script:NativeAssembly -and $script:NativeAssembly.Location -eq $resolvedPath) {
return $script:NativeAssembly
}
$script:NativeAssembly = [AppDomain]::CurrentDomain.GetAssemblies() |
Where-Object { $_.Location -eq $resolvedPath }
if (-not $script:NativeAssembly) {
$script:NativeAssembly = [System.Reflection.Assembly]::LoadFrom($resolvedPath)
}
return $script:NativeAssembly
}The function implements three-level loading strategy OfficeScrubC2R.psm1:10-35:
-
Cache check: Return
$script:NativeAssemblyif already loaded at the specified path OfficeScrubC2R.psm1:23-25 - AppDomain search: Check if assembly is already loaded in current AppDomain OfficeScrubC2R.psm1:27-28
-
LoadFrom: Load assembly from disk using
Assembly.LoadFrom()OfficeScrubC2R.psm1:31
This pattern avoids the "assembly already loaded" exceptions that would occur if OfficeScrubNative.dll were declared in RequiredAssemblies.
Sources: OfficeScrubC2R.psm1:10-35
graph TB
subgraph ModuleScope["Module Scope (OfficeScrubC2R.psm1)"]
ImportFunc["Import-OfficeScrubNative<br/>Lines 10-35<br/>Assembly loading"]
NewOrch["New-OfficeScrubOrchestrator<br/>Lines 37-46<br/>Creates orchestrator instance"]
TestPath["Test-OfficeC2RPath<br/>Lines 48-60<br/>Validates C2R paths"]
TestScope["Test-OfficeProductScope<br/>Lines 62-74<br/>Checks product scope"]
GetHelpers["Get-OfficeScrubHelpers<br/>Lines 76-96<br/>Returns helper objects"]
end
subgraph NativeScope["Native DLL (OfficeScrubNative.dll)"]
Orchestrator["OfficeScrubOrchestrator<br/>.new(Is64Bit)"]
Methods["Methods:<br/>IsC2RPath()<br/>IsInScope()"]
Helpers["Properties:<br/>Registry<br/>Files<br/>Processes<br/>Shell<br/>WindowsInstaller<br/>TypeLib<br/>License<br/>Services"]
end
ImportFunc -->|"Assembly.LoadFrom()"| Orchestrator
NewOrch -->|"Line 45"| Orchestrator
TestPath -->|"Line 59"| Methods
TestScope -->|"Line 73"| Methods
GetHelpers -->|"Lines 86-95"| Helpers
PowerShell Wrapper to Native Integration
This diagram shows how the five exported PowerShell functions map to native C# classes and methods. Each function is a thin wrapper that either loads the assembly, creates instances, or invokes methods on the OfficeScrubOrchestrator class.
Sources: OfficeScrubC2R.psm1:10-96
The primary function for creating the orchestrator instance:
function New-OfficeScrubOrchestrator {
[CmdletBinding()]
param(
[bool]$Is64Bit = [Environment]::Is64BitOperatingSystem
)
Import-OfficeScrubNative | Out-Null
return [OfficeScrubNative.OfficeScrubOrchestrator]::new($Is64Bit)
}This function OfficeScrubC2R.psm1:37-46 implements the factory pattern for creating orchestrator instances:
-
Lazy load assembly: Calls
Import-OfficeScrubNativeto ensure DLL is loaded OfficeScrubC2R.psm1:44 -
Detect architecture: Defaults
$Is64Bitto system architecture OfficeScrubC2R.psm1:41 -
Instantiate orchestrator: Creates
OfficeScrubOrchestratorwith architecture flag OfficeScrubC2R.psm1:45
The $Is64Bit parameter determines whether registry operations use WOW64 redirection. See WOW64 Registry Handling for details.
Sources: OfficeScrubC2R.psm1:37-46
Validates whether a path matches Click-to-Run patterns:
function Test-OfficeC2RPath {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$Path,
[OfficeScrubNative.OfficeScrubOrchestrator]$Orchestrator
)
if (-not $PSBoundParameters.ContainsKey('Orchestrator') -or -not $Orchestrator) {
$Orchestrator = New-OfficeScrubOrchestrator
}
return $Orchestrator.IsC2RPath($Path)
}The function OfficeScrubC2R.psm1:48-60 accepts an optional $Orchestrator parameter for performance optimization. If not provided, it creates a new orchestrator instance OfficeScrubC2R.psm1:55-57. The actual path validation logic resides in the native IsC2RPath() method OfficeScrubC2R.psm1:59.
Sources: OfficeScrubC2R.psm1:48-60
Determines whether a product code should be cleaned:
function Test-OfficeProductScope {
[CmdletBinding()]
param(
[Parameter(Mandatory)][string]$ProductCode,
[OfficeScrubNative.OfficeScrubOrchestrator]$Orchestrator
)
if (-not $PSBoundParameters.ContainsKey('Orchestrator') -or -not $Orchestrator) {
$Orchestrator = New-OfficeScrubOrchestrator
}
return $Orchestrator.IsInScope($ProductCode)
}This function OfficeScrubC2R.psm1:62-74 wraps the IsInScope() method which evaluates product codes against Office version patterns. The orchestrator maintains internal lists of Office product identifiers for scope determination.
Sources: OfficeScrubC2R.psm1:62-74
Provides access to all helper class instances:
function Get-OfficeScrubHelpers {
[CmdletBinding()]
param(
[OfficeScrubNative.OfficeScrubOrchestrator]$Orchestrator
)
if (-not $PSBoundParameters.ContainsKey('Orchestrator') -or -not $Orchestrator) {
$Orchestrator = New-OfficeScrubOrchestrator
}
[pscustomobject]@{
RegistryHelper = $Orchestrator.Registry
FileHelper = $Orchestrator.Files
ProcessHelper = $Orchestrator.Processes
ShellHelper = $Orchestrator.Shell
WindowsInstallerHelper = $Orchestrator.WindowsInstaller
TypeLibHelper = $Orchestrator.TypeLib
LicenseHelper = $Orchestrator.License
ServiceHelper = $Orchestrator.Services
}
}The function OfficeScrubC2R.psm1:76-96 returns a PSCustomObject exposing all eight helper class properties from the orchestrator OfficeScrubC2R.psm1:86-95. This provides direct access to specialized helper classes for advanced scenarios. See Helper Classes for detailed documentation of each helper.
Sources: OfficeScrubC2R.psm1:76-96
The module explicitly exports its public API:
Export-ModuleMember -Function Import-OfficeScrubNative, New-OfficeScrubOrchestrator, Test-OfficeC2RPath, Test-OfficeProductScope, Get-OfficeScrubHelpersThe Export-ModuleMember statement OfficeScrubC2R.psm1:98 lists all five wrapper functions. This declaration must match the manifest's FunctionsToExport OfficeScrubC2R.psd1:58-64 to ensure PowerShell Gallery compatibility and proper function visibility.
Sources: OfficeScrubC2R.psm1:98, OfficeScrubC2R.psd1:58-64
| Function | Purpose | Returns |
|---|---|---|
Import-OfficeScrubNative |
Loads native DLL with caching | System.Reflection.Assembly |
New-OfficeScrubOrchestrator |
Creates orchestrator instance | OfficeScrubOrchestrator |
Test-OfficeC2RPath |
Validates C2R path patterns | Boolean |
Test-OfficeProductScope |
Checks product code scope | Boolean |
Get-OfficeScrubHelpers |
Exposes helper class instances | PSCustomObject |
All five functions are defined in the root module OfficeScrubC2R.psm1:10-96. The module does not export any aliases, cmdlets, or variables. This minimal API surface reflects the wrapper pattern design.
Sources: OfficeScrubC2R.psm1:10-98, OfficeScrubC2R.psd1:58-73
sequenceDiagram
participant User["User Script"]
participant Module["OfficeScrubC2R.psm1"]
participant ImportFunc["Import-OfficeScrubNative"]
participant NewOrch["New-OfficeScrubOrchestrator"]
participant Orchestrator["OfficeScrubOrchestrator"]
participant RegistryHelper["RegistryHelper"]
User->>Module: "Import-Module OfficeScrubC2R"
Note over Module: "Module loads<br/>DLL not loaded yet"
Module-->>User: "Module ready"
User->>NewOrch: "New-OfficeScrubOrchestrator"
NewOrch->>ImportFunc: "Import-OfficeScrubNative"
ImportFunc->>ImportFunc: "Check cache, AppDomain<br/>LoadFrom() if needed"
ImportFunc-->>NewOrch: "Assembly"
NewOrch->>Orchestrator: "[OfficeScrubOrchestrator]::new($true)"
Orchestrator-->>User: "Orchestrator instance"
User->>Orchestrator: "$orch.Registry.KeyExists($key)"
Orchestrator->>RegistryHelper: "KeyExists($key)"
RegistryHelper-->>User: "$true or $false"
User->>Orchestrator: "$orch.Files.DeleteDirectory($path)"
Note over Orchestrator: "Helper methods execute<br/>native C# code"
Typical Module Usage Workflow
This diagram shows the standard usage pattern where users import the module, create an orchestrator, and call methods directly on the helper classes. The lazy loading pattern defers assembly loading until the first orchestrator creation.
Sources: OfficeScrubC2R.psm1:1-99
Users can access helper classes directly:
# Create orchestrator
$orch = New-OfficeScrubOrchestrator
# Access individual helpers
$orch.Registry.KeyExists("HKLM:\Software\Microsoft\Office\16.0\Common")
$orch.Files.DeleteDirectory("C:\Program Files\Microsoft Office", $true)
$orch.Processes.TerminateProcesses(@("WINWORD", "EXCEL"), 5000)Alternatively, use Get-OfficeScrubHelpers to retrieve all helpers as properties:
$helpers = Get-OfficeScrubHelpers
$helpers.RegistryHelper.EnumerateKeys("HKLM:\Software\Microsoft\Office")
$helpers.ProcessHelper.IsProcessRunning("OUTLOOK")The Get-OfficeScrubHelpers function OfficeScrubC2R.psm1:76-96 wraps the helper properties in a PSCustomObject for cleaner access patterns.
Sources: OfficeScrubC2R.psm1:76-96
graph TB
User["User Command"]
Manifest["OfficeScrubC2R.psd1<br/>ModuleVersion: 3.0.0<br/>RootModule: Line 3<br/>RequiredAssemblies: empty<br/>NestedModules: empty"]
RootModule["OfficeScrubC2R.psm1<br/>Lines 6-8: Script variables<br/>Lines 10-35: Import-OfficeScrubNative<br/>Lines 37-46: New-OfficeScrubOrchestrator<br/>Lines 48-96: Wrapper functions<br/>Line 98: Export-ModuleMember"]
NativeDLL["OfficeScrubNative.dll<br/>Lazy loaded by Import-OfficeScrubNative<br/>OfficeScrubOrchestrator<br/>8 Helper Classes"]
SourceFiles["Reference Files<br/>(not loaded)<br/>OfficeScrubC2R-Native.cs<br/>direct_conversion.cs<br/>docs/source/OfficeScrubC2R.vbs"]
User -->|"Import-Module"| Manifest
Manifest -->|"RootModule"| RootModule
RootModule -->|"Lazy load on first call"| NativeDLL
SourceFiles -.->|"Documentation only"| NativeDLL
style SourceFiles fill:#f5f5f5,stroke-dasharray: 5 5
Module Component Dependencies
This diagram shows the simplified component structure. The manifest references only the root module, with no RequiredAssemblies or NestedModules declarations. The native DLL loads lazily when first accessed. Reference source files are included in the package but not loaded by the module.
Sources: OfficeScrubC2R.psd1:1-158, OfficeScrubC2R.psm1:1-99
graph LR
subgraph PowerShell["PowerShell Layer"]
ImportFunc["Import-OfficeScrubNative<br/>Assembly.LoadFrom()"]
NewOrch["New-OfficeScrubOrchestrator<br/>Instantiation wrapper"]
TestPath["Test-OfficeC2RPath<br/>IsC2RPath() wrapper"]
TestScope["Test-OfficeProductScope<br/>IsInScope() wrapper"]
GetHelpers["Get-OfficeScrubHelpers<br/>Property accessor"]
end
subgraph NativeCode["C# Native Code"]
Assembly["OfficeScrubNative.dll<br/>Assembly"]
Orch["OfficeScrubOrchestrator<br/>Constructor & Methods"]
Helpers["8 Helper Classes<br/>Registry, Files, Processes,<br/>Shell, WindowsInstaller,<br/>TypeLib, License, Services"]
end
ImportFunc -->|"LoadFrom()"| Assembly
NewOrch -->|"::new(Is64Bit)"| Orch
TestPath -->|".IsC2RPath()"| Orch
TestScope -->|".IsInScope()"| Orch
GetHelpers -->|"Properties"| Helpers
Orch --> Helpers
PowerShell to Native Code Bridge
This diagram maps each PowerShell function to its corresponding C# code entity. The five wrapper functions provide minimal translation between PowerShell calling conventions and native C# methods. All business logic resides in the native layer.
Sources: OfficeScrubC2R.psm1:10-96
The v3.0.0 architecture adopts a wrapper pattern where PowerShell serves solely as the user interface. This design philosophy differs fundamentally from traditional PowerShell modules:
| Aspect | Traditional Module | OfficeScrubC2R v3.0.0 |
|---|---|---|
| Business logic | PowerShell scripts | Native C# DLL |
| Performance-critical ops | Cmdlets or external tools | Direct Win32 API calls |
| Module complexity | High (many .ps1/.psm1 files) | Low (2 files: .psd1 + .psm1) |
| Code lines in PowerShell | Hundreds to thousands | <100 lines |
| Assembly loading | RequiredAssemblies | Lazy dynamic loading |
The wrapper pattern achieves 10-50x performance improvements by delegating all operations to compiled C# code OfficeScrubC2R.psd1:24-26. The PowerShell layer contains only function definitions and basic parameter handling.
Sources: OfficeScrubC2R.psd1:24-26, OfficeScrubC2R.psm1:1-99
The module includes reference implementations for documentation:
| File | Purpose | Loaded by Module? |
|---|---|---|
OfficeScrubNative.dll |
Runtime library | Yes (lazy loaded) |
OfficeScrubC2R-Native.cs |
C# source for DLL | No |
direct_conversion.cs |
Direct VBScript conversion | No |
docs/source/OfficeScrubC2R.vbs |
Original Microsoft VBScript | No |
The reference files OfficeScrubC2R.psd1:86-88 demonstrate the evolution from VBScript to optimized C# but are not executed. They serve developers analyzing the codebase or comparing implementations.
Sources: OfficeScrubC2R.psd1:82-91
The module implements lazy assembly loading for several reasons:
| Benefit | Implementation Detail |
|---|---|
| Fast module import |
Import-Module completes without loading DLL OfficeScrubC2R.psm1:1-9
|
| Avoid conflicts | Check AppDomain before loading OfficeScrubC2R.psm1:27-28
|
| Conditional loading | DLL loads only if wrapper functions are called |
| Error isolation | Assembly load errors don't prevent module import |
| Version flexibility | Different PowerShell sessions can load different DLL versions |
The lazy loading pattern defers Assembly.LoadFrom() OfficeScrubC2R.psm1:31 until Import-OfficeScrubNative is called, typically by New-OfficeScrubOrchestrator. This contrasts with RequiredAssemblies which loads immediately during module import.
Sources: OfficeScrubC2R.psm1:10-35
flowchart TD
Start["Import-OfficeScrubNative called"]
CheckCache{"$script:NativeAssembly<br/>cached & matches path?"}
CheckCache -->|Yes| ReturnCache["Return cached assembly"]
CheckCache -->|No| CheckDomain{"Assembly in<br/>AppDomain already?"}
CheckDomain -->|Yes| CacheDomain["Cache from AppDomain<br/>Return"]
CheckDomain -->|No| Load["Assembly.LoadFrom()<br/>from disk"]
Load --> CacheNew["Cache new assembly<br/>Return"]
ReturnCache --> End["Return Assembly"]
CacheDomain --> End
CacheNew --> End
Assembly Loading Strategy with Three-Level Caching
This flowchart shows the three-level caching strategy implemented in Import-OfficeScrubNative OfficeScrubC2R.psm1:10-35. The function checks the module-level cache first OfficeScrubC2R.psm1:23-25, then the AppDomain OfficeScrubC2R.psm1:27-28, and finally loads from disk OfficeScrubC2R.psm1:31 as a last resort.
Sources: OfficeScrubC2R.psm1:10-35
When a user executes Import-Module OfficeScrubC2R, PowerShell performs these steps:
-
Locate manifest: Find
OfficeScrubC2R.psd1in module path -
Parse manifest: Read
ModuleVersion,RootModule, and configuration OfficeScrubC2R.psd1:1-158 -
Skip assembly loading: Empty
RequiredAssembliesOfficeScrubC2R.psd1:43 -
Execute RootModule: Run
OfficeScrubC2R.psm1OfficeScrubC2R.psd1:3- Set script variables OfficeScrubC2R.psm1:6-8
- Define five wrapper functions OfficeScrubC2R.psm1:10-96
- Export functions OfficeScrubC2R.psm1:98
- Module ready: Functions available, DLL not loaded yet
The module import completes quickly because no native code is loaded. Assembly loading is deferred to the first function call that requires it.
Sources: OfficeScrubC2R.psd1:1-158, OfficeScrubC2R.psm1:1-99
The Import-OfficeScrubNative function includes defensive error handling:
if (-not (Test-Path -Path $resolvedPath -PathType Leaf)) {
throw "Native assembly not found at '$resolvedPath'. Ensure OfficeScrubNative.dll is present alongside the module."
}The function validates DLL existence OfficeScrubC2R.psm1:19-21 before attempting to load, providing clear error messages. If the assembly file is missing, the module still imports successfully, but calls to New-OfficeScrubOrchestrator fail with a descriptive exception.
The Resolve-Path call OfficeScrubC2R.psm1:17 converts relative paths to absolute paths and validates path syntax, using -ErrorAction Stop to halt on invalid paths.
Sources: OfficeScrubC2R.psm1:10-35
The module structure demonstrates several PowerShell best practices:
- Explicit exports: Both manifest and module declare exports OfficeScrubC2R.psd1:65-80, OfficeScrubC2R.psm1:212-221
- Scope management: Deliberate use of global vs. module scope for different components
- Fail-fast validation: Path checks with immediate exceptions OfficeScrubC2R.psm1:15, 24
- Version tracking: Manifest version OfficeScrubC2R.psd1:6 enables update management
- CmdletBinding: Advanced function features with proper parameter attributes OfficeScrubC2R.psm1:119
-
ShouldProcess support: Enables
-WhatIfand-Confirmfor destructive operations OfficeScrubC2R.psm1:119 - Comprehensive metadata: Detailed manifest for PowerShell Gallery compatibility OfficeScrubC2R.psd1:103-168
- Auto-initialization: Environment setup on module load OfficeScrubC2R.psm1:225-231
These patterns create a robust, maintainable module structure that follows PowerShell conventions while optimizing for performance and usability.
Sources: OfficeScrubC2R.psm1:1-233, OfficeScrubC2R.psd1:1-176