Skip to content

PowerShell Components

Calvindd2f edited this page Jan 14, 2026 · 1 revision

PowerShell Components

Relevant source files

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

This document describes the PowerShell layer components that provide the user interface and orchestration for OfficeScrubC2R. The PowerShell layer is intentionally lightweight, serving as a thin wrapper around the native C# library (OfficeScrubNative.dll). All performance-critical operations are delegated to the native layer, which is documented in Native Performance Layer.

Overview

The PowerShell layer consists of two primary files:

File Lines Purpose Key Responsibilities
OfficeScrubC2R.psm1 99 Module Definition DLL loading, orchestrator creation, helper function exports
OfficeScrubC2R.psd1 158 Module Manifest Metadata, version info, PowerShell Gallery compatibility, exported functions

The architecture is designed for simplicity and performance:

  • Minimal PowerShell Code: The module contains only 5 exported functions that wrap native operations
  • Direct DLL Integration: All cleanup logic resides in the compiled OfficeScrubNative.dll
  • Dynamic Assembly Loading: The native assembly is loaded on-demand with smart caching
  • Cross-Platform Support: Compatible with both PowerShell Desktop and PowerShell Core

Sources: OfficeScrubC2R.psm1:1-99, OfficeScrubC2R.psd1:1-158

Architectural Simplification

graph TB
    subgraph "Legacy Architecture (v2.x)"
        old_psm1["OfficeScrubC2R.psm1<br/>233 lines"]
        old_ps1["OfficeScrubC2R.ps1<br/>1009 lines<br/>Three-stage pipeline"]
        old_util["OfficeScrubC2R-Utilities.psm1<br/>1091 lines<br/>45+ functions"]
        old_dll["OfficeScrubNative.dll<br/>Optional performance layer"]
        
        old_psm1 --> old_util
        old_psm1 --> old_ps1
        old_ps1 --> old_util
        old_util -.optional.-> old_dll
    end
    
    subgraph "Current Architecture (v3.0+)"
        new_psm1["OfficeScrubC2R.psm1<br/>99 lines<br/>5 functions"]
        new_psd1["OfficeScrubC2R.psd1<br/>158 lines<br/>Manifest"]
        new_dll["OfficeScrubNative.dll<br/>Required native layer"]
        orch["OfficeScrubOrchestrator<br/>Central coordinator"]
        
        new_psm1 --> new_dll
        new_dll --> orch
        new_psd1 -.defines.-> new_psm1
    end
    
    arrow["Migration: v2.x → v3.0"]
    old_psm1 -.-> arrow
    old_ps1 -.-> arrow
    old_util -.-> arrow
    arrow -.-> new_dll
    
    note1["Removed:<br/>- Complex PowerShell orchestration<br/>- 45+ utility functions<br/>- Script-based cleanup logic"]
    note2["Consolidated:<br/>- All logic moved to C# DLL<br/>- PowerShell is thin wrapper<br/>- 10-50x performance improvement"]
    
    old_util -.-> note1
    new_dll -.-> note2
Loading

Architectural Evolution

Version 3.0 represents a fundamental architectural shift. The legacy implementation used extensive PowerShell scripting (2,300+ lines) with optional native acceleration. The current implementation inverts this model: all cleanup logic resides in the compiled C# library, with PowerShell providing only a minimal interface layer. This change delivers:

  • Performance: 10-50x improvement through native code execution
  • Maintainability: Single source of truth for business logic
  • Simplicity: 99 lines of PowerShell vs. 2,300+ lines previously
  • Reliability: Compiled code with strong typing and error handling

Sources: OfficeScrubC2R.psm1:1-99, OfficeScrubC2R.psd1:124-137

Module Loading and Initialization Sequence

