Skip to content

Building from Source

Calvindd2f edited this page Jan 14, 2026 · 1 revision

Building from Source

Relevant source files

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

This document provides comprehensive instructions for compiling the OfficeScrubNative C# library from source code. It covers the automated build process using build.ps1, manual compilation procedures for both .NET Framework and .NET Core targets, build verification steps, and the CI/CD pipeline configuration.

For information about development guidelines and coding standards, see Development Guidelines. For testing procedures after building, see Testing and Validation. For the overall release workflow, see Release Process.


Prerequisites

The following tools and frameworks are required to build OfficeScrubC2R from source:

Component Requirement Purpose
Operating System Windows 10 or later Native Win32 API compilation target
PowerShell 5.1 or PowerShell 7+ Build script execution
.NET Framework 4.5 or later Desktop edition compilation target
C# Compiler (csc.exe) v4.0.30319 or later .NET Framework build
.NET SDK 7.0 or later (optional) .NET Core compilation target
Reference Assemblies System.Management.dll, Microsoft.CSharp.dll Required for WMI and dynamic operations

The C# compiler csc.exe is typically located at:

  • 64-bit: %WINDIR%\Microsoft.NET\Framework64\v4.0.30319\csc.exe
  • 32-bit: %WINDIR%\Microsoft.NET\Framework\v4.0.30319\csc.exe

Sources: .github/workflows/ci.yml:19-30, tests/Verify-NativeBuild.ps1:27-35


Build Process Overview

The following diagram illustrates the complete build workflow from source code to compiled assemblies:

Build Process Workflow

flowchart TD
    Start["Source: OfficeScrubC2R-Native.cs"] --> BuildScript["build.ps1 Execution"]
    
    BuildScript --> Clean{"-Clean Parameter?"}
    Clean -->|Yes| RemoveArtifacts["Remove OfficeScrubNative.dll<br/>Remove build artifacts"]
    Clean -->|No| SkipClean["Skip cleanup"]
    RemoveArtifacts --> Framework
    SkipClean --> Framework
    
    Framework["Detect .NET Framework"] --> CSC{csc.exe Available?}
    CSC -->|Yes| CompileNET["csc.exe /target:library<br/>/out:OfficeScrubNative.dll<br/>/optimize+ /unsafe"]
    CSC -->|No| FallbackNET["Write-Warning: No compiler"]
    
    CompileNET --> RefCheck["Reference Assemblies:<br/>System.Management.dll<br/>Microsoft.CSharp.dll"]
    RefCheck --> CompileArgs["Build Arguments:<br/>/warn:4<br/>/reference:assemblies"]
    CompileArgs --> NETOutput["Output: OfficeScrubNative.dll<br/>.NET Framework 4.5+"]
    
    NETOutput --> CoreCheck{".NET SDK Available?"}
    CoreCheck -->|Yes| ProjectGen["Generate .csproj:<br/>OfficeScrubNative.Core.csproj"]
    CoreCheck -->|No| SkipCore["Skip .NET Core build"]
    
    ProjectGen --> CoreBuild["dotnet build<br/>TargetFramework: net7.0-windows"]
    CoreBuild --> CoreOutput["Output: OfficeScrubNative.Core.dll<br/>.NET Core 7.0+"]
    
    CoreOutput --> Verify["Verify-NativeBuild.ps1:<br/>Test assembly load<br/>Instantiate OfficeScrubOrchestrator"]
    SkipCore --> Verify
    FallbackNET --> End
    
    Verify --> Success["Build complete"]
    
    style Start fill:#f9f9f9
    style NETOutput fill:#e1ffe1
    style CoreOutput fill:#e1ffe1
    style Success fill:#e1f5ff
Loading

Sources: build.ps1:1-150, tests/Verify-NativeBuild.ps1:21-143, .github/workflows/ci.yml:24-30


Building with build.ps1

The primary build method uses the build.ps1 script located in the repository root. This script handles compilation, dependency resolution, and output verification.

