指定されたパスがディレクトリパスであるかどうかを判定するスクリプトの作成は、今回で最後だ。ごくシンプルな処理を実行するスクリプトだが、だいぶそれらしい体裁になった。それほど厳密なスクリプトではないが、スクリプトに必要な最低限の要素はだいたい網羅したのではないかと思う。

パイプラインに対応させる - ファイナル

前回の処理でディレクトリの指定を引数からではなく、パイプ経由からも取得できるようにした。成果物(test-d_15.ps1)は次のようになった。

#!/usr/bin/env pwsh

<#
.SYNOPSIS
ディレクトリパスが存在するかどうかを判定。

.DESCRIPTION
指定されたパスがディレクトリパスであり、かつ、存在するかどうかを判定する。

.PARAMETER DirectoryPath
ディレクトリパスを指定。

.PARAMETER Help
ヘルプメッセージを表示。

.INPUTS
ディレクトリパス。引数でディレクトリパスが指定されていない場合に使われる。

.OUTPUTS
System.Boolean。ディレクトリパスが存在する場合にTrue、そうでない場合にFalse。

.EXAMPLE
PS> .\test-d .\Documents\
True

.EXAMPLE
PS> .\test-d .\Documents-non-exists\
False

.EXAMPLE
PS> dir | .\test-d
True

.LINK
Test-Path
#>

#====================================================================
# 引数
#====================================================================
Param(
    [string]$DirectoryPath,  # ディレクトリを指定
    [switch]$Help          # ヘルプを表示
)

if ($Help) {
    Get-Help $PSCommandPath
    exit 1
}
# 引数でディレクトリが指定されていない場合、パイプからディレクトリ
# パスの取得を試みる。
if (-Not $DirectoryPath) {
    $DirectoryPath = @($input)[0]

    if (-Not $DirectoryPath) {
        Get-Help $PSCommandPath
        exit 1
    }
}

#====================================================================
# ディレクトリパスの存在確認
#====================================================================
if (Test-Path -PathType Container -Path $DirectoryPath) {
    # 指定されたパスはディレクトリであり、存在している。
    $True
} else {
    # 指定されたパスはディレクトリではない。
    if (Test-Path -PathType Leaf -Path $DirectoryPath) {
        # 指定されたパスはファイル。
        $infomsg = "$DirectoryPath : " `
            + "ファイルです。"
    } else {
        # 指定されたパスは存在しない。
        $infomsg = "$DirectoryPath : " `
            + "そのようなディレクトリは存在しません。"
    }
    Write-Host $infomsg
    $False
}

パイプで渡ってくるデータは必ずしもパスが1つだけとは限らない。「dir」の出力が渡ってきたときなどは複数のパスが流れてくることになる。前回はパイプからの入力を「@($input)[0]」のようにアクセスすることで強制的に最初の1つに絞っていたわけだが、今回はパイプで流れてくる全てのデータを処理するように書き換えていく。

パイプから複数のパス指定を取るバージョン

というわけで、最初に答えからだ。以下のように書き換えることで、パイプから渡されてくるデータをすべてパスとして判定処理することができる(test-d_16.ps1)。

#!/usr/bin/env pwsh

<#
.SYNOPSIS
ディレクトリパスが存在するかどうかを判定。

.DESCRIPTION
指定されたパスがディレクトリパスであり、かつ、存在するかどうかを判定する。

.PARAMETER DirectoryPath
ディレクトリパスを指定。

.PARAMETER Help
ヘルプメッセージを表示。

.INPUTS
ディレクトリパス。引数でディレクトリパスが指定されていない場合に使われる。

.OUTPUTS
System.Boolean。ディレクトリパスが存在する場合にTrue、そうでない場合にFalse。

.EXAMPLE
PS> .\test-d .\Documents\
True

.EXAMPLE
PS> .\test-d .\Documents-non-exists\
False

.EXAMPLE
PS> dir | .\test-d
C:\Users\daichi\dir: True
C:\Users\daichi\file: False

.LINK
Test-Path
#>

#====================================================================
# 引数
#====================================================================
Param(
    [string]$DirectoryPath,  # ディレクトリを指定
    [switch]$Help          # ヘルプを表示
)

if ($Help) {
    Get-Help $PSCommandPath
    exit 1
}

#====================================================================
# 引数でディレクトリが指定されていない場合、パイプからディレクトリ
# パスの取得を試みつつ、ディレクトリパスの存在確認
#====================================================================
if (-Not $DirectoryPath) {
    $untreated = $True

    foreach ($DirectoryPath in $input) {
        $untreated = $False

        if (Test-Path -PathType Container -Path $DirectoryPath) {
            # 指定されたパスはディレクトリであり、存在している。
            $DirectoryPath + ": " + $True
        } else {
            # 指定されたパスはディレクトリではない。
            if (Test-Path -PathType Leaf -Path $DirectoryPath) {
                # 指定されたパスはファイル。
                $DirectoryPath + ": " + $False
            } else {
                # 指定されたパスは存在しない。
                $DirectoryPath + ": no such file or directory."
            }
        }
    }

    if ($untreated) {
        Get-Help $PSCommandPath
    }

    exit 1
}