sequenceDiagram
    participant User
    participant PSGallery as "PowerShell Gallery"
    participant psm1 as "OfficeScrubC2R.psm1"
    participant Assembly as "System.Reflection.Assembly"
    participant DLL as "OfficeScrubNative.dll"
    participant Orch as "OfficeScrubOrchestrator"
    
    User->>PSGallery: "Install-Module OfficeScrubC2R"
    PSGallery-->>User: "Module files downloaded"
    
    User->>psm1: "Import-Module OfficeScrubC2R"
    psm1->>psm1: "Initialize module variables<br/>Lines 6-8"
    
    Note over psm1: "$script:ModuleRoot = $PSScriptRoot<br/>$script:NativeAssemblyPath = Join-Path...<br/>$script:NativeAssembly = $null"
    
    psm1->>psm1: "Export-ModuleMember<br/>Line 98"
    Note over psm1: "5 functions exported:<br/>Import-OfficeScrubNative<br/>New-OfficeScrubOrchestrator<br/>Test-OfficeC2RPath<br/>Test-OfficeProductScope<br/>Get-OfficeScrubHelpers"
    
    psm1-->>User: "Module ready (DLL not loaded)"
    
    User->>psm1: "New-OfficeScrubOrchestrator"
    psm1->>psm1: "Import-OfficeScrubNative<br/>Line 44"
    
    psm1->>Assembly: "GetAssemblies()<br/>Line 27-28"
    Assembly-->>psm1: "Check if already loaded"
    
    alt "DLL not loaded"
        psm1->>Assembly: "LoadFrom(resolvedPath)<br/>Line 31"
        Assembly->>DLL: "Load assembly"
        DLL-->>Assembly: "Assembly loaded"
        Assembly-->>psm1: "$script:NativeAssembly"
    else "DLL already loaded"
        Assembly-->>psm1: "Cached assembly"
    end
    
    psm1->>Orch: "new([Environment]::Is64BitOperatingSystem)<br/>Line 45"
    Orch-->>psm1: "Orchestrator instance"
    psm1-->>User: "Return orchestrator"
    
    Note over User,Orch: "Orchestrator provides access to:<br/>Registry, Files, Processes, Shell,<br/>WindowsInstaller, TypeLib,<br/>License, Services helpers"
Loading

Module Loading Sequence

The current architecture uses lazy loading for optimal performance:

  1. Module Import - OfficeScrubC2R.psm1:6-8 initializes module-level variables for assembly paths
  2. Function Export - OfficeScrubC2R.psm1:98 exports 5 functions immediately without loading the DLL
  3. On-Demand DLL Loading - DLL is loaded only when New-OfficeScrubOrchestrator or Import-OfficeScrubNative is called
  4. Assembly Caching - OfficeScrubC2R.psm1:23-28 checks if assembly is already loaded to avoid duplicate loading
  5. Assembly Resolution - OfficeScrubC2R.psm1:17-21 resolves the full path and validates DLL existence
  6. Orchestrator Creation - OfficeScrubC2R.psm1:45 instantiates the orchestrator with automatic 64-bit detection

This lazy loading pattern ensures:

  • Fast module import times (no DLL compilation)
  • Memory efficiency (DLL loaded only when needed)
  • Multi-load safety (assembly cached after first load)

Sources: OfficeScrubC2R.psm1:6-46

PowerShell-to-Native Bridge Architecture

graph TB
    subgraph "PowerShell Interface Layer"
        import["Import-OfficeScrubNative()<br/>psm1:10-35"]
        new_orch["New-OfficeScrubOrchestrator()<br/>psm1:37-46"]
        test_path["Test-OfficeC2RPath()<br/>psm1:48-60"]
        test_scope["Test-OfficeProductScope()<br/>psm1:62-74"]
        get_helpers["Get-OfficeScrubHelpers()<br/>psm1:76-96"]
    end
    
    subgraph "Native Assembly: OfficeScrubNative.dll"
        orch["OfficeScrubOrchestrator<br/>Central coordinator"]
        
        subgraph "Helper Classes"
            reg["RegistryHelper<br/>Registry operations"]
            file["FileHelper<br/>File system operations"]
            proc["ProcessHelper<br/>Process management"]
            shell["ShellHelper<br/>Shell integration"]
            wi["WindowsInstallerHelper<br/>MSI metadata"]
            tl["TypeLibHelper<br/>COM type libraries"]
            lic["LicenseHelper<br/>OSPP/SPP operations"]
            svc["ServiceHelper<br/>Service management"]
        end
    end
    
    subgraph "User Code"
        user_script["PowerShell Script<br/>or Interactive Session"]
    end
    
    user_script -->|"1. Create orchestrator"| new_orch
    new_orch -->|"Loads if needed"| import
    import -->|"Assembly.LoadFrom()"| orch
    
    new_orch -->|"new OfficeScrubOrchestrator(is64Bit)"| orch
    
    user_script -->|"2. Get helpers"| get_helpers
    get_helpers -->|"Access properties"| orch
    
    orch --> reg
    orch --> file
    orch --> proc
    orch --> shell
    orch --> wi
    orch --> tl
    orch --> lic
    orch --> svc
    
    user_script -->|"3. Test paths/scope"| test_path
    user_script -->|"3. Test paths/scope"| test_scope
    
    test_path -->|"orchestrator.IsC2RPath(path)"| orch
    test_scope -->|"orchestrator.IsInScope(productCode)"| orch
    
    get_helpers -->|"Returns PSCustomObject with:"| helpers_obj["[pscustomobject]@{<br/>RegistryHelper = $orch.Registry<br/>FileHelper = $orch.Files<br/>ProcessHelper = $orch.Processes<br/>ShellHelper = $orch.Shell<br/>WindowsInstallerHelper = $orch.WindowsInstaller<br/>TypeLibHelper = $orch.TypeLib<br/>LicenseHelper = $orch.License<br/>ServiceHelper = $orch.Services<br/>}"]
