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)