Basic Usage

# Standard build
.\build.ps1

# Clean build (removes existing DLL first)
.\build.ps1 -Clean

# Verbose output
.\build.ps1 -Verbose

Build Script Parameters

Parameter Type Default Description
-Clean Switch $false Removes existing OfficeScrubNative.dll before building
-Verbose Switch $false Displays detailed compilation output

The build.ps1 script performs the following operations:

  1. Compiler Detection: Searches for csc.exe in standard .NET Framework installation paths
  2. Reference Resolution: Locates required reference assemblies (System.Management.dll, Microsoft.CSharp.dll)
  3. Compilation: Invokes csc.exe with optimized build flags
  4. Output Verification: Confirms OfficeScrubNative.dll was created successfully

Build Script Architecture

graph TD
    Script["build.ps1"] --> Validate["Validate-SourceFile:<br/>Test-Path OfficeScrubC2R-Native.cs"]
    
    Validate --> Compiler["Find-Compiler:<br/>Search Framework64/Framework"]
    Compiler --> CompilerPath["$compiler = csc.exe path"]
    
    CompilerPath --> References["Resolve-References:<br/>Join-Path compiler dir System.Management.dll<br/>Join-Path compiler dir Microsoft.CSharp.dll"]
    
    References --> Arguments["Build-Arguments:<br/>/target:library<br/>/out:OfficeScrubNative.dll<br/>/optimize+<br/>/unsafe<br/>/warn:4<br/>/reference:System.Management.dll<br/>/reference:Microsoft.CSharp.dll<br/>OfficeScrubC2R-Native.cs"]
    
    Arguments --> Invoke["Start-Process csc.exe<br/>-ArgumentList args<br/>-NoNewWindow -Wait"]
    
    Invoke --> ExitCode{Exit Code?}
    ExitCode -->|0| Success["Write-Host: Build succeeded<br/>Test-Path OfficeScrubNative.dll"]
    ExitCode -->|Non-zero| Error["throw: Compilation failed"]
    
    Success --> DLL["OfficeScrubNative.dll"]
    
    style DLL fill:#e1ffe1
    style Error fill:#ffe1e1
Loading

Sources: build.ps1:1-150, .github/workflows/ci.yml:24-30


Manual Build Process

Building for .NET Framework

The .NET Framework compilation target produces OfficeScrubNative.dll compatible with PowerShell 5.1 (Desktop edition).

Command-Line Compilation:

# Locate compiler
$csc = "$env:WINDIR\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
$compilerDir = Split-Path $csc -Parent

# Prepare references
$systemManagement = Join-Path $compilerDir "System.Management.dll"
$microsoftCSharp = Join-Path $compilerDir "Microsoft.CSharp.dll"

# Compile
& $csc /target:library `
    /out:OfficeScrubNative.dll `
    /optimize+ `
    /unsafe `
    /warn:4 `
    /reference:$systemManagement `
    /reference:$microsoftCSharp `
    OfficeScrubC2R-Native.cs

Compiler Flags Explanation:

Flag Purpose
/target:library Produces a DLL instead of executable
/out:OfficeScrubNative.dll Specifies output file name
/optimize+ Enables compiler optimizations
/unsafe Allows unsafe code blocks for P/Invoke operations
/warn:4 Sets warning level to maximum
/reference: Includes required reference assemblies

Sources: tests/Verify-NativeBuild.ps1:21-71, build.ps1:1-150

Building for .NET Core

The .NET Core compilation target produces OfficeScrubNative.Core.dll compatible with PowerShell 7+ (Core edition).

Project File Generation:

The build process creates a temporary .csproj file for compilation:

<Project Sdk="Microsoft.NET.Sdk">
  <PropertyGroup>
    <TargetFramework>net7.0-windows</TargetFramework>
    <OutputType>Library</OutputType>
    <ImplicitUsings>disable</ImplicitUsings>
    <Nullable>disable</Nullable>
    <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
    <RootNamespace>OfficeScrubNative</RootNamespace>
    <AssemblyName>OfficeScrubNative.Core</AssemblyName>
    <PlatformTarget>AnyCPU</PlatformTarget>
  </PropertyGroup>
  <ItemGroup>
    <Compile Include="OfficeScrubC2R-Native.cs" />
  </ItemGroup>
</Project>

Command-Line Compilation:

# Create project file
$projectContent = @"
<Project Sdk="Microsoft.NET.Sdk">
  <!-- Project configuration as shown above -->
</Project>
"@
Set-Content -Path OfficeScrubNative.Core.csproj -Value $projectContent

# Build with dotnet CLI
dotnet build OfficeScrubNative.Core.csproj `
    -nologo `
    -clp:NoSummary `
    -p:GenerateAssemblyInfo=false

