Powershell: resolve path that might not exist?

Powershell

Powershell Problem Overview


I'm trying to process a list of files that may or may not be up to date and may or may not yet exist. In doing so, I need to resolve the full path of an item, even though the item may be specified with relative paths. However, Resolve-Path prints and error when used with a non-existant file.

For example, What's the simplest, cleanest way to resolve ".\newdir\newfile.txt" to "C:\Current\Working\Directory\newdir\newfile.txt" in Powershell?

Note that System.IO.Path's static method use with the process's working directory - which isn't the powershell current location.

Powershell Solutions


Solution 1 - Powershell

You want:

c:\path\exists\> $ExecutionContext.SessionState.Path.GetUnresolvedProviderPathFromPSPath(".\nonexist\foo.txt")

returns:

c:\path\exists\nonexists\foo.txt

This has the advantage of working with PSPaths, not native filesystem paths. A PSPath may not map 1-1 to a filesystem path, for example if you mount a psdrive with a multi-letter drive name.

What's a pspath?

ps c:\> new-psdrive temp filesystem c:\temp
...
ps c:\> cd temp:
ps temp:\> 

temp:\ is a drive-qualified pspath that maps to a win32 (native) path of c:\temp.

-Oisin

Solution 2 - Powershell

When Resolve-Path fails due to the file not existing, the fully resolved path is accessible from the thrown error object.

You can use a function like the following to fix Resolve-Path and make it work like you expect.

function Force-Resolve-Path {
    <#
    .SYNOPSIS
        Calls Resolve-Path but works for files that don't exist.
    .REMARKS
        From http://devhawk.net/blog/2010/1/22/fixing-powershells-busted-resolve-path-cmdlet
    #>
    param (
        [string] $FileName
    )
    
    $FileName = Resolve-Path $FileName -ErrorAction SilentlyContinue `
                                       -ErrorVariable _frperror
    if (-not($FileName)) {
        $FileName = $_frperror[0].TargetObject
    }
    
    return $FileName
}

Solution 3 - Powershell

I think you're on the right path. Just use [Environment]::CurrentDirectory to set .NET's notion of the process's current dir e.g.:

[Environment]::CurrentDirectory = $pwd
[IO.Path]::GetFullPath(".\xyz")

Solution 4 - Powershell

Join-Path (Resolve-Path .) newdir\newfile.txt

Solution 5 - Powershell

This has the advantage of not having to set the CLR Environment's current directory:

[IO.Path]::Combine($pwd,"non\existing\path")

###NOTE This is not functionally equivalent to x0n's answer. System.IO.Path.Combine only combines string path segments. Its main utility is keeping the developer from having to worry about slashes. GetUnresolvedProviderPathFromPSPath will traverse the input path relative to the present working directory, according to the .'s and ..'s.

Solution 6 - Powershell

I've found that the following works well enough.

$workingDirectory = Convert-Path (Resolve-Path -path ".")
$newFile = "newDir\newFile.txt"
Do-Something-With "$workingDirectory\$newFile"

Convert-Path can be used to get the path as a string, although this is not always the case. See this entry on COnvert-Path for more details.

Solution 7 - Powershell

function Get-FullName()
{
    [CmdletBinding()]
    Param(
        [Parameter(ValueFromPipeline = $True)] [object[]] $Path
    )
    Begin{
        $Path = @($Path);
    }
    Process{
        foreach($p in $Path)
        {
            if($p -eq $null -or $p -match '^\s*$'){$p = [IO.Path]::GetFullPath(".");}
            elseif($p -is [System.IO.FileInfo]){$p = $p.FullName;}
            else{$p = [IO.Path]::GetFullPath($p);}
            $p;
        }
    }
}

Solution 8 - Powershell

I ended up with this code in my case. I needed to create a file later in the the script, so this code presumes you have write access to the target folder.

$File = ".\newdir\newfile.txt"
If (Test-Path $File) {
    $Resolved = (Resolve-Path $File).Path
} else {
    New-Item $File -ItemType File | Out-Null
    $Resolved = (Resolve-Path $File).Path
    Remove-Item $File
}

I also enclosed New-Item in try..catch block, but that goes out of this question.

Solution 9 - Powershell

I had a similar issue where I needed to find the folder 3 levels up from a folder that does not exist yet to determine the name for a new folder I wanted to create... It's complicated. Anyway, this is what I ended up doing:

($path -split "\\" | select -SkipLast 3) -join "\\"

Solution 10 - Powershell

You can just set the -errorAction to "SilentlyContinue" and use Resolve-Path

5 >  (Resolve-Path .\AllFilerData.xml -ea 0).Path
C:\Users\Andy.Schneider\Documents\WindowsPowerShell\Scripts\AllFilerData.xml

6 >  (Resolve-Path .\DoesNotExist -ea 0).Path

7 >

Solution 11 - Powershell

There is an accepted answer here, but it is quite lengthy and there is a simpler alternative available.

In any recent version of Powershell, you can use Test-Path -IsValid -Path 'C:\Probably Fake\Path.txt'

This simply verifies that there are no illegal characters in the path and that the path could be used to store a file. If the target doesn't exist, Test-Path won't care in this instance -- it's only being asked to test if the provided path is potentially valid.

Solution 12 - Powershell

Both most popular answers don't work correctly on paths on not existing drives.

function NormalizePath($filename)
{
    $filename += '\'
    $filename = $filename -replace '\\(\.?\\)+','\'
    while ($filename -match '\\([^\\.]|\.[^\\.]|\.\.[^\\])[^\\]*\\\.\.\\') {
        $filename = $filename -replace '\\([^\\.]|\.[^\\.]|\.\.[^\\])[^\\]*\\\.\.\\','\'
    }
    return $filename.TrimEnd('\')
}

Solution 13 - Powershell

Check if the file exists before resolving:

if(Test-Path .\newdir\newfile.txt) { (Resolve-Path .\newdir\newfile.txt).Path }

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionEamon NerbonneView Question on Stackoverflow
Solution 1 - Powershellx0nView Answer on Stackoverflow
Solution 2 - PowershelljoshuapoehlsView Answer on Stackoverflow
Solution 3 - PowershellKeith HillView Answer on Stackoverflow
Solution 4 - PowershellMax ToroView Answer on Stackoverflow
Solution 5 - PowershellRonnie OverbyView Answer on Stackoverflow
Solution 6 - PowershellsavagentView Answer on Stackoverflow
Solution 7 - PowershellJust a learnerView Answer on Stackoverflow
Solution 8 - PowershellIgorView Answer on Stackoverflow
Solution 9 - Powershell4thexView Answer on Stackoverflow
Solution 10 - PowershellAndy SchneiderView Answer on Stackoverflow
Solution 11 - PowershellJoel FrancisView Answer on Stackoverflow
Solution 12 - PowershellIlyanView Answer on Stackoverflow
Solution 13 - Powershellshane carvalhoView Answer on Stackoverflow