PowerShell scripts can change files, services, accounts, cloud resources, and system settings in seconds. A quick review before execution helps you catch syntax errors and fragile patterns while the code is still easy to change.

PSRafScan combines PowerShell's native parser with 58 focused rules. The parser catches syntax problems. The rules look for patterns related to error handling, destructive operations, credentials, portability, terminal paste behavior, and other common sources of trouble.

This guide shows a practical review process you can repeat before testing a script.

Start with the script's job

Before looking at individual commands, write down what the script is supposed to do:

  • What inputs does it accept?
  • What output should it produce?
  • Which files, services, accounts, or settings can it change?
  • Does it require a module, network connection, credential, or elevated session?
  • What should happen when an operation fails?

These answers give you a reference for judging the code. A command can be valid PowerShell and still be wrong for the task.

Check the syntax with PowerShell's parser

PowerShell exposes a parser that reads source text and returns tokens, parse errors, and an abstract syntax tree. PSRafScan uses that parser before applying its own rules.

For example, this script is missing a closing brace:

powershell
if ($true) {
    Write-Output 'The block never closes'

Save it as ParserError.ps1, then run:

powershell
RSX -Path ./ParserError.ps1 -IntendedUse Ps1File -FailOn Error

PSRafScan reports a PowerShellParseError with severity Error. Correct syntax errors first because the parser could not build a complete representation of the script.

You can also call the parser directly when you need a small syntax-only check:

powershell
$tokens = $null
$errors = $null
$ast = [System.Management.Automation.Language.Parser]::ParseFile(
    (Resolve-Path ./ParserError.ps1),
    [ref] $tokens,
    [ref] $errors
)

$errors | Select-Object Message, Extent

Review static findings in context

A script can parse cleanly and still contain code that deserves attention. Each PSRafScan finding includes a rule name, severity, category, source location, issue, and recommended change.

Hidden failures

This command suppresses a non-terminating error:

powershell
Get-ChildItem -LiteralPath $Path -ErrorAction SilentlyContinue

That can be intentional, but it can also make a failed operation look like an empty result. The SilentErrorAction rule asks you to decide whether the failure should be visible.

When failure matters, make it explicit:

powershell
try {
    Get-ChildItem -LiteralPath $Path -ErrorAction Stop
}
catch {
    Write-Error "Could not read '$Path': $($_.Exception.Message)"
}

The change is useful because the caller can distinguish an empty directory from an operation that did not succeed.

Destructive file operations

Treat the next example as source to inspect, not a command to run:

powershell
$target = Join-Path ([System.IO.Path]::GetTempPath()) 'PSRafScanDemo'
Remove-Item -LiteralPath $target -Recurse -Force

The RecursiveForceDelete rule calls attention to Remove-Item with both -Recurse and -Force when -WhatIf is absent. Before allowing a deletion, inspect how the path is created, whether it can become a root or unexpected directory, which identity runs the command, and what recovery is available.

A preview-oriented revision can add validation and -WhatIf:

powershell
$target = Join-Path ([System.IO.Path]::GetTempPath()) 'PSRafScanDemo'
$resolvedTarget = [System.IO.Path]::GetFullPath($target)
$root = [System.IO.Path]::GetPathRoot($resolvedTarget)

if ([string]::IsNullOrWhiteSpace($resolvedTarget) -or $resolvedTarget -eq $root) {
    throw 'Refusing an empty or root deletion target.'
}

Remove-Item -LiteralPath $resolvedTarget -Recurse -Force -WhatIf

-WhatIf previews the command's supported action. Continue to inspect the surrounding path and control logic before any real deletion.

Document markup inside a script

Code copied from documentation or a chat response may still contain Markdown fences:

text
```powershell
Get-Process
```

The fence lines are formatting, not PowerShell. Copy only the code into the .ps1 file. PSRafScan's MarkdownCodeFence rule catches raw fence lines left in executable source.

Choose the intended use

PSRafScan offers two modes because saved scripts and terminal input do not have the same context.

Intended useChoose it whenExample
Ps1FileThe code will remain a saved .ps1 fileRSX -Path ./script.ps1 -IntendedUse Ps1File
TerminalPasteThe code will be entered directly into a live terminalRSX -Path ./paste.ps1 -IntendedUse TerminalPaste

The choice changes which rules apply. For example, a top-level param() block is normal in a saved script but does not provide the same invocation behavior when pasted directly into a terminal.

Run a repeatable scan

For a saved script, start with an explicit command:

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

For structured output, add JSON and a destination:

powershell
RSX -Path ./candidate.ps1 `
    -IntendedUse Ps1File `
    -FailOn Warning `
    -OutputFormat Json `
    -OutputPath ./candidate.psrafscan.json

Work through the result in this order:

  1. Correct parser errors.
  2. Read Error findings in their surrounding code.
  3. Review Warning and Information findings, even when they are below the selected threshold.
  4. Make a focused edit that you can explain.
  5. Compare the revision with the previous version.
  6. Run the same scan again.

Understand the process result

CodeStatusMeaning
0PassParsing succeeded and no finding met the selected FailOn threshold.
1FailAt least one rule finding met the threshold.
2ParseErrorPowerShell reported one or more syntax errors.

FailOn controls the process result, not the contents of the report. A lower-severity finding can still be present when the process returns 0.

Plan the runtime test separately

Static analysis helps you understand source before execution. Runtime testing still answers questions about real modules, permissions, data, services, network responses, timing, and side effects.

Use known inputs, minimal privileges, and a test environment appropriate to the script. Define the expected output before running it, and make recovery or cleanup part of the plan when the script changes state.

Continue the review

Sources