Output Location: bin\Debug\net7.0-windows\OfficeScrubNative.Core.dll

Sources: tests/Verify-NativeBuild.ps1:73-116


Build Verification

The Verify-NativeBuild.ps1 script validates compilation success by testing assembly loading and class instantiation.

Verification Script Usage

# Basic verification
.\tests\Verify-NativeBuild.ps1

# Clean build with verification
.\tests\Verify-NativeBuild.ps1 -Clean

# Specify .NET Core framework version
.\tests\Verify-NativeBuild.ps1 -NetCoreFramework net8.0-windows

Verification Process

Assembly Validation Workflow

sequenceDiagram
    participant Script as "Verify-NativeBuild.ps1"
    participant NetFX as "Invoke-NetFrameworkBuild"
    participant Core as "Invoke-NetCoreBuild"
    participant Test as "Test-AssemblyLoad"
    participant Reflection as "System.Reflection.Assembly"
    participant Class as "OfficeScrubOrchestrator"
    
    Script->>Script: "Check source file exists"
    Script->>NetFX: "Build for .NET Framework"
    NetFX->>NetFX: "Locate csc.exe"
    NetFX->>NetFX: "Compile to artifacts/netfx/"
    NetFX-->>Script: "$netfxOutput path"
    
    Script->>Core: "Build for .NET Core"
    Core->>Core: "Check dotnet command"
    Core->>Core: "Generate .csproj"
    Core->>Core: "dotnet build"
    Core-->>Script: "$netcoreOutput path"
    
    Script->>Test: "Test-AssemblyLoad($assembly)"
    Test->>Reflection: "LoadFrom($AssemblyPath)"
    Reflection-->>Test: "Assembly loaded"
    
    Test->>Class: "new() constructor"
    Class-->>Test: "Instance created"
    Test-->>Script: "Validation passed"
    
    Script->>Script: "Write-Host: Verification complete"
Loading

Test-AssemblyLoad Function

The verification function performs two critical tests:

  1. Assembly Loading: Uses [System.Reflection.Assembly]::LoadFrom() to load the compiled DLL
  2. Class Instantiation: Creates an instance of OfficeScrubOrchestrator with constructor parameter $true
function Test-AssemblyLoad {
    param([string]$AssemblyPath)
    
    if (-not $AssemblyPath) { return }
    
    Write-Host "Validating load: $AssemblyPath" -ForegroundColor Green
    [System.Reflection.Assembly]::LoadFrom($AssemblyPath) | Out-Null
    [OfficeScrubNative.OfficeScrubOrchestrator]::new($true) | Out-Null
}

The function targets different assemblies based on PowerShell edition:

  • Desktop Edition ($PSEdition -eq 'Desktop'): Tests $netfxOutput
  • Core Edition (PowerShell 7+): Tests $netcoreOutput

Sources: tests/Verify-NativeBuild.ps1:118-143, .github/workflows/ci.yml:32-36


CI/CD Build Process

The GitHub Actions CI pipeline automates building and testing across multiple scenarios.

CI Workflow Structure

CI Pipeline Architecture

