Reputation: 520
PowerShell:
$file = "text.txt"
Test-Path $file
# True
Get-Location
# C:\Users\Fors1k
[IO.File]::OpenRead($file)
# FileStream
[IO.FileInfo]::new($file)
# Mode LastWriteTime Length Name
# ---- ------------- ------ ----
# -a---- 05.03.2021 18:12 7 text.txt
gc $file
# test123
Everything is ok.
PowerShell Core:
$file = "text.txt"
Test-Path $file
# True
Get-Location
# C:\Users\Fors1k
[IO.File]::OpenRead($file)
# Exception calling "OpenRead" with "1" argument(s): "Could not find file 'C:\Windows\system32\text.txt'."
[IO.FileInfo]::new($file)
# Mode LastWriteTime Length Name
# ---- ------------- ------ ----
# larhs 01.01.1601 3:00
gc $file
# test123
Here i got errors.
As i understand, problem is that the .NET methods think, that current location is sysfolder, not real current location.
Responding to recommendations:
I understand, that there are many solutions:
$file = "text.txt"
[Environment]::CurrentDirectory = Get-Location
[IO.File]::OpenRead($file)
#
#
$file = "text.txt"
[IO.Directory]::SetCurrentDirectory((Get-Location))
[IO.File]::OpenRead($file)
#
#
$file = "text.txt"
$file = Convert-Path $file
[IO.File]::OpenRead($file)
#
#
# My solution, before asking, was
$file = "text.txt"
$file = Get-Item $file
[IO.File]::OpenRead($file)
But all of this is "fix on the go"(I don't know the correct English idiom for this phrase).
I mean, why this works normally on posh 5.1?
Why this code: [IO.File]::OpenRead("text.txt")
works on pwsh my friends, which ones I asked?
Maybe there is still a setting like (exaggerating):[DotNet.Path]::SetDefaultLocation("TheSameAsPwsh")
@mathias-r-jessen , got your point:
[Environment]::CurrentDirectory and Get-Location is a initially unrelated things.
PowerShell:
"$(Get-Location)" -eq ([Environment]::CurrentDirectory)
# True
##
##
Set-Location ([Environment]::GetFolderPath("desktop"))
"$(Get-Location)" -eq ([Environment]::CurrentDirectory)
# False (!!!)
So, my question with an understanding of what is happening:
Why my pwsh has [Environment]::CurrentDirectory
as C:\Windows\system32, and is it possible to change this default value to user folder like it is in posh?
Upvotes: 3
Views: 2174
Reputation: 3859
Change the current working directory for .NET.
[Environment]::CurrentDirectory = "$(Get-Location)"
or
[System.IO.Directory]::SetCurrentDirectory("$(Get-Location)")
Alternative code - Same result
Your code uses Streams. You should free/close the stream resources at end, with try -finally.
$file = "text.txt"
if (! (Test-Path $file -PathType Leaf)) {
New-Item $file
}
Get-Content $file
File.OpenRead(String path) Method
Remarks
The path parameter is permitted to specify relative or absolute path information. Relative path information is interpreted as relative to the current working directory. To obtain the current working directory, see GetCurrentDirectory.
Directory.GetCurrentDirectory Method
Remarks
The current directory is distinct from the original directory, which is the one from which the process was started.
Checking this method in pwsh.exe and powershell.exe. The returned values are different. I think that each one has a different implementation.
if you run your code from script file. i.e. ./Script.ps1 You can use $PSScriptroot global variable, it contains the path of the directory where the script is running.
Write-Host "ScriptPath: $PSScriptroot"
[Environment]::CurrentDirectory = "$PSScriptroot"
Write-Host "CurrentDirectory: $([Environment]::CurrentDirectory)"
Upvotes: 6
Reputation: 174445
Changing locations in PowerShell doesn't automatically update the process' working directory - which is what .NET uses to resolve relative paths internally.
As Joma's answer excellently suggests, you can solve this by updating [Environment]::CurrentDirectory
before invoking the method.
If you find yourself running into this issue often when using PowerShell interactively, add a mechanism for updating it to your prompt (the following example is lifted straight out of one of my own profile scripts) - this will keep the two "in sync":
$function:prompt = {
if($PWD.Provider -eq 'FileSystem'){
[Environment]::CurrentDirectory = $PWD.Path
}
"PS $($executionContext.SessionState.Path.CurrentLocation -replace [regex]::Escape($HOME),'~')$('>' * ($nestedPromptLevel + 1)) "
}
Upvotes: 2