Loading

Bridge Pattern Implementation

The PowerShell layer acts as a bridge between user scripts and native C# operations:

  1. Assembly Loading - Import-OfficeScrubNative OfficeScrubC2R.psm1:10-35 handles DLL loading with caching
  2. Orchestrator Creation - New-OfficeScrubOrchestrator OfficeScrubC2R.psm1:37-46 creates the central coordinator
  3. Helper Access - Get-OfficeScrubHelpers OfficeScrubC2R.psm1:76-96 exposes all 8 helper classes as a PSCustomObject
  4. Validation Methods - Test-OfficeC2RPath and Test-OfficeProductScope provide path/product validation
  5. Type Safety - PowerShell functions accept strongly-typed orchestrator parameters OfficeScrubC2R.psm1:52,66,79

Sources: OfficeScrubC2R.psm1:10-96

Main Script (OfficeScrubC2R.ps1)

The main script implements the three-stage execution pipeline and contains the core business logic. It is dot-sourced into the module scope at OfficeScrubC2R.psm1:21.

Function Hierarchy

graph TD
    main["Main()<br/>Lines 924-1001"]
    
    main --> init["Initialize-Script()<br/>Lines 87-136"]
    main --> find["Find-InstalledOfficeProducts()<br/>Lines 138-163"]
    main --> uninstall["Uninstall-OfficeProducts()<br/>Lines 187-247"]
    main --> cleanreg["Clean-OfficeRegistry()<br/>Lines 497-546"]
    main --> cleanup["Complete-Cleanup()<br/>Lines 660-844"]
    main --> summary["Show-Summary()<br/>Lines 867-918"]
    
    find --> ensure["Ensure-ValidWIMetadata()<br/>Lines 165-185"]
    
    uninstall --> clearlic["Clear-OfficeLicenses()<br/>util:773-798"]
    uninstall --> stopproc1["Stop-OfficeProcesses()<br/>util:549-562"]
    uninstall --> removetasks["Remove-ScheduledTasks()<br/>Lines 602-656"]
    uninstall --> clearshort1["Clear-Shortcuts()<br/>util:949-1005"]
    uninstall --> uninstallc2r["Uninstall-OfficeC2R()<br/>Lines 249-282"]
    uninstall --> removepub["Remove-PublishedComponents()<br/>Lines 315-378"]
    uninstall --> removec2rreg["Remove-C2RRegistryData()<br/>Lines 380-400"]
    uninstall --> uninstallmsi["Uninstall-MSIProducts()<br/>Lines 421-491"]
    
    uninstallc2r --> buildxml["Build-RemoveXml()<br/>Lines 284-294"]
    uninstallc2r --> downloadodt["Download-ODT()<br/>Lines 296-313"]
    
    cleanreg --> clearoffice["Clear-OfficeHKLM()<br/>Lines 548-570"]
    cleanreg --> clearrun["Clear-RunKeyEntries()<br/>Lines 572-585"]
    cleanreg --> cleararp["Clear-ARPEntries()<br/>Lines 587-598"]
    cleanreg --> clearwi["Clear-WindowsInstallerMetadata()<br/>util:804-831"]
    cleanreg --> cleartype["Clear-TypeLibRegistrations()<br/>util:837-849"]
    
    cleanup --> stopproc2["Stop-OfficeProcesses()"]
    cleanup --> removetasks2["Remove-ScheduledTasks()"]
    cleanup --> removesvc["Remove-Service()<br/>util:747-767"]
    cleanup --> clearshort2["Clear-Shortcuts()"]
    cleanup --> removeempty["Remove-EmptyFolders()<br/>Lines 846-863"]
