前回の記事の続きです。
問題の確認
問題の箇所
if ($tmpDir.Attributes -like "*ReparsePoint*") { $tmpDir=Get-Item $tmpDir.Target }
PowerShell v2.0 では[IO.DirectoryInfo]
型に、ジャンクションなどのリンク先を示すTarget
プロパティが追加されていない。
そのため、上記コードでは$tmpDir.Target
のところで$null
と評価されうまくいかなかった。
今回はこの箇所をcmd.exe
のdir
コマンドを使って強引に解決した。
関数を作成する
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'
あとがき
望む動作のものは出来たが、なんとなくいまいちな感。
具体的には
- 今回作った関数内のパイプ処理(無理やり感)
- ファイル属性の判定方法(文字列化して比較)
あたりが気になる。