graph TB
    Trigger["Trigger: push/pull_request<br/>branches: main, master, develop"] --> Jobs["GitHub Actions Jobs"]
    
    Jobs --> TestJob["test: Test Module"]
    Jobs --> ValidateJob["validate: PowerShell Gallery"]
    
    TestJob --> Checkout1["actions/checkout@v3"]
    Checkout1 --> Setup1["Setup PowerShell:<br/>$PSVersionTable"]
    Setup1 --> Build1["Build native DLL:<br/>./build.ps1 -Clean"]
    Build1 --> CheckDLL1["Test-Path OfficeScrubNative.dll"]
    CheckDLL1 --> Import["Import-Module OfficeScrubC2R.psd1"]
    Import --> TestFuncs["Test module functions:<br/>Get-Command -Module OfficeScrubC2R"]
    TestFuncs --> Manifest1["Test-ModuleManifest:<br/>Validate metadata"]
    
    ValidateJob --> Checkout2["actions/checkout@v3"]
    Checkout2 --> Build2["Build DLL:<br/>./build.ps1"]
    Build2 --> Manifest2["Test-ModuleManifest:<br/>Gallery compatibility"]
    Manifest2 --> CheckFiles["Check required files:<br/>psd1, psm1, dll, LICENSE, README"]
    CheckFiles --> ZoneCheck["Verify no Zone.Identifier:<br/>Check blocked files"]
    
    style CheckDLL1 fill:#e1ffe1
    style ZoneCheck fill:#e1ffe1
Loading

test Job Steps

The test job validates module functionality:

  1. Checkout: Retrieves repository code
  2. Setup PowerShell: Displays $PSVersionTable for diagnostics
  3. Build native DLL: Executes .\build.ps1 -Clean
  4. Verify DLL creation: Ensures OfficeScrubNative.dll exists
  5. Test module import: Imports module with -Force -Verbose
  6. Test functions: Enumerates exported commands
  7. Validate manifest: Runs Test-ModuleManifest

Sources: .github/workflows/ci.yml:10-63

validate Job Steps

The validate job ensures PowerShell Gallery compatibility:

  1. Build DLL: Compiles native library
  2. Test manifest: Validates module manifest structure
  3. Check required files: Verifies presence of:
    • OfficeScrubC2R.psd1
    • OfficeScrubC2R.psm1
    • OfficeScrubNative.dll
    • LICENSE
    • README.md
  4. Verify no blocked files: Checks for Zone.Identifier alternate data streams

Sources: .github/workflows/ci.yml:64-109


Build Output Artifacts

The build process generates different artifacts depending on the compilation target:

Artifact Structure

Artifact Location Target Size
OfficeScrubNative.dll Repository root .NET Framework 4.5+ ~50-80 KB
OfficeScrubNative.Core.dll artifacts/netcore/bin/Debug/net7.0-windows/ .NET Core 7.0+ ~50-80 KB
Intermediate files artifacts/netfx/, artifacts/netcore/ Build artifacts Various

DLL Characteristics

OfficeScrubNative.dll Properties:

graph LR
    DLL["OfficeScrubNative.dll"] --> Framework["Target: .NET Framework 4.5+"]
    DLL --> Classes["Public Classes:<br/>OfficeScrubOrchestrator<br/>RegistryHelper<br/>FileHelper<br/>ProcessHelper<br/>WindowsInstallerHelper<br/>TypeLibHelper<br/>LicenseHelper<br/>ServiceHelper<br/>ShellHelper<br/>GuidHelper"]
    DLL --> Namespace["Namespace: OfficeScrubNative"]
    DLL --> Unsafe["Contains: Unsafe code blocks<br/>P/Invoke declarations"]
    DLL --> Refs["References:<br/>System.Management<br/>Microsoft.CSharp<br/>mscorlib"]
    
    Framework --> PS51["Compatible: PowerShell 5.1"]
    Classes --> Orchestrator["Entry point:<br/>OfficeScrubOrchestrator"]
    Unsafe --> WinAPI["Win32 APIs:<br/>advapi32.dll<br/>kernel32.dll<br/>shell32.dll"]
