Skip to content

Installation

Calvindd2f edited this page Jan 14, 2026 · 1 revision

Installation

Relevant source files

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

This document covers the installation process for the OfficeScrubC2R PowerShell module, including the three supported installation methods, module loading mechanisms, and post-installation verification. For system prerequisites, see System Requirements. For usage instructions after installation, see Quick Start.

Installation Methods

OfficeScrubC2R supports three installation methods: PowerShell Gallery (recommended), GitHub clone, and manual installation. All methods require administrator privileges for full functionality during execution, though the module itself can be installed in user scope.

PowerShell Gallery Installation

The PowerShell Gallery provides the simplest installation path and automatic updates. The module is published as OfficeScrubC2R and can be installed using Install-Module.

# Install for current user only (no admin required)
Install-Module -Name OfficeScrubC2R -Scope CurrentUser

# Install system-wide (requires administrator)
Install-Module -Name OfficeScrubC2R -Scope AllUsers

The -Scope CurrentUser option installs to $HOME\Documents\PowerShell\Modules\OfficeScrubC2R (PowerShell 7+) or $HOME\Documents\WindowsPowerShell\Modules\OfficeScrubC2R (Windows PowerShell 5.1). The -Scope AllUsers option installs to C:\Program Files\PowerShell\Modules\OfficeScrubC2R.

Module Import:

# Import the module
Import-Module OfficeScrubC2R

# Verify installation
Get-Module OfficeScrubC2R -ListAvailable

Sources: README.md:30-38, OfficeScrubC2R.psd1:1-175

GitHub Installation

Direct installation from the GitHub repository provides access to the latest development version and source code:

# Clone the repository
git clone https://github.com/Calvindd2f/OfficeScrubC2R.git
cd OfficeScrubC2R

# Import the module directly
Import-Module .\OfficeScrubC2R.psd1

This method loads the module from the local directory without copying to a module path. The module remains loaded until the PowerShell session ends or Remove-Module is called.

Sources: README.md:40-49

Manual Installation

Manual installation involves downloading the release archive, extracting files, and placing them in a PowerShell module directory:

Step 1: Extract Files

Extract the release archive to one of the following locations:

Scope Path Requires Admin
Current User $HOME\Documents\PowerShell\Modules\OfficeScrubC2R No
Current User (Windows PS) $HOME\Documents\WindowsPowerShell\Modules\OfficeScrubC2R No
All Users C:\Program Files\PowerShell\Modules\OfficeScrubC2R Yes
All Users (Windows PS) C:\Program Files\WindowsPowerShell\Modules\OfficeScrubC2R Yes

Step 2: Unblock Files

Windows marks files downloaded from the internet with the Zone.Identifier alternate data stream. This must be removed to allow module loading:

# Navigate to module directory
cd "$HOME\Documents\PowerShell\Modules\OfficeScrubC2R"

# Unblock all files
Get-ChildItem -Recurse | Unblock-File

Step 3: Import Module

Import-Module OfficeScrubC2R

Sources: README.md:51-58, docs/memory-bank/tech.md:121-124

Module File Structure

The module consists of multiple interdependent files that are loaded in a specific sequence. Understanding this structure is essential for troubleshooting installation issues.

Required Files

The manifest at OfficeScrubC2R.psd1:89-100 defines the complete file list:

File Purpose Type
OfficeScrubC2R.psd1 Module manifest with metadata PowerShell Data File
OfficeScrubC2R.psm1 Root module with public API PowerShell Module
OfficeScrubC2R.ps1 Main script with pipeline logic PowerShell Script
OfficeScrubC2R-Utilities.psm1 Nested utilities module PowerShell Module
OfficeScrubC2R-Native.cs C# source for fallback compilation C# Source
OfficeScrubNative.dll Pre-compiled native library .NET Assembly
build.ps1 Build script for native DLL PowerShell Script
LICENSE MIT license text Text
README.md Documentation Markdown

The module manifest specifies these dependencies at OfficeScrubC2R.psd1:50 (RequiredAssemblies), OfficeScrubC2R.psd1:62 (NestedModules), and OfficeScrubC2R.psd1:89-100 (FileList).

Sources: OfficeScrubC2R.psd1:89-100, docs/memory-bank/structure.md:5-12

Module Directory Structure

