Get-Content appears to use the current working directory location to resolve realative paths. However, the .Net System.Io.File Open() method does not. What is the PowerShell-centric way to resolve a relative path for .Net?
PS C:\src\t> type .\ReadWays.ps1
[CmdletBinding()]
param (
[Parameter(Mandatory=$true)]
[String]$Path
)
Write-Host "Path is $Path"
Get-Content -Path $Path | Out-Null
if ([System.IO.StreamReader]$sr = [System.IO.File]::Open($Path, [System.IO.FileMode]::Open)) { $sr.Close() }
PS C:\src\t> .\ReadWays.ps1 -Path '.\t.txt'
Path is .\t.txt
MethodInvocationException: C:\src\t\ReadWays.ps1:8
Line |
8 | if ([System.IO.StreamReader]$sr = [System.IO.File]::Open($Path, [Syst …
| ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
| Exception calling "Open" with "2" argument(s): "Could not find file 'C:\Program Files\PowerShell\7\t.txt'."
PS C:\src\t> $PSVersionTable.PSVersion.ToString()
7.2.0
CodePudding user response:
I would personally type constraint the Path
parameter to System.IO.FileInfo
then you can access the FullName
property to handle relative paths:
param(
[ValidateScript({
if(Test-Path $_ -PathType Leaf)
{
return $true
}
throw 'Invalid File Path'
})]
[System.IO.FileInfo]$Path
)
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open(
$Path.FullName, [System.IO.FileMode]::Open
)
)
$reader.BaseStream
$reader.Close()
PS /> ./script.ps1 ./test.txt
Handle : 244
CanRead : True
CanWrite : True
SafeFileHandle : Microsoft.Win32.SafeHandles.SafeFileHandle
Name : /home/user/Documents/test.txt
IsAsync : False
Length : 381
Position : 0
CanSeek : True
CanTimeout : False
ReadTimeout :
WriteTimeout :
Above worked fine for me on Linux however, on Windows seem to behave differently, thanks to OP for pointing this out. To put it into perspective:
- On Linux
PS /home/user/Documents> ([System.IO.FileInfo]'./test.txt').FullName
/home/user/Documents/test.txt
- On Windows
PS C:\Users\User\Documents> ([System.IO.FileInfo]'.\test.txt').FullName
C:\Users\User\test.txt
Clearly, [System.IO.FileInfo]
can't handle relative paths as I expected, hence I have updated the code which works for me on Windows
and Linux:
param(
[ValidateScript({
if(Test-Path $_ -PathType Leaf)
{
return $true
}
throw 'Invalid File Path'
})]
[string]$Path
)
if(-not(Split-Path $Path -IsAbsolute))
{
[string]$Path = Resolve-Path $Path
}
$reader = [System.IO.StreamReader]::new(
[System.IO.File]::Open(
$Path, [System.IO.FileMode]::Open
)
)
$reader.BaseStream
$reader.Close()
CodePudding user response:
This is a common question. Somehow .net and powershell don't agree on the current directory.
[System.IO.File]::Open("$pwd\$Path", [System.IO.FileMode]::Open)