A modern Windows Installer (MSI) inspection tool with both GUI and CLI interfaces. Package Inspector reads .msi files directly via msi.dll and also supports NuGet (.nupkg) packages. Legacy .pkg archives from the early cimipkg stop-gap format are still readable, but MSI is now the primary format going forward.
Originally part of the sbin-installer project, Package Inspector is now a standalone tool for inspecting package contents.
- Single Executable - One binary intelligently switches between GUI and CLI modes
- Self-Contained - All dependencies included, no external runtime required
- Cross-Architecture - Native support for both x64 and ARM64 Windows systems
- Simplified Distribution - One binary to maintain and sign
- Consistent Behavior - Same package inspection logic in both modes
- Modern WPF Interface - Clean, intuitive design inspired by macOS Suspicious Package
- Automatic Theme Detection - Adapts to Windows light/dark mode preferences
- Drag & Drop Support - Simply drag package files into the window
- Direct MSI Inspection - Opens
.msifiles viamsi.dllthrough the WiX DTF managed wrapper — no extraction, no WiX toolchain, no shelling out tomsiexec - cimipkg MSI Decoder - Automatically decodes PowerShell scripts embedded in cimipkg-built MSI custom actions and re-hydrates the original
build-info.yamlmetadata - NuGet Package Support - Inspect
.nupkgpayloads and.nuspecmetadata - Legacy
.pkgSupport - Still reads the original cimipkg.pkgZIP format for existing archives (kept for back-compatibility; new packages should be MSIs) - Package Overview - View metadata including name, version, author, license, and dependencies
- File Browser - Navigate through all files in the package payload with a tree view
- Script Inspector - View and analyze pre-install and post-install PowerShell scripts
- Syntax Highlighting - Code highlighting for PowerShell scripts and YAML metadata
- Export Functionality - Export entire packages or individual files/scripts
- Digital Signature Verification - Check if packages are digitally signed
- Scripting Support - Automate package inspection in scripts and CI/CD pipelines
- Quiet Mode - Minimal output for scripting and automation
- Signature Verification - Show package signature information from command line
- Flexible Navigation - Open GUI with specific tab or file pre-selected
- Batch Processing - Process multiple packages in automated workflows
Download the architecture-appropriate ZIP from the releases page:
pkginspector-x64.zip— Intel / AMD 64-bitpkginspector-arm64.zip— ARM64 (Surface Pro X, Copilot+ PCs, etc.)
Then:
- Extract to a directory of your choice (e.g.,
C:\Program Files\PkgInspector) - Add that directory to your system
PATH - Optionally create a desktop shortcut to
pkginspector.exe
After extracting, run from any shell:
pkginspector # Open GUI
pkginspector MyPackage.msi # Inspect an MSI
pkginspector --help # Show CLI helpRelease binaries are shipped unsigned. For enterprise deployment, sign them with your organization's code-signing certificate before distributing:
signtool sign /fd SHA256 /tr https://timestamp.digicert.com /td SHA256 `
/n "Your Certificate Name" pkginspector.exe# Clone repository
git clone https://github.com/windowsadmins/pkg-inspector.git
cd pkg-inspector
# Build both architectures (produces .exe in .\build\x64 and .\build\arm64)
.\build.ps1
# Build for specific architecture
.\build.ps1 -Architecture x64
.\build.ps1 -Architecture arm64
# List available code signing certificates
.\build.ps1 -ListCerts
# Build with a specific code-signing cert
.\build.ps1 -CertificateThumbprint <thumbprint>Build outputs land in .\build\<arch>\pkginspector.exe. If cimipkg is
installed locally, the build script can also produce legacy .pkg
archives of itself — this is kept for back-compatibility but is not
the recommended distribution channel going forward.
Launch the application and interact visually:
pkginspector # Open empty window
pkginspector MyPackage.msi # Inspect an MSI
pkginspector MyPackage.nupkg # Inspect a NuGet package
pkginspector LegacyPackage.pkg # Inspect a legacy cimipkg .pkg archiveOr simply drag and drop a package file onto the window.
Navigate through tabs:
- Package Info - Overview and installation details
- All Files - Tree view of payload files
- All Scripts - Pre/post-install scripts (including PowerShell decoded from MSI custom actions)
- Metadata - Raw YAML metadata (from
build-info.yamlin.pkg/.nupkgarchives, or from theCIMIAN_PKG_BUILD_INFOentry in the MSIPropertytable)
The same executable provides full command-line functionality:
# Show help
pkginspector --help
# Show signature information (reads build-info.yaml inside a .pkg/.nupkg ZIP;
# MSI Authenticode signature extraction is not yet implemented — see below)
pkginspector -g MyPackage.pkg
# Open package with specific tab
pkginspector -s MyPackage.msi # Scripts tab
pkginspector -f "path/to/file" MyPackage.msi # Files tab (navigation to a specific file is TODO)
# Quiet mode for scripting
pkginspector -g -q MyPackage.pkg-f, --reveal-file <path>- Open package in GUI and switch to the Files tab. (Navigation to the specified file is not yet implemented — see the TODO inMainWindow.xaml.cs.)-s, --reveal-scripts- Open package in GUI and switch to the Scripts tab.-g, --show-signature- Show package signature information. Currently reads the signature metadata frombuild-info.yamlinside a ZIP-based archive, so today it works with.pkgand.nupkgonly. MSI Authenticode signature extraction is a planned enhancement.-p, --show-component-packages- List component packages (CLI output).-q, --quiet- Minimal output for scripting.-h, --help- Show help message.
The application automatically detects which mode to use:
- GUI Mode: No arguments, or just a package file path
- CLI Mode: Any flags present (
-g,-s,-f, etc.)
Package Inspector reads .msi files directly via msi.dll through the
WiX DTF managed wrapper, so no
extraction, no WiX toolchain, and no msiexec shell-out is required.
Both commercial MSIs and cimipkg-built MSIs are supported.
For MSIs built by cimipkg, the inspector automatically:
- Reads the
CIMIAN_PKG_BUILD_INFOentry from the MSIPropertytable (viaSELECT Property, Value FROM Property) and re-hydrates the originalbuild-info.yamlmetadata. - Detects preinstall/postinstall custom actions whose VBScript source contains base64-chunked PowerShell, and decodes them back to their original PowerShell form for display in the Script Inspector.
Standard NuGet package format — ZIP archives with .nuspec metadata
files. Supported for inspection alongside MSI.
Note: The
.pkgZIP format was a stop-gap while cimipkg was being taught to produce real MSI installers. It is being phased out in favor of.msiand should not be used for new packages. Package Inspector will continue reading existing.pkgarchives for back-compatibility.
.pkg files from the legacy cimipkg flow are ZIP archives with this structure:
package.pkg (ZIP file)
├── payload/ # Files to be installed
├── scripts/ # Installation scripts
│ ├── preinstall.ps1
│ └── postinstall.ps1
└── build-info.yaml # Package metadata
# Build both architectures
.\build.ps1
# Build specific architecture
.\build.ps1 -Architecture x64
.\build.ps1 -Architecture arm64
# Skip legacy .pkg packaging. The script attempts .pkg creation by default;
# if cimipkg isn't installed on the build machine, it no-ops that step with a
# warning. Use -SkipPkg to skip the attempt entirely.
.\build.ps1 -SkipPkg# List available certificates
.\build.ps1 -ListCerts
# Build with specific certificate
.\build.ps1 -CertificateThumbprint <thumbprint>
# Auto-detect and use best certificate (default behavior)
.\build.ps1The build script automatically detects and uses available code-signing certificates, preferring enterprise certificates.
.\build\
├── x64\
│ ├── pkginspector.exe
│ └── [dependencies]
└── arm64\
├── pkginspector.exe
└── [dependencies]
If cimipkg is available on the build machine, the script will
additionally emit pkginspector-<arch>-<version>.pkg archives of
itself alongside the binaries — a leftover from the legacy .pkg
distribution flow, retained for back-compatibility.
Package Inspector uses a single executable that intelligently switches between GUI and CLI modes based on command-line arguments. This design provides:
- Simplified Distribution - One binary to maintain and sign
- Reduced Footprint - No duplicate code between GUI and CLI
- Consistent Behavior - Same package inspection logic in both modes
- Flexible Invocation - Works seamlessly as GUI app or CLI tool
The mode detection happens in App.xaml.cs:
protected override void OnStartup(StartupEventArgs e)
{
var args = e.Args;
// CLI mode detection: any flags (-x / --x) or the literal "help" word
bool isCliMode = args.Length > 0 && (
args.Any(a => a.StartsWith("-") || a.StartsWith("--")) ||
args.Any(a => a.Equals("help", StringComparison.OrdinalIgnoreCase))
);
if (isCliMode)
{
// Attach to the parent shell's console for CLI output; fall back
// to a fresh console if the parent isn't a console host.
if (!AttachConsole(ATTACH_PARENT_PROCESS))
{
AllocConsole();
}
Shutdown(RunCliMode(args));
return;
}
// Otherwise, continue with normal GUI startup
base.OnStartup(e);
}Note:
pkginspector -gcurrently reads signature metadata frombuild-info.yamlinside a ZIP-based package (.pkg/.nupkg), so the examples below use.pkg. MSI Authenticode signature extraction via the CLI is a planned enhancement — for now, MSI signatures are visible in the GUI only.
$result = & pkginspector -g -q MyPackage.pkg
if ($result -like "Signed|*") {
Write-Host "Package is signed"
$parts = $result -split '\|'
Write-Host "Subject: $($parts[1])"
Write-Host "Signed: $($parts[2])"
} else {
Write-Host "Package is not signed"
}Get-ChildItem *.pkg | ForEach-Object {
Write-Host "`nInspecting: $($_.Name)"
& pkginspector -g $_.FullName
}- .NET 10.0 SDK
- Windows 10/11 (x64 or ARM64)
- Windows SDK (for code signing)
- Visual Studio 2022 or VS Code (optional)
pkg-inspector/
├── App.xaml / App.xaml.cs # Application entry point, CLI detection
├── MainWindow.xaml / .cs # Main GUI window
├── WelcomeControl.xaml / .cs # Welcome screen
├── Models/
│ ├── PackageData.cs # Package + file/script/tree-node data models
│ └── BuildInfo.cs # build-info.yaml + nested ProductInfo models
├── Services/
│ ├── MsiInspectorService.cs # .msi inspection via WiX DTF / msi.dll (primary)
│ ├── CimipkgVbsDecoder.cs # Decode PS embedded in cimipkg MSI custom actions
│ └── PackageInspectorService.cs # .nupkg and legacy .pkg inspection (ZIP + YAML)
├── Converters/
│ └── BoolToVisibilityConverter.cs # BoolToVisibilityConverter, InverseBoolToVisibilityConverter, SignatureBrushConverter
├── Resources/ # Application resources
├── build.ps1 # Build automation script
├── pkginspector.csproj # Project file
└── pkg-inspector.sln # Solution file
# Run GUI
dotnet run
# Run with a package (MSI, NuGet, or legacy .pkg all work)
dotnet run -- MyPackage.msi
# Run CLI mode
dotnet run -- --help
dotnet run -- -g MyPackage.msi
# Build debug
dotnet build
# Build release
dotnet build --configuration Release- YamlDotNet 13.7.1 — YAML parsing for
build-info.yaml - AvalonEdit 6.3.0.90 — Syntax-highlighted text editor for scripts
- WixToolset.Dtf.WindowsInstaller 5.0.0 — Managed wrapper over
msi.dllfor direct MSI inspection - Microsoft.Extensions.Logging 10.0.0 — Logging framework
- Microsoft.Extensions.Logging.Console 10.0.0 — Console sink for CLI-mode diagnostics
Contributions are welcome! This project originated from sbin-installer.
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
MIT License - see LICENSE file for details.
Windows Admins
- GitHub: @windowsadmins
- Original Project: sbin-installer
See CHANGELOG.md for version history and release notes.