Run PowerShell from Command Prompt
Tasks that are hard to do in Command Prompt alone, such as compressing ZIP files, converting date formats, or parsing JSON, can be done by calling PowerShell from Command Prompt. With the powershell command, you can build PowerShell processing into a batch file as well.
This article explains the basic usage of the powershell command, along with the tricky parts: quotes, escaping, and execution policy.
Basic syntax of the powershell command
powershell [-NoProfile] [-ExecutionPolicy <policy>] -Command "<command>"
powershell [-NoProfile] [-ExecutionPolicy <policy>] -File <script_path> [arguments...]
If you type just powershell in Command Prompt, the prompt changes to PS C:\> and you enter PowerShell’s interactive mode. To go back, type exit.
The powershell command that ships with Windows is Windows PowerShell 5.1. PowerShell 7 and later, which you install separately, is started with the pwsh command. The options in this article work the same way in both.
Run a single command (-Command)
When you pass a command to -Command, you return to Command Prompt after it runs.
powershell -Command "Get-Date"
-Command can be omitted (powershell "Get-Date"). However, the way arguments are interpreted becomes harder to follow, so it is best to specify it explicitly.
PowerShell commands (cmdlets) generally follow a “verb-noun” form such as Get-ChildItem. For example, to show only the 5 most recently modified files in the current folder, newest first, do the following.
powershell -NoProfile -Command "Get-ChildItem | Sort-Object LastWriteTime -Descending | Select-Object -First 5 Name, LastWriteTime"
Because the | is inside the double quotes ", it is handled as a PowerShell pipe, not by Command Prompt.
Commonly used options
| Option | Description |
|---|---|
-Command | Runs the given string as a PowerShell command |
-File | Runs the given .ps1 script |
-NoProfile | Does not load the profile (the startup settings script). Starts faster and varies less between environments |
-NonInteractive | Does not wait for user input. Operations that need confirmation result in an error |
-ExecutionPolicy <policy> | Sets the execution policy for this process only (such as Bypass) |
-NoExit | Keeps PowerShell open after running the command |
-EncodedCommand | Passes a command encoded as a Base64 UTF-16LE string (when you want to avoid quoting problems) |
When calling from a batch file, adding -NoProfile makes things more stable.
Run a script file (-File)
When the processing gets long, it is safer to put the PowerShell code in a separate .ps1 file and run it with -File.
param([string]$Name = 'World')
Write-Host "Hello, $Name!"
powershell -NoProfile -ExecutionPolicy Bypass -File .\hello.ps1 -Name Taro
When you get an execution policy error
If you try to run a .ps1 file and get an error such as “running scripts is disabled on this system”, the execution policy is the cause. Adding -ExecutionPolicy Bypass bypasses the policy for that process only. The system-wide setting is not changed.
The execution policy restricts the running of .ps1 files. The string you pass with -Command is not itself subject to the execution policy. However, if you call a .ps1 file from within -Command, the policy applies to that script (and without -NoProfile, loading the profile can also cause an error). Also, use -ExecutionPolicy Bypass only for scripts you trust. If your organization’s administrator sets the execution policy through Group Policy, you cannot override it with -ExecutionPolicy.
Handling quotes and special characters
Because the command line passes through both Command Prompt and PowerShell, you need to be careful with special characters.
| Character | Caveat in Command Prompt (cmd) | Workaround |
|---|---|---|
" | Used to enclose the whole -Command string | Using ' (single quotes) inside is easier |
% | Expanded as a variable inside a batch file | Write %% |
|, &, > | Interpreted by cmd when outside double quotes | Put them inside double quotes, or escape with ^ |
$ | Has no special meaning in cmd. Treated as a PowerShell variable | Can be written as is |
! | Disappears when delayed expansion is enabled | Run with delayed expansion disabled |
The simplest approach is to enclose the whole command in " and use ' for string literals inside.
powershell -NoProfile -Command "Write-Host 'Hello' ; (Get-Date).ToString('yyyy-MM-dd')"
If you really need " inside, you can pass it by writing \".
powershell -NoProfile -Command "Write-Host \"Current time: $((Get-Date).ToString('HH:mm'))\""
When the escaping piles up two or three levels deep and becomes hard to read, don’t struggle with -Command. Move the code into a .ps1 file and run it with -File. It is also easier to maintain.
Use the result in a batch file
Store the output in a variable
With for /f, you can capture PowerShell’s output into a batch file variable. In a batch file, write % as %%.
@echo off
for /f "usebackq delims=" %%d in (`powershell -NoProfile -Command "Get-Date -Format yyyyMMdd_HHmmss"`) do set TIMESTAMP=%%d
echo %TIMESTAMP%
Adding usebackq to for /f lets you enclose the command in backticks (`). Even if you use single quotes ' on the PowerShell side, they do not conflict with the for /f syntax.
The format of %date% in Command Prompt changes with the regional settings, but PowerShell’s Get-Date -Format returns a string in the same format regardless of those settings.
Get the exit code
When you run with -Command, ERRORLEVEL is set to 0 if the last command succeeded and 1 if it failed. The exit code of an external program may not be passed through as is, so when you want to report it reliably or control it precisely, specify the exit code with exit.
powershell -NoProfile -Command "if (Test-Path 'C:\data') { exit 0 } else { exit 2 }"
echo %ERRORLEVEL%
A script run with -File can also return an exit code with exit <number>.
Practical example: compress and extract ZIP files
With Compress-Archive and Expand-Archive, you can work with ZIP files from Command Prompt.
powershell -NoProfile -Command "Compress-Archive -Path 'C:\data\*' -DestinationPath 'C:\backup\data.zip' -Force"
powershell -NoProfile -Command "Expand-Archive -Path 'C:\backup\data.zip' -DestinationPath 'C:\restore' -Force"
The -Force of Compress-Archive overwrites an existing ZIP file, and the -Force of Expand-Archive overwrites files with the same name in the destination.
Practical example: replace text
Replacing strings in a file is hard in Command Prompt alone, but easy with PowerShell.
powershell -NoProfile -Command "(Get-Content 'a.txt' -Raw -Encoding UTF8) -replace 'foo','bar' | Set-Content 'b.txt' -Encoding UTF8"
In Windows PowerShell 5.1, Set-Content writes using the system’s default code page when -Encoding is omitted (for example, Windows-1252 on a US English system, or a Shift_JIS-family code page on a Japanese system). To avoid garbled text, specify -Encoding explicitly for both reading and writing. Note that -Encoding UTF8 in 5.1 writes with a BOM (PowerShell 7 writes without one). Also, if you save the batch file itself as UTF-8, non-ASCII text (such as accented or Japanese characters) inside -Command may be garbled. For more on character encoding, see the related articles.
Summary
| Goal | Command |
|---|---|
| Start PowerShell in interactive mode | powershell |
| Run a single command | powershell -NoProfile -Command "..." |
Run a .ps1 script | powershell -NoProfile -ExecutionPolicy Bypass -File a.ps1 |
| Use PowerShell 7 | pwsh -NoProfile -Command "..." |
| Capture output into a variable | for /f "delims=" %%x in ('powershell ...') do set VAR=%%x |
| Get the exit code | %ERRORLEVEL% |