Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion .github/workflows/codeql.yml
Original file line number Diff line number Diff line change
Expand Up @@ -77,8 +77,10 @@ jobs:
# ℹ️ Command-line programs to run using the OS shell.
# 📚 See https://docs.github.com/en/actions/using-workflows/workflow-syntax-for-github-actions#jobsjob_idstepsrun
- if: matrix.build-mode == 'manual'
env:
NoGitVersioning: true
run: |
nuget restore /p:NoGitVersioning=true
nuget restore PowerShellWixExtension.sln
msbuild PowerShellWixExtension.sln /p:NoGitVersioning=true

- name: Perform CodeQL Analysis
Expand Down
66 changes: 66 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# Copilot Instructions for PowerShellWixExtension

## Build, test, and lint commands

This repository is built and tested on **Windows** (WiX + MSI tooling required).

```powershell
# Restore
nuget restore

# Build all projects (same command used in CI)
msbuild PowerShellWixExtension.sln /p:Configuration=Release
```

Integration tests are MSI install/uninstall + Pester log assertions:

```powershell
# Build test MSIs first, then run install/uninstall like CI
Start-Process msiexec.exe -Wait -ArgumentList "/i Tests\PowerShellWixInlineScriptTest\bin\Release\PowerShellWixInlineScriptTest.msi /q /liwearucmopvx $pwd\inlinescript-install.log"
Start-Process msiexec.exe -Wait -ArgumentList "/x Tests\PowerShellWixInlineScriptTest\bin\Release\PowerShellWixInlineScriptTest.msi /q /liwearucmopvx $pwd\inlinescript-uninstall.log"
Start-Process msiexec.exe -Wait -ArgumentList "/i Tests\PowerShellWixTest\bin\Release\PowerShellWixTest.msi /q /liwearucmopvx $pwd\script-install.log"
Start-Process msiexec.exe -Wait -ArgumentList "/x Tests\PowerShellWixTest\bin\Release\PowerShellWixTest.msi /q /liwearucmopvx $pwd\script-uninstall.log"

# Run Pester assertions
Invoke-Pester -Path .\Tests\Pester.Tests.ps1
```

Run a single Pester test:

```powershell
# Pester 5 style
Invoke-Pester -Path .\Tests\Pester.Tests.ps1 -FullNameFilter "Inline Scripts.Install"

# Pester 4 style
Invoke-Pester -Path .\Tests\Pester.Tests.ps1 -TestName "Install"
```

Linting: there is **no separate lint command wired in CI**. `Settings.StyleCop` exists for Visual Studio/StyleCop configuration, but CI runs restore/build/test/pack.

## High-level architecture

- `PowerShellWixExtension` is the WiX extension assembly loaded by candle/light:
- `PowerShellCompilerExtension` parses `<powershell:Script>` and `<powershell:File>` under `Product`/`Fragment`.
- Parsed data is written into custom MSI tables (`PowerShellScripts`, `PowerShellFiles`) defined by `TableDefinitions.xml`.
- The extension embeds and returns `PowerShellLibrary.wixlib`, which contains all custom action declarations and default sequencing.
- `PowerShellLibrary/Library.wxs` defines immediate + deferred install/uninstall custom actions for:
- inline scripts vs script files
- elevated vs non-elevated execution
- default sequencing and UI progress text
- `PowerShellActions` is the custom action runtime:
- Immediate actions query MSI tables, evaluate per-row `Condition`, serialize payload into deferred `CustomActionData`, and extend progress ticks.
- Deferred actions deserialize payload and execute PowerShell through `PowerShellTask` + `WixHost*` classes, logging via MSI session and honoring `IgnoreErrors`.
- `Tests/*/*.wixproj` build sample MSIs that consume the extension from `Libs\PowerShellWixExtension.dll`; `Tests/Pester.Tests.ps1` validates behavior by inspecting MSI log output.

## Key repository conventions

- Keep the **immediate/deferred pair pattern** intact for any new custom action behavior: immediate actions prepare validated data, deferred actions perform execution.
- Inline script payloads are stored as **Base64-encoded UTF-16** (`Encoding.Unicode`) in the `PowerShellScripts.Script` column; preserve this encoding path end-to-end.
- Execution ordering uses `Order` with implicit default `1000000000 + source line`; explicit lower `Order` values run first within each context/type bucket.
- `Elevated`, `IgnoreErrors`, and `Condition` are first-class schema/table/runtime fields; changes to extension schema must stay synchronized across:
1. `PowerShellWixExtensionSchema.xsd`
2. `TableDefinitions.xml`
3. compiler parsing (`PowerShellCompilerExtension`)
4. runtime query/execution logic (`PowerShellActions/CustomAction.cs`)
- Test WiX projects resolve the extension from `..\..\Libs\PowerShellWixExtension.dll`; keep `AfterBuild` copy steps in project files working when changing output layout.
- For inline scripts in `.wxs`, square brackets must be escaped as `[\[]` and `[\]]` to avoid MSI property expansion.
6 changes: 6 additions & 0 deletions PowerShellActions/PowerShellActions.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,12 @@
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net452">
<Version>1.0.3</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand Down
6 changes: 6 additions & 0 deletions PowerShellWixExtension/PowerShellWixExtension.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@
<PropertyGroup>
<StartupObject />
</PropertyGroup>
<ItemGroup>
<PackageReference Include="Microsoft.NETFramework.ReferenceAssemblies.net452">
<Version>1.0.3</Version>
<PrivateAssets>all</PrivateAssets>
</PackageReference>
</ItemGroup>
<ItemGroup>
<Reference Include="System" />
<Reference Include="System.Core" />
Expand Down
Loading