Loading

Stage 0: Detection (lines 138-163) validates Windows Installer metadata integrity before scanning for installed products.

Stage 1: Uninstall (lines 187-247) coordinates license cleanup, process termination, ODT-based C2R removal, and MSI product uninstallation.

Stage 2: Cleanup (lines 497-844) performs comprehensive registry cleanup and file system cleanup with reboot handling for locked files.

Stage 3: Summary (lines 867-918) displays results, logs detailed error information, and handles reboot prompts.

Sources: OfficeScrubC2R.ps1:87-1001

Script-Level Variables and Parameters

The main script accepts 12 parameters defined at OfficeScrubC2R.ps1:62-75:

[CmdletBinding()]
param(
    [switch]$Quiet,          # Minimal output
    [switch]$DetectOnly,     # Detection mode
    [switch]$Force,          # Skip confirmation
    [switch]$RemoveAll,      # Remove all products
    [switch]$KeepLicense,    # Preserve licenses
    [switch]$Offline,        # Skip ODT download
    [switch]$ForceArpUninstall,
    [switch]$ClearTaskBand,
    [switch]$UnpinMode,      # Unpin shortcuts only
    [switch]$SkipSD,         # Skip scheduled deletion
    [switch]$NoElevate,      # No elevation attempt
    [string]$LogPath         # Custom log location
)

These parameters are copied to script-scope variables at OfficeScrubC2R.ps1:87-136 via Initialize-Script(), allowing them to be accessed by all functions in the script.

Sources: OfficeScrubC2R.ps1:62-75, OfficeScrubC2R.ps1:87-136

Module Definition (OfficeScrubC2R.psm1)

The module definition provides the public API through Invoke-OfficeScrubC2R and manages module loading.

Public Function: Invoke-OfficeScrubC2R

graph LR
    user["User calls<br/>Invoke-OfficeScrubC2R"]
    validate["Parameter Validation<br/>Lines 161-173"]
    shouldprocess["ShouldProcess Check<br/>Line 177"]
    setvars["Set script: Variables<br/>Lines 180-191"]
    callmain["Call Main()<br/>Line 194"]
    return["Return Exit Code<br/>Line 197"]
    
    user --> validate
    validate --> shouldprocess
    shouldprocess --> setvars
    setvars --> callmain
    callmain --> return
    return --> user
    
    validate -.elevation check.-> admin["Test Admin Privileges<br/>Lines 161-168"]
    validate -.version check.-> psver["Test PS Version >= 5.1<br/>Lines 171-173"]
Loading

The function at OfficeScrubC2R.psm1:118-209 implements:

  1. Privilege Validation - Checks administrator rights unless -NoElevate specified (lines 161-168)
  2. Version Validation - Requires PowerShell 5.1+ (lines 171-173)
  3. ShouldProcess Support - Implements -WhatIf and -Confirm (line 177)
  4. Variable Bridge - Copies parameters to script-scope for main script access (lines 180-191)
  5. Main Execution - Calls Main() from the dot-sourced script (line 194)

Aliases

Two aliases are defined at OfficeScrubC2R.psm1:120:

  • Remove-OfficeC2R
  • Uninstall-OfficeC2R

These provide intuitive alternative names for the primary function and are exported at OfficeScrubC2R.psm1:218-220.

Sources: OfficeScrubC2R.psm1:118-209, OfficeScrubC2R.psm1:212-221

Utilities Module (OfficeScrubC2R-Utilities.psm1)

The utilities module provides 45+ functions organized into functional categories. All functions delegate performance-critical operations to $script:Orchestrator.

Function Categories

