Measure-Script.ps1

<#PSScriptInfo
.VERSION 1.0
 
.GUID c8dde45c-025a-4354-bf6e-eebe26d432c1
 
.AUTHOR Joel 'Jaykul' Bennett
 
.COMPANYNAME PoshCode.org
 
.COPYRIGHT Copyright 2019, Joel Bennett. All Rights Reserved
 
.TAGS Measure, LinesOfCode
 
.LICENSEURI https://opensource.org/licenses/MIT
 
.PROJECTURI https://gist.github.com/Jaykul/e1056d5182d0c5566a22f72387abf741
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES PSScriptAnalyzer
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
.PRIVATEDATA
 
#>


#requires -module @{ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17.1" }

<#
    .SYNOPSIS
        Count the lines of code in PowerShell script (or module) files
    .DESCRIPTION
        Counts the lines of code based on the compact One True Brace style (requires PSScriptAnalyzer)
        In -Verbose mode, outputs the OTBS formatted script with line number next to the lines that count
    .EXAMPLE
        Measure-Script $profile.CurrentUserAllHosts -Verbose
 
        Counts the number of lines in your profile script, and shows you which ones counted in verbose output
#>

[CmdletBinding()]
param(
    # The path to a script (.ps1) or module (.psm1) file
    [Parameter(ValueFromPipeline,ValueFromPipelineByPropertyName,Mandatory)]
    [Alias("PSPath")]
    [string]$Path,

    # If set, counts lines with nothing but a closing brace (default is not to count them)
    # See https://gist.github.com/Jaykul/e1056d5182d0c5566a22f72387abf741 for further details
    [switch]$IncludeTrailingBraces
)
process {
    # For lines of code, reformat everything to OTBS to produce meaningful numbers
    $Reformatted = Invoke-Formatter (Get-Content $Path -Raw) -Settings @{
        IncludeRules = @(
            'PSPlaceOpenBrace',
            'PSPlaceCloseBrace',
            'PSUseConsistentWhitespace',
            'PSUseConsistentIndentation',
            'PSAlignAssignmentStatement'
        )

        Rules        = @{
            PSPlaceOpenBrace           = @{
                Enable             = $true
                OnSameLine         = $true
                NewLineAfter       = $true
                IgnoreOneLineBlock = $false
            }

            PSPlaceCloseBrace          = @{
                Enable             = $true
                NewLineAfter       = $false
                IgnoreOneLineBlock = $true
                NoEmptyLineBefore  = $false
            }

            PSUseConsistentIndentation = @{
                Enable          = $true
                Kind            = 'space'
                IndentationSize = 4
            }

            PSUseConsistentWhitespace  = @{
                Enable         = $true
                CheckOpenBrace = $true
                CheckOpenParen = $true
                CheckOperator  = $true
                CheckSeparator = $true
            }

            PSAlignAssignmentStatement = @{
                Enable         = $true
                CheckHashtable = $true
            }
        }
    } -Verbose:$false

    $Ast = [System.Management.Automation.Language.Parser]::ParseInput($Reformatted, $Path, [ref]$Null, [ref]$Null)

    $LineNumbers = $(
        foreach ($Extent in $Ast.FindAll( {$Args[0] -ne $Ast}, $true).Extent) {
            $Extent.StartLineNumber
            if ($IncludeTrailingBraces) {
                $Extent.EndLineNumber
            }
        }
    ) | Sort-Object -Unique

    [PSCustomObject]@{
        PSTypeName = "CodeMetrics"
        "LinesOfCode" = $LineNumbers.Count
    }

    if ($VerbosePreference -notin "SilentlyContinue", "Ingore") {
        $Reformatted = $Reformatted -split "`n"
        $count = 0
        foreach($line in 0..$Reformatted.Count) {
            if(($line + 1) -in $LineNumbers) {
                Write-Verbose ("{0,3:d} {1}" -f (++$count), $Reformatted[$line])
            } else {
                Write-Verbose (" " + $Reformatted[$line])
            }
        }
    }
}