src/public/Format-ScriptPadExpressions.ps1

function Format-ScriptPadExpressions {
    <#
    .SYNOPSIS
        Pads powershell expressions with single spaces.
    .DESCRIPTION
        Pads powershell expressions with single spaces. Expressions padded include +,-,/,%, and *
    .PARAMETER Code
        Multi-line or piped lines of code to process.
    .PARAMETER SkipPostProcessingValidityCheck
        After modifications have been made a check will be performed that the code has no errors. Use this switch to bypass this check
        (This is not recommended!)
    .EXAMPLE
       PS > $testfile = 'C:\temp\test.ps1'
       PS > $test = Get-Content $testfile -raw
       PS > $test | Format-ScriptPadExpressions | clip
        
       Description
       -----------
       Takes C:\temp\test.ps1 as input, pads any expressions found with single spaces and places the result in the clipboard
       to be pasted elsewhere for review.
 
    .NOTES
       Author: Zachary Loeber
       Site: http://www.the-little-things.net/
       Requires: Powershell 3.0
 
       Version History
       1.0.0 - Initial release
    #>

    [CmdletBinding()]
    param(
        [parameter(Position=0, Mandatory=$true, ValueFromPipeline=$true, HelpMessage='Lines of code to process.')]
        [AllowEmptyString()]
        [string[]]$Code,
        [parameter(Position=1, HelpMessage='Bypass code validity check after modifications have been made.')]
        [switch]$SkipPostProcessingValidityCheck
    )
    begin {
        if ($script:ThisModuleLoaded -eq $true) { Get-CallerPreference -Cmdlet $PSCmdlet -SessionState $ExecutionContext.SessionState }
        $FunctionName = $MyInvocation.MyCommand.Name
        Write-Verbose "$($FunctionName): Begin."

        $Codeblock = @()
        $ParseError = $null
        $Tokens = $null
        $predicate = {
            ($args[0] -is [System.Management.Automation.Language.CommandExpressionAst]) -and 
            (($args[0].FindAll($predicate2,$true)).count -gt 0)
        }
        $predicate2 = {$args[0] -is [System.Management.Automation.Language.BinaryExpressionAst]}
    }
    process {
        $Codeblock += $Code
    }
    end {
        $ScriptText = $Codeblock | Out-String
        Write-Verbose "$($FunctionName): Attempting to parse AST."

        $AST = [System.Management.Automation.Language.Parser]::ParseInput($ScriptText, [ref]$Tokens, [ref]$ParseError) 
 
        if($ParseError) { 
            $ParseError | Write-Error
            throw "$($FunctionName): Will not work properly with errors in the script, please modify based on the above errors and retry."
        }

        $expressions = $ast.FindAll($predicate, $true)
        for($t = $expressions.Count - 1; $t -ge 0; $t--) {
            $expression = $expressions[$t]
            $tmpexpression = $expression
            $EmbeddedCommandExpressionAST = $false
            
            # Recurse through the parent nodes and look for embedded commandexpressionast types and skip them if found,
            # (There must be a better way to do this....)
            while ($tmpexpression.Parent -ne $null) {
                if ($tmpexpression.Parent.GetType().Name -eq 'CommandExpressionAST') {
                    $EmbeddedCommandExpressionAST = $true
                    Write-Verbose "$($FunctionName): Expression is part of a larger command expression, skipping: $($expression.expression)"
                }
                $tmpexpression = $tmpexpression.Parent
            }
            if (-not $EmbeddedCommandExpressionAST) {
                $RemoveStart = $expression.Extent.StartOffset
                $RemoveEnd = $expression.Extent.EndOffset - $RemoveStart
                $ExpressionString = $expression.Extent.Text
                $AST2 = [System.Management.Automation.Language.Parser]::ParseInput($ExpressionString, [ref]$Tokens, [ref]$ParseError)
                $binaryexpressions = $AST2.FindAll($predicate2,$true)
                $binaryexpressioncount = $binaryexpressions.count
                for($t2 = 0; $t2 -lt $binaryexpressioncount; $t2++) {
                    $AST2 = [System.Management.Automation.Language.Parser]::ParseInput($ExpressionString, [ref]$Tokens, [ref]$ParseError)
                    $binaryexpressions = $AST2.FindAll($predicate2,$true)
                    $exp = $binaryexpressions[$t2]
                    $expbegin = $exp.extent.StartOffset
                    $expend = $exp.Extent.EndOffset - $expbegin
                    $expreplace = $exp.Left.Extent.Text + ' ' + $exp.ErrorPosition.Text + ' ' + $exp.Right.Extent.Text
                    $ExpressionString = $ExpressionString.Remove($expbegin,$expend).Insert($expbegin,$expreplace)
                }
                Write-Verbose "$($FunctionName): Binary Expressions found in $($expression.expression)"
                $ScriptText = $ScriptText.Remove($RemoveStart,$RemoveEnd).Insert($RemoveStart,$ExpressionString)
            }
        }
        
        # Validate our returned code doesn't have any unintentionally introduced parsing errors.
        if (-not $SkipPostProcessingValidityCheck) {
            if (-not (Format-ScriptTestCodeBlock -Code $ScriptText)) {
                throw "$($FunctionName): Modifications made to the scriptblock resulted in code with parsing errors!"
            }
        }

        $ScriptText
        Write-Verbose "$($FunctionName): End."
    }
}