My purpose was to have a PowerShell perform that removes any remark inside my code besides assist feedback. Fortunately, with assist from Chris Dent, I created a technique that eliminates feedback from any given file and makes it manufacturing prepared. Whereas it is a part of my module builder PSPublishModule, I am attaching it if you wish to attempt it by yourself.
perform Take away-Feedback {
<#
.SYNOPSIS
Take away feedback from PowerShell file
.DESCRIPTION
Take away feedback from PowerShell file and optionally take away empty strains
By default feedback in param block will not be eliminated
By default feedback earlier than param block will not be eliminated
.PARAMETER SourceFilePath
File path to the supply file
.PARAMETER Content material
Content material of the file
.PARAMETER DestinationFilePath
File path to the vacation spot file. If not offered, the content material shall be returned
.PARAMETER RemoveEmptyLines
Take away empty strains if a couple of empty line is discovered
.PARAMETER RemoveAllEmptyLines
Take away all empty strains from the content material
.PARAMETER RemoveCommentsInParamBlock
Take away feedback in param block. By default feedback in param block will not be eliminated
.PARAMETER RemoveCommentsBeforeParamBlock
Take away feedback earlier than param block. By default feedback earlier than param block will not be eliminated
.EXAMPLE
Take away-Feedback -SourceFilePath 'C:SupportGitHubPSPublishModuleExamplesTestScript.ps1' -DestinationFilePath 'C:SupportGitHubPSPublishModuleExamplesTestScript1.ps1' -RemoveAllEmptyLines -RemoveCommentsInParamBlock -RemoveCommentsBeforeParamBlock
.NOTES
Many of the work carried out by Chris Dent, with enhancements by Przemyslaw Klys
#>
[CmdletBinding(DefaultParameterSetName="FilePath")]
param(
[Parameter(Mandatory, ParameterSetName="FilePath")]
[alias('FilePath', 'Path', 'LiteralPath')][string] $SourceFilePath,
[Parameter(Mandatory, ParameterSetName="Content")][string] $Content material,
[Parameter(ParameterSetName="Content")]
[Parameter(ParameterSetName="FilePath")]
[alias('Destination')][string] $DestinationFilePath,
[Parameter(ParameterSetName="Content")]
[Parameter(ParameterSetName="FilePath")]
[switch] $RemoveAllEmptyLines,
[Parameter(ParameterSetName="Content")]
[Parameter(ParameterSetName="FilePath")]
[switch] $RemoveEmptyLines,
[Parameter(ParameterSetName="Content")]
[Parameter(ParameterSetName="FilePath")]
[switch] $RemoveCommentsInParamBlock,
[Parameter(ParameterSetName="Content")]
[Parameter(ParameterSetName="FilePath")]
[switch] $RemoveCommentsBeforeParamBlock,
[Parameter(ParameterSetName="Content")]
[Parameter(ParameterSetName="FilePath")]
[switch] $DoNotRemoveSignatureBlock
)
if ($SourceFilePath) {
$Fullpath = Resolve-Path -LiteralPath $SourceFilePath
$Content material = [IO.File]::ReadAllText($FullPath, [System.Text.Encoding]::UTF8)
}
$Tokens = $Errors = @()
$Ast = [System.Management.Automation.Language.Parser]::ParseInput($Content material, [ref]$Tokens, [ref]$Errors)
#$functionDefinition = $ast.Discover({ $args[0] -is [FunctionDefinitionAst] }, $false)
$groupedTokens = $Tokens | Group-Object { $_.Extent.StartLineNumber }
$DoNotRemove = $false
$DoNotRemoveCommentParam = $false
$CountParams = 0
$ParamFound = $false
$SignatureBlock = $false
$toRemove = foreach ($line in $groupedTokens) {
if ($Ast.Physique.ParamBlock.Extent.StartLineNumber -gt $line.Identify) {
proceed
}
$tokens = $line.Group
for ($i = 0; $i -lt $line.Rely; $i++) {
$token = $tokens[$i]
if ($token.Extent.StartOffset -lt $Ast.Physique.ParamBlock.Extent.StartOffset) {
proceed
}
# Lets discover feedback between perform and param block and never take away them
if ($token.Extent.Textual content -eq 'perform') {
if (-not $RemoveCommentsBeforeParamBlock) {
$DoNotRemove = $true
}
proceed
}
if ($token.Extent.Textual content -eq 'param') {
$ParamFound = $true
$DoNotRemove = $false
}
if ($DoNotRemove) {
proceed
}
# lets discover feedback between param block and finish of param block
if ($token.Extent.Textual content -eq 'param') {
if (-not $RemoveCommentsInParamBlock) {
$DoNotRemoveCommentParam = $true
}
proceed
}
if ($ParamFound -and ($token.Extent.Textual content -eq '(' -or $token.Extent.Textual content -eq '@(')) {
$CountParams += 1
} elseif ($ParamFound -and $token.Extent.Textual content -eq ')') {
$CountParams -= 1
}
if ($ParamFound -and $token.Extent.Textual content -eq ')') {
if ($CountParams -eq 0) {
$DoNotRemoveCommentParam = $false
$ParamFound = $false
}
}
if ($DoNotRemoveCommentParam) {
proceed
}
# if token not remark we go away it as is
if ($token.Type -ne 'Remark') {
proceed
}
# type of ineffective to not take away signature block if we're not eradicating feedback
# this modifications the construction of a file and signature shall be invalid
if ($DoNotRemoveSignatureBlock) {
if ($token.Type -eq 'Remark' -and $token.Textual content -eq '# SIG # Start signature block') {
$SignatureBlock = $true
proceed
}
if ($SignatureBlock) {
if ($token.Type -eq 'Remark' -and $token.Textual content -eq '# SIG # Finish signature block') {
$SignatureBlock = $false
}
proceed
}
}
$token
}
}
$toRemove = $toRemove | Type-Object { $_.Extent.StartOffset } -Descending
foreach ($token in $toRemove) {
$StartIndex = $token.Extent.StartOffset
$HowManyChars = $token.Extent.EndOffset - $token.Extent.StartOffset
$content material = $content material.Take away($StartIndex, $HowManyChars)
}
if ($RemoveEmptyLines) {
# Take away empty strains if a couple of empty line is discovered. If it is only one line, go away it as is
#$Content material = $Content material -replace '(?m)^s*$', ''
#$Content material = $Content material -replace "(`r?`n){2,}", "`r`n"
# $Content material = $Content material -replace "(`r?`n){2,}", "`r`n`r`n"
$Content material = $Content material -replace '(?m)^s*$', ''
$Content material = $Content material -replace "(?:`r?`n|n|r)", "`r`n"
}
if ($RemoveAllEmptyLines) {
# Take away all empty strains from the content material
$Content material = $Content material -replace '(?m)^s*$(r?n)?', ''
}
if ($Content material) {
$Content material = $Content material.Trim()
}
if ($DestinationFilePath) Set-Content material -Path $DestinationFilePath -Encoding utf8
else {
$Content material
}
}
This perform has a few parameters:
- SourceFilePath – present a path to a file you need to clear up
- Content material – alternatively to file manner, you can even present a code (for instance
Get-Content material -Uncooked $FilePath) - DestinationFilePath – path to file the place to save lots of the cleaned-up file. If not offered, the content material shall be returned immediately as a string.
- RemoveEmptyLines – as a part of the cleanup, it tries to take away empty strains, however provided that there’s a couple of. That is helpful in case you have assist with the perform
- RemoveAllEmptyLines – removes all empty strains from a file
- RemoveCommentsInParamBlock – by default, throughout cleanup, any feedback contained in the param block will not be eliminated, as these are sometimes associated to assist. However if you would like, you can even take away these with this swap.
- RemoveCommentsBeforeParamBlock – I do not take away something between the perform and param block by default. This ensures that the assistance I create for the perform stays the place it’s. However if you wish to take away it, that is how one can repair it.
- DoNotRemoveSignatureBlock – by default, we take away any signature from a file, however if you wish to forestall that from occurring, you should use this swap. It will not provide you with a lot as a result of the signature is not going to work after you take away something from the file anyhow – however it’s there.

