Caution
Do not store passwords in source code!
See the localized readme for more details.
ps12exe is a PowerShell module that allows you to create an executable file from a .ps1 script.
Install-Module ps12exe #Install ps12exe module
Set-ps12exeIntegration #Set up right-click menu, Agent Skill and VS Code extension(you can also clone this repository and run ./ps12exe.ps1 directly)
Hard to upgrade from PS2EXE to ps12exe? No problem!
PS2EXE2ps12exe hooks PS2EXE calls into ps12exe. Uninstall PS2EXE, install this module, then use PS2EXE as usual.
Uninstall-Module PS2EXE
Install-Module PS2EXE2ps12exeOnce you have run Set-ps12exeIntegration, you can quickly compile any ps1 file into an exe or open ps12exeGUI on this file by right-clicking on it.

ps12exeGUIps12exe .\source.ps1 .\target.execompiles source.ps1 into the executable target.exe (if .\target.exe is omitted, output is written to .\source.exe).
'"Hello World!"' | ps12execompiles "Hello World!" into the executable .\a.exe.
ps12exe https://raw.githubusercontent.com/steve02081504/ps12exe/master/src/GUI/Main.ps1compiles Main.ps1 from the internet into the executable .\Main.exe.
exe21sp -inputFile .\target.exe -outputFile .\target.ps1exe21sp extracts the original PowerShell script from a ps12exe-generated executable (local path or URL) and writes it to a .ps1 file or standard output. It uses the same $LastExitCode convention as ps12exe: 0 = success, 1 = input/parse error (e.g. not a ps12exe exe), 2 = invocation error (e.g. no input when redirected), 3 = resource/internal error (e.g. file not found).
- ps12exe: When stdout (or stdin/stderr) is redirected, ps12exe writes only the path of the generated exe to stdout so you can capture it (e.g.
$exe = ps12exe .\a.ps1). - exe21sp: Accepts exe paths or URLs from pipeline input (e.g.
Get-ChildItem *.exe | exe21spor".\app.exe" | exe21sp). - exe21sp: If
-outputFileis not specified and stdout is not redirected, the decompiled script is saved to a.ps1file with the same base name as the exe in the same directory. - exe21sp: If
-outputFileis not specified and stdout is redirected, the decompiled script is written to stdout.
Start-ps12exeWebServerStarts a web server that can be used to compile PowerShell scripts online.
The ps12exe VS Code extension compiles a .ps1 script into an executable β or opens ps12exeGUI β without leaving the editor, and adds editor support for the preprocessor directives (syntax highlighting, diagnostics, #_if auto-close, folding, go-to-definition, hover, completion and formatting).
Set-ps12exeIntegration installs it automatically; you can also install steve02081504.ps12exe manually.
Set-ps12exeIntegration also writes a ps12exe Agent Skill to ~/.agents/skills, so skill-aware coding agents (opencode, Codex, Cursor, GitHub Copilot, β¦) know to use ps12exe when asked to compile a PowerShell script into an executable. Set-ps12exeIntegration -action disable removes it again, and Set-ps12exeIntegration -Skip AgentSkill leaves it untouched.
Set-ps12exeIntegration accepts [-action] 'enable'|'disable'|'reset', -Locale, -help, and -Skip with any of 'ContextMenu', 'AgentSkill' and 'VSCodeExtension' to leave those parts alone.
| Comparison Content | ps12exe | MScholtes/PS2EXE@1.0.18 |
|---|---|---|
| Pure script repository π¦ | βοΈ All text files except images & bundled helper DLLs | β Ships Win-PS2EXE.exe with an open source license |
| Command to generate hello world π | π'"Hello World!"' | ps12exe |
π€echo "Hello World!" *> a.ps1; PS2EXE a.ps1; rm a.ps1 |
| Constant hello world executable πΎ | π₯°1024 bytes (constant-evaluated at compile time) | β Not supported; 25088 bytes |
| Non-constant hello world executable πΎ | π₯°13312 bytes | π¨25088 bytes |
| Compile-time constant evaluation β‘ | βοΈ | β |
| PowerShell Core (7+) / cross-platform target 𧬠| βοΈ -Build @{Target='Core'} (Windows / Linux / macOS) |
β Windows PowerShell 5.1 only |
| GUI multilingual support π | βοΈ (7 languages, dark mode) | β |
| Syntax check during compilation βοΈ | βοΈ | β |
| Preprocessing feature π | βοΈ | β |
-extract and other special parameter parsing π§Ή |
ποΈ Removed (use the exe21sp tool instead) |
π₯² Requires source code modification |
| PR welcome level π€ | π₯° Welcome! | π€· 14 PRs, 13 of which were closed |
| Political / DEI / stance bias ποΈ | βοΈ None; any valuable PR is welcome β from a human, an AI, or a monkey at a typewriter | β Readme takes an anti-AI stance ("artificial intelligence is killing creativity and our nature") |
ps12exe's developer does not use this project to promote a political, DEI or other ideological stance β any valuable PR is welcome, whether it comes from a human, an AI, or a monkey at a typewriter.
Measured on Windows 11 with PowerShell 7.6.6 (.NET 10) and Windows PowerShell 5.1 on 2026-10-01, 20 warm runs each. The process-creation floor (cmd /c exit) is ~15 ms. Reproduce with pwsh -File ./tools/Benchmark/Compare-Compilers.ps1 -IncludeCore (add -Compile for the compilation-speed table below).
| Build | Output size | Warm startup |
|---|---|---|
| Windows PowerShell 5.1 running the script directly | β | ~294 ms |
| ps12exe Β· constant Β· Framework4.0 | 1024 bytes | ~47 ms |
| ps12exe Β· non-constant Β· Framework4.0 | 13312 bytes | ~248 ms |
| PS2EXE 1.0.18 Β· non-constant | 25088 bytes | ~261 ms |
| ps12exe Β· non-constant Β· large script Β· Framework4.0 | 25088 bytes | ~293 ms |
| PS2EXE 1.0.18 Β· non-constant Β· large script | ~496 KB | ~275 ms |
| ---------------------------------------------------- | ----------- | ------------ |
| pwsh 7 running the script directly | β | ~461 ms |
| ps12exe Β· constant Β· Core | ~165 KB | ~86 ms |
| ps12exe Β· non-constant Β· Core | ~180 KB | ~370 ms |
| ps12exe Β· non-constant Β· large script Β· Core | ~188 KB | ~401 ms |
| PS2EXE 1.0.18 Β· non-constant Β· Core | not support | not support |
A constant script is evaluated at compile time, so its exe is 1 KB and never starts PowerShell β about 24Γ smaller and 6Γ faster to launch than a PS2EXE hello world. Non-constant exes are smaller than PS2EXE's in these measurements, and for top-level-variable-heavy scripts they can also run faster because the script executes inside a function (local scope) rather than at global scope. Non-constant exes are always compressed, and the compression scales with the payload: a ~0.5 MB script produces a 25 KB Framework exe while PS2EXE produces ~496 KB, while PS2EXE leaves its payload essentially uncompressed and balloons with script size. The Core exe adds only ~8 KB over its small-script counterpart, so large payloads stay small instead of ballooning.
The hello-world benchmark above measures the launch of a console app that exits immediately, so its numbers are dominated by process startup. A GUI app stays alive while the user interacts, so the meaningful figure there is the time between double-clicking and the window appearing β the startup and script-execution overhead, not the process lifetime. Measured with the same tool (-Windowed), using a WinForms window that closes itself after ~800 ms; each row's warm startup includes process startup and script execution (the window lifetime is nearly identical across rows, and the ~15 ms process-creation floor is negligible here).
| Build | Output size | Warm startup |
|---|---|---|
| Windows PowerShell 5.1 running the script directly (hidden window) | β | ~1154 ms |
| ps12exe Β· windowed Β· DarkMode Auto Β· Framework4.0 | 29184 bytes | ~1128 ms |
| PS2EXE 1.0.18 Β· windowed Β· non-constant | 33792 bytes | ~1128 ms |
| ------------------------------------------------------------------ | ----------- | ------------ |
| pwsh 7 running the script directly (hidden window) | β | ~1349 ms |
| ps12exe Β· windowed Β· DarkMode Auto Β· Core | ~6385 KB | ~1317 ms |
A windowed ps12exe app starts about as fast as PS2EXE's (~1128 ms), and both are a hair faster than running the same script through PowerShell directly β ps12exe strips -NoProfile-style overhead and never re-parses, while still adding a Silence/OutputEncoding host wrapper and dark-mode support. The Core windowed app (~1317 ms) is only slightly slower than the Framework one and a bit faster than pwsh running the script directly (~1349 ms). The ~6.4 MB Core output is self-contained by default; disable it with -Build @{Target='Core'; SelfContained=$false} to fall back to the ~0.2 MB shared-runtime exe. The size gain of the Framework windowed app over PS2EXE's (~4.5 KB) is smaller than for console apps because both must embed the WinForms bootstrap.
Measured with the same tool (-Compile -IncludeCore). Each sample is a fresh host process (Windows PowerShell 5.1 for Framework/PS2EXE, pwsh 7 for Core); "warm" is the median of 5 compiles after the first. PS2EXE numbers use the locally installed release (1.0.18 in this environment).
| Build | Warm compile |
|---|---|
| ps12exe Β· constant Β· Framework4.0 | ~1466 ms |
| ps12exe Β· non-constant Β· Framework4.0 | ~900 ms |
| PS2EXE Β· non-constant | ~585 ms |
| ps12exe Β· non-constant Β· large script Β· Framework4.0 | ~2063 ms |
| PS2EXE Β· non-constant Β· large script | ~596 ms |
| ---------------------------------------------------- | ------------ |
| ps12exe Β· constant Β· Core | ~2742 ms |
| ps12exe Β· non-constant Β· Core | ~3633 ms |
| ps12exe Β· non-constant Β· large script Β· Core | ~5402 ms |
| PS2EXE Β· non-constant Β· Core | not support |
PS2EXE compiles a hello world faster because it is a thin wrapper around the .NET Framework compiler built into Windows: it performs a single CodeDom pass and nothing else. ps12exe additionally runs a syntax check, classifies the script and (for constant scripts) evaluates it, and packs the program frame as a payload inside a launcher, so its non-constant compile is ~1.5Γ PS2EXE's in this run. The trade-off shows up in the output: ps12exe emits 1024 / 13312 bytes where PS2EXE emits 25088, and constant programs launch about 6Γ faster. Core compilation is dominated by dotnet publish; the first compile for a given configuration also restores NuGet packages, after which ps12exe reuses the generated project directory and runs dotnet publish --no-restore.
The compiler itself is installed as a PowerShell module:
| Compiler package | Unpacked | Compressed |
|---|---|---|
| ps12exe (current working tree) | 1,899,082 bytes | 647,312 bytes |
| PS2EXE 1.0.18 (installed files) | 169,382 bytes | 44,082 bytes |
ps12exe's module is larger because it is a dependency-free, pure-script compiler that bundles trimmed AsmResolver binaries, 7 localizations and a pure-script GUI; PS2EXE ships almost nothing and relies on the .NET Framework compiler built into Windows.
A script with #_DllExport is compiled into a Win32 DLL callable through LoadLibrary/GetProcAddress (Framework4.0 + x86/x64 only; PS2EXE has no equivalent). Fixed two-export script (Add, Greet):
| Build | Output size | Warm compile |
|---|---|---|
| ps12exe Β· DLL export Β· Framework4.0 | 16384 bytes | ~1864 ms |
| PS2EXE 1.0.18 Β· DLL export | not support | not support |
Whether native child processes started by the EXE see a real console TTY (#59), whether the script can read raw stdin (#62), and whether the special path variables resolve β all verified from a real console window on Windows 11:
| Capability | ps12exe | MScholtes/PS2EXE@1.0.18 |
|---|---|---|
Native child process sees a console TTY (isTTY) |
βοΈ | β |
Raw stdin ([Console]::In) readable |
βοΈ (unless the script uses $input) |
β |
$PSCommandPath / $PSScriptRoot resolve |
βοΈ (exe path / exe directory) | β |
PS2EXE 1.0.18 always pipes script output through Out-String and eagerly drains redirected stdin before the script runs, so native children lose the console handle and stdin reaches EOF; ps12exe runs the script through the host (Out-Default) and only drains stdin when the script actually uses $input. PS2EXE also leaves $PSCommandPath/$PSScriptRoot empty inside the compiled program (it offers its own $ScriptRoot instead), while ps12exe maps both to the generated exe.
Compared to MScholtes/PS2EXE@1.0.18, this project brings the following improvements:
| Improvement Content | Description |
|---|---|
| βοΈ Syntax check during compilation | Syntax check during compilation to improve code quality |
| β‘ Compile-time constant evaluation | Side-effect-free scripts are evaluated at build time and emitted as ~1 KB exes |
| 𧬠PowerShell Core / cross-platform target | -Build @{Target='Core'} targets PowerShell 7+ on Windows, Linux and macOS |
| π Powerful preprocessing feature | Preprocess the script before compilation, no need to copy and paste all content into the script |
π οΈ -Build @{Options=β¦} parameter |
New parameter, allowing you to further customize the generated executable file |
π¦οΈ -Build @{Minify=β¦} parameter |
Preprocess the script before compilation to generate a smaller executable file |
| π Support for compiling scripts and included files from URL | Support for downloading icons from URL |
π₯οΈ Optimization of App.Windowed parameter |
Optimized option handling and window title display, you can now set the title of the custom pop-up |
| βοΈ Code signing and icon auto-conversion | Sign output with a PFX certificate or a store thumbprint, and convert icons automatically |
π§° Extras: exe21sp, web server, context menu, interact mode |
Decompile exes, compile online, right-click compile and more |
| π§Ή Removed exe files | Removed exe files from the code repository |
| π Multilingual support, pure script GUI | Better multilingual support, pure script GUI, support for dark mode |
| π Separated cs files from ps1 files | Easier to read and maintain |
| π More improvements | And more... |
See the localized readme for more details.







