Reputation: 7139
I have some path, let's say C:\Windows\System32\WindowsPowerShell\
. I would like to find such a string, that when appended (from the right side), will make this path point to C:\
.
Well, that is easy if the path is set; I could just make it C:\Windows\System32\WindowsPowerShell\..\..\..\
.
What I am looking for however, is a fixed string that would work every time, no matter how the initial path looks (and especially how long it is). Does Windows offer some tricks to help this? If it is impossible to achieve, then it's a valid answer.
Bonus points: can I refer to a different hard drive this way?
Upvotes: 0
Views: 168
Reputation: 16236
The root is available in the FileInfo object.
PS C:\src\t> (Get-ChildItem -Path 'C:\Windows\System32\WindowsPowerShell\').PSDrive.Root
C:\
Upvotes: 0
Reputation: 437823
A fixed string is not an option, but it's easy to dynamically construct one for a given path of arbitrary length.
Taking advantage of the fact that *
, when applied to string on the LHS, replicates that string a given number of times (e.g., 'x' * 3
yields xxx
):
# Sample input path.
$path = 'C:\Windows\System32\WindowsPowerShell'
# Concatenate as many '..\' instances as there are components in the path.
$relativePathToRoot = '..\' * $path.Split('\').Count
$absolutePathToRoot = Join-Path $path $relativePathToRoot
# Sample output
[pscustomobject] @{
RelativePathToRoot = $relativePathToRoot
AbsolutePathToRoot = $absolutePathToRoot
}
Note: On Unix, use '../' * $path.Split('/').Count
; for a cross-platform solution, use "..$([IO.Path]::DirectorySeparatorChar)" * $path.Split([IO.Path]::DirectorySeparatorChar).Count
; for a solution that can handle either separator on either platform (and uses /
in the result), use '../' * ($path -split '[\\/]').Count
Output:
RelativePathToRoot AbsolutePathToRoot
------------------ ------------------
..\..\..\..\ C:\Windows\System32\WindowsPowerShell..\..\..\..\
Upvotes: 1
Reputation: 174485
Use Convert-Path
to resolve/consolidate the given path, then keep adding ..
until you reach the root of the volume:
# Grab current location from `$pwd` automatic variable
$path = "$pwd"
# Calculate path root
$root = [System.IO.Path]::GetPathRoot($path)
while((Convert-Path $path) -ne $root){
# We haven't reached the root yet, keep backing up
$path = Join-Path $path '..'
}
$path
now contains C:\Current\Relative\Path\..\..\..
and you can now do:
& path\to\myBinary.exe (Join-Path $path.Replace("$pwd","").TrimStart('\') targetfile.ext)
$path.Replace("$pwd", "")
gives us just \..\..\..
, and TrimStart('\')
removes the leading path separator so as to make the path relative, so the resulting string passed to the binary will be ..\..\..\targetfile.ext
Upvotes: 2