OfficeScrubC2R/
├── OfficeScrubC2R.psd1              # Manifest (loads first)
├── OfficeScrubC2R.psm1              # Root module (loads second)
├── OfficeScrubC2R.ps1               # Main script (dot-sourced)
├── OfficeScrubC2R-Utilities.psm1    # Nested module (imported)
├── OfficeScrubC2R-Native.cs         # C# source (fallback)
├── OfficeScrubNative.dll            # Pre-compiled assembly
├── build.ps1                        # Build automation
├── en-US/
│   └── about_OfficeScrubC2R.help.txt
├── LICENSE
└── README.md

Sources: README.md:146-159, docs/memory-bank/structure.md:21-33

Module Loading Sequence

The module initialization follows a specific sequence defined by PowerShell's module loading conventions and the manifest configuration. Understanding this sequence is critical for diagnosing loading failures.

Initialization Flow Diagram

sequenceDiagram
    participant User
    participant PowerShell as "PowerShell Engine"
    participant Manifest as "OfficeScrubC2R.psd1"
    participant RootModule as "OfficeScrubC2R.psm1"
    participant NativeDLL as "OfficeScrubNative.dll"
    participant Compiler as "C# Compiler"
    participant NativeCS as "OfficeScrubC2R-Native.cs"
    participant Utilities as "OfficeScrubC2R-Utilities.psm1"
    participant MainScript as "OfficeScrubC2R.ps1"
    
    User->>PowerShell: Import-Module OfficeScrubC2R
    PowerShell->>Manifest: Load manifest
    
    Note over Manifest: Validate metadata<br/>ModuleVersion 2.19.2<br/>PowerShellVersion 5.1+<br/>DotNetFrameworkVersion 4.5+
    
    Manifest->>NativeDLL: Load RequiredAssemblies
    
    alt DLL exists and not blocked
        NativeDLL-->>Manifest: Assembly loaded
    else DLL missing or blocked
        Manifest->>Compiler: Attempt fallback compilation
        Compiler->>NativeCS: Compile C# source
        NativeCS-->>Compiler: Compilation result
        alt Compilation successful
            Compiler-->>Manifest: Runtime DLL available
        else Compilation failed
            Compiler-->>Manifest: ERROR: Native layer unavailable
        end
    end
    
    Manifest->>RootModule: Load RootModule
    RootModule->>Utilities: Import NestedModules
    Note over Utilities: Import-Module -Force -Global
    Utilities-->>RootModule: Functions exported to global scope
    
    RootModule->>MainScript: Dot-source script
    Note over MainScript: . $PSScriptRoot\OfficeScrubC2R.ps1
    MainScript-->>RootModule: Functions available in module scope
    
    RootModule->>RootModule: Initialize-Environment
    Note over RootModule: Auto-execute on module load<br/>Set $script:LogDir<br/>Create orchestrator instance
    
    RootModule->>PowerShell: Export-ModuleMember
    Note over RootModule: Export functions:<br/>Invoke-OfficeScrubC2R<br/>Get-InstalledOfficeProducts<br/>Test-IsC2R<br/>Initialize-Environment<br/>Stop-OfficeProcesses
    
    PowerShell-->>User: Module ready
Loading

Key Loading Steps:

  1. Manifest Validation - OfficeScrubC2R.psd1:1-175 validates metadata, PowerShell version, and .NET Framework version
  2. Native Assembly Loading - OfficeScrubC2R.psd1:50 loads OfficeScrubNative.dll via RequiredAssemblies
  3. Fallback Compilation - If DLL load fails, the root module attempts runtime compilation from OfficeScrubC2R-Native.cs
  4. Root Module Execution - OfficeScrubC2R.psm1 executes, importing nested modules
  5. Utilities Import - OfficeScrubC2R.psd1:62 specifies OfficeScrubC2R-Utilities.psm1 as nested module
  6. Main Script Dot-Sourcing - Root module dot-sources OfficeScrubC2R.ps1 into module scope
  7. Environment Initialization - Initialize-Environment function executes automatically
  8. Function Export - OfficeScrubC2R.psd1:65-71 defines exported functions and OfficeScrubC2R.psd1:80 defines aliases

Sources: OfficeScrubC2R.psd1:1-175, docs/memory-bank/structure.md:96-103

Smart Fallback Compilation Mechanism

The module implements a smart fallback strategy for the native DLL. If OfficeScrubNative.dll cannot be loaded (due to missing file, zone blocking, or security policy), the root module attempts to compile OfficeScrubC2R-Native.cs at runtime.

