21
votes

When you use a .NET object from PowerShell, and it takes a filename, it always seems to be relative to C:\Windows\System32.

For example:

[IO.File]::WriteAllText('hello.txt', 'Hello World')

...will write C:\Windows\System32\hello.txt, rather than C:\Current\Directory\hello.txt

Why does PowerShell do this? Can this behaviour be changed? If it can't be changed, how do I work around it?

I've tried Resolve-Path, but that only works with files that already exist, and it's far too verbose to be doing all the time.

6

6 Answers

29
votes

You can change .net working dir to powershell working dir:
[Environment]::CurrentDirectory = (Get-Location -PSProvider FileSystem).ProviderPath
After this line all .net methods like [io.path]::GetFullPath and [IO.File]::WriteAllText will work without problems

15
votes

The reasons PowerShell doesn't keep the .NET notion of current working directory in sync with PowerShell's notion of the working dir are:

  1. PowerShell working dirs can be in a provider that isn't even file system based e.g. HKLM:\Software
  2. A single PowerShell process can have multiple runspaces. Each runspace can be cd`d into a different file system location. However the .NET/process "working directory" is essentially a global for the process and wouldn't work for a scenario where there can be multiple working dirs (one per runspace).
4
votes

For convenience, I added the following to my prompt function, so that it runs whenever a command finishes:

# Make .NET's current directory follow PowerShell's
# current directory, if possible.
if ($PWD.Provider.Name -eq 'FileSystem') {
    [System.IO.Directory]::SetCurrentDirectory($PWD)
}

This is not necessarily a great idea, because it means that some scripts (that assume that the Win32 working directory tracks the PowerShell working directory) will work on my machine, but not necessarily on others.

2
votes

When you use filenames in .Net methods, the best practice is to use fully-qualified path names. Or use

$pwd\foo.cer

If you do in powershell console from:

C:\> [Environment]::CurrentDirectory

C:\WINDOWS\system32\WindowsPowerShell\v1.0

you can see what folder .net use.

1
votes

That's probably because PowerShell is running in System32. When you cd to a directory in PowerShell, it doesn't actually change the working directory of powershell.exe.

See:

PowerTip article on syncing the two directories

Channel9 forum thread

0
votes

I ran into the same problem a long time ago and now I add the following to the beginning of my profile:

# Setup user environment when running session under alternate credentials and
# logged in as a normal user.
if ((Get-PSProvider FileSystem).Home -eq "")
{
    Set-Variable HOME $env:USERPROFILE -Force
    $env:HOMEDRIVE = Split-Path $HOME -Qualifier
    $env:HOMEPATH = Split-Path $HOME -NoQualifier
    (Get-PSProvider FileSystem).Home = $HOME
    Set-Location $HOME
}