LoginSignup
1
2

More than 5 years have passed since last update.

続・全てのジャンクションを解決したパスを取得したい PSv2版

Last updated at Posted at 2016-11-13

前回の記事の続きです。

問題の確認

問題の箇所

    if ($tmpDir.Attributes -like "*ReparsePoint*")
    {
        $tmpDir=Get-Item $tmpDir.Target
    }

PowerShell v2.0 では[IO.DirectoryInfo]型に、ジャンクションなどのリンク先を示すTargetプロパティが追加されていない。
そのため、上記コードでは$tmpDir.Targetのところで$nullと評価されうまくいかなかった。

今回はこの箇所をcmd.exedirコマンドを使って強引に解決した。

関数を作成する

Get-Item $tmpDir.Targetと同じような動作を行うものとして、以下のような関数を作成した。

Function Solve-Junction #名前がいまいち
{
    param(
        [Parameter(Mandatory=$true)]
        [IO.DirectoryInfo]$InputDir
    )

    [String]$junctionName = $InputDir.Name
    [String]$dirTarget    = $InputDir.Fullname + "*"

    [Text.RegularExpressions.Match]$myMatch=
        # ファイル名・属性指定検索
        cmd.exe /c dir $dirTarget /al |

        # [Microsoft.PowerShell.Commands.MatchInfo]→
        Select-String -Pattern "<JUNCTION> +(.+) \[(.+)\]" |

        # [Text.RegularExpressions.Match]→
        ForEach-Object -Process {$_.Matches} |

        # "$_.Groups[1].Value"=(.+)が今のフォルダ名と一致したもののみフィルタリング
        Where-Object -FilterScript {$_.Groups[1].Value -eq $junctionName}


    #\[(.+)\]の(.+)部分
    Return Get-Item $myMatch.Groups[2].Value
}

この関数により「問題の箇所」を以下のように書き換えができる。

Get-Item $tmpDir.Target
#↓
Solve-Junction -InputDir $tmpDir

まとめ

PowerShell

前回の記事のコードに、上記の関数を追加しPowerShell v2.0非対応の部分を省くと以下のようになる。

○○.ps1
#引数
[String]$FilePath = $Args[0]

Function Solve-Junction #名前がいまいち
{
    param(
        [Parameter(Mandatory=$true)]
        [IO.DirectoryInfo]$InputDir
    )

    [String]$junctionName = $InputDir.Name
    [String]$dirTarget    = $InputDir.Fullname + "*"

    [Text.RegularExpressions.Match]$myMatch=
        # ファイル名・属性指定検索
        cmd.exe /c dir $dirTarget /al |

        # [Microsoft.PowerShell.Commands.MatchInfo]→
        Select-String -Pattern "<JUNCTION> +(.+) \[(.+)\]" |

        # [Text.RegularExpressions.Match]→
        ForEach-Object -Process {$_.Matches} |

        # "$_.Groups[1].Value"=(.+)が今のフォルダ名と一致したもののみフィルタリング
        Where-Object -FilterScript {$_.Groups[1].Value -eq $junctionName}

    #\[(.+)\]の(.+)部分
    Return Get-Item $myMatch.Groups[2].Value
}


[IO.FileSystemInfo]$argPath=Get-Item $FilePath

#一階層毎のフォルダ名配列 Leaf To Root
[Collections.Generic.IList[String]]$DirNameList = New-Object -TypeName Collections.Generic.List[String]


if ($argPath.Attributes -like "*Directory*")
{
    [IO.DirectoryInfo]$tmpDir = $argPath
} else {
    [IO.DirectoryInfo]$tmpDir = $argPath.Directory
}

do
{
    if ($tmpDir.Attributes -like "*ReparsePoint*")
    {
        $tmpDir = Solve-Junction -InputDir $tmpDir
    }

    #ジャンクション解決後のフォルダ名を取得する
    $DirNameList.Add($tmpDir.Name)

    $tmpDir = $tmpDir.Parent
}
until($tmpDir.FullName -eq $tmpDir.Root.FullName)

#Root To Leaf
$DirNameList.Reverse()


[String]$out = $tmpDir.FullName + ($DirNameList -join '\')

#フォルダを開く
Explorer.exe $out
#結果確認用
#$out

動作確認用bat

以下の記述のbatファイルで動作を確認。

○○.bat
@PowerShell.exe -Version 2.0 -ExecutionPolicy RemoteSigned %~dpn0.ps1 '%~1'

あとがき

望む動作のものは出来たが、なんとなくいまいちな感。
具体的には

  • 今回作った関数内のパイプ処理(無理やり感)
  • ファイル属性の判定方法(文字列化して比較)

あたりが気になる。

1
2
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
1
2