flowchart TD
    Start["Module Import Begins"]
    LoadManifest["Load OfficeScrubC2R.psd1"]
    CheckDLL{"OfficeScrubNative.dll<br/>exists and not blocked?"}
    LoadDLL["Load pre-compiled DLL<br/>(OptimizedPath)"]
    CheckCSC{"C# compiler<br/>(csc.exe)<br/>available?"}
    CompileSource["Compile OfficeScrubC2R-Native.cs<br/>using Add-Type"]
    CheckCompile{"Compilation<br/>successful?"}
    UseDLL["Use native performance layer<br/>(10-50x speedup)"]
    Fallback["WARN: Native layer unavailable<br/>Continue with PowerShell-only mode"]
    LoadRootModule["Load OfficeScrubC2R.psm1"]
    Complete["Module initialization complete"]
    
    Start --> LoadManifest
    LoadManifest --> CheckDLL
    CheckDLL -->|Yes| LoadDLL
    CheckDLL -->|No| CheckCSC
    LoadDLL --> UseDLL
    CheckCSC -->|Yes| CompileSource
    CheckCSC -->|No| Fallback
    CompileSource --> CheckCompile
    CheckCompile -->|Yes| UseDLL
    CheckCompile -->|No| Fallback
    UseDLL --> LoadRootModule
    Fallback --> LoadRootModule
    LoadRootModule --> Complete
Loading

Compiler Detection:

The module searches for csc.exe in the following locations:

  • C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe (64-bit)
  • C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe (32-bit)

If compilation fails, the module continues in PowerShell-only mode with degraded performance. The native layer provides 10-50x performance improvements, so fallback should only be used when necessary.

Sources: docs/memory-bank/tech.md:28-47, README.md:175-179

Dependency Resolution

The module has specific runtime dependencies that must be satisfied for successful loading.

Runtime Dependencies

Dependency Source Required By Failure Impact
PowerShell 5.1+ OfficeScrubC2R.psd1:38 Module loading Module import fails
.NET Framework 4.5+ OfficeScrubC2R.psd1:41 Native assembly DLL load fails, fallback triggers
OfficeScrubNative.dll OfficeScrubC2R.psd1:50 Performance layer Fallback to compilation
OfficeScrubC2R-Utilities.psm1 OfficeScrubC2R.psd1:62 Helper functions Module load fails
Administrator privileges Runtime Cleanup operations Operations fail with access denied

Assembly References

The native DLL requires the following .NET assemblies:

  • System.dll (core types)
  • System.Management.dll (WMI operations for license cleanup)
  • Microsoft.CSharp.dll (dynamic compilation support)

These are part of the .NET Framework 4.5+ installation and do not require separate installation.

Sources: OfficeScrubC2R.psd1:38-50, docs/memory-bank/tech.md:16-21

Post-Installation Verification

After installation, verify that the module loaded correctly and all components are functional.

Verification Steps

Step 1: Check Module Availability

# List installed module
Get-Module OfficeScrubC2R -ListAvailable

# Expected output:
# ModuleType Version    Name                PSEdition ExportedCommands
# ---------- -------    ----                --------- ----------------
# Script     2.19.2     OfficeScrubC2R      Desk      {Invoke-OfficeScrubC2R, Get-InstalledOfficeProducts...}

Step 2: Import Module

# Import with verbose output
Import-Module OfficeScrubC2R -Verbose

# Check imported module
Get-Module OfficeScrubC2R

Step 3: Verify Exported Functions

# List exported functions
Get-Command -Module OfficeScrubC2R

# Expected functions (from OfficeScrubC2R.psd1:65-71):
# - Invoke-OfficeScrubC2R
# - Get-InstalledOfficeProducts
# - Test-IsC2R
# - Initialize-Environment
# - Stop-OfficeProcesses

Step 4: Verify Aliases

# Check aliases
Get-Alias | Where-Object { $_.Source -eq 'OfficeScrubC2R' }

# Expected aliases (from OfficeScrubC2R.psd1:80):
# - Remove-OfficeC2R -> Invoke-OfficeScrubC2R
# - Uninstall-OfficeC2R -> Invoke-OfficeScrubC2R

Step 5: Test Native Layer

# Run detection-only mode (requires admin for full access)
Invoke-OfficeScrubC2R -DetectOnly -Verbose

# Check for native layer initialization messages in verbose output
# Look for "OfficeScrubOrchestrator" references indicating native DLL loaded

Sources: OfficeScrubC2R.psd1:65-80, README.md:60-79

Component Loading Verification Diagram

