src/public/Format-ScriptExpandParameterBlocks.ps1
function Format-ScriptExpandParameterBlocks { <# .SYNOPSIS Expand any parameter blocks found in curly braces from inline to a more readable format. .DESCRIPTION Expand any parameter blocks found in curly braces from inline to a more readable format. .PARAMETER Code Multiline or piped lines of code to process. .PARAMETER SplitParameterTypeNames Place Parameter typenames on their own line. .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-ScriptExpandParameterBlocks | clip Description ----------- Takes C:\temp\test.ps1 as input, expands parameter blocks and places the result in the clipboard. .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='Place Parameter typenames on their own line.')] [switch]$SplitParameterTypeNames, [parameter(Position = 2, HelpMessage='Bypass code validity check after modifications have been made.')] [switch]$SkipPostProcessingValidityCheck, $testparam ) begin { # Pull in all the caller verbose,debug,info,warn and other preferences 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.ParamBlockAST]} if ($SplitParameterTypeNames) { $TypeBreak = "`r`n" + ' ' } else { $TypeBreak = "" } } 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." } # First get all blocks $ParamBlocks = $AST.FindAll($predicate, $true) # Just in case we screw up and create more blocks than we started with this will prevent an endless loop $ParamBlockCount = $ParamBlocks.count for($t = 0; $t -lt $ParamBlockCount; $t++) { $NewParamBlock = '' $RemoveStart = $null $ParamAttribs = @($ParamBlocks[$t].Attributes | Where {($_.PSobject.Properties.name -match "NamedArguments")}) for($p = 0; $p -lt $ParamAttribs.Count; $p++) { if ($p -eq 0) { $RemoveStart = $ParamAttribs[$p].Extent.StartOffset } $NewParamBlock += $ParamAttribs[$p].Extent.Text + "`r`n" } $NewParamBlock += 'param (' + "`r`n" # We have to reprocess the entire ast lookup process every damn time we make a change. Must be a better way... $AST = [System.Management.Automation.Language.Parser]::ParseInput($ScriptText, [ref]$Tokens, [ref]$ParseError) $ParamBlocks = $AST.FindAll($predicate, $true) $AllParams = $ParamBlocks[$t].get_Parameters() for ($t2 = 0; $t2 -lt $AllParams.Count; $t2++) { $CurrParam = $AllParams[$t2] Write-Verbose "$($FunctionName): Processing Parameter $($CurrParam.Name.Extent.Text)" $CurrParam.Attributes | Where {($_.PSobject.Properties.name -match "NamedArguments")} | ForEach { $NewParamBlock += ' ' + $_.Extent.Text + "`r`n" } if ($CurrParam.Statictype.Name -eq 'SwitchParameter') { $ParamType = 'switch' } else { $ParamType = $CurrParam.Statictype.Name } $NewParamBlock += ' ' + '[' + $ParamType + ']' + $TypeBreak + $CurrParam.Name.Extent.Text if ($t2 -lt ($AllParams.Count -1)) { $NewParamBlock += ',' } else { $NewParamBlock += "`r`n" + ' ' + ')' } $NewParamBlock += "`r`n" } if ($RemoveStart -eq $null) { $RemoveStart = $ParamBlocks[$t].Extent.StartOffset } $RemoveEnd = $ParamBlocks[$t].Extent.EndOffset - $RemoveStart $ScriptText = $ScriptText.Remove($RemoveStart,$RemoveEnd).Insert($RemoveStart,$NewParamBlock) } # 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." } } |