#====================================================================
# ディレクトリパスの存在確認
#====================================================================
if (Test-Path -PathType Container -Path $DirectoryPath) {
    # 指定されたパスはディレクトリであり、存在している。
    $True
} else {
    # 指定されたパスはディレクトリではない。
    if (Test-Path -PathType Leaf -Path $DirectoryPath) {
        # 指定されたパスはファイル。
        $infomsg = "$DirectoryPath : " `
            + "ファイルです。"
    } else {
        # 指定されたパスは存在しない。
        $infomsg = "$DirectoryPath : " `
            + "そのようなディレクトリは存在しません。"
    }
    Write-Host $infomsg
    $False
}

具体的に、どの部分を書き換えたかを説明しよう。

変更した部分 - パイプ処理

まず、前回のスクリプトではパイプから渡されるデータを「@($input)[0]」でアクセスしていた。これだと最初の1個が強制的に処理の対象になる。該当部分は次のコードだ。

# 引数でディレクトリが指定されていない場合、パイプからディレクトリ
# パスの取得を試みる。
if (-Not $DirectoryPath) {
    $DirectoryPath = @($input)[0]

    if (-Not $DirectoryPath) {
        Get-Help $PSCommandPath
        exit 1
    }
}

まず、この部分を「@($input)[0]」のところ以外は意味が変わらないように、次のような感じに書き替える。

大枠の書き換え

#====================================================================
# 引数でディレクトリが指定されていない場合、パイプからディレクトリ
# パスの取得を試みつつ、ディレクトリパスの存在確認
#====================================================================
if (-Not $DirectoryPath) {
    $untreated = $True

// ここに新しい処理

    if ($untreated) {
        Get-Help $PSCommandPath
    }

    exit 1
}

これでパイプから何もデータが流れてこなかった場合にはヘルプが表示されるようになる。前回の処理を踏襲したものだ。

次に、パイプからデータを読み取ってそれぞれ処理するコードを追加する。ポイントは「foreach ($DirectoryPath in $input) { … }」のようにしてデータを個別に判定処理するようにしたところだ。次のように書き換えてある。

#====================================================================
# 引数でディレクトリが指定されていない場合、パイプからディレクトリ
# パスの取得を試みつつ、ディレクトリパスの存在確認
#====================================================================
if (-Not $DirectoryPath) {
    $untreated = $True

    foreach ($DirectoryPath in $input) {
        $untreated = $False

        if (Test-Path -PathType Container -Path $DirectoryPath) {
            # 指定されたパスはディレクトリであり、存在している。
            $DirectoryPath + ": " + $True
        } else {
            # 指定されたパスはディレクトリではない。
            if (Test-Path -PathType Leaf -Path $DirectoryPath) {
                # 指定されたパスはファイル。
                $DirectoryPath + ": " + $False
            } else {
                # 指定されたパスは存在しない。
                $DirectoryPath + ": no such file or directory."
            }
        }
    }

    if ($untreated) {
        Get-Help $PSCommandPath
    }

    exit 1
}

実行すると次のようになる。

パイプから複数のパスを取得して処理 その1

パイプから複数のパスを取得して処理 その2

このスクリプトの機能としては、ここまで仕上げれば十分だろう。

ヘルプをアップデート

パイプ経由でデータが来たときの挙動が変わったので、ヘルプの内容を書き換える。次の部分が前回のヘルプの内容だ。

.EXAMPLE
PS> dir | .\test-d
True

これを次のように書き換える。

.EXAMPLE
PS> dir | .\test-d
C:\Users\daichi\dir: True
C:\Users\daichi\file: False

実行すると、次のようにヘルプのサンプルが更新されたことを確認できる。

更新されたヘルプを確認

最初のスクリプトはこれでコンプリート

本連載では数回にわたり、ごく簡単な機能をピックアップしてPowerShellスクリプトに書き換えていく方法を取り上げてきた。スクリプトは用途に応じていくつも作成していくものだが、ここで取り上げたやり方は、ほかの多くのスクリプトへ応用することができる。

スクリプトのコツは、あまり詰め込まないこと、こだわらないこと、必要に応じて新しく作成したり、すぐに書き換えたりできるようにしておくことだ。あくまでも自分が使うツールとして、手軽にいつでも作れる――そういう位置付けで活用していきたい。

今後は、作業を自動化することで効率を高めることが重要になるのは言うまでもない。次回以降は、より実用的な機能を取り上げながらスクリプトを書く方法を紹介していく。