DetentShell The PowerShell 7 ISE we should have been delivered 8 years ago*

Tutorial: harden a script with Quick Fix

Fifteen minutes with a deliberately rough script. Quick Fix runs five hardening transforms against the function under your caret, shows each proposed change side by side, and touches nothing until you click Apply.

DetentShell logo
Before you start

The outputs below come from running each step against the example script. What you need:

01 Paste the rough script

Press Ctrl+N and paste this. It works, and it has the problems reviewers flag: parameters accept anything, failures are unhandled, and the deletion runs with no safety net.

function Clear-OldLogs {
    param(
        [Parameter(Mandatory)]
        $LogFolder,
        $DaysToKeep = 30
    )

    $cutoff = (Get-Date).AddDays(-$DaysToKeep)
    $old = Get-ChildItem -Path $LogFolder -Filter *.log |
        Where-Object { $_.LastWriteTime -lt $cutoff }

    foreach ($file in $old) {
        Remove-Item $file.FullName
    }

    Write-Output "Removed $($old.Count) old log files from $LogFolder"
}
02 Open Quick Fix

Put the caret inside the function and pick Edit > Quick Fix (right-click works too). A dialog lists the five transforms. Each row is either applicable, with a Preview, or declined, with its reason stated in a sentence. Your script hasn’t changed; the analysis ran against a copy.

03 Preview the try/catch wrapping

Open the preview for try/catch wrapping: your function on the left, the proposed version on the right. On this script it wraps three statements and leaves one alone. The Remove-Item call comes back like this:

# wrapped by Add-MWTryCatch v1.24.0
try {
Remove-Item $file.FullName
}
catch [System.IO.FileNotFoundException] { throw }
catch [System.IO.DirectoryNotFoundException] { throw }
catch [System.UnauthorizedAccessException] { throw }
catch [System.IO.IOException] { throw }
catch { throw }

Two things to notice. The catch blocks are typed for the failures a file operation can produce, so you can later handle a missing file differently from a permissions problem. And Write-Output was skipped, with the reason recorded: it’s on the always-safe list, and wrapping it would add noise without protection.

04 Apply it

Click Apply. The change splices into the enclosing function and nothing else in your buffer moves. Cancel, at any point in this dialog, leaves the buffer byte-identical to how you found it.

05 Walk the rest of the list

On a function that passes user text to Invoke-Expression, the guard’s injected line looks like this:

Write-Warning "DangerousCmdlet: Invoke-Expression at line 3 -- review before shipping (MWGUARD)"

A transform reporting “nothing to do” is a result, not a failure. The list tells you where your script already stands.

06 See a refusal

Open a new tab and paste:

Set-StrictMode -Off

function Get-LooseValue {
    param($Name)
    $settings = @{ Retries = 3 }
    return $settings[$Name]
}

Run Quick Fix. The strict-mode row declines, and its reason reads:

The reason it gives

This script explicitly turns strict mode off; that looks deliberate, so this won’t override it.

There’s no do-it-anyway on this one; if you want strict mode here, remove the -Off line yourself. Other refusals, where overriding is reasonable, carry a do-it-anyway row so the choice stays yours.

07 What the markers are for

Every applied change carries a comment naming the tool and version that made it, like the # wrapped by Add-MWTryCatch v1.24.0 line in step 3. In a code review or a diff six months from now, tool-applied hardening stays distinguishable from hand-written logic, which is exactly what a reviewer wants to know.

If something doesn’t match
Where to go next

The Quick Fix wiki page covers the feature per audience, and the blog series has a post on why every transform previews before it applies.

Get DetentShell
PS> Start-Process "https://detentpoint.com/detentshell/download"
# Coming soon — ships once the installer is code-signed

Coming soon. DetentShell launches at $29.99 in the Microsoft Store for its first two weeks. The regular price that follows is not final yet and will be published here first; volume licensing for teams is handled separately.

Follow progress on the changelog →