Loading

Sources: docs/memory-bank/structure.md:68-79, build.ps1:1-150


Troubleshooting Common Build Issues

Issue: csc.exe Not Found

Symptom: Build script reports "Compiler not found"

Diagnosis:

  • .NET Framework 4.5+ not installed
  • Incorrect installation path

Resolution:

# Verify .NET Framework installation
Get-ChildItem "$env:WINDIR\Microsoft.NET\Framework*" -Directory

# Expected paths:
# Framework\v4.0.30319\
# Framework64\v4.0.30319\

Sources: tests/Verify-NativeBuild.ps1:27-35

Issue: Missing Reference Assemblies

Symptom: Compilation error "The type or namespace name 'Management' does not exist"

Diagnosis:

  • System.Management.dll not found in compiler directory

Resolution:

# Check reference assembly availability
$compilerDir = "C:\Windows\Microsoft.NET\Framework64\v4.0.30319"
Test-Path (Join-Path $compilerDir "System.Management.dll")
Test-Path (Join-Path $compilerDir "Microsoft.CSharp.dll")

Sources: tests/Verify-NativeBuild.ps1:39-47

Issue: Assembly Load Failure

Symptom: Test-AssemblyLoad throws exception during verification

Diagnosis:

  • Compilation produced corrupt DLL
  • Dependency mismatch
  • Zone.Identifier alternate data stream blocking load

Resolution:

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

# Verify DLL is not corrupt
[System.Reflection.Assembly]::LoadFrom(".\OfficeScrubNative.dll")

# Check for Zone.Identifier
Get-Item .\OfficeScrubNative.dll -Stream Zone.Identifier -ErrorAction SilentlyContinue

Sources: .github/workflows/ci.yml:101-108, tests/Verify-NativeBuild.ps1:118-130

Issue: .NET Core Build Fails

Symptom: dotnet build command not found or build errors

Diagnosis:

  • .NET SDK not installed
  • Incorrect target framework version

Resolution:

# Verify .NET SDK installation
dotnet --version

# Install .NET SDK if missing
# Download from: https://dotnet.microsoft.com/download

# Specify different framework
.\tests\Verify-NativeBuild.ps1 -NetCoreFramework net8.0-windows

Sources: tests/Verify-NativeBuild.ps1:80-84, tests/Verify-NativeBuild.ps1:4

Issue: Build Succeeds but Import Fails

Symptom: DLL builds successfully but Import-Module fails

Diagnosis:

  • PowerShell edition mismatch (Desktop vs Core)
  • Missing module manifest dependencies

Resolution:

# Check PowerShell edition
$PSEdition  # Should be 'Desktop' or 'Core'

# For Desktop edition (PowerShell 5.1)
# Use OfficeScrubNative.dll (.NET Framework)

# For Core edition (PowerShell 7+)
# Use OfficeScrubNative.Core.dll (.NET Core)

# Test import with verbose output
Import-Module .\OfficeScrubC2R.psd1 -Force -Verbose

Sources: tests/Verify-NativeBuild.ps1:135-140, .github/workflows/ci.yml:32-36


Build Performance Considerations

The build process typically completes within the following timeframes:

Build Type Duration Notes
Clean build 2-5 seconds Includes DLL deletion
Incremental build 1-3 seconds No cleanup required
.NET Framework only 1-3 seconds Single compiler invocation
.NET Core only 3-6 seconds Includes project generation
Dual-target build 4-8 seconds Both frameworks
CI/CD pipeline 30-60 seconds Includes checkout, setup, testing

The C# compiler (csc.exe) performs faster compilation compared to MSBuild due to direct invocation without project system overhead.

Sources: .github/workflows/ci.yml:10-109, tests/Verify-NativeBuild.ps1:1-143

Clone this wiki locally