Skip to content

Instantly share code, notes, and snippets.

@victorvogelpoel
Last active January 3, 2016 01:19
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save victorvogelpoel/8388014 to your computer and use it in GitHub Desktop.
Save victorvogelpoel/8388014 to your computer and use it in GitHub Desktop.
Measure-ScriptCode (PowerShell 3+ version) calculates some metrics about the script- and module files it is fed, like number of comments, lines-of-code, number of functions, workflows and filters.
# Measure-ScriptCode.ps1
# Return metrics about the script and module files
# PowerShell 3 is required as Abstract Syntax Trees are used.
# Jan 2014
# If this works, Victor Vogelpoel <victor@victorvogelpoel.nl> wrote this.
# If it doesn't, I don't know who wrote this.
#
# Disclaimer
# This script is provided AS IS without warranty of any kind. I disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose. The entire risk arising out of the use or
# performance of the sample scripts and documentation remains with you. In no event shall I be liable for any damages whatsoever
# (including, without limitation, damages for loss of business profits, business interruption, loss of business information,
# or other pecuniary loss) arising out of the use of or inability to use the script or documentation.
#requires -version 3
Set-PSDebug -Strict
Set-StrictMode -Version Latest
function Measure-ScriptCode
{
[CmdletBinding()]
param
(
[Parameter(Mandatory=$true, Position=1, ValueFromPipeline=$true, ValueFromPipelineByPropertyName=$true, HelpMessage="One or more PS1 or PSM1 files to calculate code metrics for")]
[Alias('PSPath', 'Path')]
[string[]]$ScriptFile
)
begin
{
$files = 0
$modules = 0
$manifests = 0
$lines = 0
$words = 0
$characters = 0
$codeLines = 0
$comments = 0
$functions = 0
$workflows = 0
$filters = 0
$parseErrors = 0
}
process
{
foreach ($file in $ScriptFile)
{
if ($file -like "*.ps1") { $files++ }
if ($file -like "*.psm1") { $modules++ }
if ($file -like "*.psd1") { $manifests++ }
$fileContentsArray = Get-Content -Path $file
if ($fileContentsArray)
{
# First, measure basic metrics
$measurement = $fileContentsArray | Measure-Object -Character -IgnoreWhiteSpace -Word -Line
$lines += $measurement.Lines
$words += $measurement.Words
$characters += $measurement.Characters
$tokenAst = $null
$parseErrorsAst = $null
# Use the PowerShell 3 file parser to create the scriptblock AST, tokens and error collections
$scriptBlockAst = [System.Management.Automation.Language.Parser]::ParseFile($file, [ref]$tokenAst, [ref]$parseErrorsAst)
# Get the number of comment lines and comments on the end of a code line
$comments += @($tokenAst | where { $_.Kind -eq "Comment" } ).Length
# Calculate the 'lines of code': any line not containing comment or commentblock and not an empty or whitespace line.
# Remove comment tokens from the tokenAst, remove all double newlines and count all the newlines (minus 1)
$prevTokenIsNewline = $false
$codeLines += @($tokenAst | select -ExpandProperty Kind | where { $_ -ne "comment" } | where {
if ($_ -ne "NewLine" -or (!$prevTokenIsNewline))
{
$_
}
$prevTokenIsNewline = ($_ -eq "NewLine")
} | where { $_ -eq "NewLine" }).Length-1
$parseErrors += @($parseErrorsAst).Length
if ($scriptBlockAst -ne $null)
{
# Find all functions, filters and workflows in the AST, including nested functions
$functionAst = $scriptBlockAst.FindAll({ $args[0] -is [System.Management.Automation.Language.FunctionDefinitionAst]}, $true)
# Count the specific implementation: 'function', 'filter' or 'workflow'
$functions += @($functionAst | where { (!$_.IsFilter) -and (!$_.IsWorkflow) }).Length
$filters += @($functionAst | where { $_.IsFilter }).Length
$workflows += @($functionAst | where { $_.IsWorkflow }).Length
}
}
}
}
end
{
return [PSCustomObject]@{
Files = $files
Modules = $modules
Manifests = $manifests
CodeLines = $codeLines
Comments = $comments
Functions = $functions
Workflows = $workflows
Filters = $filters
ParseErrors = $parseErrors
Characters = $characters
Lines = $lines
Words = $words
}
}
}
Measure-ScriptCode -ScriptFile (Join-Path $PSScriptRoot "Write-HelloWorld.ps1")
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment