For various applications, I need to get the parent folder of some files to use to create other output.
$x = "C:\MyFolder\test.txt"
$parent = Split-Path (Split-Path $x) -Leaf
This works fine, unless I am near the top level.
$x = "C:\test.txt"
$parent = Split-Path (Split-Path $x) -Leaf
This works, and $parent = C:\
but there is no -Leaf
as such. What I am left with could be `D:, E:, F:" or maybe even a network location. What in general would be a good way to deal with these cases?
I could do:
if ($parent.length -eq 3) {
handle-top-level-situation
}
But this feels a little inelegant. Is there a better way to check on a top level when I am checking for a parent folder name in this way?
A solution based on .NET APIs:
Casting your path to [System.IO.FileInfo]
allows you to get the parent directory name via .Directory.Name
[System.IO.Path]::IsRooted()
tells you whether the name represents a root directory or UNC share.
"C:\MyFolder\test.txt", "C:\test.txt" | ForEach-Object {
$parent = ([IO.FileInfo] $_).Directory.Name
if ([IO.Path]::IsPathRooted($parent)) {
"parent dir. is root path: $parent"
} else {
"parent dir. name: $parent"
}
}
Output:
parent dir. name: MyFolder
parent dir. is root path: C:\
Alternatively, if you want to rule out files in root directories up front, before even trying to extract the parent directory name, you can use a regex with -notmatch
:
"C:\MyFolder\test.txt", "C:\test.txt" | ForEach-Object {
if ($_ -notmatch '^[a-z]:\\.+?\\.|^\\\\.+?\\.+?\\.') {
"file is located in a root dir: $_"
} else {
"parent dir. name: " + ([IO.FileInfo] $_).Directory.Name
}
}
Note: The above assumes:
regular full paths (no accidental doubling of \
such as in c:\\temp
), though the regex could be tweaked to handle them.
Windows path separators, i.e. \
; to make the regex cross-platform, replace all \\
instances with [\\/]
.