QuietShell – Executing PowerShell without a Console Window

For some time I’ve used a simple VBScript wrapper in code projects and scheduled tasks to allow silent execution of PowerShell scripts in the user context without displaying a console window:

p = CreateObject("Scripting.FileSystemObject").GetParentFolderName(WScript.ScriptFullName)
location = p &"\"& WScript.Arguments(0)
command = "powershell.exe -nologo -ExecutionPolicy Bypass -File """ &location &""""
set shell = CreateObject("WScript.Shell")
shell.Run command,0

But with the deprecation of VBScript and it’s eventually being removed from the Windows OS, it was time to look at alternative ways to do that.

A super-simple way is to use an undocumented switch on the Console Window Host utility (conhost.exe) that is native to Windows since Windows 7. The PowerShell process itself is not a console application; instead it relies on the Console Window Host provide the visible UI window that the PowerShell process is attached to. Conhost.exe has a ‘–headless’ switch that essentially prevents a visible UI, and you can call it like this:

conhost.exe --headless powershell.exe -File ".\MyScript.ps1" (arg1) (arg2..)

Or in a scheduled task:

This is pretty convenient, but it is undocumented so you use at your own risk. There is also the possibility that this could be flagged by antivirus engines, since it is not the usual way to execute PowerShell and could be indicative of malicious use.

Another way to get silent PowerShell execution is to use a C# executable wrapper. I’ve created several projects where I’ve done this – either creating a PowerShell instance as a runspace which is embedded in the host process, or starting the PowerShell process directly but using the UseShellExecute and CreateNoWindow properties to prevent attaching the process to a visible window host.

To that end, I created QuietShell, which is a simple, standalone C# wrapper for silent PowerShell execution. It supports either runspace or process modes, common PowerShell cmdline switches and logs in CMTrace format. The executable is digitally signed to help minimise interference from AV engines. You can use it to execute PowerShell scripts or commands silently, for example:

# Execute the PowerShell script in an embedded runspace
QuietShell.exe .\MyScript.ps1

# Execute the PowerShell command in an embedded runspace
QuietShell.exe -Command "$csinfo = Get-ComputerInfo; $csinfo | Out-File C:\Temp\csinfo.txt -Force"

# Execute the PowerShell script in an isolated process, logging to C:\Temp and including script output in the log file
QuietShell.exe -UseProcess -File .\MyScript.ps1 -LogPath "C:\Temp" -LogOutputStream

Or as a scheduled task:

You can download the executable (in the Releases) and read the full documentation over on GitHub.

In some cases, you don’t want to deploy the QuietShell.exe seperately, for example in a self-contained script, so you can also just base64 encode the file and export it using PowerShell:

# Base64 encoded content of QuietShell.exe
$QuietShellBase64 = "TVqQAAMAAAAEAAAA//...."
$bytes = [Convert]::FromBase64String($QuietShellBase64)
[System.IO.File]::WriteAllBytes("$UserFolderPath\QuietShell.exe", $bytes)

Of course, I highly recommend using my Base64Convert app available in the Microsoft Store for your encoding!