LoginSignup
3
1

More than 5 years have passed since last update.

PowerShellステップカウンタ

Posted at

概要

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 $_ }
    }
}

実行例

結果をファイルにリダイレクト
ps22.PNG

ファイルをExcelで開いたところ
ps23.png

動作確認した環境

  • PowerShell V4 (Windows 8.1)
  • PowerShell V5 (Windows 10)
3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1