To run a PowerShell command in an open PowerShell 7 session, type the cmdlet, function, script, or executable name and press Enter. Use pwsh -Command to run a short PowerShell expression from another process, and use pwsh -File for a reusable .ps1 script.
Get-Process -Id $PID | Select-Object Id, ProcessName, StartTime
./Get-Health.ps1 -Environment 'Production'
pwsh -NoProfile -NonInteractive -Command 'Get-Date -Format o'
pwsh -NoProfile -NonInteractive -File ./Get-Health.ps1 -Environment Production
The correct form depends on who parses the command, whether a new process is required, how output must be captured, and which exit code the caller needs. Keep a one-line check inline. Put repeatable automation in a script file with explicit parameters and errors.
Choose the right PowerShell invocation method
| Need | Use | Important behavior |
|---|---|---|
| Run a cmdlet or function now | Type it in the current session | Returns PowerShell objects to the current pipeline |
| Run a script in the current session | ./Task.ps1 or & $scriptPath |
Normal invocation uses a child scope; & supports a path stored in a variable |
| Run a short expression from another process | pwsh -Command |
The calling shell parses the command line before PowerShell parses the command text |
| Run maintained automation | pwsh -File |
Arguments follow the script path; the script should set intentional exit codes |
| Launch and configure a separate process | Start-Process |
Does not return process output by default; waiting and capture must be requested |
| Run work in the background | Start-Job or the background operator |
Results are retrieved later and the job depends on its parent session |
| Run on another machine | Invoke-Command |
Requires configured remoting; remote objects are serialized on return |
This page uses PowerShell 7.5 and the pwsh executable. Windows PowerShell 5.1 uses powershell.exe and differs in native argument handling, available parameters, and platform support. Test automation in the exact host that will run it.
Run a cmdlet, script, or native executable
PowerShell sends cmdlet and function output as objects through its pipeline. Filter objects before formatting them:
Get-Process |
Where-Object WorkingSet64 -GT 500MB |
Select-Object Id, ProcessName, WorkingSet64
Formatting cmdlets such as Format-Table belong at the end of an interactive command, not in reusable data that another command must filter or serialize.
Run a PS1 script
PowerShell does not search the current directory for commands by default. Use an explicit relative or absolute path:
./Get-Health.ps1 -Environment 'Production'
On Windows, ./Get-Health.ps1 and .\Get-Health.ps1 both express a path relative to the current directory. In a script, build paths relative to that script rather than assuming the caller's working directory:
$childScript = Join-Path $PSScriptRoot 'Get-DatabaseState.ps1'
& $childScript -Database 'orders'
The call operator & runs a command, script, or script block stored in a variable. It is also the correct form for a quoted path containing spaces:
$scriptPath = 'C:\Operations Files\Get-Health.ps1'
& $scriptPath -Environment 'Production'
The call operator does not split one string into a command and arguments. Keep each argument separate. Do not use Invoke-Expression with untrusted input because it turns text into PowerShell code. See about_Operators.
If execution policy blocks an approved script, diagnose the effective scopes and file origin instead of routinely adding -ExecutionPolicy Bypass. The guide to allowing PowerShell scripts to run covers that separate security decision.
Run a native executable
PowerShell can invoke an executable directly. Store a path with spaces in a variable and use &:
$toolPath = (Get-Command pwsh -ErrorAction Stop).Source
& $toolPath '-NoProfile' '-NonInteractive' '-Command' 'Get-Date -Format o'
if ($LASTEXITCODE -ne 0) {
throw "pwsh failed with exit code $LASTEXITCODE"
}
For a native program, $LASTEXITCODE contains its exit code and $? is true only when that code is zero. Do not assume that text written to native stderr always means failure; the program's documented exit-code contract is authoritative.
PowerShell 7.5 defaults to Windows native-argument mode on Windows and Standard elsewhere; selected Windows file types retain legacy handling. The parsing documentation covers $PSNativeCommandArgumentPassing and the Windows-only --% token. Test embedded quotes with the exact program and operating system instead of copying escape rules between shells.
Use pwsh -Command for short expressions
pwsh -Command starts a new PowerShell process and executes a string, script block, or standard-input command. From Windows Command Prompt, the command is a string:
pwsh -NoProfile -NonInteractive -Command "Get-Date -Format o"
From a POSIX shell such as Bash, single quotes stop that shell from expanding PowerShell's dollar-prefixed variables:
pwsh -NoProfile -NonInteractive -Command '$PSVersionTable.PSVersion.ToString()'
From an existing PowerShell session, a literal script block can be passed as a real ScriptBlock object:
pwsh -NoProfile -NonInteractive -Command { Get-Date -Format o }
If -Command receives a string, it must be the last pwsh parameter. The calling shell parses first, then PowerShell parses the resulting text. This boundary explains why quoting can differ across PowerShell, CMD, Bash, YAML, and task schedulers.
Use -NoProfile when automation must not depend on aliases, functions, modules, or preferences from a user's profile. Use -NonInteractive for jobs that must fail instead of waiting for Read-Host or a confirmation prompt. Both behaviors are documented in about_Pwsh.
Move the code into a .ps1 file when the command needs nested quoting, several statements, typed parameters, tests, or structured error handling.
Use pwsh -File for repeatable automation
pwsh -File executes a script in a new PowerShell process. Place the script path after -File, followed by its parameters:
pwsh -NoProfile -NonInteractive -File ./Get-PathState.ps1 -Path ./input.json
The shell that starts pwsh interprets the command line first. Microsoft notes that values passed after -File arrive as literal strings after that shell's interpretation. A PowerShell script can then bind and validate them through its param block.
This cross-platform script returns one compact JSON event and an intentional process status:
[CmdletBinding()]
param(
[Parameter(Mandatory)]
[string] $Path
)
$ErrorActionPreference = 'Stop'
try {
$item = Get-Item -LiteralPath $Path
if ($item.PSProvider.Name -ne 'FileSystem') {
throw 'Path must use the FileSystem provider'
}
[pscustomobject]@{
timestamp = (Get-Date).ToUniversalTime().ToString('o')
severity = 'INFO'
event = 'path_check_completed'
item_type = if ($item.PSIsContainer) { 'directory' } else { 'file' }
message = 'Configured path is accessible'
} | ConvertTo-Json -Compress
exit 0
}
catch {
$failure = [pscustomobject]@{
timestamp = (Get-Date).ToUniversalTime().ToString('o')
severity = 'ERROR'
event = 'path_check_failed'
error_type = $_.Exception.GetType().FullName
message = 'Configured path could not be inspected'
}
[Console]::Error.WriteLine(($failure | ConvertTo-Json -Compress))
exit 1
}
$ErrorActionPreference = 'Stop' makes non-terminating errors from cmdlets that honor the preference stop the script, allowing catch to handle them. It does not make a nonzero native exit code throw automatically. Check $LASTEXITCODE after each native command whose result matters.
Do not log credentials, tokens, secret-bearing command lines, or unrestricted exception objects. Histories, process listings, CI output, transcripts, and script-block logs can expose arguments. Use the host's approved secret mechanism and log only safe identifiers or outcomes.
Return reliable exit codes to automation
PowerShell success, PowerShell error streams, and native process exit codes are related but not identical.
| Invocation | Normal completion | Failure behavior to design for |
|---|---|---|
pwsh -File ./Task.ps1 |
Returns 0 unless the script uses exit |
A script-terminating exception returns 1; exit N returns the chosen numeric status |
pwsh -Command '...' |
Returns 0 when the final $? is true |
Returns 1 when final $? is false or a script-terminating error occurs |
| Native executable inside PowerShell | Sets $LASTEXITCODE |
Nonzero does not automatically become a terminating PowerShell error |
| Cmdlet with a non-terminating error | Usually continues under the default preference | Use -ErrorAction Stop or a scoped preference when failure must stop the task |
When a native executable is the final command, pwsh -Command normalizes its nonzero result to process exit code 1 unless the command explicitly ends with exit $LASTEXITCODE. Preserve a tool's specific code when the caller depends on it:
pwsh -NoProfile -NonInteractive -Command {
& git 'status' '--short'
exit $LASTEXITCODE
}
Microsoft documents the differences for -Command, -File, and direct script calls under $LASTEXITCODE. In CI and scheduled tasks, test success, an expected handled failure, an unexpected terminating error, and a native nonzero exit before trusting the runner's status.
Use Start-Process when process control is the requirement
Direct invocation is normally best when output should remain in the current pipeline. Use Start-Process when the task needs a separate process, working directory, environment overrides, Windows verb, redirected native streams, or an explicit wait.
$stdoutPath = Join-Path $PWD 'health.stdout.log'
$stderrPath = Join-Path $PWD 'health.stderr.log'
$processOptions = @{
FilePath = (Get-Command pwsh -ErrorAction Stop).Source
ArgumentList = '-NoProfile -NonInteractive -Command "Get-Date -Format o"'
RedirectStandardOutput = $stdoutPath
RedirectStandardError = $stderrPath
Wait = $true
PassThru = $true
}
$process = Start-Process @processOptions
if ($process.ExitCode -ne 0) {
throw "pwsh failed with exit code $($process.ExitCode)"
}
The example changes two files. Use approved paths and protect their contents. -PassThru returns a process object; without it, Start-Process returns no output. -Wait waits for the process and its descendants.
-ArgumentList becomes one string passed to the process, so quoting must match the target program. Microsoft recommends one string containing the required quotes. Prefer direct & invocation when separate-process controls are unnecessary.
On Windows, Start-Process -Verb RunAs requests elevation and displays the operating-system consent flow. Elevation changes the security context; it does not make a command safe. Approve the exact operation first, and do not use an elevated shell merely to bypass an unexplained access failure.
See the current Start-Process reference for platform-specific process lifetime, environment, redirection, and working-directory behavior.
Capture PowerShell output without losing errors
PowerShell has redirectable Success, Error, Warning, Verbose, Debug, and Information streams. Progress is separate and cannot be redirected. This command overwrites the destination with all redirectable streams:
./Get-Health.ps1 *> ./Get-Health.log
This command appends instead:
./Get-Health.ps1 *>> ./Get-Health.log
Both commands change a file. Use Out-File -NoClobber to reject replacement, and set an explicit encoding when needed. Combining streams loses the distinction between data and errors; keep stdout and stderr separate when a runner or collector relies on it.
PowerShell 7.4 and later preserve native bytes when stdout is redirected directly to a file. Merging native stderr converts the combined data to strings, so keep streams separate for exact binary output. See about_Redirection.
Use background jobs for session-scoped work
Start-Job runs work in a separate local process and returns a job object immediately:
$job = Start-Job -ScriptBlock {
Get-Process | Select-Object Id, ProcessName, CPU
}
$results = Receive-Job -Job $job -Wait
Remove-Job -Job $job
$results
The remoting layer serializes objects moving between a background job and its parent. Returned objects are snapshots and may not retain live methods. Receive-Job also consumes cached results by default; use its documented -Keep behavior only when the results must be received again.
A Start-Job child is not durable automation. If the parent PowerShell session ends, its running child jobs are terminated. Use an operating-system scheduler, service, CI runner, or another managed execution system when work must survive logout or host-process termination. Microsoft explains the lifetime and serialization boundaries in about_Jobs.
Run commands remotely with Invoke-Command
Invoke-Command runs a script block on one or more configured remote endpoints. -ComputerName uses PowerShell remoting over WS-Management, while -HostName selects SSH transport in PowerShell 7. The target must already expose an authorized PowerShell endpoint.
This read-only Windows example passes the service name as data rather than interpolating it into code:
$serviceName = 'Spooler'
Invoke-Command -ComputerName 'server01', 'server02' -ScriptBlock {
param([string] $Name)
Get-Service -Name $Name -ErrorAction Stop |
Select-Object Name, Status
} -ArgumentList $serviceName
-ComputerName creates a temporary connection for the command. Use New-PSSession and Invoke-Command -Session only when multiple related commands must share remote state. Returned remote objects cross a serialization boundary, so inspect their properties rather than assuming they still expose the methods of live objects.
Use approved authentication and endpoint configuration. Never put passwords, tokens, or private keys in command lines. Restrict targets, identities, endpoint capabilities, and command permissions. State-changing remote commands require the same approval as local changes.
SSH remoting needs SSH plus a configured PowerShell subsystem. WS-Management has separate listener, network, authentication, and authorization requirements. Do not weaken host verification or broadly add trusted hosts. Follow Invoke-Command and the remoting guidance.
Troubleshoot a PowerShell command that will not run
The command is not recognized
Confirm what the exact session can resolve:
Get-Command -Name 'Get-Health' -All -ErrorAction SilentlyContinue
$PSVersionTable | Select-Object PSEdition, PSVersion, Platform
$env:PSModulePath -split [IO.Path]::PathSeparator
Do not rely on a profile-defined alias or function in automation. Import the required module explicitly, use a fully qualified script path, and run the same PowerShell edition as the target job.
A path with spaces prints instead of running
A quoted path is a string. Invoke it with & and pass arguments separately:
$scriptPath = 'C:\Operations Files\Get-Health.ps1'
& $scriptPath -Environment 'Production'
The script works interactively but fails in automation
Compare identity, current directory, profile loading, environment variables, installed modules, PowerShell version, architecture, and interactive prompts. Reproduce with -NoProfile -NonInteractive, absolute paths, explicit imports, and non-secret diagnostic fields. Do not solve a missing dependency by silently changing execution policy or elevating the whole task.
The task reports success after an error
Identify whether the failure came from a cmdlet or native executable. For cmdlets, decide which non-terminating errors must become terminating with -ErrorAction Stop. For native programs, check $LASTEXITCODE. End pwsh -Command with exit $LASTEXITCODE when a specific native code must reach the caller.
Start-Process returns before the tool finishes
Add -Wait and -PassThru, then inspect the returned process object's ExitCode. Redirect stdout and stderr to separate protected files if output is required. In a remote session, a process started without waiting is terminated when that remote session ends; do not use Start-Process there as an undocumented persistence mechanism.
A remote command fails
Separate name resolution and network reachability from endpoint configuration, authentication, authorization, and the command itself. Test a bounded read-only command first. Confirm whether the connection uses WS-Management or SSH, and verify the exact endpoint and identity rather than changing several trust settings at once.
Centralize PowerShell command evidence carefully
Console output, redirected files, PowerShell event channels, task history, and CI logs are different evidence sources. Decide which source is authoritative, then configure a Windows-capable collector to read only the approved files or event channels. Preserve timestamps, host identity, script or task name, exit code, and a safe correlation identifier. Collector parsing determines which fields reach the destination.
Avoid forwarding unrestricted transcripts or full command lines by default. They can include passwords, tokens, personal data, confidential paths, and remote target names. Apply allowlisted fields, least access, encryption, retention, and deletion rules before central collection. The Windows Event Log command guide explains bounded event queries and native EVTX preservation.
Fluxtail log management is a paid, self-service logs-focused destination with Starter and Pro plans. After a separately configured collector sends approved PowerShell records through a documented receiver, Fluxtail provides named streams, Live Tail, search, filters, and alerts for the fields the collector actually delivers. Fluxtail does not run PowerShell commands or replace the scheduler, remoting endpoint, or source-side security controls.
Verify one non-sensitive success and one handled failure from source to stream before relying on a field or alert. Keep the original event or runner record for comparison. If centralized search fits the requirement, create a Fluxtail account and connect an approved collector through a supported receiver.
PowerShell command checklist
- Run a cmdlet directly when the current PowerShell pipeline should receive its objects.
- Use an explicit path for scripts; use
&when the command or script path is stored in a variable. - Use
pwsh -Commandfor short expressions andpwsh -Filefor maintained automation. - Add
-NoProfile -NonInteractivewhen a scheduled job must avoid profile dependencies and prompts. - Keep command paths and arguments separate; never evaluate untrusted text as PowerShell code.
- Check
$LASTEXITCODEfor native executables and make important cmdlet errors terminating deliberately. - Use
Start-Processonly when separate-process controls are needed; request waiting, process output, and stream capture explicitly. - Treat
Start-Jobas session-scoped work, not a durable scheduler. - Configure and authorize WS-Management or SSH remoting before using
Invoke-Command. - Log safe outcomes and identifiers, not secrets or unrestricted command lines.