I need to store a relative path, as an absolute path in a file. I've tried quite a few things, including:
$path = (resolve-path -path "C:\Folder\..\Folder2").Path.ToString()
Add-content "d:\textfile.txt" $path
Which leaves an empy file. So I'm stumped.
CodePudding user response:
The simplest way to resolve a relative and/or non-normalized path (one with components such as ..
and .
) to a normalized full path, directly as a string, is to use the Convert-Path
cmdlet:
Convert-Path -LiteralPath "C:\Folder\..\Folder2"
In the context of your command (note that Add-Content
appends to a preexisting target file; to write the given content only, use Set-Content
):
Add-Content "d:\textfile.txt" (Convert-Path -LiteralPath "C:\Folder\..\Folder2")
Note:
Unlike
Resolve-Path
,Convert-Path
returns a file-system-native path, which is generally preferable.- This means that file-system paths that are based on PowerShell-only drives (created with
New-PSDrive
) are resolved to the underlying native file-system location, as understood by outside processes too. (E.g., ifMyDrive:
is mapped toC:\Projects
,Convert-Path -LiteralPath MyDrive:\Foo
returnsC:\Projects\Foo
)
- This means that file-system paths that are based on PowerShell-only drives (created with
Like
Resolve-Path
,Convert-Path
requires that the item the path refers to exist - which is an unfortunate limitation, discussed in GitHub issue #2993.
If the input path refers to a nonexistent file or directory:
.NET offers the [System.IO.Path]::GetFullPath()
method, which offers the same functionality also for nonexistent paths.
The challenge is that relative paths are resolved to .NET's current (working) directory, which usually differs from PowerShell's - see this answer for more information.
In PowerShell (Core) 7 , you can work around this problem by specifying the reference path (to resolve the relative path against) explicitly:
# Note: The 'System.' prefix in the type literal is optional.
[IO.Path]::GetFullPath("C:\Folder\..\Folder2", $PWD.ProviderPath)
The automatic $PWD
variable refers to PowerShell's current location (directory). Note the use of .ProviderPath
, which again ensures uses of a file-system-native path. For maximum robustness - to guard agains the case where the current PowerShell location isn't a file-system location - use (Get-Location -PSProvider FileSystem).ProviderPath
.
In Windows PowerShell, where this method overload isn't available, a more cumbersome approach is needed, as suggested by Theo:
[IO.Path]::GetFullPath(
[IO.Path]::Combine($PWD.ProviderPath, "C:\Folder\..\Folder2")
)
[IO.Path]::Combine()
conditionally combines the first path given with the second one, if the latter is relative - otherwise, the latter is used as-is.[IO.Path]::GetFullPath()
then ensures normalization of the resulting full path (to resolve any.
and..
components).