# About

PowerShell Pro Tools documentation for PowerShell developer and automation tools.

PowerShell Pro Tools brings together editors, packagers, designers, installers, and automation utilities for PowerShell developers. Choose the tool you are using, or jump straight into a common workflow.

{% hint style="info" %}
**Start here:** Check [System Requirements](/system-requirements), then open the product card for your editor or tool. Each product area includes installation notes, examples, and feature references.
{% endhint %}

## Choose a project

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Visual Studio</strong></td><td>PowerShell editing, debugging, project support, refactoring, analysis, and UI design inside Visual Studio.</td><td><a href="/pages/-LTiC3_SB9tVOVhUzJcL">/pages/-LTiC3_SB9tVOVhUzJcL</a></td></tr><tr><td><strong>Visual Studio Code</strong></td><td>Packaging, conversion, diagnostics, automation, RapidSense, decompilation, and editor productivity for VS Code.</td><td><a href="/pages/-LSfZArZAzgew_pVS5GN">/pages/-LSfZArZAzgew_pVS5GN</a></td></tr><tr><td><strong>PowerShell Module</strong></td><td>Command-line tools for packaging, code conversion, hotkeys, merge scripts, and launching the form designer.</td><td><a href="/pages/-LNFFku-qi18ZOa3vNtD">/pages/-LNFFku-qi18ZOa3vNtD</a></td></tr><tr><td><strong>PSMSI</strong></td><td>Create Windows installers with files, directories, shortcuts, installer identity, custom actions, and UI settings.</td><td><a href="/pages/dIcntAzHOgOAF7OnDBOJ">/pages/dIcntAzHOgOAF7OnDBOJ</a></td></tr><tr><td><strong>PSEdit</strong></td><td>A focused PowerShell script editor for quickly opening and editing scripts outside a full IDE.</td><td><a href="/pages/QPCynf3UfPmCTGu901xM">/pages/QPCynf3UfPmCTGu901xM</a></td></tr><tr><td><strong>PSCommander</strong></td><td>Desktop automation with commands, tray menus, global hot keys, protocol handlers, widgets, and shortcuts.</td><td><a href="/pages/GJqGukJ5fCke9C8SBseO">/pages/GJqGukJ5fCke9C8SBseO</a></td></tr><tr><td><strong>PowerShell Protect</strong></td><td>Protect scripts with configurable rules and actions that help control how protected scripts are used.</td><td><a href="/pages/-MYfC2gOmc71kx0-Bj9W">/pages/-MYfC2gOmc71kx0-Bj9W</a></td></tr></tbody></table>

## Common workflows

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Install</strong></td><td>Find the right installer, extension, module, and offline package for your environment.</td><td><a href="/pages/-LNFFktqtmbs_dwMAtvO">/pages/-LNFFktqtmbs_dwMAtvO</a></td></tr><tr><td><strong>Package scripts</strong></td><td>Bundle scripts, package executables, configure package.psd1, and prepare builds for Windows, Linux, or macOS.</td><td><a href="/pages/-LNFFktr-HjY-sTbdgaH">/pages/-LNFFktr-HjY-sTbdgaH</a></td></tr><tr><td><strong>Build a GUI</strong></td><td>Use Windows Forms and WPF designers to create PowerShell user interfaces from Visual Studio or VS Code.</td><td><a href="/pages/-LNFFktxdL2r0lXVeE74">/pages/-LNFFktxdL2r0lXVeE74</a></td></tr><tr><td><strong>Create an installer</strong></td><td>Use PSMSI to define installer identity, directories, files, shortcuts, custom actions, and installer UI.</td><td><a href="/pages/6kJoLaRJkk9Cpjen5DHI">/pages/6kJoLaRJkk9Cpjen5DHI</a></td></tr><tr><td><strong>Automate the desktop</strong></td><td>Configure PSCommander events, data sources, context menus, widgets, global hot keys, and tray actions.</td><td><a href="/pages/-MWqBYm9rr76m-kQmN1y">/pages/-MWqBYm9rr76m-kQmN1y</a></td></tr><tr><td><strong>Protect scripts</strong></td><td>Get started with PowerShell Protect rules, actions, and configuration for protected script workflows.</td><td><a href="/pages/-MYfCFbsrcDfp4jGahsZ">/pages/-MYfCFbsrcDfp4jGahsZ</a></td></tr></tbody></table>

## Download

PowerShell Pro Tools is free to use.

<table data-view="cards"><thead><tr><th></th><th></th><th data-hidden data-card-target data-type="content-ref"></th></tr></thead><tbody><tr><td><strong>Visual Studio 2017-2019</strong></td><td>Install PowerShell Tools for Visual Studio from the Visual Studio Marketplace.</td><td><a href="https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsforVisualStudio2017-18561">https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsforVisualStudio2017-18561</a></td></tr><tr><td><strong>Visual Studio 2022</strong></td><td>Install the Visual Studio 2022 extension from the Visual Studio Marketplace.</td><td><a href="https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsVS2022">https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsVS2022</a></td></tr><tr><td><strong>Visual Studio Code</strong></td><td>Install PowerShell Pro Tools for Visual Studio Code from the Visual Studio Marketplace.</td><td><a href="https://marketplace.visualstudio.com/items?itemName=ironmansoftware.powershellprotools">https://marketplace.visualstudio.com/items?itemName=ironmansoftware.powershellprotools</a></td></tr><tr><td><strong>PowerShellProTools</strong></td><td>Install the PowerShell Pro Tools module from the PowerShell Gallery.</td><td><a href="https://www.powershellgallery.com/packages/PowerShellProTools">https://www.powershellgallery.com/packages/PowerShellProTools</a></td></tr><tr><td><strong>PSMSI</strong></td><td>Install the PowerShell installer authoring module from the PowerShell Gallery.</td><td><a href="https://www.powershellgallery.com/packages/PSMSI">https://www.powershellgallery.com/packages/PSMSI</a></td></tr><tr><td><strong>PSEdit</strong></td><td>Install the focused PowerShell editor from the PowerShell Gallery.</td><td><a href="https://www.powershellgallery.com/packages/psedit">https://www.powershellgallery.com/packages/psedit</a></td></tr><tr><td><strong>PSCommander</strong></td><td>Install the desktop automation module from the PowerShell Gallery.</td><td><a href="https://www.powershellgallery.com/packages/PSCommander">https://www.powershellgallery.com/packages/PSCommander</a></td></tr><tr><td><strong>PowerShell Protect</strong></td><td>Install the script protection module from the PowerShell Gallery.</td><td><a href="https://www.powershellgallery.com/packages/PowerShellProtect">https://www.powershellgallery.com/packages/PowerShellProtect</a></td></tr></tbody></table>


# System Requirements

Each tool has its own requirements page. Use the per-tool page when installing a single component.

* [Visual Studio requirements](/open-source-tools/visual-studio/system-requirements)
* [Visual Studio Code requirements](/open-source-tools/visual-studio-code/system-requirements)
* [PowerShell Module requirements](/open-source-tools/powershell-module/system-requirements)
* [PSMSI requirements](/open-source-tools/psmsi/system-requirements)
* [PSEdit requirements](/open-source-tools/psedit/system-requirements)
* [PSCommander requirements](/open-source-tools/pscommander/system-requirements)
* [PowerShell Protect requirements](/open-source-tools/powershell-protect/system-requirements)

## Shared Requirements

Most tools are distributed from the Visual Studio Marketplace or the PowerShell Gallery. Machines that install PowerShell Gallery modules need PowerShellGet or PSResourceGet configured with access to the gallery. Packaging and installer generation may also require internet access to restore .NET or NuGet dependencies unless those packages are available from an internal feed.


# PoshTools VS

PowerShell Tools for Visual Studio

PowerShell Pro Tools for Visual Studio adds a PowerShell-focused development experience to Visual Studio. It provides editor services, project templates, debugging, analysis, test discovery, packaging, and UI design tools for PowerShell scripts and modules.

Use this tool when Visual Studio is your primary IDE or when you want PowerShell project support alongside .NET development.

## Features

* Syntax highlighting and IntelliSense for PowerShell files.
* Local and remote script debugging.
* PowerShell project and item templates.
* Pester unit test discovery through the Visual Studio Test Explorer.
* PSScriptAnalyzer integration.
* Refactoring commands and go to definition.
* PowerShell Interactive Window.
* Script packaging and MSBuild integration.
* Windows Forms designer support.
* Windows PowerShell and PowerShell 7 support.

## Quick Examples

Create a PowerShell project from **File > New > Project**, select a PowerShell project template, and press **F5** to run or debug the script entry point.

Package a script from a project by configuring the PowerShell project properties or by using the MSBuild packaging task documented in [Packaging in Visual Studio](/open-source-tools/visual-studio/bundling-and-packaging-with-msbuild).

Design a Windows Forms UI from Visual Studio with the form item templates and designer documented in [User Interface Design](/open-source-tools/visual-studio/user-interface-design).

## Downloads

