概要
PowerShellスクリプトの行数(コメント行、空白行、その他)をカウントする。
コード
<#
.SYNOPSIS
PowerShellスクリプトのステップ数をカウント
.DESCRIPTION
スクリプトの実行行、コメント行、空行を出力する
.PARAMETER ScriptFile
スクリプトファイル
.PARAMETER NoFolder
ファイル名にパスを付与しない
.NOTES
ヒアドキュメント中のコメント記号は考慮しない
.EXAMPLE
CountPsLine .\Test1.ps1
Test1.ps1をカウントする
.EXAMPLE
ls D:\Scripts\*.ps1 | CountPsLine > LineCount.csv
D:\Scriptsにあるps1ファイルを全てカウントして結果をLineCount.csvに出力する
.EXAMPLE
CountPsLine .\Test3.ps1 -NoFolder
Test3.ps1をカウントする
(結果の「ファイル名」列にパスを付けない。NoFolder指定無しだとフルパス表示)
# >
function CountPsLine(
[Parameter(Mandatory, ValueFromPipeline=$true)]$ScriptFile,
[switch]$NoFolder)
{
begin
{
if ($ScriptFile -ne $null -and $ScriptFile.Contains("*"))
{
throw "パラメータにワイルドカードは使えません。複数ファイルはパイプライン経由で渡してください。"
}
# ヘッダー出力
Write-Output "ファイル名`t実行行`tコメント行`t空行`t合計"
}
process
{
function MainProc($ScriptFile)
{
[string]$filePath = ""
if($ScriptFile.GetType().FullName -eq "System.String")
{
$filePath = Convert-Path $ScriptFile
}
elseif ($ScriptFile.GetType().FullName -eq "System.IO.FileInfo")
{
$filePath = $ScriptFile.FullName
}
else
{
Write-Error "この型は処理できません。"
return
}
# 拡張子チェック
if ($filePath.ToLower().EndsWith(".ps1") -or $filePath.ToLower().EndsWith(".psm1"))
{
# OK
}
else
{
Write-Error "ps1またはpsm1ファイルを指定してください。"
return
}
[long]$exec = 0
[long]$comment = 0
[long]$blank = 0
[bool]$multiCommentMode = $false
Get-Content -LiteralPath $filePath | ForEach-Object {
# 左右の空白除去
[string]$lineTrim = $_.Trim()
# 複数行コメントの開始・終了記号っぽい文字列を除去
[string]$lineRemove = $lineTrim -replace "`".*<#.*?`"",""
$lineRemove = $lineRemove -replace "`".*#>.*?`"",""
if ($multiCommentMode)
{
# 複数行コメントの途中
if ($lineRemove.EndsWith("#>"))
{
# 複数行コメントの終わり
$comment++
$multiCommentMode = $false
}
elseif ($lineRemove.Contains("#>"))
{
# 複数行コメントの終わり、その右にコード有り
$exec++
$multiCommentMode = $false
}
else
{
# 複数行コメントの途中
$comment++
}
}
else
{
if ($lineTrim -eq "")
{
# 空白行
$blank++
}
elseif ($lineRemove.ToLower().StartsWith("#requires"))
{
# 実行行
$exec++
}
elseif ($lineRemove.StartsWith("#"))
{
# コメント行
$comment++
}
elseif ($lineRemove.StartsWith("<#") -and $lineRemove.EndsWith("#>"))
{
# 一行で複数行コメント形式
$comment++
}
elseif ($lineRemove -match "<#.*#>")
{
# 一行で複数行コメント、コメントの外(左右)にコード有り
$exec++
}
elseif ($lineRemove.StartsWith("<#"))
{
# 複数行コメントの開始
$comment++
$multiCommentMode = $true
}
elseif ($lineRemove.Contains("<#"))
{
# 複数行コメントの開始、その左にコード有り
$exec++
$multiCommentMode = $true
}
else
{
# 実行行
$exec++
}
}
}
if ($NoFolder)
{
$filePath = Split-Path $filePath -Leaf
}
# 結果表示
[long]$total = $blank + $comment + $exec
Write-Output "${filePath}`t${exec}`t${comment}`t${blank}`t${total}"
}
$ScriptFile | ForEach-Object { MainProc $_ }
}
}
実行例
動作確認した環境
- PowerShell V4 (Windows 8.1)
- PowerShell V5 (Windows 10)