Category Functions Purpose
Environment Initialize-Environment, Get-SystemInfo, Test-IsElevated System detection and orchestrator setup
Logging Initialize-Log, Write-Log, Write-LogHeader, Write-LogSubHeader, Write-LogOnly, Close-Log Comprehensive logging infrastructure
Error Handling Set-ErrorCode, Clear-ErrorCode, Set-ReturnValue Bitmask-based error code management
Registry Get-RegistryValue, Set-RegistryValue, Remove-RegistryKey, Remove-RegistryValue, Get-RegistryKeys, Get-RegistryValues, Test-RegistryKeyExists Registry operations with WOW64 support
File System Remove-FolderRecursive, Remove-FileForced, Add-PendingFileDelete File operations with reboot scheduling
Process Stop-OfficeProcesses, Test-ProcessRunning Process management
Detection Get-InstalledOfficeProducts, Test-IsC2R, Test-ProductInScope Product detection and filtering
Services Remove-Service Service management
Licensing Clear-OfficeLicenses OSPP/SPP operations
Windows Installer Clear-WindowsInstallerMetadata MSI metadata cleanup
TypeLib Clear-TypeLibRegistrations COM type library cleanup
Shell Clear-ShellIntegration, Clear-Shortcuts Shell extension and shortcut cleanup

Registry Operations Pattern

All registry functions follow a consistent delegation pattern to the orchestrator:

graph LR
    caller["Calling Function"]
    regfunc["Registry Function<br/>(e.g., Get-RegistryValue)"]
    orch["$script:Orchestrator.Registry"]
    regh["RegistryHelper<br/>(Native C#)"]
    win32["Win32 APIs<br/>(advapi32.dll)"]
    
    caller --> regfunc
    regfunc --> orch
    orch --> regh
    regh --> win32
    win32 -.result.-> regh
    regh -.result.-> orch
    orch -.result.-> regfunc
    regfunc -.result.-> caller
    
    note1["Example:<br/>Get-RegistryValue<br/>(util:382-391)"]
    note2["Orchestrator property<br/>(util:391)"]
    note3["30x faster than<br/>PowerShell native"]
    
    regfunc -.-> note1
    orch -.-> note2
    regh -.-> note3
Loading

For example, Get-RegistryValue at OfficeScrubC2R-Utilities.psm1:382-391:

return $script:Orchestrator.Registry.GetValue($Hive, $SubKey, $ValueName, $DefaultValue)

This pattern provides:

  • Consistent API across all registry operations
  • 30x performance improvement through native code
  • WOW64 registry view support
  • Silent error handling with logging

Sources: OfficeScrubC2R-Utilities.psm1:380-471

File Operations Pattern

File operations at OfficeScrubC2R-Utilities.psm1:477-543 implement automatic reboot scheduling for locked files:

graph TD
    remove["Remove-FolderRecursive<br/>or Remove-FileForced"]
    exists["Check if path exists"]
    detectonly["Check $script:DetectOnly"]
    callorchestrator["Call $script:Orchestrator.Files"]
    success["Operation successful?"]
    schedule["Schedule for reboot<br/>Set $script:RebootRequired<br/>Set ERROR_REBOOT_REQUIRED"]
    done["Return result"]
    
    remove --> exists
    exists -->|No| done
    exists -->|Yes| detectonly
    detectonly -->|True| done
    detectonly -->|False| callorchestrator
    callorchestrator --> success
    success -->|Yes| done
    success -->|No| schedule
    schedule --> done
Loading

Key features:

  • Detect-Only Mode: Previews operations without executing (lines 484-503)
  • Reboot Scheduling: Automatically schedules locked files via PendingFileRenameOperations (lines 492-495)
  • Error Tracking: Sets ERROR_REBOOT_REQUIRED flag in error code (line 495)

Sources: OfficeScrubC2R-Utilities.psm1:477-543

Product Detection

Get-InstalledOfficeProducts at OfficeScrubC2R-Utilities.psm1:575-717 implements comprehensive product detection across multiple registry locations:

Detection Source Registry Path Lines
O15 Configuration SOFTWARE\Microsoft\Office\15.0\ClickToRun\Configuration 586-599
O15 PropertyBag SOFTWARE\Microsoft\Office\15.0\ClickToRun\propertyBag 603-615
Office C2R (QR8+) SOFTWARE\Microsoft\Office\ClickToRun\ProductReleaseIDs 619-645
Office C2R (QR7) SOFTWARE\Microsoft\Office\ClickToRun\Configuration 649-664
O16 Configuration (QR6) SOFTWARE\Microsoft\Office\16.0\ClickToRun\Configuration 668-683
ARP Entries SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall 687-713

The function populates two script-level dictionaries:

  • $script:InstalledSku: Product ID → Version mapping
  • $script:C2RSuite: Product ID → Display string mapping

Sources: OfficeScrubC2R-Utilities.psm1:575-717

Script-Level State Management

State Variables