graph TB
    ImportModule["Import-Module OfficeScrubC2R"]
    
    subgraph "Manifest Loading"
        LoadManifest["Load OfficeScrubC2R.psd1"]
        CheckVersion["Verify PowerShell >= 5.1"]
        CheckDotNet["Verify .NET >= 4.5"]
    end
    
    subgraph "Assembly Loading"
        LoadDLL["Load OfficeScrubNative.dll"]
        DLLSuccess{"DLL Loaded?"}
        CompileFallback["Compile OfficeScrubC2R-Native.cs"]
        NativeReady["Native Layer Ready"]
        NativeUnavailable["Native Layer Unavailable"]
    end
    
    subgraph "Module Loading"
        LoadRoot["Load OfficeScrubC2R.psm1"]
        LoadUtilities["Import OfficeScrubC2R-Utilities.psm1"]
        DotSource["Dot-source OfficeScrubC2R.ps1"]
        InitEnv["Execute Initialize-Environment"]
    end
    
    subgraph "Export Phase"
        ExportFunctions["Export Functions:<br/>Invoke-OfficeScrubC2R<br/>Get-InstalledOfficeProducts<br/>Test-IsC2R<br/>Initialize-Environment<br/>Stop-OfficeProcesses"]
        ExportAliases["Export Aliases:<br/>Remove-OfficeC2R<br/>Uninstall-OfficeC2R"]
    end
    
    Complete["Module Ready"]
    
    ImportModule --> LoadManifest
    LoadManifest --> CheckVersion
    CheckVersion --> CheckDotNet
    CheckDotNet --> LoadDLL
    
    LoadDLL --> DLLSuccess
    DLLSuccess -->|Yes| NativeReady
    DLLSuccess -->|No| CompileFallback
    CompileFallback --> NativeReady
    CompileFallback --> NativeUnavailable
    
    NativeReady --> LoadRoot
    NativeUnavailable --> LoadRoot
    LoadRoot --> LoadUtilities
    LoadUtilities --> DotSource
    DotSource --> InitEnv
    
    InitEnv --> ExportFunctions
    ExportFunctions --> ExportAliases
    ExportAliases --> Complete
Loading

Sources: OfficeScrubC2R.psd1:1-175, docs/memory-bank/structure.md:96-118

File Unblocking

Windows attaches the Zone.Identifier alternate data stream to files downloaded from the internet, marking them as potentially unsafe. PowerShell blocks execution of such files by default.

Checking for Blocked Files

# Navigate to module directory
$modulePath = (Get-Module OfficeScrubC2R -ListAvailable)[0].ModuleBase
cd $modulePath

# Check for Zone.Identifier streams
Get-ChildItem -Recurse | Get-Item -Stream Zone.Identifier -ErrorAction SilentlyContinue

Unblocking Methods

Method 1: PowerShell Cmdlet (Recommended)

# Unblock all files in module directory
Get-ChildItem -Path $modulePath -Recurse | Unblock-File

Method 2: File Properties (GUI)

  1. Right-click the DLL file (OfficeScrubNative.dll)
  2. Select "Properties"
  3. Check "Unblock" at the bottom of the General tab
  4. Click "Apply" then "OK"
  5. Repeat for all .dll, .ps1, and .psm1 files

Method 3: Remove Alternate Data Stream Directly

# Remove Zone.Identifier stream
Get-ChildItem -Recurse | ForEach-Object {
    Remove-Item -Path $_.FullName -Stream Zone.Identifier -ErrorAction SilentlyContinue
}

Sources: README.md:57, README.md:209-217

Troubleshooting Installation Issues

Issue: Module Import Fails with "RequiredAssemblies" Error

Symptoms:

Import-Module : Could not load file or assembly 'OfficeScrubNative.dll'

Causes:

  1. DLL is blocked (Zone.Identifier present)
  2. .NET Framework version mismatch
  3. DLL corruption or missing file

Resolution:

# Step 1: Verify .NET version
[System.Environment]::Version

# Step 2: Unblock DLL
$modulePath = (Get-Module OfficeScrubC2R -ListAvailable)[0].ModuleBase
Unblock-File "$modulePath\OfficeScrubNative.dll"

# Step 3: Rebuild DLL from source (if available)
cd $modulePath
.\build.ps1

# Step 4: Import with verbose output
Import-Module OfficeScrubC2R -Verbose -Force

Sources: README.md:209-217, docs/memory-bank/tech.md:16-21

Issue: PowerShell Version Error

Symptoms:

Import-Module : This module requires PowerShell version 5.1 or later

