How to normalize a path in PowerShell?
You can use a combination of $pwd
, Join-Path
and [System.IO.Path]::GetFullPath
to get a fully qualified expanded path.
Since cd
(Set-Location
) doesn't change the process current working directory, simply passing a relative file name to a .NET API that doesn't understand PowerShell context, can have unintended side-effects, such as resolving to a path based off the initial working directory (not your current location).
What you do is you first qualify your path:
Join-Path (Join-Path $pwd fred\frog) '..\frag'
This yields (given my current location):
C:\WINDOWS\system32\fred\frog\..\frag
With an absolute base, it is now safe to call the .NET API GetFullPath
:
[System.IO.Path]::GetFullPath((Join-Path (Join-Path $pwd fred\frog) '..\frag'))
Which gives you the fully qualified path, with the ..
correctly resolved:
C:\WINDOWS\system32\fred\frag
It's not complicated either, personally, I disdain the solutions that depend on external scripts for this, it's simple problem solved rather aptly by Join-Path
and $pwd
(GetFullPath
is just to make it pretty). If you only want to keep only the relative part, you just add .Substring($pwd.Path.Trim('\').Length + 1)
and voila!
fred\frag
UPDATE
Thanks to @Dangph for pointing out the C:\
edge case.
You can expand ..\frag to its full path with resolve-path:
PS > resolve-path ..\frag
Try to normalize the path using the combine() method:
[io.path]::Combine("fred\frog",(resolve-path ..\frag).path)