Powershell PS1 to EXE converter – PS2EXE by Markus Scholtes

What is Powershell PS1 to EXE script converter?

Powershell PS1 to EXE converter is very useful when you want to simplify your Powershell scripts execution. You can execute the compiled script directly within explorer as any other executable. In addition, it can simplify script usage by field technicians in enterprise environments.

Affiliate: Experience limitless no-code automation, streamline your workflows, and effortlessly transfer data between apps with Make.com.

There’s a great converter that exports EXE files from PS1 by Markus Scholtes (which is an updated version of the script by Ingo Karstein). There is some limitation with Script Variables like “$PSScriptRoot”, which returns empty due to conversion to EXE. There’s a workaround at the end of this article. You can visit “PS2EXE GUI by Markus Scholtes” GitHub page for more information.

The compiled executable is alerted by Antiviruses because adversaries use it to compile malware. There are other PS1 to EXE converters, but if they aren’t alerting – it will happen sooner or later. Another converter you can try – PS1 to EXE converter by Fatih Kodak.

How to install “PS2EXE GUI” PS1 to EXE converter

1. Run “powershell.exe”
2. Execute the following:

Install-Module -Name ps2exe

You might be notified about:

Nuget provider is required to continue

Press [Y] for yes and [Enter].
Another possible notification:

Untrusted repository
You are installing the modules from an untrusted repository.

Press [Y] for yes and [Enter].

*** On powershell 5 and higher “PowershellGet” package is included. On Powershell 4 you might need to install it separately.
You can also download “PS2EXE” from GitHub manually.
3. While, you can use “ps2exe” switches while scripting automations, I prefer the GUI. For GUI, execute in powershell.exe:

win-ps2exe

4.1. Fill in the fields:
Source file: *** Browse for your source “*.ps1” file ***
Target file: *** Fill the full path to the exported executable ***
Icon file: *** This one isn’t mandatory, but it would distinguish your EXE from others ***

4.2. Next four fields will be shown in the [Properties] of your executable in the [Details] tab:
Version, File description, Product name, Copyright.

4.3. Since I compile simple scripts with console support without GUI, I don’t select any options, but I will explain each one:
[ ] Compile a graphic windows program (parameter -noConsole)
*** This one will not show console at all while running the executable, since it will use Windows Forms.
[ ] Suppress output (-noOutput)
*** No standard powershell output will be shown, like verbose and informational messages.
[ ] Suppress error output (-noError)
*** No errors and alerts will be shown in the output.

[ ] Require administrator rights at runtime (parameter -requireAdmin)
*** If UAC is enabled the user will be prompted to approve, otherwise the executable won’t run.
[ ] Generate config file (parameter -configFile)
*** Output.exe.config

Thread Apartment State:
(*) STA – Single Thread
( ) MTA – Multi Thread
[AnyCPU]
*** I use AnyCPU architecture type, but if you want to be more specific, you can choose [x86] or [x64].

Remarks and Tips of PS2EXE GUI

For full switch usage of the tool you can visit its GitHub page. There are more switches and options available in GUIless version. Additional switches include: powershell version specific executable setting, GUI for prompting credentials, more details for the file properties, virtualization and long paths options.

The source PS1 script can be decompiled back from the EXE using the “-extract” switch on the executable:

Executable.exe -extract:C:\Source.ps1

So, make sure you don’t store any sensitive data in your script.

Since, “$PSScriptRoot” variable is returned empty, there was a workaround posted on the GitHub page of the tool to identify the root folder of the script:

if ($MyInvocation.MyCommand.CommandType -eq "ExternalScript")
 { $ScriptPath = Split-Path -Parent -Path $MyInvocation.MyCommand.Definition }
 else
 { $ScriptPath = Split-Path -Parent -Path ([Environment]::GetCommandLineArgs()[0])
      if (!$ScriptPath){ $ScriptPath = "." } }

There is also a limitation of “-noConsole” switch. You can read about this on the PS2EXE GUI GitHub page.

Leave a Comment

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.