* [Visual Studio 2022 extension](https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsVS2022)
* [Visual Studio 2017 and 2019 extension](https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsforVisualStudio2017-18561)
* [Changelog](https://github.com/ironmansoftware/powershell-pro-tools/releases)

## More Information

* [Installation](/open-source-tools/visual-studio/installation)
* [System Requirements](/open-source-tools/visual-studio/system-requirements)
* [Project System](/open-source-tools/visual-studio/project-system)
* [Debugging](/open-source-tools/visual-studio/chapter1)


# Installation

PowerShell Pro Tools for Visual Studio is distributed as a Visual Studio extension.

## Visual Studio Marketplace

Install the extension that matches your Visual Studio version.

* [PowerShell Pro Tools for Visual Studio 2022](https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsVS2022)
* [PowerShell Tools for Visual Studio 2017 and 2019](https://marketplace.visualstudio.com/items?itemName=AdamRDriscoll.PowerShellToolsforVisualStudio2017-18561)

You can install from the Marketplace website or from **Extensions > Manage Extensions** inside Visual Studio.

## Offline Installation

Download the VSIX package from the Marketplace and install it on the target machine. For environments without internet access, see [Visual Studio Offline Installation](/reference/installation-and-configuration/visual-studio-offline-installation).


# System Requirements

## Visual Studio

* Visual Studio Community, Professional, or Enterprise.
* Visual Studio 2022 for the current extension.
* Visual Studio 2017 or 2019 for the legacy extension.
* Visual Studio core editor.
* .NET Desktop Development workload.

## Runtime

* Windows.
* .NET Framework 4.7.2 for the Visual Studio extension assemblies.
* Windows PowerShell 5.1.
* PowerShell 7 for features that target modern PowerShell runtimes.

## Packaging

Packaging scripts as executables may require additional .NET SDKs or developer packs based on the target PowerShell version. See the [PowerShell Module requirements](/open-source-tools/powershell-module/system-requirements) and [Package.psd1](/open-source-tools/powershell-module/packaging/package.psd1) for target framework details.


# Analysis

Script analysis for PowerShell scripts.

PowerShell Pro Tools uses PSScriptAnalyzer to run static code analysis of PowerShell scripts in Visual Studio. You can enable analysis by click View->PowerShell->Settings. Click Save after modifying the settings.

![Script Analyzer Settings](/files/xEWdGtxeNZpnPJ6Wb5TV)

On the options page, you can turn on and off script analyzer completely, manage solution wide analysis, disable specific severities or even specific rules.

When Script Analyzer is enabled, squiggly lines will be present within source files to provide information on potential issues with the ability to provide quick fixes for those issues.

If you have solution wide analysis enabled, you will be able to see errors within your entire solution within the Error List window.

![Error List Window](/files/-LtN_mz-Upm3Q57FN9Qd)

## Quick Fix

PowerShell Pro Tools supports quick fix actions provided by PSScriptAnalyzer. If the suggestion has a Suggested Correction, PowerShell Pro Tools will provide a Quick Action light bulb next to the line that needs to be addressed.

![Executing quick fix actions](/files/-LPpPZBNPkI6qNlt0K4U)


# Debugging

{% embed url="<https://youtu.be/53lsdzhcKr0>" %}

You can debug local and remote scripts with the PowerShell Tools for Visual Studio. The extension also supports attaching to processes that are hosting runspaces and debugging the scripts they are executing.


# Local Debugging

## Local Debugging

## Executing the Debugger

### Run from a PowerShell Project

With PowerShell Tools for Visual Studio, a couple new project templates are included. When working with a script that is part of a PowerShell project, you can execute the current script by simply starting debugging like you would with any other language inside Visual Studio. Pressing F5 or the Start Debugging button will allow you to execute and debug your script.

To create a PowerShell Project, just navigate to File->New->Project and select one of the PowerShell project types.

![](https://camo.githubusercontent.com/fa0d1edc98590c9db85fa9dbd47d6263ecca0dfc/687474703a2f2f692e696d6775722e636f6d2f717331386a724d2e706e67)

### Run a script from any project type

Scripts can also be run from any type of project using the context menu items or shortcut commands. Right clicking in a PowerShell script will show the option to run the script or the selection.

![](https://camo.githubusercontent.com/136651d8e10a744a6515287469c6734644a7e6cb/687474703a2f2f692e696d6775722e636f6d2f4d7133376a4b552e706e67)

You can also run a script from the solution explorer. Just right click on the script and select Execute as Script.

![](https://camo.githubusercontent.com/49415f7630b636d8914d44440f59596a67b03552/687474703a2f2f692e696d6775722e636f6d2f6b5a6f6872364b2e706e67)

## Execute Selection

You can execute a selection using the Ctrl+F8 key or by right clicking the code and clicking Execute Selection.

![](/files/-M3NwBTM9qN0DAvJtbVu)

You can execute a selection from within a PS1 file.


# Remote Debugging

Remote process debugging is now supported! You can use this feature to attach and debug any PowerShell host process, exactly the same as you would with a normal PowerShell console.

## Remote Attaching

### Difference between Remote Attaching and Remote Session

Remote Debugging is a totally new and separate feature from the already existing Remote Session feature. If you are wanting to debug an already running process that is say stuck in a loop or producing odd log data, then you can now Remote Debug it. By doing so, you are not required to actually stop the process. Remote Session on the other hand is simply starting/executing a script on a remote machine from Visual Studio.

### Remote Attaching Prerequisites

* Your local machine (the one running Visual Studio) must have PowerShell v4 or higher installed
* Your remote machine (the one running the remote process) must have PowerShell v5 or higher installed
* If your remote machine has a PowerShell version lower than 5.0.10240.0, then the remote process must be run as administrator. This is a bug with earlier versions of the PowerShell 5 preview.

### Attaching to a Remote Process

Before attaching to a remote process, you will need to know the name or address of your machine, such as:

> some.machine.net

Next, you will need to know whether or not your machine requires you to connect with a secure (SSL) connection. If it does, you will need to install the SSL certificate of your remote machine before continuing (see Remote Attaching with Azure below for more information). Finally, you will need to know the port number your remote machine uses for PowerShell sessions. By default, PowerShell and PowerShell Tools attempt to connect to 5985 for non-SSL connections and 5986 for SSL connections. If your port is different you can simply add it to the end of your machine name/address as so:

> some.machine.net:5988

You can now open up Visual Studio and go to Debug -> Attach to Process, and then select the appropriate PowerShell Tools remote debugging transport from the transport dropdown. Which one you choose will depend on whether or not you need to use SSL. Once you have chosen a transport, enter in your machine name (and port if needed) as the qualifier and then hit refresh. You will now be prompted to login:

![](https://camo.githubusercontent.com/8c167068e8bd25878adff1b1244d16d208094e1f/687474703a2f2f692e696d6775722e636f6d2f476166493575692e706e67)

You’ll need to login with either a<username@domain.com>format or domain\username format. If your machine doesn’t have a domain, you can simply use MachineName\username to login. For example, if your machine name is poshtools and your username is Matthew:

![](https://camo.githubusercontent.com/fae69c56104b3184758c93728352081ca5f29a25/687474703a2f2f692e696d6775722e636f6d2f38436b347438472e706e67)

Once you have entered your credentials hit OK. Your window should now look something like this:

![](https://camo.githubusercontent.com/11f299ef07de8817f48fd3d9631b19211de8d16b/687474703a2f2f692e696d6775722e636f6d2f4b6747767854422e706e67)

If for some reason you don’t see your process, make sure you are running it as administrator if you have a PowerShell version lower than 5.0.10240.0. You may also not have the rights to debug the process depending on who started it.

If you do see your process, then go ahead and hit attach. The process you selected will now be attached to and the script that it was running copied over to your local machine.

![](https://camo.githubusercontent.com/cf045c94657f589799a7dc700cb7f1bd12ebf532/687474703a2f2f692e696d6775722e636f6d2f784733764a47362e706e67)

You have now successfully attached to the remote process. From here you can set and remove breakpoints, step into, step over, step out, view the call stack, the locals window, and execute commands in the PowerShell Tools Interactive Window (edit and continue, variable examination, etc.).

Once you have finished debugging, you may complete your session by hitting the Stop Debugging button.

A final few things to note about remote attaching:

* Stepping into external files is currently not supported.
* If you stop/detach while the script is running any set breakpoints may not be cleared from the remote program which could cause it to stop in the future.
* If you have a copy of the remote script open before you attach, set breakpoints and then attach, those breakpoints will not be transferred over to the remote program.
* Issuing debugging cmdlets in the interactive window while attached to a process is not fully supported.
* You should not be using remote attaching to debug a local process. You should use local attaching to attach to a local process (see below).

### Remote Attaching with Azure

Attaching to a remote process running on Azure is just as easy as attaching to a process running on any other machine. The first thing you will need to do is install the SSL certificate from your Azure machine onto your local computer. You can follow the first half of[this MSDN blog post](http://blogs.msdn.com/b/sriharsha/archive/2013/10/26/remote-powershell-in-azure-iaas-virtual-machines.aspx)for instructions on how to do so. Once you have installed the certificate, simply follow the steps above on how to remote attach. Remember, if you have configured your machine to have a SSL port other than 5986 you will need to specify it in your qualifier.

## Local Debugging

### Local Debugging Prerequisites

* Your machine must have PowerShell v5 or higher installed

### Attaching to a Local Process

To attach to a local process, go to Debug -> Attach to Process, and then make sure that the Default transport option is selected. You will then need to make sure that the “Attach to:” type is only PowerShell code:

![](https://camo.githubusercontent.com/d0343f6b1ae7c85f939d1fd3c4beea6d286d04ec/687474703a2f2f692e696d6775722e636f6d2f346758354c6d452e706e67)

You may then scroll down the list of running processes to find the one you want to attach to. In most cases, you will probably be looking for powershell.exe, but other processes are attachable. Once you find it, select it and hit attach.

![](https://camo.githubusercontent.com/b05959abb268589356db46687ac618184741d498/687474703a2f2f692e696d6775722e636f6d2f6b4b31373855552e706e67)

If you are unsure as to whether or not you can attach to a process, simply look for the PowerShell Debug Engine in the Type column of the process.

![](https://camo.githubusercontent.com/8c1ad2c36c60bc46cc2d8983016a2fa058437abc/687474703a2f2f692e696d6775722e636f6d2f4c76484e4132342e706e67)

You will now be attached to the selected program and the running script opened in Visual Studio. Similar to remote attaching, you can set and remove breakpoints, step into, step over, step out, view the call stack, the locals window, and execute commands in the PowerShell Tools Interactive Window (edit and continue, variable examination, etc.). Once you have finished debugging, you may complete your session by hitting the Stop Debugging button.

A final few things to note about remote debugging:

* If you stop/detach while the script is running, any set breakpoints may not be cleared from the remote program which could cause it to stop in the future.
* If you have a copy of the script open before you attach, set breakpoints and then attach, those breakpoints will not be transferred over to the remote program.
* Issuing debugging cmdlets in the interactive window while attached to a process might produce negative behavior.
* Attaching directly to the PowerShell Tools Host process is not fully supported.
* If you are running PowerShell tools in 32 bit mode, the ability to attach to a 64 bit process is not yet supported


# Format Document

Code formatting for PowerShell.

Code formatting can be accomplished by using the standard `Ctrl+K`, `Ctrl+D` keyboard shortcut within Visual Studio.

The PSScriptAnalyzer module is required to perform formatting. From Windows PowerShell, you can install PSScriptAnalyzer with `Install-Module`.

```powershell
Install-Module 'PSScriptAnalyzer' -Scope CurrentUser
```


# Go to Definition

Navigate to function definitions.

Go to definition allows you to navigate from a command to a function definition by right clicking on the command and clicking Go To Definition. It will open the script and highlight the line where the function is defined. This feature requires Solution Wide Analysis to be enabled.

![](/files/-MJ2lUjCcBXI-YIhg0k_)


# Packaging in Visual Studio

Package PowerShell scripts as executables.

PowerShell Pro Tools exposes bundling and packaging as an MSBuild task and PowerShell project system property page.

## About Packaging

Packaging a PowerShell script embeds the scrip in a .NET executable so that other users cannot modify the contexts of the script. When the executable is launched, the script will be executed just as it was from the command line. The script can still accept arguments, you can package Windows Forms applications and embed dependent modules.

### Configuring Packaging

Packaging is configured via the PowerShell Project properties page of either a module or script project in Visual Studio. You can configure many types of options for your package.

![Packaging settings for a PowerShell Project](/files/-LPfX3-lHpCrTdJLe8z1)

#### Entry Point

The entry point is the script that will be executed when you start your executable. This script can include other scripts or modules and enabling the bundling feature will include them as well.

#### Bundle

Enabling the bundling feature will automatically include scripts that are dot source with the entry point script. This setting is recursive. For example, if you have a root.ps1 that dot sources a child\_level\_1.ps1 script with then references a child\_level\_2.ps1 script, all the scripts will be included together.

#### Package as Executable

You can bundle without packaging as an executable by unchecking the Package as executable checkbox.

#### Obfuscate executable

While you cannot open an executable in a text editor such as VS Code or Notepad, you can use a tool like dotPeek or .NET Reflector to disassemble the executable and look at the source code. Using the Obfuscate executable option, the contents of the executable will be scrambled. The executable will work the same but will be much harder to determine what is going on in the script. It prevents the casual reverse engineer from figuring out what is going on.

#### Hide Console Window

You can chose to hide the console window. This is especially nice when you are packaging a Windows Forms script. It will hide the PowerShell console and only show the form. You may see a brief flash of a console when starting your packaged executable with this option selected.

#### .NET Framework Version

This is the target .NET Framework version to target for your executable. You should have the .NET Developer Pack installed for that version of the framework to successfully compile your executable. The end-user's machine will need this version of .NET (or later) installed on their machine to run your executable.

It's recommended to use at least .NET 4.6.2.

#### Package Modules

Selecting this option will package modules into the executable. Modules are zipped and embedded into the package. When the executable is run, they are extracted to a temporary location for the executable script to access.

#### File Description

Sets the file description on the executable in the Details tab when viewing the properties of the executable.

#### File Version

Sets the file version on the executable in the Details tab when viewing the properties of the executable.

#### Product Name

Sets the product name on the executable in the Details tab when viewing the properties of the executable.

#### Product Version

Sets the product version on the executable in the Details tab when viewing the properties of the executable.

#### Icon

Sets the icon for the executable.

#### Require Elevation

Forces the user to run the executable as administrator when starting the executable. This is helpful when the script needs to access administrative resources on a machine.

### Executing Packaging

After configuring packaging, you can execute the package process when building the project you configured. You can do this by right clicking on the project and selecting Build or by click Build and then Build Solution in the main Visual Studio Menu.

Output from the packaging process will be shown in the Output pane.

### Package Output

The package is output to the configured output directory in the PowerShell Project. You can get the full path to the executable by looking in the Output pane after packaging.

## Packaging PowerShell 7 in Visual Studio

In Visual Studio, you can package PowerShell 7 into the executable. When you package for PowerShell 7, it includes the .NET Core runtime and PowerShell SDK directly into your executable. Your executable will be significantly larger in size but will also be able to run without having to install PowerShell 7.

{% hint style="info" %}
You will need the [.NET Core 3.1 or later](https://dotnet.microsoft.com/download/dotnet-core/thank-you/sdk-3.1.404-windows-x64-installer) SDK installed to bundle PowerShell 7 executables.
{% endhint %}

To bundle for PowerShell 7, you will need to set two settings. First, set the .NET version to `netcoreapp31`. This will use the .NET Core 3.1 SDK to bundle your executable. Next, you will need to set the PowerShell version to 7.0 or later.

![](/files/-MMHyyc4zoh91BMBkSlc)

The resulting executable will be written to the output directory listed in the Output pane.

![](/files/-MMHzDWTLLcfGolXazWL)

To deploy your executable, you will only need to include the exe file. For example:

```
 C:\Users\adamr\source\repos\PowerShellProject3\PowerShellProject3\bin\Debug\Form.exe
```

## Packaging Resources

Packaging resources, such as images, can be helpful when creating UI's like WPF windows. You can follow the below steps to embed resources.

First, add the resource to your PowerShell Project. Right click on your project and then click Add \ Existing Item. When the file browser dialog opens, select your resource.

Next, right click on your resource and select properties. In the property dialog, change the Resource property to true. This will embed the resource into the assembly.

![](/files/-Mf69otraWcrCE4K3x_Z)

Finally, if you are using WPF, then you can reference the assembly by name.

```
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Image Source="image.png" />
    </Grid>
</Window>
```


# PowerShell 7 Support

PowerShell 7 support is available if you have either of the environments installed. PowerShell Pro Tools will automatically locate the pwsh.exe that is required.

## Selecting PowerShell 7

You can use the General options page of PowerShell Tools to select PowerShell 7.

![](/files/-Lsr_PhhSdyKHtFgOvuZ)

You can also use the PowerShell Tools toolbar PowerShell Version combo box to select the PowerShell version. You can enable the toolbar by right clicking on the Visual Studio toolbar and then select PowerShell Tools.

![](/files/-MMsakGe6_q0phhjvAaJ)

To select the PowerShell version, select the version in the drop down.

![](/files/-MMsasMoU2j5SRWSL1yO)


# PowerShell Interactive Window

The PowerShell Interactive Window provides a console like experience within Visual Studio. The interactive window can execute PowerShell scripts and commands, connect to remote machines and interact with the Visual Studio environment.

## Accessing the PowerShell Interactive Window

To access the PowerShell interactive window, click View->PowerShell->PowerShell Interactive Window. You can also use the default key combination Ctrl+Shift+\\.

![](/files/-MHrqO2UBMPqQIUQrgZf)

## Executing Commands

You can execute commands in the PowerShell interactive window just like any other PowerShell prompt. PowerShell Tools IntelliSense is available in the interactive window. You can simply press enter to execute a command. The interactive window has access to the current PowerShell session. Any scripts run through the Visual Studio debugger will influence the environment of the interactive window. Variables and functions defined in these scripts can be called in the interactive window.

## Connecting to a Remote Machine

The interactive window can connect to a remote machine by clicking the Enter PowerShell Session button or using Enter-PSSession. Clicking the Enter PowerShell Session button will prompt you for a computer name.

You can then enter your credentials. You will be connected to the remote machine using Enter-PSSession.

You can disconnect from a remote session with the Exit PowerShell Session button.

## Clear the Screen

You can clear the screen with the Clear Screen button.

## Interact with Visual Studio

The Visual Studio DTE automation variable is available in the entire PowerShell session, including the interactive window, as $dte. The DTE object exposes useful functionality such as Solutions, Projects, Files, Commands and Windows.


# Project System

PowerShell Project System.

PowerShell Pro Tools integrates with the MSBuild project system. You can configure PowerShell Projects to run build events and package scripts as executables.


# Advanced

Advanced settings for PowerShell Projects.

The advanced tab is used to configure packaging for projects. You can select which script to package, whether to include modules, what target framework to use and more.

![Advanced Tab](/files/mgDq09ldRFs8ew2pivZy)


# Debug

Debug options for PowerShell Projects.

By default, the currently active window will be launched when pressing F5 or by clicking the Start button on the task bar. You can use the Debug options within your project to configure a different file to run when the Start button is clicked.

![](/files/xX0GXkNJl011wOBatqnh)


# Build Events

PowerShell Projects support pre-build and post-build events. Currently, there is no actual build step so running pre-build will simply run a script before the post-build script.

![](/files/FulsnJpI4R0U08Akxzrq)

You can access the pre and post build events by opening the Properties page for you project. Right click on your project within the Solution Explorer window and select Properties. You can add PowerShell scripts and access MSBuild variables in your build events. You build events are executed when MSBuild builds your PowerShell project.

![Project Properties](/files/GMs9zwysY9iTwVoXUHaK)


# Settings

Syntax highlighting is configured just like any other language in Visual Studio.

1. Click Tools
2. Click Options
3. Click Fonts and Colors
4. Modify the Display Items under the Text Editor that start with PowerShell

![](https://camo.githubusercontent.com/2f6362e1063eb7e9a346f55092974b59fbf28056/687474703a2f2f692e696d6775722e636f6d2f73574a576679452e706e67)


# General

General settings can be found in Tools \ Options \ PowerShell Tools \ General.

![](/files/-MHrqEgBSM4HeuEKt9iD)


# .editorconfig

Editorconfig support for PowerShell Tools for Visual Studio

PowerShell Tools for Visual Studio supports `.editorconfig` files. You can include these files in your PowerShell projects to control aspects of the editor based on the file.

More information on [editor config files here](https://learn.microsoft.com/en-us/visualstudio/ide/create-portable-custom-editor-options?view=vs-2022).

## Spaces

To control the number of spaces inserted when pressing tab, you can create a `.editorconfig` file like the following. This will insert 6 spaces per tab.

```editorconfig
# PowerShell files
[*.{ps1,psm1,psd1}]
indent_size = 6
indent_style = space
```

## Tabs

You can choose to insert tabs by setting the `indent_style` to `tab.`

```editorconfig
# PowerShell files
[*.{ps1,psm1,psd1}]
indent_style = tab
```

## Adaptive Formatting

Adaptive formatting may change the format of your document. Disable it to ensure that your `.editorconfig` file is honored.

<figure><img src="/files/ZaoJeu1q2C3R2Kv9qvHv" alt=""><figcaption></figcaption></figure>


# Analysis

Script analysis settings can be found in View \ PowerShell \ Settings \ Script Analysis. You can enable script analyzer, severities and individual rules.

![](/files/G9FKPjyaFMyOJB9uU06z)


# Diagnostics

If you happen to encounter an issue with PowerShell Tools for Visual Studio, it may be helpful to enable diagnostic logging. To enable it, visit the options page within the Tools->Options menu.

![](/files/-MHrpfTmEveZzrw6VgPa)

Click on the PowerShell Tools section and check the Enable Diagnostic Logging check box. You will need to restart Visual Studio.

Logging will output to `%AppData%\PowerShell Tools for Visual Studio\log.txt`


# Tool Windows

## Variables

The variables tool window allows you to view and expand variables; even when not in the debugger.

To access the variables window, click View \ PowerShell \ PowerShell Variables

![Variables Tool Window](/files/-M_aXl7bYldbMtiqb83d)


# Refactoring

Refactoring tools for Visual Studio.

### About

Refactorings allow you to change or generate code based on the code you have. You will find a list of refactors below. You can invoke a refactor by pressing `Ctrl+.` or by clicking the light bulb.

Only valid refactors will be returned in the drop down menu.

### Convert to $\_

This refactoring converts a `$PSItem` variable to the `$_` variable.

### Convert to $PSItem

Converts a reference to the `$_` variable to `$PSItem`.

### Convert to Multiline Command

Converts a command invocation into a multi-line command. Each parameter and argument is broken up with backticks.

### Convert to Splat

Converts a command invocation into a splatting expression and creates a hashtable named `$Parameters` and then passes that hashtable as a splatting expression to the command. Positional arguments are not added to the hashtable.

### Export Module Member

Exports the selected variable or function from a module using `Export-ModuleMember`.

### Extract Function

You can use the Extract Function refactor to convert a section of code into a function. It will analyze the selected block and determine if there are variables that should be added as parameters. These variables will be added to the `param` block.

### Extract Selection to File

You can use the Extract Selection to File refactor to create a new file based on the selection in the current active editor.

### Generate Function from Usage

You can generate a function based on a command example. This refactoring will analyze the parameters, arguments and whether the command is used in a pipeline. If used in a pipeline, this refactoring will generate an advanced function.

### Generate Proxy Function

Proxy functions allow you to extend existing functions with new parameters and functionality. You can select a command that you use within your script and select the Generate Proxy Function refactoring to have it generate the proxy function code for you.

### Introduce Using Namespace

The introduce using namespace refactoring adds a `using namespace` statement to the top of a script and replaces the selected type expression with the namespace removed.

### Reorder Parameters

You can reorder parameters by using the `Ctrl+PageUp` and `Ctrl+PageDown` key bindings. Ensure that your cursor is on top of a parameter for a command. Press one of the key bindings. To move a parameter to the right, use Page Up. To move a parameter to the left, use Page Down.

### Split Pipeline

The split pipe refactoring will split a pipe into multiple lines. Each element in the pipe is stored in a variable and passed to the next item in the pipe. This can be useful for debugging long or complex pipeline operations.


# Unit Test Adapter

## Unit Test Adapter

## Getting Started

The PowerShell Tools for Visual Studio integrates a unit test adapter that can discover and execute[Pester](https://github.com/pester/Pester)tests. To write tests you will need to create a PS1 file that ends in the extension “Tests.PS1”. The test adapter will only look in files with this extension. From there, you can author Pester tests as you normally would. The Test Explorer window will display the tests it finds and you can execute them by clicking Run All or Run.

Test results are shown just like any other testing framework. They will include the result of the test, the reason for failure and a stack trace to the offending code that has failed.

## Pester Installation

The test adapter will look in a few places while attempting to load the Pester module.

1. Test run directory
2. Solution Package directory

   *Note: this does not follow the NuGet package resolution logic and only currently uses the solution directory*
3. PSModule path

## Debugging Issues with the test adapter

The test adapater will log to the Output pane in the Tests category. Check here first for any issues you may encounter when writing tests.


# User Interface Design

## Building a GUI with WPF in Visual Studio

## Applies to:

* Visual Studio 2017, 2019, 2022

## Creating a Project

You can create a module or script project.

Click File->New->Project

![](https://i0.wp.com/wandering.life/wp-content/uploads/2017/04/newproject.png?resize=581%2C155)

Select the Module or Script project type, name it and then click Ok.

Right click on your project to create a new file and select the PowerShell WPF Window item template.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/05/newWpfItem.png?resize=778%2C539)

After creating your WPF window, you will see the same designer you would for a C# or VB.NET project.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/05/WpfDesigner.png?resize=728%2C572)

A code behind file is automatically created that contains a PowerShell script capable of loading the XAML and running the WPF window.

![](https://i0.wp.com/wandering.life/wp-content/uploads/2017/05/codeBehind.png?resize=937%2C175)

Pressing F5 or clicking the Start button on the menu will launch your WPF window.

‘

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/05/debuggingWpf.png?resize=617%2C582)

## Wiring up Event Handlers

In order to enable execution of actions based on different events, you’ll want to hook up some event handlers. To do so, the first thing you’ll need to do is name your control. Named controls are currently a requirement for event handlers.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/05/myButton.png?resize=521%2C149)

Next, select the event you would like wired up, enter a name for the event handler function and press enter.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/05/addEventHandler.png?resize=527%2C354)

The code behind generator will create a bunch of code to wire your event handler function to your control.

The first section removes the actual event handler XML attribute from the XAML. This is because PowerShell doesn’t actually support this type of event binding. I’ll look into supporting it somehow in the future but for now the event handlers in the XAML are placeholders for what is created in the code behind. They are removed at runtime.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/05/RemoveEventHandlers.png?resize=726%2C140)

The next piece of generated code is for variables that define the controls within your XAML. Currently, only the control you are adding an event handler for is generated in this section. In the future, all named controls will show up here. This allows PowerShell scripts to interact with the live controls.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/05/controlVariables.png?resize=722%2C92)

Finally, we create an event handler function and wire it to the event on the control.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/05/eventHandler.png?resize=648%2C238)

From here, we can define logic in the onClick function to take actions like opening a message box.

![](https://i0.wp.com/wandering.life/wp-content/uploads/2017/05/hey.png?resize=522%2C419)

## Packaging as an executable

XAML and the code behind script can be[packaged as an executable](https://poshtools.com/docs/posh-pro-tools/package-as-executable/). Simply right click on the WPF XAML window in the Solution Explorer window and select “Package as executable”.


# Windows Forms

Building a GUI with Windows Forms in Visual Studio

## Creating a Project

You can create a module or script project.

Click File->New->Project

![](https://i0.wp.com/wandering.life/wp-content/uploads/2017/04/newproject.png?resize=581%2C155)

Select the Module or Script project type, name it and then click Ok.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/newproject2.png?resize=753%2C522)

## Create the Form

After installing the Pro tools, you should now have a Form item template available. Right click on your project and select Add->New Item.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/newitem.png?resize=481%2C222)

Once the New Item dialog pops up, select the PowerShell Form template, name it and click Ok.

![](https://i0.wp.com/wandering.life/wp-content/uploads/2017/04/additem2.png?resize=696%2C482)

## Working with the Form Designer

### Adding Controls

The form designer works the same way with any language. You can select items from the Toolbox window and drag them onto your form. Properties of the controls can be set using the Properties window.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/04/workingwithforms.png?resize=849%2C457)

Adding controls automatically updates the Form.Designer.ps1 file. Do not edit this file by hand as the editor will simply recreate it after changes are made to the form.

![](https://i2.wp.com/wandering.life/wp-content/uploads/2017/04/designer.png?resize=682%2C296)

### Adding Event Handlers

To do anything interesting, you’ll need to add event handles. You can access a control’s events by selecting it in the designer and clicking the Event button in the Properties window.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/events.png?resize=628%2C255)

Enter the name of your event handler function and click enter.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/createhandler.png?resize=325%2C149)

After you press enter, you will be moved into the code-behind view where you can wire up your event handler.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/codebehind.png?resize=628%2C204)

The event handler will automatically be wired up to your control.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/add_Click.png?resize=515%2C82)

## Debugging A Form

Once you are ready to test out your form, you can click Start or press F5 from either the designer window or the code-behind window. PoshTools will fire off the script and you can set breakpoints and debug like any other PowerShell script.

![](https://i0.wp.com/wandering.life/wp-content/uploads/2017/04/debuger.png?resize=709%2C237)

And just like that you have a working Windows Form.

![](https://i1.wp.com/wandering.life/wp-content/uploads/2017/04/running.png?resize=775%2C400)

## Accessing Controls Added to the Form

In many circumstances, you’ll want to access a control that you’ve add to the form. The $MainForm variable will have parameters for each of it's child items. You can access those through the control's name.

```
$MainForm.lblMyLabel.Value = "Some Text"
```

## Conclusion

The PowerShell scripts generated by PoshProTools can be used in any PowerShell host. The designer and code-behind files can be joined into a single script. You can use the bundling functionality of PoshProTools to do this automatically.


# PoshTools VSC

The [PowerShell Pro Tools extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ironmansoftware.powershellprotools) adds packaging, form design, refactoring, explorers, profiling, and automation tools to PowerShell development in VS Code.

Use this tool when you want lightweight editor workflows with command palette commands, editor toolbar actions, and a dedicated PowerShell Pro Tools activity bar.

## Features

* Script Packaging
* Windows Form Designer
* Variable Explorer
* History Explorer
* Module Explorer
* Provider Explorer
* Session and Job Explorer
* Form Generator
* One-Click Attach
* Code Conversion
* Profiling
* RapidSense
* DLL Decompilation
* Refactoring

PowerShell Pro Tools provides an activity bar icon to access many of the tools.

![](/files/-MLI_IyUBCUo50PFucpw)

Within the activity bar, you'll find tools like the AST explorer, the module explorer and the variable explorer.

![](/files/-MLI_VymTBW8vdAfqmd8)

{% hint style="info" %}
Features available from the right-click Context Menu (e.g. Refactoring) require that the PowerShell script being edited is not in an unsaved state.
{% endhint %}

## Quick Examples

Package a script by right-clicking a `.ps1` file in the Explorer and selecting **Package Script as Exe**, or by running the `PowerShell Pro Tools: Package Script as Exe` command.

Open the Windows Forms designer from a `.ps1` file with `PowerShell Pro Tools: Show Form Designer`.

Attach to a running PowerShell host from the **Host Processes** view and then select a runspace.

## More Information

* [Changelog](https://github.com/ironmansoftware/powershell-pro-tools/releases)
* [Installation](/open-source-tools/visual-studio-code/installation)
* [System Requirements](/open-source-tools/visual-studio-code/system-requirements)
* [Packaging in Visual Studio Code](/open-source-tools/visual-studio-code/packaging-in-visual-studio-code)
* [Windows Forms Designer](/open-source-tools/visual-studio-code/windows-forms-designer)


# Installation

PowerShell Pro Tools for Visual Studio Code is distributed through the Visual Studio Marketplace.

## Visual Studio Code

Install the extension from the Marketplace or from the Extensions view in VS Code.

* [PowerShell Pro Tools](https://marketplace.visualstudio.com/items?itemName=ironmansoftware.powershellprotools)

You can also install it from the command line.

```powershell
code --install-extension ironmansoftware.powershellprotools
```

## PowerShell Pro Tools Module

Some commands use the PowerShell Pro Tools module. The extension includes an **Install PowerShell Pro Tools Module** command, or you can install the module yourself.

```powershell
Install-Module PowerShellProTools
```


# System Requirements

## Editor

* Visual Studio Code 1.46.0 or later.
* PowerShell extension for VS Code is recommended for the core PowerShell language service.

## Runtime

* Windows PowerShell 5.1 or PowerShell 7 for running scripts.
* Windows is required for Windows Forms designer features.
* Packaging features may require the .NET SDK that matches the target PowerShell runtime.

## Optional Dependencies

* PowerShell Pro Tools PowerShell module for module-backed commands.
* A code signing certificate for Sign On Save.
* Internet access to install module dependencies from the PowerShell Gallery or NuGet unless an internal repository is configured.


# Automating Visual Studio Code

Automate Visual Studio Code with PowerShell

## Overview

Using PowerShell Pro Tools for Visual Studio Code you can automate the editor itself. This allows you to script repetitive actions you may take within Visual Studio Code. You can edit documents, show information and more.

## Getting Started

To automate Visual Studio Code, you will need to first import the PowerShell Pro Tools VS Code module.

```
PS C:\> Import-Module PowerSHellProTools.VSCode
```

Once the module is loaded, you can begin running commands.

```
PS C:\> Get-VSCodeTerminal


Name            : pwsh
Id              : 1
Columns         : 0
Rows            : 0
CreationOptions :  - C:\Program Files\PowerShell\7\pwsh.exe

Name            : PowerShell Integrated Console
Id              : 2
Columns         : 140
Rows            : 13
CreationOptions : PowerShell Integrated Console - C:\Program Files\PowerShell\7\pwsh.exe
```

## Available Commands

**Opening Documents**

Open documents by file name.

```
PS C:\> Open-VSCodeTextDocument -FileName .\form.designer.ps1
```

**Closing Text Editors**

Close editors that are already open.

```
PS C:\> Get-VSCodeTextEditor | Remove-VSCodeTextEditor
```

**Getting Document Text**

Get the text of a document. You can also pass in a range to select only a partial section of the text.

```
PS C:\> Get-VSCodeTextDocument | Get-VSCodeTextDocumentText
```

**Inserting Text**

Inserts text into a particular position in the selected document. This creates an edit but does not save the file.

```
PS C:\> $position = New-VSCodePosition -Line 0 -Character 2
PS C:\> Get-VSCodeTextDocument | Add-VSCodeTextDocumentText -Position $position -Text NewText
```

**Removing Text**

Removes a range of text from a document. This creates an edit but does not save the file.

```
PS C:\> $Range = New-VSCodeRange -StartLine 0 -EndLine 0 -StartCharacter 0 -EndCharacter 10
PS C:\> Get-VSCodeTextDocument | Remove-VSCodeTextDocumentText -Range $Range
```

**Setting Text Decorations**

Decorates a range of text with an optional set of colors, outlines, borders, and text.

```
PS C:\> $Range = New-VSCodeRange -StartLine 0 -EndLine 0 -StartCharacter 0 -EndCharacter 55
PS C:\> Get-VSCodeTextEditor | Set-VSCodeTextEditorDecoration -BackgroundColor 'descriptionForeground' -Range $Range -Key 12321 -FontWeight bold
```

You can clear decorations by using the Clear-VSCodeTextEditorDecoration cmdlet. If you want to only clear a single decoration, you can specify the key.

[![](https://i1.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/decoration.png?resize=669%2C155\&ssl=1)](https://i1.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/decoration.png?ssl=1)

**Sending Text to a Terminal**

Sends text to the specified terminal. You can commit this text by including the -AddNewLine parameter.

```
PS C:\> Get-VSCodeTerminal | Where-Object Name -eq 'PowerShell Integrated Console' | Send-VSCodeTerminalText -Text 'Write-Host "Hello World!"'
```

[![](https://i2.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/sendtext.png?resize=1260%2C82\&ssl=1)](https://i2.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/sendtext.png?ssl=1)

**Showing Messages**

Show a message to the user. You can show information, warning, and error messages.

```
PS C:\> Show-VSCodeMessage -Message 'Error!!!' -Type Error
```

[![](https://i2.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/error.png?resize=609%2C89\&ssl=1)](https://i2.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/error.png?ssl=1)

**Showing a Message with a Response**

Show a message to the user and provide an option for them to select.

```
PS C:\> Show-VSCodeMessage -Message 'What should we do?' -Items @('Party', 'Sleep')
```

[![](https://i0.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/showmessagewithoptions.png?resize=589%2C129\&ssl=1)](https://i0.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/showmessagewithoptions.png?ssl=1)

**Showing a Quick Pick List**

Shows a quick pick list for a user to select items from. This cmdlet will return the user’s selection to PowerShell.

```
PS C:\> Show-VSCodeQuickPick -PlaceHolder 'What should we do?' -Items @('Party', 'Sleep')
```

[![](https://i0.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/quicklist.png?resize=800%2C166\&ssl=1)](https://i0.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/quicklist.png?ssl=1)

**Showing an Input Box**

Shows an input box for the user to enter arbitrary text. This cmdlet will return the result to PowerShell.

```
PS C:\> Show-VSCodeInputBox -PlaceHolder 'Enter some text'
```

[![](https://i1.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/inputbox.png?resize=815%2C124\&ssl=1)](https://i1.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/inputbox.png?ssl=1)

**Set Status Bar Message**

Sets the status bar message.

```
PS C:\> Set-VSCodeStatusBarMessage -Message 'Hellllloooo'
```

[![](https://i0.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/statusbar.png?resize=797%2C100\&ssl=1)](https://i0.wp.com/ironmansoftware.com/wp-content/uploads/2020/04/statusbar.png?ssl=1)


# Code Conversion

{% hint style="warning" %}
Code Conversion is no longer supported with PowerShell Pro Tools. It is still available as an [open-source project](https://github.com/ironmansoftware/code-conversion).
{% endhint %}


# Debugging


# Run in New Terminal

Information about the run in new terminal command.

When working with PowerShell scripts, you may want to run the current script in a new terminal rather than the existing PowerShell session. You can do so by clicking the Run in New Terminal button. This will execute the PowerShell script in a new PowerShell process and open the terminal in Visual Studio Code. You can also use the default key binding `Shift+F5` to start scripts in a new terminal.

![](/files/-MOSB0HyvzgA_o3yAlT9)


# One-Click Attach

Within the PowerShell Pro Tools action panel, you can expand the Host Processes node to view processes that are running PowerShell on your machine. If you expand the processes you will see the runspaces that are currently allocated within that process. You can then click the Attach Runspace command to attach the debugger to the selected runspace.

{% embed url="<https://youtu.be/mZo12kq-92c>" %}


# Decompiler

The decompiler allows you to view the source code for C# types that are loaded within your PowerShell process. This can be helpful to understand how types and cmdlets work.

You can access the decompiler by using the Reflection section of the PowerShell explorer. Navigate to a type and click the Decompile Type button. A text editor will open with the decompiled source code.

![](/files/-MZTmGuHnVmlm04QrG3O)


# Diagnostics

If you are having any issues with PowerShell Pro Tools for Visual Studio Code, you can view the log within the Output tab. Select the PowerShell Pro Tools Output Channel to view log information about PoshTools.

![Output Channel for PowerShell Pro Tools](/files/-MADUmNZ-wvoOskZzoqr)


# Enhanced Hover

Enhanced hover support

Enhanced hover support provides additional information about details within the script you are hovering. You can simply hover your mouse over aspects of your script to view information about it.

## AST Type Hover

When you hover over portions of a PowerShell script, the AST Type will be shown.

![AST Type Hover](/files/-MP_kWdv_GJN_qeI_6Rh)

## Variable Value and Type Hover

When you hover over a variable that has been assigned, you will be shown the value and type.

![Variable value and type hover](/files/-MP_kaz1HnLefdzO42C9)


# Generating a UI from a function

With the PowerShell Pro Tools VS Code extension, you can convert a PowerShell function into a Windows Form app without using the form designer at all. To this, you'll want to start with a PS1 file with a single function defined within it.

```
function New-User {
    param([String]$UserName, [Switch]$Enabled, [ValidateSet("Administrator", "IT", "HR")]$Department)
}
```

In VS Code, open the PS1 file you'd like to make a UI out of. Then open the command palette with `Ctrl+Shift+P` and search for `PowerShell: Generate Windows Form`.

Once you select that, two new files will be created. One will include `form.ps1` and another will include `form.designer.ps1`.

If you execute the `form.ps1` file, your UI will be shown.

![Auto-generated UI](/files/-LcED17lLKG6vj4A1kda)


# Generate a Tool from a Function

Using the `PowerShell Pro Tools: Generate Tool` command you can generate a WinForm and then compile it into an executable in one step. It uses the same concept as the Generate a UI from a function and the PoshTools packager to create the tool.

Press `Ctrl+Shift+P` to open the command pallete and search for the command. You will need to have a PS1 file open with a single function in it that defines the parameters for the tool you'd like to create.

For example, you could have a new user function like this.

```
function New-User {
    param([String]$UserName, [Switch]$Enabled, [ValidateSet("Administrator", "IT", "HR")]$Department)
}
```

This would generate a form that looked like this.

![Auto-generated UI](/files/-LcED17lLKG6vj4A1kda)

If the file was named `NewUser.ps1` , then a `NewUser.exe` would be created that would show the form and execute your tool.


# Packaging in Visual Studio Code

Information about compiling PowerShell Scripts into executables with VS Code.

PowerShell Pro Tools provides an [extension for Visual Studio Code](https://marketplace.visualstudio.com/items?itemName=ironmansoftware.powershellprotools). PowerShell Pro Tools takes advantage of the package.psd1 file to configure packaging for scripts within VS Code.

## Requirements for Packaging

* PowerShell Pro Tools Visual Studio Code Extension
* .NET Core SDK 2.0 or later

## Compiling a Script

To compile a script into an executable, open a PS1 file. In the top right of the toolbar, you will find a Package Script as Exe button. Clicking this button will start the packaging process.

![Package Script as Exe Button](/files/-MMfYUFOXuAduy3B7kf-)

If this is the first time you have clicked the button, a `package.psd1` file will be created in the current workspace's root. So for example, if you have the folder `C:\src\scripts` open in Visual Studio Code, the file `C:\src\scripts\package.psd1` will be created.

Next, the packaging process will start. The PowerShell Pro Tools Output Pane will be activated and will display log information about the packaging process.

![](/files/-MMfZ4cFoDYixVgRXTOZ)

## Configuration Packaging

To configure packaging, you can change settings within the generated `package.psd1` file. You can learn more about the syntax of the file by [clicking here](/open-source-tools/powershell-module/packaging/package.psd1).

The default configuration will look something like this.

```
@{
    Root = 'c:\Users\adamr\Desktop\test\test\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\test\out'
    Package = @{
        Enabled = $true
        Obfuscate = $false
        HideConsoleWindow = $false
        DotNetVersion = 'v4.6.2'
        FileVersion = '1.0.0'
        FileDescription = ''
        ProductName = ''
        ProductVersion = ''
        Copyright = ''
        RequireElevation = $false
        ApplicationIconPath = ''
        PackageType = 'Console'
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
```

### Root Package.psd1

The root `package.psd1` file is generated at the root of the current workspace folder. Here's an example of a file structure with a root `package.psd1` file. Clicking Package Script as Exe on an script will use this `package.psd1` file.

![](/files/-MMfZniNUT6o1WkQMK4g)

### Scoped Package.psd1

You can also include the `package.psd1` file in a particular folder. When packaging scripts in that folder, the scoped `package.psd1` file will be used.

Take the following folder structure for example.

![](/files/-MMf__C7Z7YnXw1bfhsf)

When packaging the `test\test.ps1` file, the `test\package.psd1` will be used to package the script. When packaging the `test2\test2.ps1` file, the `test\package.psd1` file will be used. The root `package.psd1` will used when packaging `test3\test3.ps1` because that folder does not have a scoped package config file.

### Package.psd1 template

You can set the package.psd1 template that is used to create the default package.psd1 by setting the path to the file within your settings.

![](/files/-MZERUFeKy_zbs6WhILX)

You can use two replacement variables that will be set when the file is created.

**$root** - Replaced by the path to the PS1 file being packaged

**$outputPath** - Path to the directory to output to.


# Pin Session

Using the `Pin Session` command you can pin a particular document to a particular session. Any time you switch to that document, that session will be used.

To pin a session to a document, open the document you wish to pin and press `Ctrl+Shift+P` and search for Pin Session. A list of sessions will be displayed. Select the session to pin. Any time you switch to that tab, that session will be used. You can unpin a session with `Unpin Session`.

![](/files/-M_7Kz_b_om7f1PZXJuN)


# PowerShell Explorer

The PowerShell Explorer allows you to view the AST, Modules and Providers in your PowerShell Environment.

![Viewing the PowerShell Explorer Window](/files/-LtjToLS5m2FCUMDaT1_)

## AST Explorer

You can explore the AST of the current PowerShell file by using the AST node in the PowerShell Explorer. Open a PS1 or PSM1 file and click the refresh button. The AST node will show which file the AST is currently showing. You can then click the nodes within the AST. Click the Select AST button to highlight the text in the editor that relates to that AST node.

![Selecting an AST Node](/files/-LtjUE6A9nwN3qAPVKil)

If you want to clear the AST node selection, click the Clear Selection button.

![Clear the AST Selection](/files/-LtjULNwYgB4CLFEUDKv)

## Custom Tree View

The custom tree view allows you to define your own tree views with custom items. Items can have children and support invocation which can call any cmdlet you'd like. You can also integrate with the [VS Code cmdlets](/open-source-tools/visual-studio-code/automating-visual-studio-code).

The following example creates a tree view named test that creates nested tree items. When each item is clicked, it will display a VS Code message.

```
Register-VSCodeTreeView -Label 'Test' -LoadChildren {
    1..10 | % { New-VSCodeTreeItem -Label "Test$_" -Icon 'archive' -HasChildren } 
} -Icon 'account' -InvokeChild {
    Show-VSCodeMessage -Message $args[0].Path
}
```

![](/files/-MZsyBv4UsKbm1JI2q0h)

This example creates a tree view of GitHub repositories and opens then when clicked.

```
Register-VSCodeTreeView -Label 'GitHub' -LoadChildren {
    New-VSCodeTreeItem -Label 'PowerShell Universal' -Description 'https://github.com/ironmansoftware/powershell-universal' -Icon 'github-inverted'
    New-VSCodeTreeItem -Label 'Issues' -Description 'https://github.com/ironmansoftware/issues' -Icon 'github-inverted'
    New-VSCodeTreeItem -Label 'PowerShell' -Description 'https://github.com/powershell/powershell' -Icon 'github-inverted'
} -Icon 'github' -InvokeChild {
    Start-Process $args[0].Description
}
```

## Host Process Explorer

The host process explorer lets you view processes running PowerShell on your machine. You can click the Attach button to use the [One-Click Attach](/open-source-tools/visual-studio-code/debugging/one-click-attach) feature.

![](/files/-MORam-RkmY0SFPMwfM_)

## History Explorer

View the history from PSReadline and insert it into the PowerShell Integrated terminal

![](/files/-MZtNOQX99IZI8VzjDwb)

## Jobs Explorer

The Jobs explorer displays the status of jobs within your PowerShell session. You can stop, receive, debug and remove jobs.

![](/files/-M_MLyioLMiBLm7NXOvh)

## Modules Explorer

The Module Explorer node provides the ability to view modules within your PowerShell environment. It will list all the modules and their versions directly in the tree view. If there is an updated version of a module, the update icon will be available and a description on the node will state the updated version that is available on the gallery. You can click the update button to update that module.

![Module Explorer in VS Code](/files/-LtjUmBvqKcAFJPectEx)

## Provider Explorer

You can use the PowerShell Provider Explorer in the PowerShell Explorer window to traverse providers in your environment.

![](/files/-LtjV7p9TaG62yLjunPv)

### Insert Selected Item Paths into Scripts

You can insert selected item paths into scripts using the Insert Path command.

![Insert Provider Path](/files/-MORg4mSoMvNOkiDLy92)

### View Item Properties

You can view the properties of a container or item by using the View Item Properties command.

![](/files/-MORgzg3ki_FtzLvp2dK)

### View Child Items

You can view child items in a grid by using the View Items command on containers.

![](/files/-MORh1DyW4MJY73zsgE5)

## Reflection Explorer

The reflection explorer allows you to view assemblies, types, and members of those types within the side panel.

![](/files/-MZP6WSoXJPHcyL0JWVU)

## Session Explorer

The session explorer allows you to view active PSSessions in your environment. You can connect, disconnect and remove sessions from the session explorer.

![](/files/-M_7JyFZvn9cZgx8f12x)

## Variable Explorer

The Variable Explorer allows you to see variables defined in your session without being in the debugger. You can expand and view their properties. Clicking the refresh button will refresh the variable list.

![Variable Explorer](/files/-LtwSXh4IQiIDvk4P71t)

### Insert Variables into Scripts

You can insert selected variables into scripts using the Insert Variable button.

![](/files/-MORavg7T0ks3nW0doWL)

Selecting nested properties will insert the path to the property into the script.

![](/files/-MORhNtRdYS6uURty9Pz)


# Profiler

PowerShell Pro Tools offers a script performance profiler to time the execution of your script. It helps to locate slow sections of code and provides the number of times particular lines are called.

The feature is best defined as an instrumentation profiler that injects cmdlet calls into your script to thoroughly analyze your script. The script is executed with this injected code to accurately time the pipelines within your script.

{% embed url="<https://youtu.be/9DkxJ78C5ks>" %}

## Profiling a Script

To profile a script, open the script you wish to profile and execute the `PowerShell: Profile Script` command from within VS Code (Ctrl+Shift+P). The script will be instrumented and then executed within the VS Code PowerShell Session. After execution is complete, script timings will be added directly to the editor on the lines in which they were recorded.

![Profiler information](/files/-LRoygTJw92LfHDrEA3x)

The profile information will remain in the editor until you execute the `PowerShell: Clear Profiling Information` command in VS Code.

### Limitations <a href="#limitations" id="limitations"></a>

Being an early version of the profiler, there are some limitations.

#### **Single Script Support** <a href="#single-script-support" id="single-script-support"></a>

The profiler only profiles the current script. It will not profile scripts or modules that you reference. If you use functions within pipelines in your profiled script, those functions will be timed but their internal operations will not.

**Hot Path Support**

Although the hot path information is available in the output from the profiler, there is no visual representation of this information.

#### Pipeline Element Timing <a href="#pipeline-element-timing" id="pipeline-element-timing"></a>

The profiler has early support for pipeline element timing but does not expose this in this version. For example, a pipeline like the one below will result in a single timing even though multiple commands are being called.

```
Get-Process | Select-Object Name | Out-String  40.85% (1 calls)
```


# Sign On Save

Sign scripts after they are saved.

The Sign on Save features provides a way to sign scripts right after they are saved using a configured code-signing certificate.

## Configuring Sign On Save

You can configure sign on save by enabling the feature in settings and providing a certificate path.

![](/files/-MZJhS6b7O8rNfJ0jZgS)

The path can be left empty and the extension will provide a quick pick drop down the first time you save a file.

![](/files/-MZJheC8lja-spmsI8P6)

Once you select a certificate, it will store that in the Sign On Save Certificate setting. You'll notice the setting is the full path to the certificate in the certificate store.

```
Microsoft.PowerShell.Security\Certificate::CurrentUser\My\Aasdfasdf23fdasfd0as872389723soad
```

With the setting enabled, any time you save a file, `Set-AuthenticodeSignature` will be called and your file will be signed.


# RapidSense

High performance statement completion.

![RapidSense](/files/-MNxs1YcO0CiMMdovshq)

RapidSense is an alternative to the default PowerShell IntelliSense that provides high performance, customizable statement completion. It aggressively caches PowerShell elements to provide to the best performance possible. It sacrifices some of the features of IntelliSense to provide this performance but aims to provide the most common statement completion suggestions. You can quickly toggle between IntelliSense and RapidSense.

RapidSense works with Windows PowerShell and PowerShell 7.

{% embed url="<https://youtu.be/rIp6VPh91h0>" %}

## Enabling RapidSense

To enable RapidSense, click the IntelliSense button on the status bar.

![](/files/-MNv7QxuzgzEUmK1Tcgd)

After clicking the IntelliSense button, it will toggle to RapidSense. RapidSense will begin the caching problem. It should only take a couple of seconds.

![](/files/-MNv7d6PKIgxpiIPmMB7)

## Using RapidSense

![](/files/-MNv7s8I0UbGwpZcdXH8)

RapidSense works the same as IntelliSense. As you begin typing, it will suggest commands, parameters, variables, properties, methods, paths and types. RapidSense currently does not complete static members, classes, or attributes.

RapidSense triggers on on the following characters:

```
,
.
-
[
\
```

When a trigger character is pressed the standard statement completion UI will be shown.

![](/files/-MNv88iH47Uoth9oszam)

## Configuring RapidSense

RapidSense can be configured to ignore certain assemblies, types, modules and commands. You can change these settings in the VS Code settings UI.

For each of the ignored elements, you can define an array and separate them with semicolons. Each segment is treated as a regular expression.

For example, if you wanted to prevent cmdlets in the `ActiveDirectory` module from showing in RapidSense, add the following to the Ignored Modules setting.

```
ActiveDirectory
```

If you wanted to exclude all `System` assemblies from type completion. You could add a regular expression to the Ignore Assemblies setting.

```
System.*
```

You can still use these commands in your scripts but they will not be suggested to you are you type. Ignoring elements improves performance because they are not included in the cache at all. Including many ignored elements may reduce performance of the recaching process as it need to process additional regular expressions across the elements. Recaching happens after executing the debugger.

### Available Settings

**Ignored Assemblies** - Ignore types in certain assemblies\
**Ignored Types** - Ignore specific types\
**Ignore Modules** - Ignore commands found in certain modules\
**Ignore Commands** - Ignore specific commands\
**Ignore Variables** - Ignore specific variables.

## Disabling RapidSense

You can toggle back to standard IntelliSense by click the RapidSense button in the status bar. RapidSense caches will not be recached when RapidSense is disabled.

![](/files/-MNv9O0XLIcLtH-es55L)


# Refactoring

Refactoring commands for VS Code.

## About

Refactorings allow you to change or generate code based on the code you have. You will find a list of refactors below. You can invoke a refactor by invoke the Refactor command or by pressing the key binding `Ctrl+Alt+R` .

Only valid refactors will be returned in the drop down menu.

## Convert to $\_

This refactoring converts a `$PSItem` variable to the `$_` variable.

![Convert to $\_](/files/-MPXO04v5yHzXhiR1aTm)

## Convert to $PSItem

Converts a reference to the `$_` variable to `$PSItem`.

![Convert to $PSItem](/files/-MPXOJpL1Oup_fK-FvSh)

## Convert to Multiline Command

Converts a command invocation into a multi-line command. Each parameter and argument is broken up with backticks.

![](/files/-MOZS9SXQsx48tayR16e)

## Convert to Splat

Converts a command invocation into a splatting expression and creates a hashtable named `$Parameters` and then passes that hashtable as a splatting expression to the command. Positional arguments are not added to the hashtable.

![Convert to Splat](/files/-MOUGowA5Q-fn30u2UTF)

## Export Module Member

Exports the selected variable or function from a module using `Export-ModuleMember`.

![Export Module Member](/files/-MOU6cJ8KcTt9uMTBq7s)

## Extract Function

You can use the Extract Function refactor to convert a section of code into a function. It will analyze the selected block and determine if there are variables that should be added as parameters. These variables will be added to the `param` block.

![Extract Function](/files/-MOUgHXdNw7fZnFH_Z1v)

## Extract Selection to File

You can use the Extract Selection to File refactor to create a new file based on the selection in the current active editor.

![Extract Selection to File](/files/-MOTrwRfBGcOtWZdOcM_)

## Generate Function from Usage

You can generate a function based on a command example. This refactoring will analyze the parameters, arguments and whether the command is used in a pipeline. If used in a pipeline, this refactoring will generate an advanced function.

![Generate Function from Usage](/files/-MOnjGH6ICKfhLoAMKdW)

## Generate Proxy Function

Proxy functions allow you to extend existing functions with new parameters and functionality. You can select a command that you use within your script and select the Generate Proxy Function refactoring to have it generate the proxy function code for you.

![Generate Proxy Function](/files/-MPsICFqK3dXdKAczbda)

## Introduce Using Namespace

The introduce using namespace refactoring adds a `using namespace` statement to the top of a script and replaces the selected type expression with the namespace removed.

![Introduce Using Namespace](/files/-MPSCRt_mo2RtJDZ8U63)

## Reorder Parameters

You can reorder parameters by using the `Ctrl+PageUp` and `Ctrl+PageDown` key bindings. Ensure that your cursor is on top of a parameter for a command. Press one of the key bindings. To move a parameter to the right, use Page Up. To move a parameter to the left, use Page Down.

![Reorder Parameters](/files/-MOsRAZOJjGKyJVvLHSZ)

## Split Pipeline

The split pipe refactoring will split a pipe into multiple lines. Each element in the pipe is stored in a variable and passed to the next item in the pipe. This can be useful for debugging long or complex pipeline operations.

![Split pipeline](/files/-MPRuUr-DpGW2sRPuBs1)


# Rename Symbols

You can press F2 on variables within Visual Studio Code to rename them across the workspace or function you are working in.

## Variables

### Global Scope

Renaming variables that appear at the top level scope will rename them across the workspace.

![](/files/-Ma-Z0JEx1YO27lBZTE5)

### Function Scope

Function scoped variables will only be renamed within the function you are working with.

![](/files/-Ma-Z784fvzHEU1gEBS8)


# Quick Scripts

Quick Scripts allow you to save and quickly access scripts that are stored anywhere on your machine. The scripts are stored across workspaces so whenever you open VS Code, you'll have access to the scripts. Quick scripts are listed in the PowerShell Explorer window.

![](/files/-LtjlfrR5FWM67YEHvUj)

## Adding Quick Scripts

Quick Scripts can be added by issuing the Add Quick Script command or clicking the Add Quick Script button in the editor. In either case, it will add the current file to Quick Scripts.

![](/files/-LtjlvEKOjq_NVfUJfAX)

After issuing the command or clicking the button, you will have to enter a short name for the Quick Script.

![](/files/-Ltjm60xa_EMdSNW4KuU)

## Opening Quick Scripts

You can either open a Quick Script by click the button in the PowerShell Explorer window or by issuing the Open Quick Script command. When issuing the command, you'll have to enter the name of the Quick Script.

![](/files/-LtjmIKICWFhXnMH0uLi)

## Removing Quick Scripts

You can remove quick scripts by clicking the Trash icon in the PowerShell Explorer window.


# Windows Forms Designer

{% hint style="info" %}
The Windows Form Designer is only supported on Windows.
{% endhint %}

{% embed url="<https://youtu.be/LULI64meTUs>" %}
Building A Windows Form with PowerShell in Visual Studio Code
{% endembed %}

## Creating a New Form

Create a PowerShell script by clicking File \ New File, entering the name of the file with a `.PS1` extension. This will be the script that is used to launch your form.

## Opening the Designer

To open the designer press `Ctrl+Shift+P` and then type `Show Windows Forms Designer` . The `PowerShell Pro Tools: Show Forms Designer` command should be show. Click or press enter.

You can also open a form by clicking the Show Windows Forms Designer button in the tool bar of a PS1 file.

![](/files/-MLItSO51IwWk1NLCbOw)

## Working with the Designer

The designer is very much like the standard Visual Studio designer. The design surface on the left allows you to modify your form. You can resize and delete controls from the bottom.

On the right right it provides a toolbox with controls that can be selected and placed on the form. The add a new control, click the control you'd like to place and then click the design surface of where you would like to place the control.

Below the toolbox is the properties dialog. You can select a control and modify its properties within this control.

On the bottom of the designer is a status bar. It displays the file that is being modified by the designer. An asterisk will be shown when the form is modified.

![](/files/-LU73h7_sjSmyrDnKmw0)

## Event Handlers

To implement an event handler, double click on the control you'd like to add the event handler to. It will automatically generate the event handler code in Visual Studio Code.

Event handlers can also be generated by clicking the event handler tab in the property pane.

![Event handler pane](/files/-LeTshJGu5PyHxqrIGa-)

To create a new event handler, type the name of the handler in the text box next to the event handler. Once you press enter and then save the form, with Ctrl+s or the Save button, the event handler will be generated in the code file.

##


# PowerShell Module

The PowerShell Pro Tools PowerShell module provides command-line access to packaging and Windows Forms design tooling. It is useful for local scripts, repeatable build steps, and CI systems where you do not want to drive an editor.

## Features

* Bundle dot-sourced scripts into a single script with `Merge-Script`.
* Package scripts as executables with a `package.psd1` configuration.
* Generate Windows Forms code from PowerShell functions with `ConvertTo-WinForm`.
* Launch the Windows Forms designer with `Show-WinFormDesigner`.
* Open PSScriptPad with `Show-PSScriptPad`.

## Quick Examples

Install the module from the PowerShell Gallery.

```powershell
Install-Module PowerShellProTools
```

Bundle a script and its dot-sourced dependencies.

```powershell
Merge-Script -Config @{
    Root = ".\Start-Tool.ps1"
    OutputPath = ".\out"
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

Open a script in the Windows Forms designer.

```powershell
Show-WinFormDesigner -Path .\MainForm.ps1
```

## More Information

* [Changelog](https://github.com/ironmansoftware/powershell-pro-tools/releases)
* [Installation](/open-source-tools/powershell-module/installation)
* [System Requirements](/open-source-tools/powershell-module/system-requirements)
* [Packaging](/open-source-tools/powershell-module/packaging)
* [PowerShell Gallery](https://www.powershellgallery.com/packages/PowerShellProTools)


# Installation

The PowerShell Pro Tools module is distributed through the PowerShell Gallery.

```powershell
Install-Module PowerShellProTools
```

To install for the current user only, use `-Scope CurrentUser`.

```powershell
Install-Module PowerShellProTools -Scope CurrentUser
```

## Update

```powershell
Update-Module PowerShellProTools
```


# System Requirements

## PowerShell

* Windows PowerShell 5.1 or PowerShell 7.
* PowerShellGet or PSResourceGet configured for the PowerShell Gallery.

## Packaging

Packaging requirements depend on the runtime you target.

| Target PowerShell  | .NET target                                  |
| ------------------ | -------------------------------------------- |
| Windows PowerShell | .NET Framework 4.6.2 or later Developer Pack |
| PowerShell 7.2     | .NET 6 SDK                                   |
| PowerShell 7.3     | .NET 7 SDK                                   |
| PowerShell 7.4     | .NET 8 SDK                                   |

The packaging process may need access to NuGet.org or an internal NuGet feed to restore runtime packages. See [Package.psd1](/open-source-tools/powershell-module/packaging/package.psd1) for supported package configuration values.

## Windows Forms

Windows Forms designer and packaged Windows Forms applications require Windows.


# Packaging

## Requirements:

* [.NET Core 3.1 SDK or Later](https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-3.1.415-windows-x64-installer)
* [.NET 5.0 SDK for Packaging PowerShell 7.1](https://dotnet.microsoft.com/download/dotnet/thank-you/sdk-5.0.403-windows-x64-installer)
* [.NET 4.6.2 Developer Pack](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net462)
* Internet Connection

The packaging component of PowerShell Pro Tools allows you to bundle, package as an executable and obfuscate the resulting executable.

## Bundling

The process of bundling takes multiple scripts and creates a single script. Bundling automatically follows dot sourced scripts and includes them in the final output script. This process is recursive and will include scripts that are included by other scripts. Take for example you have three scripts. The first script looks like this.

`Write-Host "Hi! I'm script 1"`

`. $PSScriptRoot\Script2.ps1`

Script1.ps1 outputs “Hi! I’m script 1” and then calls Script2.ps1 found at the $PSScriptRoot. Script2.ps1 could then look like this.

\`Write-Host "Hi! I'm script 2"

.\Script3.ps1\`

Script2.ps2 outputs “Hi! I’m script 2” and the calls Script3.ps1. Script3.ps1 could consist of something like this.

`Write-Host "Hi! I'm script 3"`

If you wanted to deploy these scripts to an environment, you’d need to make sure to copy each script. Using bundling, you could combine the scripts, automatically, into a single script. The resulting script would look like this.

\`Write-Host "Hi! I'm script 1"

Write-Host "Hi! I'm script 2"

Write-Host "Hi! I'm script 3"\`

This enables developers to organize their code into multiple scripts but then deploy a single script. You could store all three scripts in source control, such as GitHub, and then run a bundling step using a continuous integration system, such as AppVeyor.

You can bundle scripts with PowerShell Pro tools using [Visual Studio](https://poshtools.com/docs/posh-pro-tools/bundling-packaging-msbuild/) or [Merge-Script](https://poshtools.com/docs/posh-pro-tools/merge-script/).

## Packaging as an Executable

Scripts can be packaged as a .NET executable for easy deployment on any Windows system. You can combine bundling with packaging to include multiple scripts into a single executable.

You can package scripts with PowerShell Pro tools using [Visual Studio](https://poshtools.com/docs/posh-pro-tools/bundling-packaging-msbuild/) or [Merge-Script](https://poshtools.com/docs/posh-pro-tools/merge-script/).

## Obfuscation

Once scripts have been packaged as a .NET executable, you can take an additional step and obfuscate the executable **(this feature is limited to Windows PowerShell only)**. This will make it much more difficult for users to decompile your executable and inspect your PowerShell script. Obfuscated assemblies scramble the C# code as well as the PowerShell script.

You can obfuscate executables with PowerShell Pro tools using Visual Studio, Visual Studio Code and Merge-Script.

## Anti-Virus

Anti-Virus vendors may flag executables as malicious after they have been compiled. You can use [VirusTotal](https://www.virustotal.com/gui/) to verify which vendors may flag your executable. If you need to submit a executable for evaluation, you can use the below list of vendor verification processes.

* [Microsoft Defender](https://www.microsoft.com/en-us/wdsi/filesubmission)

Learn more about issues with [anti-virus here](/open-source-tools/powershell-module/packaging/anti-virus).

## NuGet

We use the Microsoft NuGet.org package system to download the packages necessary to host PowerShell in .NET. You will need an internet connection to access NuGet.org.

By default, you should have the package source defined. If you do not, you can do so with the following `dotnet` command line.

```
dotnet nuget add source https://api.nuget.org/v3/index.json -n nuget.org
```

For offline builds, you can also host your [own NuGet feed](https://docs.microsoft.com/en-us/nuget/hosting-packages/overview).


# Package.psd1

{% hint style="info" %}
Requires [PowerShell Pro Tools](https://ironmansoftware.com/poshtools)
{% endhint %}

## About

This about file contains information about using hashtables and psd1 files to configure Merge-Script. These psd1 files (e.g. "package.psd1") are also used by PowerShell Tools for Visual Studio Code.

### Config File Schema

```powershell
@{
        Root = 'c:\Users\Adam\Desktop\service.ps1' # Root script to package. This is the main entry point for the package. 
        OutputPath = 'c:\Users\Adam\Desktop\out' # The output directory for the packaging process. 
        Package = @{
            Enabled = $true # Whether to package as an executable. 
            Obfuscate = $false # Whether to obfuscate the resulting executable. 
            HideConsoleWindow = $false # Whether to hide the console window.  Only valid for console applications.
            # The target .NET Framework version. You will need the .NET Developer Pack for this version installed on your machine.
            # If target PowerShell 7, you can also use netcoreapp31 here 
            DotNetVersion = 'v4.6.2'
            FileVersion = '1.0.0' # The output file version
            FileDescription = '' # The output file description
            ProductName = '' # The output file product name
            ProductVersion = '' # The output file product version.
            Copyright = '' # The output file copyright
            RequireElevation = $false # Whether to require elevation when running the executable. Only valid for console applications. 
            ApplicationIconPath = '' # The path to the application icon to use for the executable. 
            PackageType = 'Console' # The type of executable to generate. Valid values are Service or Console. 
            ServiceName = "" # The name of the service if the package type is Service. 
            ServiceDisplayName = "" # The display name of the service if the package type is Service. 
            HighDPISupport = $true  # Whether to enable high DPI support for WinForm applications
            PowerShellArguments = '' # Sets the arguments for the PowerShell process that is hosted within the executable. You can use arguments like -NoExit, -ExecutionPolicy and -NoProfile.
            Platform = 'x64' # Sets the architecture of the executable. Can be either 'x86' or 'x64'
            PowerShellVersion = 'Windows PowerShell' # You can specify Windows PowerShell or PowerShell 7 or later versions version (e.g. 7.0.0)
            RuntimeIdentifier = 'win-x64' # You can specify other runtimes like linux-x64 (See .NET Core runtime identifiers)
            DisableQuickEdit = $false # Disables the quick edit mode on windows console apps
            Resources = [string[]]@() # Resources to embed in the output executable
            Host = 'Default' # The PowerShell Host to use. 
            Lightweight = $false # Removes WPF and WinForm support in PowerShell 7 executables.
        }
        Bundle = @{
            Enabled = $true # Whether to bundle multiple PS1s into a single PS1. Always enabled when Package is enabled. 
            Modules = $true # Whether to bundle modules into the package
        }
    }
    
```

### Using a config file

A config file can be used either from within a PowerShell script as a hashtable or imported from a psd1 file containing the hashtable. The standard name for this file is *package.psd1*.

## Options

### Root

The root script to package.

### OutputPath

The path of the output directory for the resulting executable.

### Package

Options for the packager. See the config file schema for the proper layout.

#### Enabled

Whether the packager is enabled. Valid values are either $true or $false.

#### Obfuscate

Whether to obfuscate the assembly. Only valid for Windows PowerShell. Valid values are $true or $false. Note: this is a legacy technique (for educational purposes) which is easily reversed by free modern security tools.

#### HideConsoleWindow

Whether to hide the console window. Useful for when packaging form applications. Valid values are $true or $false.

#### DotNetVersion

The .NET version to target for the executable. You can find the valid values below.

| PowerShell Version | Valid .NET Versions                              |
| ------------------ | ------------------------------------------------ |
| Windows PowerShell | net4.6.2, net4.7.0, net4.7.1, net4.7.2, net4.8.0 |
| PowerShell 7.0.x   | netcoreapp31                                     |
| PowerShell 7.1.x   | net5.0                                           |
| PowerShell 7.2.x   | net6.0                                           |
| PowerShell 7.3.x   | net7.0                                           |
| PowerShell 7.4.x   | net8.0                                           |

#### FileVersion

The file version to display in the assembly properties.

#### FileDescription

The file description to display in the assembly properties.

#### ProductName

The product name to display in the assembly properties.

#### ProductVersion

The product version to display in the assembly properties.

#### Copyright

The copyright to display in the assembly properties.

#### RequireElevation

Whether the executable requires elevation to run. This setting is only supported on Windows. Either $true or $false.

#### ApplicationIconPath

The path to the icon to display for this application.

#### PackageType

The type of package to product. Valid values are Console or Service.

#### ServiceName

The name of the service when packaging a service (e.g. "MyService").

#### ServiceDisplayName

The display name of the service when packaging a service (e.g. "My Utility Service").

#### HighDPISupport

Enable high DPI support for Windows Forms applications. Either $true or $false.

#### PowerShellArguments

Additional arguments to provide to the PowerShell process. This can include arguments like `-ExecutionPolicy` or `-NoProfile`. Do not include `-Command`.

#### Platform

The target architecture for the executable. This should be either x86 or x64.

#### PowerShellVersion

The PowerShell version to target. Ensure that you specify a supported .NET version when selecting your PowerShell version. Supported versions are (replace x with specific version number):

* Windows PowerShell
* 7.0.x
* 7.1.x
* 7.2.x
* 7.3.x
* 7.4.x

#### RuntimeIdentifier

The .NET runtime identifier to target. This defaults to `win-x64`. If you wish to target Linux, you could specify `linux-x64`. You can find a list of valid [.NET runtime identifiers here](https://docs.microsoft.com/en-us/dotnet/core/rid-catalog).

#### DisableQuickEdit

Disables the quick edit mode on Windows console applications. This defaults to $false. Either $true or $false.

#### Resources

An array of resources to include with the executable. This should be an array of strings. These resources will be stored as embedded resources.

#### DotNetSdk

This is an advanced option. The target .NET SDK to use when packaging the executable. If not specified, the highest version will be used.

#### Certificate

The certificate used to sign the assembly. The packager will use `Set-AuthenticodeSignature` to sign the assembly. This should be the path to a valid code signing certificate. For example: `'Cert:\CurrentUser\AuthRoot\02FAF3E291435468607857694DF5E45B68851555'`

#### OutputName

The name of the output assembly. When this is not specified, this will be the root script name.

#### Host

Specifies the PowerShell host to use. The Default host will use the .NET SDK to create and package a script executable. The Ironman Software host's do not function this way. You can read more about Ironman Software hosts [here](https://docs.poshtools.com/powershell-pro-tools-documentation/packaging/package-hosts).

**Lightweight**

Removes WinForms and WPF support from .NET 7\PowerShell 7 executables. This reduces the overall footprint of the executable by about 45%.

### Bundle

#### Enabled

Whether bundling is enabled. Bundling will include referenced scripts and modules in the resulting executable.

#### Modules

Whether to bundle modules with the script executable. Modules will only be bundled when imported with `Import-Module`.

#### NestedModules

Whether to include nested modules of packaged modules. Requires Modules to be set to $true.

#### IgnoredModules

A list of modules to ignore during packaging. This should be an array of strings.

## EXAMPLES

It is not required to include all aspects of the config when using Merge-Script. The only required components are Root and OutputPath. Aside from that, anything that is not include will be considered false. This means that in the below example, packaging is disabled but bundling is not. The below operation will not bundle nested modules or required assemblies of any modules it is bundling.

```powershell
Merge-Script -Config @{ 
    Root = ".\MyScript.ps1"
    OutputPath = ".\"
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

### Create console application

Creates a PowerShell console based application that has an application icon and hides the console window.

```powershell
@{
        Root = 'c:\Users\Adam\Desktop\form.ps1'
        OutputPath = 'c:\Users\Adam\Desktop\out'
        Package = @{
            Enabled = $true
            HideConsoleWindow = $true
            DotNetVersion = 'v4.6.2'
            ApplicationIconPath = 'C:\users\adam\desktop\icon.ico'
        }
    }
    
```

### Ironman Software Host

Use the Ironman Software host to build your executable without having to install the .NET SDK.

```powershell
@{
    Root = 'c:\Users\Adam\Desktop\form.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        Host = 'IronmanPowerShellHost'
        FileVersion = '2.1.0.0'
    }
}
```

### Create a service

Creates a PowerShell service based on the service.ps1 file and outputs to the out directory on the desktop. It will use the .NET 4.6.2 Developer Pack. The service name will be PSService and the display name will be PowerShell Service.

For more information on services, see the [Package as Service](/open-source-tools/powershell-module/packaging/package-a-service) section.

```powershell
@{
        Root = 'c:\Users\Adam\Desktop\service.ps1'
        OutputPath = 'c:\Users\Adam\Desktop\out'
        Package = @{
            Enabled = $true
            DotNetVersion = 'v4.6.2'
            FileVersion = '1.0.0'
            FileDescription = ''
            ProductName = ''
            ProductVersion = ''
            Copyright = ''
            PackageType = 'Service'
            ServiceName = "PSService"
            ServiceDisplayName = "PowerShell Service"
        }
    }
    
```

After building a service, you can install the service with the `--install` parameter of your service's executable. To uninstall a service, use the `--uninstall` parameter.

### Package PowerShell 7.0

Creates an executable that contains the PowerShell 7.0 engine. This executable does not require the target machine to have PowerShell or .NET Core installed. The size of the executable will be considerably larger than a typical `Merge-Script` executable.

{% hint style="info" %}
Note: PowerShell 7.0 is no longer supported by Microsoft or IronmanSoftware and is considered legacy. *You must use a currently supported version of PowerShell with PowerShell Pro Tools to receive support from Ironman Software*.

See [Microsoft Support LifeCycle for PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle) for a list of supported versions.
{% endhint %}

```powershell
@{
    Root = 'c:\Users\Adam\Desktop\script.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        DotNetVersion = 'netcoreapp3.1'
        PowerShellVersion = "7.0.0"
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

### Package PowerShell 7.1

You can package PowerShell 7.1 scripts by targeting .NET 5.0. You will need the [.NET 5.0 SDK or later](https://dotnet.microsoft.com/en-us/download/dotnet/5.0).

{% hint style="info" %}
Note: PowerShell 7.1 is no longer supported by Microsoft or IronmanSoftware and is considered legacy. *You must use a currently supported version of PowerShell with PowerShell Pro Tools to receive support from Ironman Software*.

See [Microsoft Support LifeCycle for PowerShell](https://learn.microsoft.com/en-us/powershell/scripting/install/powershell-support-lifecycle) for a list of supported versions.
{% endhint %}

```powershell
@{
    Root = 'c:\Users\Adam\Desktop\script.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        DotNetVersion = 'net5.0'
        PowerShellVersion = "7.1.0"
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

### Package PowerShell 7.2

{% hint style="info" %}
PowerShell Pro Tools 2021.12.0 or later required.
{% endhint %}

You can package PowerShell 7.2 scripts by targeting .NET 6.0. You will need the [.NET 6.0 SDK or later](https://dotnet.microsoft.com/en-us/download/dotnet/6.0).

```powershell
@{
    Root = 'c:\Users\Adam\Desktop\script.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        DotNetVersion = 'net6.0'
        PowerShellVersion = "7.2.18"
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

### Package PowerShell 7.3

{% hint style="info" %}
PowerShell Pro Tools 2023.7.0 or later required.
{% endhint %}

You can package PowerShell 7.3 scripts by targeting .NET 7.0. You will need the .NET 7.0 SDK or later.

```powershell
@{
    Root = 'c:\Users\Adam\Desktop\script.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        DotNetVersion = 'net7.0'
        PowerShellVersion = "7.3.11"
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

### Package PowerShell 7.4

{% hint style="info" %}
PowerShell Pro Tools 2023.7.0 or later required.
{% endhint %}

You can package PowerShell 7.4 scripts by targeting .NET 8.0. You will need the .NET 8.0 SDK or later.

```
@{
    Root = 'c:\Users\Adam\Desktop\script.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        DotNetVersion = 'net8.0'
        PowerShellVersion = "7.4.1"
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

## Bundle resources in a WPF application

Embeds the `image.png` file within the application so you can reference it in your XAML. This file resides in the same folder as `window.ps1`.

```powershell
@{
    Root = 'c:\Users\Adam\Desktop\Window.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        Resources = [string[]]@("image.png")
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

In the XAML, you can reference the image like this.

```xml
<Window x:Class="WpfApp1.MainWindow"
        xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
        xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
        xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
        xmlns:local="clr-namespace:WpfApp1"
        mc:Ignorable="d"
        Title="MainWindow" Height="450" Width="800">
    <Grid>
        <Image Source="image.png" />
    </Grid>
</Window>
```

## Access Resources in Your Script

You can access resources in your script using the following function.

```powershell
function Get-ResourceAsString {
     param($Name)
     
     $ProcessName = (Get-Process -Id $PID).Name
     $Stream = [System.Reflection.Assembly]::GetEntryAssembly().GetManifestResourceStream("$ProcessName.g.resources")
     $KV = [System.Resources.ResourceReader]::new($Stream) | Where-Object Key -EQ $Name
     [System.IO.StreamReader]::new($KV.Value).ReadToEnd()
}
```

In your script, just use this function to load the file.

```powershell
$MyManifest = Get-ResourceAsString -Name 'manifest.json'
```

You will package the resource file, just like you do with WPF applications.

```powershell
@{
    Root       = 'c:\Users\adamr\Desktop\variables.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\out'
    Package    = @{
        Enabled   = $true
        Resources = [string[]]@("manifest.json")
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
    }
}
```

## Adding an Icon to a WPF Window

You cannot directly add icons to WPF windows with PowerShell and will need to do so using code. First, you'll need to ensure that your icon is in the same directory of the script. You will also need to add your icon as a resource.

```powershell
@{
    Root       = 'c:\Users\adamr\Desktop\WpfWindow.xaml.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\out'
    Package    = @{
        Enabled   = $true
        Resources = [string[]]@("favicon.ico")
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
    }
}
```

If you are using Visual Studio rather than `package.psd1`, you can set the add the icon to your project and set it as a resource.

<figure><img src="/files/RjTHvL20ebpFjwhfInhQ" alt=""><figcaption></figcaption></figure>

Next, in your PS1 file for your WPF window, you will need to load your icon from either the file system or the packaged resources. The `Get-Resource` function below attempts to load from the packaged resource and, if not found, will instead load it from disk.

```powershell
function Get-ResourceAsStream {
     param($Name)
     
     $ProcessName = (Get-Process -Id $PID).Name
     try 
     {
        $Stream = [System.Reflection.Assembly]::GetEntryAssembly().GetManifestResourceStream("$ProcessName.g.resources")
        $KV = [System.Resources.ResourceReader]::new($Stream) | Where-Object Key -EQ $Name
        $Stream = $KV.Value
     } catch {}

    if (-not $Stream)
    {
        $Stream = [IO.File]::OpenRead("$PSScriptRoot\favicon.ico")
    }

    $Stream
}
```

Next, you'll need to create a new bitmap and set the window's icon property to the bitmap.

```powershell
$bitmap = New-Object System.Windows.Media.Imaging.BitmapImage
$bitmap.BeginInit()
$bitmap.StreamSource = Get-ResourceAsStream -Name 'favicon.ico'
$bitmap.EndInit()
$bitmap.Freeze()
 
$window.Icon = $bitmap
```

An entire working example of the PS1 file can be found below.

```powershell
[System.Reflection.Assembly]::LoadWithPartialName("PresentationFramework") | Out-Null

function Import-Xaml {
	[xml]$xaml = Get-Content -Path $PSScriptRoot\WpfWindow1.xaml
	$manager = New-Object System.Xml.XmlNamespaceManager -ArgumentList $xaml.NameTable
	$manager.AddNamespace("x", "http://schemas.microsoft.com/winfx/2006/xaml");
	$xamlReader = New-Object System.Xml.XmlNodeReader $xaml
	[Windows.Markup.XamlReader]::Load($xamlReader)
}

$window = Import-Xaml

function Get-Resource {
     param($Name)
     
     $ProcessName = (Get-Process -Id $PID).Name
     try 
     {
        $Stream = [System.Reflection.Assembly]::GetEntryAssembly().GetManifestResourceStream("$ProcessName.g.resources")
        $KV = [System.Resources.ResourceReader]::new($Stream) | Where-Object Key -EQ $Name
        $Stream = $KV.Value
     } catch {}

    if (-not $Stream)
    {
        $Stream = [IO.File]::OpenRead("$PSScriptRoot\favicon.ico")
    }

    $Stream
}

$bitmap = New-Object System.Windows.Media.Imaging.BitmapImage
$bitmap.BeginInit()
$bitmap.StreamSource = Get-Resource -Name 'favicon.ico'
$bitmap.EndInit()
$bitmap.Freeze()
 
$window.Icon = $bitmap

$window.ShowDialog()
```

The result is a WPF window with a custom icon that is shown both when packaged and when running the script outside of the package.

<figure><img src="/files/gRE6zTiM7Evu6PjZRwrk" alt=""><figcaption></figcaption></figure>


# PowerShell Packager

Packager PowerShell scripts as executables.

{% hint style="info" %}
Download from the [PowerShell Pro Tools download page](https://ironmansoftware.com/powershell-pro-tools/downloads).
{% endhint %}

The PowerShell Packager uses the same packaging tools as the PowerShell Pro Tools module and PowerShell Pro Tools for VS Code but provides a simple interface that does not require configuration files or special build tools. This tool currently only supports Windows PowerShell executables.

Running the packager will provide a simple wizard that you can step through to provide details for the resulting executable.

<figure><img src="/files/BQ9QPJsdUc7ga1VdgSrz" alt=""><figcaption></figcaption></figure>

## Properties

### Root Script

The root script is the script that will run when the executable is run. You can dot source other scripts and import modules in this script. This script will also receive the parameters passed to the executable.

### Package Referenced Scripts

Any dot-sourced script referenced in the root script will be packaged as well. If those scripts include other dot-sourced scripts, they will also be included and so on.

### Package Referenced Modules

Any module imported with `Import-Module` will be included with the executable.

### File Properties

These are the properties that will be set on the resulting executable. For example, File Version, Description and Company name.

### Application Properties

These are properties of the application itself. These include hiding the console window and Windows UI support.

### Output Path

The folder path to output the resulting executable to.

## Certificate

The certificate is optional and will cause the packager to call `Set-AuthenticodeSignature` against the executable. The certificate path should be a certificate provider path.

```powershell
Cert:\LocalMachine\My\1111DDDDD
```

## Diagnostic Logging

The packager will automatically write diagnostic logs to the following location.

```powershell
$Env:LOCALAPPDATA\PowerShellTools\PSPackager
```


# Package Hosts

Learn about the different ways to host your PowerShell scripts.

## Default Host

The default host uses the .NET SDK to compile an executable that runs your PowerShell script. The default host currently provides more options than the other hosts but is often flagged as suspicious by anti-virus applications. It also requires the .NET SDK installed on the local machine in order to function.

You do not need to make any changes to use the default host.

## Ironman Software Host

The Ironman Software host is a precompiled executable that is updated to include your script and settings. It does not require the .NET SDK and is less likely to be flagged by antivirus.

To use the Ironman Software PowerShell host, you will need to set the Host property in `package.psd1` to the `IronmanPowerShellHost` or `IronmanPowerShellWinFormsHost`.

The different between the standard host and the Win Forms host is that the latter will hide the console window.

### Supported Features

A subset of the packaging features is supported by the Ironman Software host.

* Script Bundling and Packaging
* Automatic Module Bundling and Packaging
* File Information (Version, Description, Company, etc)
* Custom Application Icon
* Windows PowerShell
* Hidden Console Window

Features that are not supported include:

* PowerShell 7
* Obfuscation
* Services
* Resources


# Package as Service

{% hint style="info" %}
Requires [PowerShell Pro Tools](https://ironmansoftware.com/poshtools)
{% endhint %}

Please read the previous section on Package.psd1 before proceeding.

The PowerShell Pro Tools package can create Windows services based on PS1 files. It has all the same options as other exectuables but requires a special entry point script. This script should be used at the `Root` value when using `Merge-Script` or the Entry Point when packaging through Visual Studio.

```
<#
	This function is called when the service is started. Once this function returns, 
	your service will be set to a Running state.
#>
function OnStart() {

}

<#
	This function is called when the service is stopped. Once this function returns,
	your service will be set to a Stopped state and the process will terminate.
#>
function OnStop() {

}

# Specifies whether this service can be stopped once started
$CanStop = $true
```

## OnStart Function

The `OnStart` function will be called when the service is started. You should not block the execution of this function. If you need to start a background process, consider using `Start-Job` . Once the function returns, the service will be listed as running in Service Control Manager.

You will have access to a `$Service` variable within the `OnStart` function that is the [ServiceBase ](https://docs.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicebase?view=netframework-4.8)instance for your service.

## OnStop Function

The `OnStop` function will be called when the Service Control Manager attempts to stop the service. You can do any clean up of resources for your service in this function. This would be a good place to stop any jobs using `Stop-Job`.

You will have access to a `$Service` variable within the `OnStop` function that is the [ServiceBase ](https://docs.microsoft.com/en-us/dotnet/api/system.serviceprocess.servicebase?view=netframework-4.8)instance for your service.

## CanStop Variable

You can set the `$CanStop` variable to either `$true` or `$false`. If set to `$false`, the service cannot be stopped by the Service Control Manager.

## Arguments

PowerShell services have access to both the process arguments and the service startup parameters. You can access the process arguments by referencing the `$ProcessArgs` variable. You can access the service startup parameters by accessing the `$ServiceArgs` variable.

## Installing a Service for Windows PowerShell

You can install your service by passing `--install` to the service's executable. Install will not start the service so use Start-Service to start your new service by the name you provided.

## Uninstall a Service for Windows PowerShell

To uninstall a service, use the `--uninstall` flag for your service's executable. It will also take care of stopping the service.

## Install a Service for PowerShell 7

You will need to use the `New-Service` cmdlet to install a service for PowerShell 7.

```
New-Service -Name 'PowerShellService' -BinaryPathName "C:\myService.exe"
```

## Uninstall a Service for PowerShell 7

You will need to use the `Remove-Service` cmdlet to uninstall a service built for PowerShell 7.

```
Remove-Service -name 'PowerShellService'
```


# Packaging on Linux

Packaging is supported on Linux systems. Packaged executables will contain the entire PowerShell and .NET runtime so destination systems will not need either of these installed.

## Prerequisites

You will need to install the following in order to package on Linux

* [.NET Core SDK 3.1 or later](https://docs.microsoft.com/en-us/dotnet/core/install/linux)
* [PowerShell 7 or later](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-linux?view=powershell-7.1)

Once you have them installed, you can setup your script for packaging.

## Configuration

You will need to create a [Package.psd1](/open-source-tools/powershell-module/packaging/package.psd1) file in order to package. Here is an example configuration that will package the `test.ps1` script and output it to the `desktop` of the mounted Windows drive in WSL2. You need to ensure that you set the .NET framework version to `netcoreapp31` and the platform to `linux-x64`.

```
@{
    Root = '/mnt/c/Users/adamr/desktop/test.ps1' # Root script to package. This is the main entry point for the package. 
    OutputPath = '/mnt/c/Users/adamr/desktop/out' # The output directory for the packaging process. 
    Package = @{
        Enabled = $true # Whether to package as an executable. 
        DotNetVersion = 'netcoreapp31'
        PackageType = 'Console' # The type of executable to generate. Valid values are Service or Console. 
        PowerShellArguments = '' # Sets the arguments for the PowerShell process that is hosted within the executable. You can use arguments like -NoExit, -ExecutionPolicy and -NoProfile.
        Platform = 'x64' # Sets the architecture of the executable. Can be either 'x86' or 'x64'
        PowerShellVersion = '7.0.3' # You can specify Windows PowerShell or PowerShell 7 or later versions version (e.g. 7.0.0)
        RuntimeIdentifier = 'linux-x64' # You can specify other runtimes like linux-x64 (See .NET Core runtime identifiers)
    }
    Bundle = @{
        Enabled = $true # Whether to bundle multiple PS1s into a single PS1. Always enabled when Package is enabled. 
        Modules = $true # Whether to bundle modules into the package
    }
}
```

By default, some core modules are included. Additional modules will also be included when enabling the Modules bundle.

## Running the Packager

You can run the packager by using the `Merge-Script` cmdlet of the PowerShell Pro Tools module. If you include the `-Verbose` flag, you will see output from the packaging process.

In this example, we have a script named `test.ps1` with the following content.

```
"Hello. I'm running on $($PSVersionTable.Platform)"
```

You can install the PowerShell Pro Tools module and then run merge script against the package.psd1 file we created earlier.

```
Install-Module PowerShellProTools
Merge-Script -ConfigFile ./package.psd1 -Verbose
VERBOSE: OutputPath is /mnt/c/Users/adamr/desktop/out
VERBOSE: Bundling /mnt/c/Users/adamr/desktop/test.ps1
VERBOSE: Packaging /tmp/test.ps1
VERBOSE: Creating temp directory: /tmp/259a5b5f8e164250af2fb04c10e1b829
VERBOSE: Packaging modules...
VERBOSE: Checking dotnet version.
VERBOSE: Checking dotnet version.
VERBOSE: 5.0.102

VERBOSE: 5.0.102

VERBOSE: Creating package project.
VERBOSE: Using .NET Framework version: netcoreapp31
VERBOSE:   Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 1.22 sec).

VERBOSE:   Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 1.22 sec).

VERBOSE: Packaging /tmp/test.ps1 -> /mnt/c/Users/adamr/desktop/out/test
VERBOSE: Microsoft (R) Build Engine version 16.8.3+39993bd9d for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 566 ms).
  test -> /tmp/259a5b5f8e164250af2fb04c10e1b829/bin/Debug/netcoreapp3.1/linux-x64/test.dll
  test -> /mnt/c/Users/adamr/desktop/out/

VERBOSE: Microsoft (R) Build Engine version 16.8.3+39993bd9d for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 566 ms).
  test -> /tmp/259a5b5f8e164250af2fb04c10e1b829/bin/Debug/netcoreapp3.1/linux-x64/test.dll
  test -> /mnt/c/Users/adamr/desktop/out/
```

After the packaging process is done, you can run your executable.

```
PS /mnt/c/Users/adamr> ./Desktop/out/test
Hello. I'm running on Unix
```


# Packaging on Mac OS X

Packaging is supported on Mac OSX systems. Packaged executables will contain the entire PowerShell and .NET runtime so destination systems will not need either of these installed.

## Prerequisites

You will need to install the following in order to package on Mac OS X.

* [.NET Core SDK 3.1 or later](https://docs.microsoft.com/en-us/dotnet/core/install/macos)
* [PowerShell 7 or later](https://docs.microsoft.com/en-us/powershell/scripting/install/installing-powershell-core-on-macos?view=powershell-7.1)

Once you have them installed, you can setup your script for packaging.

## Configuration

You will need to create a [Package.psd1](/open-source-tools/powershell-module/packaging/package.psd1) file in order to package. Here is an example configuration that will package the `test.ps1` script and output it to the `Downloads`You need to ensure that you set the .NET framework version to `netcoreapp31` and the platform to `osx-x64`.

```
@{
    Root = '/Users/adamdriscoll/Downloads/test.ps1' # Root script to package. This is the main entry point for the package. 
    OutputPath = '/Users/adamdriscoll/Downloads/out' # The output directory for the packaging process. 
    Package = @{
        Enabled = $true # Whether to package as an executable. 
        DotNetVersion = 'netcoreapp31'
        PackageType = 'Console' # The type of executable to generate. Valid values are Service or Console. 
        PowerShellArguments = '' # Sets the arguments for the PowerShell process that is hosted within the executable. You can use arguments like -NoExit, -ExecutionPolicy and -NoProfile.
        Platform = 'x64' # Sets the architecture of the executable. Can be either 'x86' or 'x64'
        PowerShellVersion = '7.0.3' # You can specify Windows PowerShell or PowerShell 7 or later versions version (e.g. 7.0.0)
        RuntimeIdentifier = 'osx-x64' # You can specify other runtimes like linux-x64 (See .NET Core runtime identifiers)
    }
    Bundle = @{
        Enabled = $true # Whether to bundle multiple PS1s into a single PS1. Always enabled when Package is enabled. 
        Modules = $true # Whether to bundle modules into the package
    }
}
```

By default, some core modules are included. Additional modules will also be included when enabling the Modules bundle.

## Running the Packager

You can run the packager by using the `Merge-Script` cmdlet of the PowerShell Pro Tools module. If you include the `-Verbose` flag, you will see output from the packaging process.

In this example, we have a script named `test.ps1` with the following content.

```
"Hello. I'm running on $($PSVersionTable.OS)"
```

You can install the PowerShell Pro Tools module and then run merge script against the package.psd1 file we created earlier.

```
Install-Module PowerShellProTools
Merge-Script -ConfigFile ./package.psd1 -Verbose
VERBOSE: OutputPath is /Users/adamdriscoll/Downloads/out
VERBOSE: Bundling /Users/adamdriscoll/Downloads/test.ps1
VERBOSE: Packaging /tmp/test.ps1
VERBOSE: Creating temp directory: /tmp/259a5b5f8e164250af2fb04c10e1b829
VERBOSE: Packaging modules...
VERBOSE: Checking dotnet version.
VERBOSE: Checking dotnet version.
VERBOSE: 5.0.102

VERBOSE: 5.0.102

VERBOSE: Creating package project.
VERBOSE: Using .NET Framework version: netcoreapp31
VERBOSE:   Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 1.22 sec).

VERBOSE:   Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 1.22 sec).

VERBOSE: Packaging /tmp/test.ps1 -> /Users/adamdriscoll/Downloads/out/test
VERBOSE: Microsoft (R) Build Engine version 16.8.3+39993bd9d for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 566 ms).
  test -> /tmp/259a5b5f8e164250af2fb04c10e1b829/bin/Debug/netcoreapp3.1/osx-x64/test.dll
  test -> /Users/adamdriscoll/Downloads/out

VERBOSE: Microsoft (R) Build Engine version 16.8.3+39993bd9d for .NET
Copyright (C) Microsoft Corporation. All rights reserved.

  Determining projects to restore...
  Restored /tmp/259a5b5f8e164250af2fb04c10e1b829/test.csproj (in 566 ms).
  test -> /tmp/259a5b5f8e164250af2fb04c10e1b829/bin/Debug/netcoreapp3.1/osx-x64/test.dll
  test -> /Users/adamdriscoll/Downloads/out
```

After the packaging process is done, you can run your executable.

![](/files/-MT89hQ079zorLibb5Y9)


# Continuous Integration

Setup packaging within a continuous integration environment.

## MSBuild and Azure DevOps

You will need to include the MSBuild targets and assemblies in your repository in order to packaging during the build process.

### Add Assets to Repository

The MSBuild assets are stored in the Visual Studio MSBuild directory when the extension is installed.

```
C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\PowerShell Tools for Visual Studio
```

Your path to this folder may different based on your version and edition of Visual Studio. [VSWhere ](https://github.com/microsoft/vswhere)can be used to determine this file location.

Place the files in a directory that you can link to during the build process. As an example, you can place them at the root of the repo.

<figure><img src="/files/7YAVvaQHFmAsEUT094ap" alt=""><figcaption><p>PowerShell Tools for VS Folder</p></figcaption></figure>

### Update PSSProj File

Next, update the PSSProj file to import the targets file for PowerShell Tools for Visual Studio. Include a condition so the build still works locally. This should be placed at the bottom of the file after the existing import. If you placed the assets in a different location, you will need to update your path. The below example uses the SolutionDir MSBuild property to locate the directory of the solution file.

```markup
<!-- Existing:  <Import Project="$(MSBuildExtensionsPath)\PowerShell Tools for Visual Studio\PowerShellTools.targets" Condition="Exists('$(MSBuildExtensionsPath)\PowerShell Tools for Visual Studio\PowerShellTools.targets')" /> -->
<Import Project="$(SolutionDir)\PowerShell Tools for Visual Studio\PowerShellTools.targets" Condition="Exists('$(SolutionDir)\PowerShell Tools for Visual Studio\PowerShellTools.targets')" />
```

### Setup the Azure DevOps Pipeline

Finally, setup the Azure DevOps pipeline to run the `VSBuild` target against the Solution Directory. This example uploads the compiled artifact after the build so it can be downloaded from the Azure DevOps portal.

```yaml
trigger:
- main

pool:
  vmImage: windows-latest

steps:
- task: VSBuild@1
  inputs:
    solution: '**\*.sln'
- publish: $(System.DefaultWorkingDirectory)/bin/Debug
  artifact: App
```

### Run the Build

Once the pipeline is complete, it should run automatically. If it hasn't you can run it manually and view the job output. The built binaries will be included under the related section.

<figure><img src="/files/0PjwakIVj9NzHxpmiZPk" alt=""><figcaption></figcaption></figure>


# Anti-Virus

Information about anti-virus and packaged applications.

PowerShell that is packaged as an executable can often trigger anti-virus software after packaged. The use of PowerShell within malicious executables has led to false positives being found in your own packages. This document contains information about anti-virus and PowerShell Pro Tools packaging.

{% hint style="info" %}
These tests were completed with PowerShell Pro Tools 2021.9.2.
{% endhint %}

## Default Package Detection

The packaging itself will not flag anti-virus for most providers. You will see that if you package an empty PS1 file and upload it to VirusTotal, most AV providers will not flag the executable.

{% embed url="<https://www.virustotal.com/gui/file/1a81a4317dc578cac298a22c3bd420b0b9c3bd19b2628adf5f2f10565dfaf899?nocache=1>" %}

![](/files/-MlVshA3VyjqSKopRM-M)

The package settings for this are the default ones provided by the Visual Studio Code extension.

```
@{
    Root = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package = @{
        Enabled = $true
        Obfuscate = $false
        HideConsoleWindow = $false
        DotNetVersion = 'v4.6.2'
        FileVersion = '1.0.0'
        FileDescription = ''
        ProductName = ''
        ProductVersion = ''
        Copyright = ''
        RequireElevation = $false
        ApplicationIconPath = ''
        PackageType = 'Console'
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
```

## Custom Script Results

As you can see when we start to include additional PowerShell script, you will begin to see certain AV providers begin to flag the results. This example uses the [Clean Windows 10 PowerShell](https://gist.github.com/halkyon/b73fb75e61c37b7ba5f65bb6f3979f00) script.

Additionally, we enabled require elevation in the package.psd1 file to ensure that administrator access is allowed to modify the Windows features.

```
@{
    Root       = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package    = @{
        Enabled             = $true
        Obfuscate           = $false
        HideConsoleWindow   = $false
        DotNetVersion       = 'v4.6.2'
        FileVersion         = '1.0.0'
        FileDescription     = ''
        ProductName         = ''
        ProductVersion      = ''
        Copyright           = ''
        RequireElevation    = $true
        ApplicationIconPath = ''
        PackageType         = 'Console'
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
```

This example yields another false positive.

{% embed url="<https://www.virustotal.com/gui/file/2f61c7f8bd7aaa2d5d3fed908b40b36f00fd6367a52e7c584641d33f6134ad8f?nocache=1>" %}

![](/files/-MlVtr6D6iaGtEyPoTjD)

## Obfuscation

{% hint style="info" %}
Obfuscation does not work with PowerShell 7
{% endhint %}

Obfuscation of the assembly greatly increases the probability of the executable being marked as malicious. We are using the same Windows 10 clean up script but have now enabled obfuscation.

The package.psd1 has been updated to turn on obfuscation.

```
@{
    Root       = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package    = @{
        Enabled             = $true
        Obfuscate           = $true
        HideConsoleWindow   = $true
        DotNetVersion       = 'v4.6.2'
        FileVersion         = '1.0.0'
        FileDescription     = ''
        ProductName         = ''
        ProductVersion      = ''
        Copyright           = ''
        RequireElevation    = $true
        ApplicationIconPath = ''
        PackageType         = 'Console'
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
        
```

As you can see, the number of AV vendors to flag the assembly has increased to 10.

{% embed url="<https://www.virustotal.com/gui/file/eaa796e33fc476ef8b1a168aab5f411fff58ec66610a54edfebd7e71f88e54fb?nocache=1>" %}

![](/files/-MlVuXoyJzXxTxK17_Do)

## Code Signing

While not directly supported within PowerShell Pro Tools, code signing can reduce the number of false positives. Using the same script and package settings as in the obfuscated example, we can use `signtool` to sign the resulting executable.

```
signtool sign /f some.pfx /sha1 MYSHA1 /p MYPASSWORD .\text.exe
```

This results in an executable that is only flagged by 2 vendors.

{% embed url="<https://www.virustotal.com/gui/file/ba87f47b2fd6da78b7dc254c0ab408d5c4d0f95f04a5d46a2af7c2fe52a3fdd6>" %}

![](/files/-MlVve8HyhD8kykmtgQE)

## Modules

Including modules also increases the probability of false positives. In this example, we are packaging the `ActiveDirectory` module and obfuscating the resulting binary. 12 vendors flag this executable.

{% embed url="<https://www.virustotal.com/gui/file/d7a9a87a358cb5aedd3326c55f6bdd42e9575055602192e7d66553012fb3f23e?nocache=1>" %}

![](/files/-MlVx2S5EvPh6w_OHDFk)

Again, signing the binary greatly reduces the number of false positives. Only 3 vendors now flag that same binary.

{% embed url="<https://www.virustotal.com/gui/file/b7df37aa077de8f38e73b9d1d4fc4bbf5908c12347fd16c5ca4b13408800c1a0?nocache=1>" %}

![](/files/-MlVxQBWYdpqUAtX-jzv)

## PowerShell 7

PowerShell 7 executables are packaged differently. Rather than relying on the local PowerShell DLLs, the PowerShell SDK is packaged with the binary. This results in a larger binary but it's completely self-contained.

I've changed the package settings to this. We are using the .NET Core 3.1 SDK and the 7.0.3 PowerShell SDK. This is again packaging the clean up script and the Active Directory module.

```
@{
    Root       = 'c:\Users\adamr\Desktop\Tests\test.ps1'
    OutputPath = 'c:\Users\adamr\Desktop\Tests\out'
    Package    = @{
        Enabled             = $true
        Obfuscate           = $false
        HideConsoleWindow   = $true
        DotNetVersion       = 'netcoreapp3.1'
        PowerShellVersion   = '7.0.3'
        FileVersion         = '1.0.0'
        FileDescription     = ''
        ProductName         = ''
        ProductVersion      = ''
        Copyright           = ''
        RequireElevation    = $false
        ApplicationIconPath = ''
        PackageType         = 'Console'
    }
    Bundle     = @{
        Enabled = $true
        Modules = $true
        # IgnoredModules = @()
    }
}
        
```

In this example, the package is flagged by 1 AV vendor.

{% embed url="<https://www.virustotal.com/gui/file/e9245e9f1672b913eda01a20e684119fdb30d4ea1c7132d0a5707e2b9f1ab470?nocache=1>" %}

![](/files/-MlVyW2rkrKEop4xqvQc)

## Cmdlet Usage

Certain cmdlets will also cause AV engines to flag. For example, if you use the `Set-MpPreference` cmdlet within your script, it may flag several vendors. This cmdlet is used for disabling Windows Defender.

```
Set-MpPreference -DisableRealtimeMonitoring $true
```

This script was flagged by 8 vendors.

{% embed url="<https://www.virustotal.com/gui/file/38d7bf811117c99652a4378661da7f307a98b2f946abe85867ca60fb9dc9423e?nocache=1>" %}

![](/files/-MlVzHysUMQLuZEOdIE7)

Obfuscating and code signing this same assembly, reduces that number to 2.

{% embed url="<https://www.virustotal.com/gui/file/17bb2ee29b1693ed62e030e13967ecfd996616bfda64909d7db473eb1f3ee641?nocache=1>" %}

![](/files/-MlVzoeZFcYdtQkWURbs)


# ConvertTo-PowerShell

{% hint style="warning" %}
This cmdlet is no longer supported but is still available as an [open-source project](https://github.com/ironmansoftware/code-conversion).
{% endhint %}


# Merge-Script

## SYNOPSIS

Packages, bundles and\or obfuscates scripts.

## SYNTAX

```
Merge-Script -Script <String> [-OutputPath <String>] [-Bundle] [-Package] [-Obfuscate]

Merge-Script -Config <Hashtable>

Merge-Script -ConfigFile <String>
```

## DESCRIPTION

Packages, bundles and\or obfuscates scripts. Packaging and bundling are not mutually exclusive. Obfuscation\
requires packaging.

## EXAMPLES

### Example 1

```
PS C:\> Merge-Script -Script .\MyScript.ps1 -Output .\ -Package
```

Packages MyScript.ps1 into MyScript.exe and then outputs it to .\\

### Example 2

```
PS C:\> Merge-Script -Script .\MyScript.ps1 -Output .\Bundle -Bundle
```

Bundles MyScript.ps1 and any scripts it dot sources into a single file and outputs it to .\Bundle.

### Example 3

```
PS C:\> Merge-Script -Script .\MyScript.ps1 -Output .\Bundle -Bundle -Package
```

Bundles MyScript.ps1 and any scripts it dot sources into a single file and then packages it into MyScript.exe and outputs it to .\Bundle.

### Example 4

```
PS C:\> Merge-Script -Script .\MyScript.ps1 -Output .\Bundle -Bundle -Package -Obfuscate
```

Bundles MyScript.ps1 and any scripts it dot sources into a single file and then packages it into MyScript.exe and outputs it to .\Bundle. The resulting executable will be obfuscated.

## PARAMETERS

### -Bundle

Bundles the script with dot sourced scripts found in the script.

```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases: 

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -Config

Config hashtable. More information found on about\_MergeScriptConfig.

```yaml
Type: Hashtable
Parameter Sets: (All)
Aliases: 

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -ConfigFile

Config file. More information found on about\_MergeScriptConfig.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -Obfuscate

Obfuscate the .NET executable and PowerShell script.

```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases: 

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -OutputPath

The output path for the resulting script or executable.\
This should be a directory.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -Package

Package the script as a .NET executable.

```yaml
Type: SwitchParameter
Parameter Sets: (All)
Aliases: 

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -Script

The script to package in an executable and optionally bundle with other scripts.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

## INPUTS

### None

## OUTPUTS

### System.Object

## NOTES

## RELATED LINKS


# about\_MergeScriptConfig

{% hint style="info" %}
Requires [PowerShell Pro Tools](https://ironmansoftware.com/poshtools)
{% endhint %}

## SHORT DESCRIPTION

About config hashtables for Merge-Script

## LONG DESCRIPTION

This about file contains information about using hashtables and PSD1 files to configure Merge-Script.

### Config File Schema

```
@{
        Root = 'c:\Users\Adam\Desktop\service.ps1' # Root script to package. This is the main entry point for the package. 
        OutputPath = 'c:\Users\Adam\Desktop\out' # The output directory for the packaging process. 
        Package = @{
            Enabled = $true # Whether to package as an executable. 
            Obfuscate = $false # Whether to obfuscate the resulting executable. 
            HideConsoleWindow = $false # Whether to hide the console window.  Only valid for console applications.
            DotNetVersion = 'v4.6.2' # The target .NET Framework version. You will need the .NET Developer Pack for this version installed on your machine.  
            FileVersion = '1.0.0' # The output file version
            FileDescription = '' # The output file description
            ProductName = '' # The output file product name
            ProductVersion = '' # The output file product version.
            Copyright = '' # The output file copyright
            RequireElevation = $false # Whether to require elevation when running the executable. Only valid for console applications. 
            ApplicationIconPath = '' # The path to the application icon to use for the executable. 
            PackageType = 'Console' # The type of executable to generate. Valid values are Service or Console. 
            ServiceName = "" # The name of the service if the package type is Service. 
            ServiceDisplayName = "" # The display name of the service if the package type is Service. 
            PowerShellCore = $true # Whether to bundle the PowerShell Core runtime within your executable. 
            HighDPISupport = $true  # Whether to enable high DPI support for WinForm applications
            PowerShellArguments = '' # Sets the arguments for the PowerShell process that is hosted within the executable. You can use arguments like -NoExit, -ExecutionPolicy and -NoProfile.
            Platform = 'x64' # Sets the architecture of the executable. Can be either 'x86' or 'x64'
        }
        Bundle = @{
            Enabled = $true # Whether to bundle multiple PS1s into a single PS1. Always enabled when Package is enabled. 
            Modules = $true # Whether to bundle modules into the package
        }
    }
    
```

### Using a config file

A config file can be used either from within a PowerShell script as a hashtable or imported from a PSD1 file containing the hashtable.

## EXAMPLES

It is not required to include all aspects of the config when using Merge-Script. The only required components are Root and OutputPath. Aside from that, anything that is not include will be considered false. This means that in the below example, packaging is disabled but bundling is not. The below operation will not bundle nested modules or required assemblies of any modules it is bundling.

```
Merge-Script -Config @{ 
    Root = ".\MyScript.ps1"
    OutputPath = ".\"
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```

### Create console application

Creates a PowerShell console based application that has an application icon and hides the console window.

```
@{
        Root = 'c:\Users\Adam\Desktop\form.ps1'
        OutputPath = 'c:\Users\Adam\Desktop\out'
        Package = @{
            Enabled = $true
            HideConsoleWindow = $true
            DotNetVersion = 'v4.6.2'
            ApplicationIconPath = 'C:\users\adam\desktop\icon.ico'
        }
    }
    
```

### Create a service

Creates a PowerShell service based on the service.ps1 file and outputs to the out directory on the desktop. It will use the .NET 4.6.2 Developer Pack. The service name will be PSService and the display name will be PowerShell Service.

```
@{
        Root = 'c:\Users\Adam\Desktop\service.ps1'
        OutputPath = 'c:\Users\Adam\Desktop\out'
        Package = @{
            Enabled = $true
            DotNetVersion = 'v4.6.2'
            FileVersion = '1.0.0'
            FileDescription = ''
            ProductName = ''
            ProductVersion = ''
            Copyright = ''
            PackageType = 'Service'
            ServiceName = "PSService"
            ServiceDisplayName = "PowerShell Service"
        }
    }
    
```

After building a service, you can install the service with the `--install` parameter of your service's executable. To uninstall a service, use the `--uninstall` parameter.

### Bundle PowerShell Core Engine with your Script

Creates an executable that contains the PowerShell Core engine. This executable does not require the target machine have PowerShell Core or .NET Core installed. The size of the executable will be considerably larger than a typical `Merge-Script` executable.

```
@{
    Root = 'c:\Users\Adam\Desktop\script.ps1'
    OutputPath = 'c:\Users\Adam\Desktop\out'
    Package = @{
        Enabled = $true
        PowerShellVersion = '7.2.0'
        DotNetVersion = 'net6.0'
    }
    Bundle = @{
        Enabled = $true
        Modules = $true
    }
}
```


# Show-WinFormDesigner

## SYNOPSIS

Shows the Windows Form designer.

## SYNTAX

```
Show-WinFormDesigner -DesignerFilePath <String> -CodeFilePath <String> [-EditorPipeName <String>] [-Theme <String>]
```

## DESCRIPTION

Shows the Windows Form designer.

## EXAMPLES

### Example 1

```
PS C:\> Show-WinFormDesigner -DesignerFilePath .\form.designer.ps1 -CodeFilePath .\form.ps1
```

Opens the Windows Form designer and loads the form.designer.ps1 form.

## PARAMETERS

### -DesignerFilePath

The path to the designer PS1. This file should not be edited by hand.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -CodeFilePath

The path to the code PS1 that will contain the event handlers for the form designer.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: True
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -EditorPipeName

A named pipe to connect to the allow interaction with an editor. This is used by the VS Code extension.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```

### -Theme

The VS Code theme file to use. This should be the full path to a VS Code theme file.

```yaml
Type: String
Parameter Sets: (All)
Aliases: 

Required: False
Position: Named
Default value: None
Accept pipeline input: False
Accept wildcard characters: False
```


# PSMSI

PSMSI is a PowerShell module for creating Windows MSI installers from PowerShell scripts. It builds WiX XML from cmdlets such as `New-Installer`, `New-InstallerDirectory`, and `New-InstallerFile`, then runs the WiX Toolset v3 compiler and linker that ship with the module.

Use PSMSI when you want a repeatable installer build script for files, folders, shortcuts, simple installer UI customization, and PowerShell custom actions.

## Features

* Create MSI packages from PowerShell build scripts.
* Install files into predefined Windows Installer folders such as `LocalAppDataFolder`, `ProgramFilesFolder`, `ProgramMenuFolder`, and `DesktopFolder`.
* Build per-user installers or per-machine installers that require elevation.
* Create nested application folders and allow one folder to be configurable during install.
* Add Add/Remove Programs metadata, icons, help links, and about links.
* Create file and folder shortcuts with arguments, working directories, icons, and window state.
* Run PowerShell scripts during install or uninstall with custom actions.
* Add a basic installer UI with a EULA, completion text, and custom images.

## Quick Example

```powershell
$OutputDirectory = Join-Path $PSScriptRoot "output"
$ConfigPath = Join-Path $PSScriptRoot "appsettings.json"

New-Installer -ProductName "My First Product" `
    -Manufacturer "Example Company" `
    -UpgradeCode "1a73a1be-50e6-4e92-af03-586f4a9d9e82" `
    -Version "1.0.0" `
    -OutputDirectory $OutputDirectory `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "LocalAppDataFolder" -Content {
            New-InstallerDirectory -DirectoryName "My First Product" -Content {
                New-InstallerFile -Source $ConfigPath
            }
        }
    }
```

The output directory contains the generated `.wxs`, `.wxsobj`, and `.msi` files. The `.msi` file is the installer you distribute.

## Feature Guides

* [Getting Started](/open-source-tools/psmsi/getting-started)
* [Installer Identity](/open-source-tools/psmsi/installer-identity)
* [Directories and Files](/open-source-tools/psmsi/directories-and-files)
* [Per-User and Per-Machine Installs](/open-source-tools/psmsi/per-user-and-per-machine-installs)
* [Shortcuts](/open-source-tools/psmsi/shortcuts)
* [Custom Actions](/open-source-tools/psmsi/custom-actions)
* [Installer UI](/open-source-tools/psmsi/installer-ui)
* [Command Reference](/open-source-tools/psmsi/command-reference)
* [Troubleshooting](/open-source-tools/psmsi/troubleshooting)

## More Information

* [Changelog](https://github.com/ironmansoftware/psmsi/releases)
* [Installation](/open-source-tools/psmsi/installation)
* [System Requirements](/open-source-tools/psmsi/system-requirements)
* [GitHub](https://github.com/ironmansoftware/psmsi)
* [PowerShell Gallery](https://www.powershellgallery.com/packages/PSMSI)


# Installation

PSMSI is distributed through the PowerShell Gallery.

```powershell
Install-Module PSMSI
```

To install without administrator permissions, use the current-user scope.

```powershell
Install-Module PSMSI -Scope CurrentUser
```

## Update

```powershell
Update-Module PSMSI
```

## Verify Installation

```powershell
Import-Module PSMSI
Get-Command -Module PSMSI
```


# System Requirements

## PowerShell

* Windows PowerShell 5.1 or PowerShell 7.
* PowerShellGet or PSResourceGet configured for the PowerShell Gallery.

## Operating System

* Windows is required to build and validate MSI packages.

## Installer Engine

PSMSI includes WiX Toolset v3 binaries and uses them to compile generated WiX XML into MSI packages. You do not need to install WiX separately for the standard module workflow.

## Build Inputs

* Files referenced by `New-InstallerFile` must exist at build time.
* Per-machine installers and installers targeting protected locations require elevation when installed.


# Getting Started

Create a build script, place the files you want to install next to the script, and run the script from PowerShell.

```powershell
$OutputDirectory = Join-Path $PSScriptRoot "output"
$ConfigPath = Join-Path $PSScriptRoot "appsettings.json"

New-Installer -ProductName "My First Product" `
    -Manufacturer "Example Company" `
    -UpgradeCode "1a73a1be-50e6-4e92-af03-586f4a9d9e82" `
    -Version "1.0.0" `
    -OutputDirectory $OutputDirectory `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "LocalAppDataFolder" -Content {
            New-InstallerDirectory -DirectoryName "My First Product" -Content {
                New-InstallerFile -Source $ConfigPath
            }
        }
    }
```

The output directory contains the generated `.wxs`, `.wxsobj`, and `.msi` files. The `.msi` file is the installer you distribute. The other files are WiX build artifacts that are useful when troubleshooting installer generation.

Use `-Verbose` on `New-Installer` to see the WiX compiler and linker output while the installer is built.


# Installer Identity

`New-Installer` defines the MSI package and runs the WiX build. These parameters are the ones you will usually set first.

* `ProductName` is required and appears in the installer and Add/Remove Programs.
* `UpgradeCode` is required. Generate it once for a product and keep it the same for every release of that product.
* `Version` defaults to `1.0`. Increase it when shipping upgrades. Windows Installer blocks downgrades.
* `ProductId` defaults to `*`, which lets Windows Installer generate a new product code for the package.
* `Manufacturer` defaults to `Ironman Software, LLC`; set it to your organization for published installers.
* `OutputDirectory` is required and receives the MSI and WiX build artifacts.
* `Platform` defaults to `x86` and accepts `x86`, `x64`, `ia64`, `arm`, `intel`, or `intel64`.
* `Description`, `HelpLink`, `AboutLink`, and `AddRemoveProgramsIcon` add installer metadata.

Generate an upgrade code once and store it in your build script or build configuration.

```powershell
New-Guid
```

Do not call `New-Guid` inside the installer build for `UpgradeCode` after your first release. Changing the upgrade code makes Windows Installer treat the MSI as a different product.


# Directories and Files

Every installer content tree should start with a predefined Windows Installer directory. Use `New-InstallerDirectory -PredefinedDirectoryName` for the root folder, then nest custom directories and files inside it.

```powershell
New-Installer -ProductName "My App" `
    -Manufacturer "Example Company" `
    -UpgradeCode "66ad7f2c-e176-4a91-b73b-5dced490ec67" `
    -Version "1.0.0" `
    -OutputDirectory ".\output" `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "ProgramFilesFolder" -Content {
            New-InstallerDirectory -DirectoryName "My App" -Id "INSTALLFOLDER" -Content {
                New-InstallerFile -Source ".\bin\MyApp.exe" -Id "MyAppExe"
                New-InstallerFile -Source ".\bin\MyApp.dll"
                New-InstallerFile -Source ".\README.txt"
            }
        }
    } `
    -RequiresElevation
```

Use `-Id` when another installer item needs to reference the directory or file. If you do not provide an ID, PSMSI generates one.

`New-InstallerFile` accepts pipeline input, so you can add a group of files to the current directory.

```powershell
Get-ChildItem ".\assets\*.png" | New-InstallerFile
```

Use `-Configurable` on one custom directory when the user should be able to choose the install location.

```powershell
New-InstallerDirectory -PredefinedDirectoryName "LocalAppDataFolder" -Content {
    New-InstallerDirectory -DirectoryName "My App" -Id "INSTALLFOLDER" -Configurable -Content {
        New-InstallerFile -Source ".\MyApp.exe" -Id "MyAppExe"
    }
}
```

Only one configurable directory is supported.


# Per-User and Per-Machine Installs

By default, PSMSI creates a per-user installer. A common per-user target is `LocalAppDataFolder`.

```powershell
New-InstallerDirectory -PredefinedDirectoryName "LocalAppDataFolder" -Content {
    New-InstallerDirectory -DirectoryName "My App" -Content {
        New-InstallerFile -Source ".\MyApp.exe"
    }
}
```

For an all-users installer, install under a machine-wide folder such as `ProgramFilesFolder` and add `-RequiresElevation` to `New-Installer`.

```powershell
New-Installer -ProductName "My App" `
    -UpgradeCode "66ad7f2c-e176-4a91-b73b-5dced490ec67" `
    -OutputDirectory ".\output" `
    -RequiresElevation `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "ProgramFilesFolder" -Content {
            New-InstallerDirectory -DirectoryName "My App" -Content {
                New-InstallerFile -Source ".\MyApp.exe"
            }
        }
    }
```

The person installing a per-machine MSI needs administrative permissions.


# Shortcuts

Create shortcuts with `New-InstallerShortcut` inside the directory where the shortcut should be installed. Reference an installed file by the file ID.

```powershell
New-Installer -ProductName "My App" `
    -Manufacturer "Example Company" `
    -UpgradeCode "66ad7f2c-e176-4a91-b73b-5dced490ec67" `
    -OutputDirectory ".\output" `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "LocalAppDataFolder" -Content {
            New-InstallerDirectory -DirectoryName "My App" -Id "INSTALLFOLDER" -Content {
                New-InstallerFile -Source ".\MyApp.exe" -Id "MyAppExe"
            }
        }

        New-InstallerDirectory -PredefinedDirectoryName "DesktopFolder" -Content {
            New-InstallerShortcut -Name "My App" `
                -FileId "MyAppExe" `
                -Description "Launch My App" `
                -IconPath ".\app.ico" `
                -WorkingDirectoryId "INSTALLFOLDER" `
                -Arguments "--profile default" `
                -Show "normal"
        }
    }
```

`New-InstallerShortcut` can also target a directory with `-DirectoryId`. `-Show` accepts `normal`, `minimized`, or `maximized`.


# Custom Actions

Custom actions run installed PowerShell scripts during install or uninstall. Add the script as an installer file, give it an ID, and pass one or more `New-InstallerCustomAction` results to the `New-Installer -CustomAction` parameter.

```powershell
$CustomActions = @(
    New-InstallerCustomAction -FileId "ConfigureScript" `
        -RunOnInstall `
        -CheckReturnValue `
        -Arguments "-NoProfile -ExecutionPolicy Bypass" `
        -ScriptArguments "-Mode Install"
)

New-Installer -ProductName "My App" `
    -UpgradeCode "66ad7f2c-e176-4a91-b73b-5dced490ec67" `
    -OutputDirectory ".\output" `
    -CustomAction $CustomActions `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "ProgramFilesFolder" -Content {
            New-InstallerDirectory -DirectoryName "My App" -Content {
                New-InstallerFile -Source ".\MyApp.exe" -Id "MyAppExe"
                New-InstallerFile -Source ".\Configure.ps1" -Id "ConfigureScript"
            }
        }
    } `
    -RequiresElevation
```

Use `-RunOnInstall` for install-time scripts and `-RunOnUninstall` for uninstall-time scripts. `-Arguments` are passed to `powershell.exe`; `-ScriptArguments` are passed to your script. `-CheckReturnValue` causes the install to fail if the PowerShell process returns a non-zero exit code.

Custom actions are passed to `New-Installer` with `-CustomAction`; do not place `New-InstallerCustomAction` inside the `-Content` script block.


# Installer UI

Use `New-InstallerUserInterface` to create UI options, then pass them to `New-Installer -UserInterface`.

```powershell
$UserInterface = New-InstallerUserInterface `
    -Eula ".\eula.rtf" `
    -TopBanner ".\banner.png" `
    -WelcomeAndCompletionBackground ".\welcome.png" `
    -ExitDialogText "My App has been installed."

New-Installer -ProductName "My App" `
    -UpgradeCode "66ad7f2c-e176-4a91-b73b-5dced490ec67" `
    -OutputDirectory ".\output" `
    -UserInterface $UserInterface `
    -Content {
        New-InstallerDirectory -PredefinedDirectoryName "LocalAppDataFolder" -Content {
            New-InstallerDirectory -DirectoryName "My App" -Content {
                New-InstallerFile -Source ".\MyApp.exe"
            }
        }
    }
```

Recommended image sizes are:

* `TopBanner`: 493 by 58 pixels.
* `WelcomeAndCompletionBackground`: 493 by 312 pixels.
* `ExclamationIcon`: 32 by 32 pixels.
* `InformationIcon`: 32 by 32 pixels.
* `NewIcon`: 16 by 16 pixels.
* `UpIcon`: 16 by 16 pixels.

PSMSI warns when a referenced UI file is missing or when an image does not match the recommended size.


# Command Reference

| Command                      | Purpose                                                                                     |
| ---------------------------- | ------------------------------------------------------------------------------------------- |
| `New-Installer`              | Creates the MSI and writes the `.wxs`, `.wxsobj`, and `.msi` files to the output directory. |
| `New-InstallerDirectory`     | Adds a predefined or custom directory to the installer content tree.                        |
| `New-InstallerFile`          | Adds a file to the current installer directory.                                             |
| `New-InstallerShortcut`      | Adds a shortcut to a file or directory.                                                     |
| `New-InstallerCustomAction`  | Defines a PowerShell custom action for install or uninstall.                                |
| `New-InstallerUserInterface` | Defines EULA, image, icon, and completion text options for the installer UI.                |


# Troubleshooting

* Use `-Verbose` on `New-Installer` to see WiX compiler and linker output.
* Verify every file referenced by `New-InstallerFile`, `AddRemoveProgramsIcon`, shortcut icons, and UI parameters exists before building.
* Keep file and directory IDs unique when you specify them manually.
* Use a stable `UpgradeCode` and increase `Version` for upgrade releases.
* Use `-RequiresElevation` for installers that write to protected machine locations such as Program Files.
* Inspect the generated `.wxs` file when WiX reports validation or linking errors.


# PSEdit

PSEdit is a terminal-based editor for PowerShell and common text-based configuration files. It runs from PowerShell and provides a focused editing experience without leaving the terminal.

Use PSEdit when you need a lightweight editor for scripts, JSON, YAML, XML, Markdown, or plain text files in a shell-first workflow.

## Features

* PowerShell IntelliSense.
* Syntax highlighting for PowerShell, JSON, YAML, XML, Markdown, and plain text.
* PowerShell script execution.
* Error and syntax error views.
* Format on save for supported file types.
* Custom themes through `psedit.json`.

## Quick Examples

Start the editor.

```powershell
Show-PSEditor
```

Open a file.

```powershell
Show-PSEditor -Path .\build.ps1
```

Use the alias.

```powershell
psedit .\settings.json
```

Run the current PowerShell script with `F5`, run a selection with `F8`, or run and exit with `Ctrl+Shift+F5`.

## Formatting PowerShell

PowerShell formatting requires PSScriptAnalyzer.

```powershell
Install-Module PSScriptAnalyzer
```

## More Information

* [Changelog](https://github.com/ironmansoftware/psedit/releases)
* [Installation](/open-source-tools/psedit/installation)
* [System Requirements](/open-source-tools/psedit/system-requirements)
* [GitHub](https://github.com/ironmansoftware/psedit)
* [PowerShell Gallery](https://www.powershellgallery.com/packages/psedit)


# Installation

PSEdit is distributed through the PowerShell Gallery.

```powershell
Install-Module psedit
```

To install without administrator permissions, use the current-user scope.

```powershell
Install-Module psedit -Scope CurrentUser
```

## Optional Formatting Dependency

Install PSScriptAnalyzer to enable PowerShell formatting.

```powershell
Install-Module PSScriptAnalyzer
```

## Verify Installation

```powershell
Import-Module psedit
Get-Command Show-PSEditor
Get-Alias psedit
```


# System Requirements

## PowerShell

* Windows PowerShell 5.1 or PowerShell 7.
* PowerShellGet or PSResourceGet configured for the PowerShell Gallery.

## Terminal

PSEdit runs in a terminal host. Use a terminal that supports interactive console applications.

## Optional Dependencies

* PSScriptAnalyzer is required for PowerShell formatting.

## Supported File Types

* PowerShell
* JSON
* YAML
* XML
* Markdown
* Plain text


# PSCommander

Command your desktop with PSCommander.

PSCommander is a Windows desktop automation module. It lets you define PowerShell script blocks for Windows integration points such as hot keys, tray menus, schedules, Explorer context menus, file associations, custom protocol handlers, and desktop widgets.

Use PSCommander when you want persistent desktop automation that is configured with PowerShell.

## Features

* [CRON schedules](/open-source-tools/pscommander/feature-reference/cron-schedules).
* [Desktop shortcuts](/open-source-tools/pscommander/feature-reference/desktop-shortcuts).
* [Desktop widgets](/open-source-tools/pscommander/feature-reference/desktop-widgets).
* [Data sources for widgets](/open-source-tools/pscommander/feature-reference/data-sources).
* [Windows and PSCommander events](/open-source-tools/pscommander/feature-reference/events).
* [Explorer context menus](/open-source-tools/pscommander/feature-reference/explorer-context-menus).
* [File associations](/open-source-tools/pscommander/feature-reference/file-associations).
* [Custom protocol handlers](/open-source-tools/pscommander/feature-reference/custom-protocol-handlers).
* [Global hot keys](/open-source-tools/pscommander/feature-reference/global-hot-keys).
* [Tray icon and menus](/open-source-tools/pscommander/feature-reference/tray-icon-and-menu).

## Quick Examples

Install the module and register PSCommander to run at logon.

```powershell
Install-Module PSCommander
Install-Commander
```

Create and open the user configuration file.

```powershell
Start-Commander
```

Add a hot key to `Documents\PSCommander\config.ps1`.

```powershell
New-CommanderHotKey -Key 'T' -ModifierKey 'Ctrl' -Action {
    Start-Process notepad
}
```

Add a tray menu item.

```powershell
New-CommanderToolbarIcon -MenuItem @(
    New-CommanderMenuItem -Text 'Open Notepad' -Action {
        Start-Process notepad
    }
)
```

## Configuration

PSCommander loads its configuration from `Documents\PSCommander\config.ps1`. Add PSCommander commands to that file. Changes to the file are reloaded while PSCommander is running.

See [Configuration](/open-source-tools/pscommander/configuration) for more information.

## More Information

* [Changelog](https://github.com/ironmansoftware/pscommander/releases)
* [Installation](/open-source-tools/pscommander/installation)
* [Uninstallation](/open-source-tools/pscommander/uninstallation)
* [System Requirements](/open-source-tools/pscommander/system-requirements)
* [Configuration](/open-source-tools/pscommander/configuration)
* [Feature Reference](/open-source-tools/pscommander/feature-reference)
* [GitHub](https://github.com/ironmansoftware/pscommander)
* [PowerShell Gallery](https://www.powershellgallery.com/packages/PSCommander)


# Installation

PSCommander is distributed through the PowerShell Gallery.

```powershell
Install-Module PSCommander
```

To install without administrator permissions, use the current-user scope.

```powershell
Install-Module PSCommander -Scope CurrentUser
```

## Start PSCommander

Create the starter configuration and launch PSCommander.

```powershell
Start-Commander
```

## Run at Logon

Register PSCommander to run when the user logs on.

```powershell
Install-Commander
```

Remove the logon registration with `Uninstall-Commander`.

```powershell
Uninstall-Commander
```


# Uninstallation

To completely remove PSCommander, first clear its configuration while PSCommander is still running. This lets PSCommander unregister the shortcuts, file associations, Explorer context-menu entries, and custom protocols that it manages.

Back up the configuration, replace it with an empty configuration, and wait a few seconds for PSCommander to reload it.

```powershell
$configPath = Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'PSCommander\config.ps1'
Copy-Item -LiteralPath $configPath -Destination "$configPath.bak" -Force
Set-Content -LiteralPath $configPath -Value '# PSCommander configuration removed'
Start-Sleep -Seconds 2
```

If PSCommander is not running, start it and wait for it to initialize before clearing the configuration.

```powershell
Start-Commander
```

Disable its logon startup entry, stop the process, and remove every installed version of the module.

```powershell
Uninstall-Commander -ErrorAction SilentlyContinue
Stop-Commander -ErrorAction SilentlyContinue
Uninstall-Module PSCommander -AllVersions
```

Finally, remove the saved configuration and local database. This permanently deletes the configuration backup and all PSCommander settings and registration data.

```powershell
Remove-Item -LiteralPath (Join-Path ([Environment]::GetFolderPath('MyDocuments')) 'PSCommander') -Recurse -Force
Remove-Item -LiteralPath (Join-Path ([Environment]::GetFolderPath('ApplicationData')) 'PSCommander') -Recurse -Force
```


# System Requirements

## Operating System

* Windows.

PSCommander uses Windows desktop integration points, WPF, Windows Forms, Explorer context menu registration, tray icons, file associations, custom protocol handlers, and global hot keys.

## PowerShell

* Windows PowerShell 5.1 or PowerShell 7.
* PowerShellGet or PSResourceGet configured for the PowerShell Gallery.

## Runtime

* .NET 6 Windows Desktop runtime support is required by the PSCommander desktop application.

## Permissions

Some features modify user-level Windows integration points. Per-machine changes or protected paths may require elevation.


# Configuration

PSCommander is configured using a single PowerShell script file. This file is stored in `Documents\PSCommander\config.ps1`.

To create the file with a starter configuration and open it in the editor, run `Start-Commander`.

```powershell
Start-Commander
```

PSCommander uses this configuration file to load settings. Changes to the file will cause PSCommander to reconfigure itself while it is running.

Add PSCommander configuration commands to this file, such as schedules, hot keys, tray menus, desktop widgets, and Explorer context menus.


# Feature Reference

Feature reference for PSCommander configuration commands.

PSCommander allows you to configure Windows desktop integration points and execute PowerShell script blocks when events happen on your desktop. Add these commands to `Documents\PSCommander\config.ps1`.

The PSCommander configuration commands only work inside PSCommander. Create and open the configuration file with `Start-Commander`.

```powershell
Start-Commander
```

## Features

* [CRON Schedules](/open-source-tools/pscommander/feature-reference/cron-schedules)
* [Custom Protocol Handlers](/open-source-tools/pscommander/feature-reference/custom-protocol-handlers)
* [Data Sources](/open-source-tools/pscommander/feature-reference/data-sources)
* [Desktop Widgets](/open-source-tools/pscommander/feature-reference/desktop-widgets)
* [Desktop Shortcuts](/open-source-tools/pscommander/feature-reference/desktop-shortcuts)
* [Events](/open-source-tools/pscommander/feature-reference/events)
* [Explorer Context Menus](/open-source-tools/pscommander/feature-reference/explorer-context-menus)
* [File Associations](/open-source-tools/pscommander/feature-reference/file-associations)
* [Global Hot Keys](/open-source-tools/pscommander/feature-reference/global-hot-keys)
* [Tray Icon and Menu](/open-source-tools/pscommander/feature-reference/tray-icon-and-menu)

{% embed url="<https://youtu.be/Pzjr88j8yL4>" %}


# CRON Schedules

PSCommander allows you to run script blocks based on CRON schedules. PSCommander uses a single runspace, so long running scripts are not recommended.

To create a CRON schedule, use `New-CommanderSchedule` within `config.ps1`. This configuration opens Notepad every minute.

You can use a site like [crontab guru](https://crontab.guru/) to define schedules.

```powershell
New-CommanderSchedule -CronExpression "* * * * *" -Action {
     Start-Process Notepad
}
```


# Custom Protocol Handlers

A custom protocol handler can cause a PSCommander action to be taken from a website or other invocation of the custom protocol.

To define a custom protocol, use `New-CommanderCustomProtocol`. The `$args[0]` parameter contains the URL that was clicked.

```powershell
New-CommanderCustomProtocol -Protocol myApp -Action {
     if ($args[0] -eq 'notepad') { Start-Process notepad }
     if ($args[0] -eq 'calc') { Start-Process calc }
     if ($args[0] -eq 'wordpad') { Start-Process wordpad }
}
```

To use the custom protocol, include regular links in websites. The links invoke PSCommander remotely.

```html
<html>
  <body>
    <a href="myApp://notepad">Start Notepad</a>
  </body>
</html>
```

![](/files/-MXhYUvWhquu9z2m5mGI)


# Data Sources

Data sources allow you to load data a single time and use it with multiple desktop widgets. This provides better performance than loading the data in each widget. It also provides data binding support for WPF components.

To register a data source, use the `Register-CommanderDataSource` cmdlet. The following data source loads computer performance information every 5 seconds.

```powershell
Register-CommanderDataSource -Name 'ComputerInfo' -LoadData {
   $Stats = Get-NetAdapterStatistics
   $NetworkDown = 0
   $Stats.ReceivedBytes | Foreach-Object { $NetworkDown += $_ }

   $NetworkUp = 0
   $Stats.SentBytes | Foreach-Object { $NetworkUp += $_ }

   @{
       CPU = Get-CimInstance Win32_Processor | Measure-Object -Property LoadPercentage -Average | Select-Object -Expand Average
       Memory = (Get-Counter '\Memory\Available MBytes').CounterSamples.CookedValue
       NetworkUp = $NetworkUp / 1KB
       NetworkDown = $NetworkDown / 1KB
   }
} -RefreshInterval 5
```

To use this data source with a desktop widget, use the `-DataSource` parameter for a custom widget. Every time the data source is updated, the WPF custom widget is notified and loads UI components.

This example creates a small, grey bar that formats and displays the computer information.

```powershell
New-CommanderDesktop -Widget @(
   New-CommanderDesktopWidget -LoadWidget {
       [xml]$Form = Get-Content C:\Users\adamr\Desktop\test.xaml -Raw
       $XMLReader = (New-Object System.Xml.XmlNodeReader $Form)
       [Windows.Markup.XamlReader]::Load($XMLReader)
   } -Height 200 -Width 1400 -Top 20 -Left 100 -DataSource 'ComputerInfo'
}
```

The XAML can take advantage of binding to the hashtable created by the data source.

```xml
<Window
    xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
    WindowStyle="None"
    ResizeMode="NoResize"
    Background="Transparent"
    Height="200"
    Width="1900"
>
    <Grid Margin="10">
        <Border BorderBrush="#333333" BorderThickness="1" Background="#333333" Grid.Column="1"
                CornerRadius="10" VerticalAlignment="Center"
                HorizontalAlignment="Stretch">
            <Grid Margin="10">

                <Grid.ColumnDefinitions>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="200"/>
                    <ColumnDefinition Width="300"/>
                    <ColumnDefinition Width="300"/>
                </Grid.ColumnDefinitions>

                <Grid.RowDefinitions>
                    <RowDefinition />
                    <RowDefinition Height="Auto" />
                </Grid.RowDefinitions>
                <TextBlock DataContext="{Binding CurrentValue}" Text="{Binding CPU, StringFormat=CPU: {0}%}" TextWrapping="Wrap" Margin="5" Foreground="#28bf37" FontFamily="Consolas" Grid.Column="0"/>
                <TextBlock DataContext="{Binding CurrentValue}" Text="{Binding Memory, StringFormat=Available Memory: {0:N0} MB}" TextWrapping="Wrap" Margin="5" Foreground="#28bf37" FontFamily="Consolas" Grid.Column="1"/>
                <TextBlock DataContext="{Binding CurrentValue}" Text="{Binding NetworkUp, StringFormat=Network Up: {0:N0} KB\s}" TextWrapping="Wrap" Margin="5" Foreground="#28bf37" FontFamily="Consolas" Grid.Column="2"/>
                <TextBlock DataContext="{Binding CurrentValue}" Text="{Binding NetworkDown, StringFormat=Network Down: {0:N0} KB\s}" TextWrapping="Wrap" Margin="5" Foreground="#28bf37" FontFamily="Consolas" Grid.Column="3"/>
            </Grid>
        </Border>
    </Grid>
</Window>
```

This produces a widget that looks like this.

![](/files/-MYH2Z8UjNeeTOVLrwQC)


# Desktop Widgets

PSCommander provides a desktop widget system that allows you to place text, images, web pages, custom WPF windows and measurement counters on the desktop. It is a similar experience to SysInternals bginfo and Rainmeter.

All widgets are created using the `New-CommanderDesktopWidget` cmdlet in combination with the `New-CommanderDesktop` or `Set-CommanderDesktop` cmdlets.

![](/files/-MXmcf043MD9wMBdJTcK)

## Widget Types

* [Text Widget](/open-source-tools/pscommander/feature-reference/desktop-widgets/text-widget)
* [Image Widget](/open-source-tools/pscommander/feature-reference/desktop-widgets/image-widget)
* [Webpage Widget](/open-source-tools/pscommander/feature-reference/desktop-widgets/webpage-widget)
* [Custom WPF Widget](/open-source-tools/pscommander/feature-reference/desktop-widgets/custom-wpf-widget)
* [Measurement Widget](/open-source-tools/pscommander/feature-reference/desktop-widgets/measurement-widget)


# Text Widget

The following example creates a text widget with some computer information.

```powershell
$CI = Get-ComputerInfo

$ComputerInfo = @"
    Number of Processes: $($CI.OsNumberOfProcesses)
    Number of Users: $($CI.OsNumberOfUsers)
    User Name: $($CI.CsUserName)
    System Family: $($CI.CsSystemFamily)
"@

New-CommanderDesktop -Widget @(
   New-CommanderDesktopWidget -Text $ComputerInfo -Height 300 -Width 1000 -FontSize 30 -Top 500 -Left 500 -FontColor 'Black'
)
```


# Image Widget

The following example creates an image widget on the desktop.

```powershell
New-CommanderDesktop -Widget @(
   New-CommanderDesktopWidget -Image 'C:\src\blog\content\images\news.png' -Height 200 -Width 200 -Top 200
)
```


# Webpage Widget

The following example creates a webpage widget on the desktop.

```powershell
New-CommanderDesktop -Widget @(
   New-CommanderDesktopWidget -Url 'https://www.google.com' -Height 500 -Width 500 -Top 400
)
```


# Custom WPF Widget

The following example creates a custom WPF widget on the desktop.

```powershell
New-CommanderDesktop -Widget @(
   New-CommanderDesktopWidget -LoadWidget {
       [xml]$Form = "<Window xmlns=`"http://schemas.microsoft.com/winfx/2006/xaml/presentation`"><Grid><Label Content=`"Hello, World`" Height=`"30`" Width=`"110`"/></Grid></Window>"
       $XMLReader = (New-Object System.Xml.XmlNodeReader $Form)
       [Windows.Markup.XamlReader]::Load($XMLReader)
   } -Height 200 -Width 200 -Top 200 -Left 200
)
```


# Measurement Widget

The following creates a measurement widget on the desktop.

```powershell
New-CommanderDesktop -Widget @(
   New-CommanderDesktopWidget -LoadMeasurement {Get-Random} -MeasurementTitle 'Random' -MeasurementSubtitle 'A random number' -MeasurementUnit 'units' -Height 300 -Width 500 -Left 600 -Top 200 -MeasurementFrequency 1 -MeasurementDescription "Nice" -MeasurementTheme 'DarkBlue'
)
```


# Desktop Shortcuts

PSCommander can create desktop shortcuts that will execute PowerShell when clicked. Desktop shortcuts require that PSCommander is running, so you may want to use `Install-Commander` to ensure that it has been started before a user clicks a shortcut.

You can configure the text, description and icon for the shortcut. This example creates a desktop shortcut that opens Notepad when clicked.

```powershell
New-CommanderShortcut -Text 'Click Me' -Description 'Nice' -Action {
    Start-Process notepad
}
```


# Events

PSCommander can register event handlers that invoke script blocks based on events happening within your system. Use the `Register-CommanderEvent` cmdlet to listen to these events.

The following example starts Notepad when Commander starts.

```powershell
Register-CommanderEvent -OnCommander Start -Action {
   Start-Process notepad
}
```

You can also listen to events that are happening with Windows using WMI event filters. This example uses the built-in `ProcessStarted` event to run a script block whenever a process is started. The example writes to a file. The `$args[0]` value is the WMI object that was created.

```powershell
Register-CommanderEvent -OnWindows ProcessStarted -Action {
   $Args[0]['Name'] | Out-File C:\users\adamr\desktop\process-name.txt
}
```

To configure a custom WMI event, use the `-WmiEventType` and `-WmiEventFilter` parameters.

```powershell
Register-CommanderEvent -OnWindows WmiEvent -WmiEventType '__InstanceCreationEvent' -WmiEventFilter 'TargetInstance isa "Win32_Process"' -Action {
   $Args[0]['Name'] | Out-File C:\users\adamr\desktop\process-name.txt
}
```


# Explorer Context Menus

PSCommander can create context menu items that appear when right clicking on folders and files within Windows Explorer. Your script block receives the path to the folder or file via the `$Args[0]` variable.

You can create context menu items that appear on folders or only apply to particular extensions of files.

This example creates a context menu that displays as Click Me and opens VS Code to the file that was clicked.

```powershell
New-CommanderContextMenu -Text 'Click me' -Action {
    Start-Process code -ArgumentList $args[0]
}
```




---

[Next Page](/llms-full.txt/1)

