扱うパスが存在する場合
Test-Path
で$true
が返ってくるパスを扱う場合、Resolve-Path
で相互変換できる。
相対パスから絶対パスへの変換例
.ps1
$root = "C:\foo\bar" # 基準となるパス
$rltv = "..\baz.txt" # 相対パス
Push-Location $root
(Resolve-Path $rltv).Path # => C:\foo\baz.txt (変換される)
$root | Test-Path # => True
Resolve-Path $rltv | Test-Path # => True
Pop-Location
絶対パスから相対パスへの変換例
.ps1
$root = "C:\foo\bar" # 基準となるパス
$abs = "C:\foo\baz.txt" # 絶対パス
Push-Location $root
Resolve-Path $abs -Relative # => ..\baz.txt (変換される)
$root | Test-Path # => True
$abs | Test-Path # => True
Pop-Location
扱うパスが存在しない場合
Push-Location
とResolve-Path
は、存在しないパスを指定すると例外が発生するので別の方法が必要になる。
後述するConvert-LocalPath
を定義すると下記のようになんとかなる。
相対パスから絶対パスへの変換例
.ps1
$root = "X:\foo\bar\" # 基準となるパス
$rltv = "..\baz.txt" # 相対パス
$rltv | Convert-LocalPath -Location $root # => X:\foo\baz.txt (変換される)
$root | Test-Path # => False
$rltv | Convert-LocalPath -Location $root | Test-Path # => False
絶対パスから相対パスへの変換例
.ps1
$root = "X:\foo\bar\" # 基準となるパス
$abs = "X:\foo\baz.txt" # 絶対パス
$abs | Convert-LocalPath -Location $root -Relative # => ..\baz.txt (変換される)
$root | Test-Path # => False
$abs | Test-Path # => False
Convert-LocalPath
中身はURI クラスを使っているだけ。
.ps1
filter Convert-LocalPath
{
Param
(
[parameter(
Mandatory=$true,
ValueFromPipeline=$true,
ValueFromPipelineByPropertyName=$true
)]
[string] $Path,
[ValidateNotNullOrEmpty()]
[uri] $Location = (Get-Location).Path,
[switch] $Relative
)
if (-not $Relative) {return [uri]::new($Location, $Path).LocalPath}
$localPath = $Location.MakeRelative($Path) -replace '/', '\'
if ($localPath.StartsWith('.')) {$localPath} else {".\${localPath}"}
}
注意点
末尾に""がないとフォルダ扱いされません。
.ps1
PS C:\> "..\baz.txt" | Convert-LocalPath -Location "X:\foo\bar"
X:\baz.txt
Function
やVariable
などのPSDriveは扱えません。
.ps1
PS C:\> ".\NG" | Convert-LocalPath -Location "Function:"
./NG
PS C:\> ".\NG" | Convert-LocalPath -Location "Variable:"
./NG
小ネタ
動的型付けとオーバーロードの地獄感がすごい
.ps1
PS C:\> [URI]::new("Z:\", "zzz").LocalPath
Z:\
PS C:\> [URI]::new("Z:\", [string]"zzz").LocalPath
Z:\zzz
PS C:\> [URI]::new
OverloadDefinitions
-------------------
uri new(string uriString)
uri new(string uriString, bool dontEscape)
uri new(uri baseUri, string relativeUri, bool dontEscape)
uri new(string uriString, System.UriKind uriKind)
uri new(uri baseUri, string relativeUri)
uri new(uri baseUri, uri relativeUri)