Resolution:

Check PowerShell version:

$PSVersionTable.PSVersion

# Expected: Major >= 5, Minor >= 1

If version is below 5.1, upgrade PowerShell:

Sources: OfficeScrubC2R.psd1:38

Issue: Execution Policy Restriction

Symptoms:

Import-Module : File cannot be loaded because running scripts is disabled

Resolution:

Check execution policy:

Get-ExecutionPolicy -List

Set execution policy (requires admin for system-wide):

# For current user only (recommended)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope CurrentUser

# System-wide (requires admin)
Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Scope LocalMachine

Sources: docs/memory-bank/tech.md:135

Issue: Permission Denied During Installation

Symptoms:

Install-Module : Access to the path 'C:\Program Files\PowerShell\Modules' is denied

Resolution:

Option 1: Install to user scope (no admin required):

Install-Module -Name OfficeScrubC2R -Scope CurrentUser

Option 2: Run PowerShell as Administrator:

Start-Process powershell -Verb RunAs

Then re-run installation with -Scope AllUsers.

Sources: README.md:30-38

Issue: Native Layer Compilation Fails

Symptoms: Verbose output shows:

WARNING: Failed to load native assembly, attempting fallback compilation
ERROR: Native layer unavailable, continuing in PowerShell-only mode

Causes:

  1. C# compiler (csc.exe) not found
  2. .NET Framework SDK not installed
  3. Insufficient permissions to write temporary files

Resolution:

Verify compiler availability:

# Check for 64-bit compiler
Test-Path 'C:\Windows\Microsoft.NET\Framework64\v4.0.30319\csc.exe'

# Check for 32-bit compiler
Test-Path 'C:\Windows\Microsoft.NET\Framework\v4.0.30319\csc.exe'

If compiler is missing, install .NET Framework Developer Pack 4.5 or later.

Workaround: Pre-compile the DLL on another machine and copy to module directory:

# On build machine:
cd <module-path>
.\build.ps1

# Copy OfficeScrubNative.dll to target machine module directory

Sources: docs/memory-bank/tech.md:28-47, README.md:175-187

Issue: Nested Module Import Failure

Symptoms:

Import-Module : The specified module 'OfficeScrubC2R-Utilities.psm1' was not loaded

Resolution:

Verify file integrity:

$modulePath = (Get-Module OfficeScrubC2R -ListAvailable)[0].ModuleBase

# Check for utilities module
Test-Path "$modulePath\OfficeScrubC2R-Utilities.psm1"

# Check FileList in manifest matches actual files
$manifest = Import-PowerShellDataFile "$modulePath\OfficeScrubC2R.psd1"
$manifest.FileList | ForEach-Object {
    $exists = Test-Path "$modulePath\$_"
    [PSCustomObject]@{
        File = $_
        Exists = $exists
    }
}

If files are missing, reinstall the module.

Sources: OfficeScrubC2R.psd1:89-100

Building from Source

Developers and users in restricted environments may need to build the native DLL from source.

Build Process

The build.ps1 script compiles OfficeScrubC2R-Native.cs into OfficeScrubNative.dll:

# Navigate to module directory
cd <module-path>

# Build DLL
.\build.ps1

# Clean and rebuild
.\build.ps1 -Clean

Build Requirements

Requirement Purpose Location
C# Compiler (csc.exe) Compile C# source to DLL C:\Windows\Microsoft.NET\Framework64\v4.0.30319\
.NET Framework 4.5+ Runtime target System-wide
PowerShell 5.1+ Execute build script System-wide

Build Output

The build process produces:

  • OfficeScrubNative.dll - Compiled assembly (required by manifest)
  • build.log - Compilation output and errors (if any)

After building, reimport the module:

Import-Module .\OfficeScrubC2R.psd1 -Force

Sources: README.md:175-187, docs/memory-bank/tech.md:28-47

Summary

Installation of OfficeScrubC2R requires:

  1. PowerShell 5.1+ and .NET Framework 4.5+ installed
  2. Module files extracted to a PowerShell module path
  3. Files unblocked using Unblock-File
  4. Module imported using Import-Module
  5. Native DLL loaded or compiled from source

The module's smart fallback mechanism ensures functionality even when the pre-compiled DLL cannot be loaded, though performance is degraded in PowerShell-only mode. Verification after installation confirms that all components loaded successfully and functions are exported correctly.

For usage instructions, see Quick Start. For troubleshooting runtime issues, see Troubleshooting.

Clone this wiki locally