build/dotSource/New-CommentBasedHelp.ps1
function Script:New-CommentBasedHelp { <# .SYNOPSIS Create comment based help for a function. .DESCRIPTION Create comment based help for a function. .PARAMETER Code Multi-line or piped lines of code to process. .PARAMETER ScriptParameters Process the script parameters as the source of the comment based help. .EXAMPLE PS > $testfile = 'C:\temp\test.ps1' PS > $test = Get-Content $testfile -raw PS > $test | New-CommentBasedHelp | clip Takes C:\temp\test.ps1 as input, creates basic comment based help and puts the result in the clipboard to be pasted elsewhere for review. .EXAMPLE PS > $CBH = Get-Content 'C:\EWSModule\Get-EWSContact.ps1' -Raw | New-CommentBasedHelp -Verbose -Advanced PS > ($CBH | Where {$FunctionName -eq 'Get-EWSContact'}).CBH Consumes Get-EWSContact.ps1 and generates advanced CBH templates for all functions found within. Print out to the screen the advanced CBH for just the Get-EWSContact function. .NOTES Author: Zachary Loeber Site: http://www.the-little-things.net/ Requires: Powershell 3.0 Version History 1.0.0 - Initial release 1.0.1 - Updated for PSModuleBuild #> [CmdletBinding()] param( [parameter(Position=0, ValueFromPipeline=$true, HelpMessage='Lines of code to process.')] [string[]]$Code, [parameter(Position=1, HelpMessage='Process the script parameters as the source of the comment based help.')] [switch]$ScriptParameters ) begin { $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." function Get-FunctionParameter { <# .SYNOPSIS Return all parameters for each function found in a code block. .DESCRIPTION Return all parameters for each function found in a code block. .PARAMETER Code Multi-line or piped lines of code to process. .PARAMETER Name Name of fuction to process. If no funciton is given first the entire script will be processed for general parameters. If none are found every function in the script will be processed. .PARAMETER ScriptParameters Parse for script parameters only. .EXAMPLE PS > $testfile = 'C:\temp\test.ps1' PS > $test = Get-Content $testfile -raw PS > $test | Get-FunctionParameter -ScriptParameters Takes C:\temp\test.ps1 as input, gathers any script's parameters and prints the output to the screen. .NOTES Author: Zachary Loeber Site: http://www.the-little-things.net/ Requires: Powershell 3.0 Version History 1.0.0 - Initial release 1.0.1 - Updated function name to remove plural format Added Name parameter and logic for getting script parameters if no function is defined. Added ScriptParameters parameter to include parameters for a script (not just ones associated with defined functions) #> [CmdletBinding()] param( [parameter(ValueFromPipeline=$true, HelpMessage='Lines of code to process.')] [string[]]$Code, [parameter(Position=1, HelpMessage='Name of function to process.')] [string]$Name, [parameter(Position=2, HelpMessage='Try to parse for script parameters as well.')] [switch]$ScriptParameters ) begin { $FunctionName = $MyInvocation.MyCommand.Name Write-Verbose "$($FunctionName): Begin." $Codeblock = @() $ParseError = $null $Tokens = $null # These are essentially our AST filters $functionpredicate = { ($args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst]) } $parampredicate = { ($args[0] -is [System.Management.Automation.Language.ParameterAst]) } $typepredicate = { ($args[0] -is [System.Management.Automation.Language.TypeConstraintAst]) } $paramattributes = { ($args[0] -is [System.Management.Automation.Language.NamedAttributeArgumentAst]) } $output = @() } process { $Codeblock += $Code } end { $ScriptText = ($Codeblock | Out-String).trim("`r`n") 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." } if (-not $ScriptParameters) { $functions = $ast.FindAll($functionpredicate, $true) if (-not [string]::IsNullOrEmpty($Name)) { $functions = $functions | where {$_.Name -eq $Name} } # get the begin and end positions of every for loop foreach ($function in $functions) { Write-Verbose "$($FunctionName): Processing function - $($function.Name.ToString())" $Parameters = $function.FindAll($parampredicate, $true) foreach ($p in $Parameters) { $ParamType = $p.FindAll($typepredicate, $true) Write-Verbose "$($FunctionName): Processing Parameter of type [$($ParamType.typeName.FullName)] - $($p.Name.VariablePath.ToString())" $OutProps = @{ 'FunctionName' = $function.Name.ToString() 'ParameterName' = $p.Name.VariablePath.ToString() 'ParameterType' = $ParamType[0].typeName.FullName } # This will add in any other parameter attributes if they are specified (default attributes are thus not included and output may not be normalized) $p.FindAll($paramattributes, $true) | Foreach { $OutProps.($_.ArgumentName) = $_.Argument.Value } $Output += New-Object -TypeName PSObject -Property $OutProps } } } else { Write-Verbose "$($FunctionName): Processing Script parameters" if ($ast.ParamBlock -ne $null) { $scriptparams = $ast.ParamBlock $Parameters = $scriptparams.FindAll($parampredicate, $true) foreach ($p in $Parameters) { $ParamType = $p.FindAll($typepredicate, $true) Write-Verbose "$($FunctionName): Processing Parameter of type [$($ParamType.typeName.FullName)] - $($p.Name.VariablePath.ToString())" $OutProps = @{ 'FunctionName' = 'Script' 'ParameterName' = $p.Name.VariablePath.ToString() 'ParameterType' = $ParamType[0].typeName.FullName } # This will add in any other parameter attributes if they are specified (default attributes are thus not included and output may not be normalized) $p.FindAll($paramattributes, $true) | Foreach { $OutProps.($_.ArgumentName) = $_.Argument.Value } $Output += New-Object -TypeName PSObject -Property $OutProps } } else { Write-Verbose "$($FunctionName): There were no script parameters found" } } $Output Write-Verbose "$($FunctionName): End." } } $CBH_PARAM = @' .PARAMETER %%PARAM%% %%PARAMHELP%% '@ $Codeblock = @() } process { $Codeblock += $Code } end { $ScriptText = ($Codeblock | Out-String).trim("`r`n") Write-Verbose "$($FunctionName): Attempting to parse parameters." $FuncParams = @{} if ($ScriptParameters) { $FuncParams.ScriptParameters = $true } $AllParams = Get-FunctionParameter @FuncParams -Code $Codeblock | Sort-Object -Property FunctionName $AllFunctions = @($AllParams.FunctionName | Select -unique) foreach ($f in $AllFunctions) { $OutCBH = @{} $OutCBH.'FunctionName' = $f [string]$OutParams = '' $fparams = @($AllParams | Where {$_.FunctionName -eq $f} | Sort-Object -Property Position) $fparams | foreach { $ParamHelpMessage = if ([string]::IsNullOrEmpty($_.HelpMessage)) {' ' + $_.ParameterName + " explanation`n`r"} else {' ' + $_.HelpMessage + "`n`r"} $OutParams += $CBH_PARAM -replace '%%PARAM%%',$_.ParameterName -replace '%%PARAMHELP%%',$ParamHelpMessage } $OutCBH.'CBH' = $Script:CBHTemplate -replace '%%PARAMETER%%',$OutParams New-Object PSObject -Property $OutCBH } Write-Verbose "$($FunctionName): End." } } |