'What to append to a path to make it point to the file system root?

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?



Solution 1:[1]

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..\..\..\..\

Solution 2:[2]

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

Solution 3:[3]

The root is available in the FileInfo object.

PS C:\src\t> (Get-ChildItem -Path 'C:\Windows\System32\WindowsPowerShell\').PSDrive.Root
C:\

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 mklement0
Solution 2
Solution 3 lit