あるパスから全てのジャンクションを解決したパス(要するに本来の場所のパス)を取得したいと思った。
汚いなりに形が出来たと喜んだのも束の間、対象としたいWindows7(PowerShell v2.0)では動かなそうなことが判明。
とりあえず現状を備忘録として残す。
思考の流れ
Get-Item 'フォルダパス'
でSystem.IO.DirectoryInfo
を取得すれば、Attribute
からリパースポイント(ジャンクションなど)かどうかわかる(参考)。一階層ずつジャンクションかどうか判断し、ジャンクションなら本来の場所へ移動して、また登って行けば良い。
ルートフォルダまで辿り着いたら探索終了とし、それまで通ってきたフォルダの履歴をパスとして接合する。
出来上がったもの
#引数の設定
Param(
[Parameter (Mandatory=$true)]
[String]$FilePath #=$Args[0]
)
[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 = Get-Item $tmpDir.Target
}
#ジャンクション解決後のフォルダ名を取得する
$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
使用例
上記のコードを"Solve-JunctionPath.ps1"という名前で保存し、同じ場所に以下のようなbatファイルを作成する。
@PowerShell.exe -ExecutionPolicy RemoteSigned %~dp0\Solve-JunctionPath.ps1 '%~1'
このバッチファイルに調べたいパスを送ると、本来の場所のフォルダが開く。
問題の箇所
if ($tmpDir.Attributes -like "*ReparsePoint*")
{
$tmpDir=Get-Item $tmpDir.Target
}
PowerShell 2.0では
(161110修正)
DirectoryInfoのAttributesに再解析ポイントかどうかの情報を持たないので、
リンク先本来の場所の情報を持たない(.Target
プロパティが存在しない)ため、
この方法では辿ることができない。
実際、Get-Member
をしてみると.Target
プロパティはCodeProperty
となっている。
つまりPowerShell側で追加されたプロパティであるため、PowerShellのバージョンが低いと存在しないということになる。
対応策
とりあえず思いつく解決策としては、
cmd.exe /c dir "ディレクトリパス" /AL
の出力結果を正規表現なりで解析する方法。
更新日時 <JUNCTION> ジャンクション名 [参照先]
の形式で取得できるのでジャンクション名で判定し、参照先へ移動、すれば何とかなると思われる。
参考
PowerShell で シンボリックリンクを 使えるようにしよう
PowerShellでジャンクションを作ったら削除はRomove-Itemしてはダメ