Repository navigation
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.
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
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
Sources: build.ps1:1-150, tests/Verify-NativeBuild.ps1:21-143, .github/workflows/ci.yml:24-30
The primary build method uses the build.ps1 script located in the repository root. This script handles compilation, dependency resolution, and output verification.
# Standard build
.\build.ps1
# Clean build (removes existing DLL first)
.\build.ps1 -Clean
# Verbose output
.\build.ps1 -Verbose| 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:
-
Compiler Detection: Searches for
csc.exein standard .NET Framework installation paths -
Reference Resolution: Locates required reference assemblies (
System.Management.dll,Microsoft.CSharp.dll) -
Compilation: Invokes
csc.exewith optimized build flags -
Output Verification: Confirms
OfficeScrubNative.dllwas 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
Sources: build.ps1:1-150, .github/workflows/ci.yml:24-30
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.csCompiler 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
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=falseOutput Location: bin\Debug\net7.0-windows\OfficeScrubNative.Core.dll
Sources: tests/Verify-NativeBuild.ps1:73-116
The Verify-NativeBuild.ps1 script validates compilation success by testing assembly loading and class instantiation.
# 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-windowsAssembly 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"
The verification function performs two critical tests:
-
Assembly Loading: Uses
[System.Reflection.Assembly]::LoadFrom()to load the compiled DLL -
Class Instantiation: Creates an instance of
OfficeScrubOrchestratorwith 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
The GitHub Actions CI pipeline automates building and testing across multiple scenarios.
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
The test job validates module functionality:
- Checkout: Retrieves repository code
-
Setup PowerShell: Displays
$PSVersionTablefor diagnostics -
Build native DLL: Executes
.\build.ps1 -Clean -
Verify DLL creation: Ensures
OfficeScrubNative.dllexists -
Test module import: Imports module with
-Force -Verbose - Test functions: Enumerates exported commands
-
Validate manifest: Runs
Test-ModuleManifest
Sources: .github/workflows/ci.yml:10-63
The validate job ensures PowerShell Gallery compatibility:
- Build DLL: Compiles native library
- Test manifest: Validates module manifest structure
-
Check required files: Verifies presence of:
OfficeScrubC2R.psd1OfficeScrubC2R.psm1OfficeScrubNative.dllLICENSEREADME.md
-
Verify no blocked files: Checks for
Zone.Identifieralternate data streams
Sources: .github/workflows/ci.yml:64-109
The build process generates different artifacts depending on the compilation target:
| 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 |
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"]
Sources: docs/memory-bank/structure.md:68-79, build.ps1:1-150
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
Symptom: Compilation error "The type or namespace name 'Management' does not exist"
Diagnosis:
-
System.Management.dllnot 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
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 SilentlyContinueSources: .github/workflows/ci.yml:101-108, tests/Verify-NativeBuild.ps1:118-130
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-windowsSources: tests/Verify-NativeBuild.ps1:80-84, tests/Verify-NativeBuild.ps1:4
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 -VerboseSources: tests/Verify-NativeBuild.ps1:135-140, .github/workflows/ci.yml:32-36
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