The utilities module maintains extensive script-level state at OfficeScrubC2R-Utilities.psm1:4-71:

Error Code System (lines 9-22):

$script:ERROR_SUCCESS = 0
$script:ERROR_FAIL = 1
$script:ERROR_REBOOT_REQUIRED = 2
$script:ERROR_USERCANCEL = 4
$script:ERROR_STAGE1 = 8
$script:ERROR_STAGE2 = 16
$script:ERROR_INCOMPLETE = 32
$script:ERROR_DCAF_FAILURE = 64
$script:ERROR_ELEVATION_USERDECLINED = 128
$script:ERROR_ELEVATION = 256
$script:ERROR_SCRIPTINIT = 512
$script:ERROR_RELAUNCH = 1024
$script:ERROR_UNKNOWN = 2048

These constants form a bitmask system where multiple errors can be combined using bitwise OR.

Execution State (lines 28-47):

  • $script:ErrorCode: Current error bitmask
  • $script:RebootRequired: Boolean flag for reboot necessity
  • $script:IsElevated: Administrator privilege status
  • $script:Is64Bit: 64-bit OS detection
  • Parameter flags: $script:Quiet, $script:DetectOnly, $script:Force, etc.

Product Collections (lines 49-54):

  • $script:InstalledSku: Detected Office products
  • $script:C2RSuite: C2R suite information
  • $script:KeepSku: Products to preserve
  • $script:DelInUse: Files scheduled for reboot deletion

Environment Paths (lines 56-67):

  • Standard folder paths (ProgramFiles, ProgramData, etc.)
  • Computed paths (WICacheDir, ScrubDir, LogDir)

Native Orchestrator (line 70):

  • $script:Orchestrator: The OfficeScrubOrchestrator instance providing access to all native helpers

Sources: OfficeScrubC2R-Utilities.psm1:4-71

Error Code Management

Error codes use a bitmask pattern implemented at OfficeScrubC2R-Utilities.psm1:333-362:

graph TD
    seterror["Set-ErrorCode(ErrorBit)"]
    bitwiseor["ErrorCode = ErrorCode OR ErrorBit"]
    checkcritical["Is ErrorBit critical?"]
    setfail["ErrorCode = ErrorCode OR ERROR_FAIL"]
    done1["Return"]
    
    seterror --> bitwiseor
    bitwiseor --> checkcritical
    checkcritical -->|Yes| setfail
    checkcritical -->|No| done1
    setfail --> done1
    
    clearerror["Clear-ErrorCode(ErrorBit)"]
    bitwisenot["ErrorCode = ErrorCode AND NOT ErrorBit"]
    checkclearable["Is ErrorBit clearable?"]
    clearfail["ErrorCode = ErrorCode AND NOT ERROR_FAIL"]
    done2["Return"]
    
    clearerror --> bitwisenot
    bitwisenot --> checkclearable
    checkclearable -->|Yes| clearfail
    checkclearable -->|No| done2
    clearfail --> done2
    
    note1["Critical errors:<br/>DCAF_FAILURE<br/>STAGE2<br/>ELEVATION_USERDECLINED<br/>ELEVATION<br/>SCRIPTINIT"]
    note2["Clearable errors:<br/>ELEVATION_USERDECLINED<br/>ELEVATION<br/>SCRIPTINIT"]
    
    checkcritical -.-> note1
    checkclearable -.-> note2
Loading

This pattern allows:

  • Multiple simultaneous error conditions
  • Automatic ERROR_FAIL cascading for critical errors
  • Individual error flag clearing while maintaining others

Sources: OfficeScrubC2R-Utilities.psm1:333-362

Module Export Manifest

The utilities module exports 45 functions and 39 variables at OfficeScrubC2R-Utilities.psm1:1011-1089, making them available to:

  • The main script (dot-sourced into module scope)
  • The module definition
  • Other PowerShell scripts that import the module with -Force -Global

The root module exports only 5 functions at OfficeScrubC2R.psm1:212-221:

  • Invoke-OfficeScrubC2R (with aliases)
  • Get-InstalledOfficeProducts
  • Test-IsC2R
  • Initialize-Environment
  • Stop-OfficeProcesses

This selective export pattern maintains a clean public API while providing internal functions full access to the utilities.

Sources: OfficeScrubC2R.psm1:212-221, OfficeScrubC2R-Utilities.psm1:1011-1089

Clone this wiki locally