Loading…

Self Contained PowerShell Scripts

Unlike Windows PowerShell, PowerShell Core does not come pre-installed on Windows machines. This means to run a PowerShell Core script, you need to deploy the engine itself as well as the script you wish to run. To make this a single step process, PowerShell Pro Tools now offers PowerShell Core Packaging. With this feature, you no longer need to have a version of PowerShell or .NET installed on target machines to run your PowerShell scripts.

PowerShell Core Packaging

With the PowerShell Pro Tools new PowerShell Core packaging feature, you can now include the PowerShell Core engine directly in your package. This means you do not need to install PowerShell on the target machine to be able to run your script. Just as with standard packaging, you can also include any dependent modules.

As you can see in the example below, we have a script.exe that has been compiled with PowerShell Pro Tools. It includes the PowerShell Engine, .NET Core and a PowerShell script. The script simply outputs $PSVersionTable to show the current version of PowerShell that is running. You can see in the background window that pwsh is not found as PowerShell Core has not been installed on this machine.

Packaging your script with PowerShell Core

To use the new PowerShell Core packaging feature, you need to install the following.

Additionally, you need to run Merge-Script in PowerShell Core for this feature to work correctly. Once you have installed the prerequisites, you will need to enable the PowerShell Core option in the Merge-Script configuration. Enabling bundling with modules is also required. Here is an example configuration.

 Merge-Script -Config @{
    Root = $Script
    OutputPath = $OutputPath
    Package = @{
        Enabled = $true
        PowerShellCore = $true
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}

Merge-Script will automatically locate your installed version of PowerShell Core and use that engine as the one that it will package along with your script.

You will need internet access the first time this runs because it needs to download a couple .NET global tools to accomplish the task of packaging the engine with the script.

After running Merge-Script you will have a Windows x64 native executable you can deploy to machines without PowerShell Core or .NET Core installed.

Package Size

Because the entire .NET Core runtime and PowerShell Core engine are included with your script, the package will be considerably larger than a standard executable packaged with Merge-Script. The current base size of a packaged script with this method is 48MB. Depending on your module requirements, this may increase.

Performance

The first time the executable runs it will take a few seconds before the script is launched. This is because the executable is decompressing all the bits that are necessary to run PowerShell Core. A local application cache is used on future launches to provide much better start up times.

Limitations

Since the script is running in PowerShell Core, you cannot (yet) use Windows Forms or WPF. Once PowerShell Core has moved over to .NET Core 3.0, you should be able to do so.

Application icons and run as administrator options will not be honored.

Future

This technique can also be accomplished for other platforms. It should be possible to package self contained PowerShell scripts for Mac OSX and Linux. If that is something you’d like to see, please let me know.

Also, it would be great to support all the options of Merge-Script. Application icons and run as administrator will be coming in the near future.

The .NET Core team is working on tools to provide tree shaking for IL Code that should help reduce the size of self contained executables. Once this feature is implemeneted, the deployment size of Merge-Script executables should be much smaller.

Please provide any feedback you have to our issue tracker.

Leave a Reply