A saved PowerShell script and a live terminal do not provide the same execution context. The difference matters even when the visible code is identical.

A .ps1 file has a path, a script-level parameter binding step, and prerequisite handling tied to script invocation. Terminal input is assembled and submitted by a host and line editor. That changes how constructs such as param(), #Requires, script-path variables, scope, and multiline input should be handled.

PSRafScan makes the choice explicit: use Ps1File for a saved script and TerminalPaste for code that will be entered directly into a terminal.

The contexts at a glance

FeatureSaved .ps1 scriptLive terminal input
InvocationThe file is invoked by pathThe host submits interactive input
ParametersTop-level param() binds script argumentsA bare paste has no script-file invocation
Prerequisites#Requires applies to the scriptUse deliberate checks or keep the code as a script
Script path$PSScriptRoot and $PSCommandPath describe the fileNo executing .ps1 path exists
ScopeScript scope ends with the invocationDefinitions can remain in the session
Multiline inputThe parser receives the file as one source unitThe host decides when input is complete

Interactive behavior can vary with the terminal, PowerShell host, line editor, PowerShell and PSReadLine versions, edit mode, and paste method. Test the terminal workflow you actually plan to use.

Top-level param() belongs to script invocation

This is a normal saved script:

powershell
param(
    [Parameter(Mandatory)]
    [string] $Name
)

"Hello, $Name"

Save it as Hello.ps1 and invoke it with a named argument:

powershell
./Hello.ps1 -Name Ada

The script invocation binds Ada to $Name. Pasting the same source into a running terminal does not create a file invocation with arguments.

For a short terminal task, assign the value explicitly:

powershell
$name = 'Ada'
"Hello, $name"

For reusable terminal work, define a function and call it:

powershell
function Write-Greeting {
    param(
        [Parameter(Mandatory)]
        [string] $Name
    )

    "Hello, $Name"
}

Write-Greeting -Name Ada

PSRafScan's TopLevelParamInTerminalPaste rule calls attention to a top-level param() block when the intended use is TerminalPaste.

#Requires describes a script prerequisite

A saved script can declare requirements at the top of the file:

powershell
#Requires -Version 7.4
#Requires -Modules Microsoft.PowerShell.Management

Get-ChildItem -LiteralPath .

Keeping prerequisite declarations with the script makes the dependency clear and lets PowerShell evaluate them as part of script startup.

For terminal input, check the prerequisite explicitly or leave the code as a script:

powershell
if ($PSVersionTable.PSVersion -lt [version]'7.4') {
    throw 'PowerShell 7.4 or later is required.'
}

Get-ChildItem -LiteralPath .

The RequiresInTerminalPaste rule helps identify #Requires lines that need this decision.

Script-path variables need an executing file

Saved scripts can build paths relative to their own location:

powershell
$configPath = Join-Path -Path $PSScriptRoot -ChildPath 'config.json'
Get-Content -LiteralPath $configPath

That is valuable when the caller's working directory can change. In direct terminal input, there is no executing script path to describe.

Use an explicit base path for terminal work:

powershell
$basePath = (Get-Location).ProviderPath
$configPath = Join-Path -Path $basePath -ChildPath 'config.json'
Get-Content -LiteralPath $configPath

An explicit parameter is often even better when the path should come from the user. PSRafScan's ScriptFileVariableInTerminalPaste rule covers $PSScriptRoot and $PSCommandPath in paste-oriented code.

Definitions can remain in the terminal session

A script has its own script scope. Functions and variables created inside it do not automatically become permanent additions to the caller's global session.

Interactive input is different. A function pasted into the terminal can remain available until it is removed or the session ends:

powershell
function Get-ProjectName {
    'PSRafScan'
}

Get-ProjectName

That persistence may be useful, but it should be intentional. The FunctionInsidePasteWrapper rule points out wrapper patterns that can obscure which definitions remain available after a paste.

Multiline input is controlled by the host

A saved file is parsed as a complete source unit. In a terminal, the host and line editor decide whether the current input is complete or whether another line is expected.

Consider a continuation-based pipeline:

powershell
Get-Process |
    Where-Object CPU -gt 10 |
    Sort-Object CPU -Descending

The source is clear in a file. In a terminal, the outcome depends on how the text is delivered and when the host submits it. Natural PowerShell constructs such as braces and parentheses often communicate continuation more clearly than fragile line endings.

This do loop also depends on receiving the complete construct:

powershell
$count = 0
do {
    $count++
    "Count: $count"
} while ($count -lt 3)

PSRafScan includes PasteSensitiveContinuationBlock and PasteSensitiveDoWhile to highlight patterns worth checking in the intended terminal.

Scan for the way the code will be used

For a saved script:

powershell
RSX -Path ./candidate.ps1 -IntendedUse Ps1File -FailOn Warning

For code prepared for terminal input:

powershell
RSX -Path ./paste-candidate.ps1 -IntendedUse TerminalPaste -FailOn Warning

The second command scans a saved copy of the text while applying terminal-specific rules. This makes the candidate easy to inspect and compare before anything is pasted.

PSRafScan 0.2.0-alpha1 applies 52 rules in both modes. Six are specific to TerminalPaste:

  • FunctionInsidePasteWrapper
  • PasteSensitiveContinuationBlock
  • PasteSensitiveDoWhile
  • RequiresInTerminalPaste
  • ScriptFileVariableInTerminalPaste
  • TopLevelParamInTerminalPaste

Choose with two questions

  1. Will the code be saved as a .ps1 file and invoked by its path? Choose Ps1File.
  2. Will the code be entered directly into a live PowerShell terminal? Choose TerminalPaste.

If a block needs script parameters, prerequisite declarations, stable relative paths, repeatable invocation, or source control, keeping it as a saved script is usually the clearer choice.

Sources