Copyright © 2020 by Bill Stewart
This program may be used freely in any environment without payment to the author, with the following conditions:
This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the IMPLIED WARRANTY OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE.
This program is based on an earlier utility I wrote called ps1exec. I wrote it to address the following challenges of running PowerShell scripts from outside the PowerShell command line:
runposh addresses these limitations by doing the following:
runposh requires at least Windows PowerShell version 2. (Windows PowerShell version 2 is included with Windows 7/Server 2008 R2. Later OS versions include newer Windows PowerShell versions.)
runposh is provided in 64-bit (x64) and 32-bit (x86) versions.
The program's command-line syntax is as follows:
runposh [options] ["scriptfile" [-- parameters [...]]]
General options:
Option | Description |
---|---|
--core[="path"] | Runs PowerShell Core instead of Windows PowerShell. Specify a path and filename to pwsh.exe (optional) to run PowerShell Core from a specific path. If you don't specify a filename, runposh tries to find PowerShell Core by reading the registry. The quote marks (") are required if the path contains whitespace. See PowerShell Core for more information. |
--elevate | Requests elevation for the PowerShell process (i.e., Run as administrator). |
--help | Displays a dialog box containing help information. |
--quiet | Suppresses error message dialogs. |
--startdir="path" | Specifies a starting directory for the PowerShell process. The quote marks (") are required if the directory name contains whitespace. If you specify --elevate, this parameter is ignored. |
--windowstyle=style | Sets the window style for the PowerShell process. style Must be one of the following: Normal, Minimized, Maximized, Hidden, NormalNotActive, or MinimizedNotActive. |
--windowtitle="title" | Specifies a title for the PowerShell console window. The quote marks (") are required if the title contains whitespace. |
--configurationname="name" | Specifies a configuration endpoint in which PowerShell is run. |
--outputformat=format | Determines how output from PowerShell is formatted. format must be either Text (text strings) XML (serialized CLIXML format). |
If you specify a script filename on the command line, the following options apply:
Option | Description |
---|---|
--loadprofile | Loads PowerShell profile(s) before running the script. Normally, runposh uses the -NoProfile parameter on the PowerShell command line when running a script; if you specify --loadprofile, runposh omits the -NoProfile parameter when running a script. |
--noninteractive | Specifies the script should run in non-interactive mode (i.e., this parameter adds the -NonInteractive parameter to PowerShell's command line). |
--pause | Pauses the console window after the script completes with a Press ENTER to continue: prompt. |
--wait | Waits for the script to complete and returns the exit code of the PowerShell process. If you omit --wait, runposh simply runs the script using PowerShell and does not wait for PowerShell to exit. |
"scriptfile" | Specifes the path and filename of the PowerShell script you want to run. The quote marks (") are required if the path or filename contains whitespace. |
-- | Anything after the -- parameter is command-line parameters for the script. |
If you are not running a PowerShell script, the following options apply:
Option | Description |
---|---|
--noprofile | Do not load PowerShell profile(s) for the interactive console (i.e., runposh adds the -NoProfile parameter to the PowerShell command line). |
IMPORTANT: All command-line options are case-sensitive (e.g., you must specify --startdir, not --StartDir or --STARTDIR).
The --elevate parameter requests elevation for the PowerShell process. It is a shortcut for the following manual steps:
IMPORTANT: The --elevate parameter only provokes the elevation prompt; it cannot automatically enter credentials or bypass the elevation prompt.
If the current process is already elevated, the --elevate parameter does nothing.
Windows automatically sets the starting directory for an elevated process to the System32 directory (e.g., C:\Windows\System32). This is by design for security reasons. This means that, when you use --elevate, runposh ignores the --startdir parameter. Also, if you run a script, you will need to specify the full path and filename of the script.
Do not use --elevate when scheduling a script for unattended use because there's no one to answer the elevation prompt (i.e., runposh will simply hang indefinitely).
runposh supports both Windows PowerShell and PowerShell Core. If you don't specify --core, runposh defaults to Windows PowerShell.
In either case, runposh tries to find PowerShell on your system two ways:
Alternatively, you can specify a path and filename to a specific PowerShell Core executable using the --core parameter (see Usage for more information).
It is important to understand that PowerShell's execution policy is an administrator safety feature; it is not a security boundary. (Think seatbelt, not door lock.)
It is possible to configure the execution policy to prevent scripts from running, and some domain administrators have configured this option because they are under the impression that it increases security.
This impression is not correct, because PowerShell running a script does not enable the user to bypass security. The user's account is the security boundary. When a user runs PowerShell, the PowerShell process runs as that user. Another way to say this: Running a PowerShell script does not somehow give the user more rights than they had previously.
Preventing script execution does not increase security. The PowerShell execution policy is designed to prevent users from accidentally running unsigned scripts; it should not be (ab)used to try to prevent users from running scripts altogether.
Using PowerShell to automate tasks is not going away; preventing scripts from running breaks many administrative functions and prevents many users from doing their jobs.
Accordingly, runposh disables the execution policy for the PowerShell process it starts (see Technical Details).
The following table lists some sample commands. (The script names are made up.)
Command | Description |
---|---|
runposh | Opens a Windows PowerShell console. |
runposh --core | Opens a PowerShell Core console. |
runposh --core="C:\Program Files\PowerShell\Test\pwsh.exe" | Opens a PowerShell Core console using the specified PowerShell Core executable. |
runposh --elevate | Opens an elevated Windows PowerShell console. |
runposh --core --noprofile | Opens a PowerShell Core console but does not load the PowerShell profile(s). |
runposh "C:\Dir Name\Script Name.ps1" | Runs a PowerShell script using Windows PowerShell. |
runposh --windowstyle=hidden "C:\Script Files\AddUser.ps1" -- "Ken O'Dell" | Runs a PowerShell script using Windows PowerShell and some parameters in a hidden window. |
runposh --core --elevate --windowstyle=minimized C:\Scripts\MyAdminScript.ps1 | Runs an elevated PowerShell script using PowerShell Core in a minimized window. |
runposh builds a command string and uses PowerShell's -EncodedCommand parameter to run it. The command string is built using the components listed in the following table:
Command String | Description |
---|---|
Disable-ExecutionPolicy | Disables the execution policy for the process (see below) |
$Host.UI.RawUI.WindowTitle='title' | (If -t specified) Sets the PowerShell console window title |
& 'scriptfile' [parameters ...] | (If running a script) Runs the script file using the invocation/call operator (&) |
Read-Host "Press ENTER to continue" | (If running a script and --pause specified) Pauses the console window after the script runs |
exit $LASTEXITCODE | (If running a script and --wait specified) Sets the exit code for the PowerShell process |
The Disable-ExecutionPolicy function contains the following code:
function Disable-ExecutionPolicy { ($c = $ExecutionContext.GetType().GetField("_context", "nonpublic,instance").GetValue($ExecutionContext)).GetType().GetField("authorizationmanager", "nonpublic,instance").SetValue($c, (New-Object Management.Automation.AuthorizationManager "Microsoft.PowerShell")) }
The authorizationmanager name depends on whether you are running Windows PowerShell or PowerShell Core. In Windows PowerShell, the authorization manager is named _authorizationManager; in PowerShell Core, it is named <AuthorizationManager>k__BackingField.
runposh constructs the PowerShell command line as follows:
path [-NoExit] [other parameters] -EncodedCommand encodedcommand
Notes:
Once runposh has constructed the command line, it executes PowerShell using the ShellExecuteEx Windows API function. If elevation was requested (--elevate), runposh uses the runas verb; otherwise, it uses the open verb.
If --wait is used, runposh waits for the PowerShell process to terminate. Once PowerShell terminates, runposh exits with PowerShell's exit code.
1.1 (2020 Mar 05)
1.0 (2020 Feb 24)