Vscode-powershell: System.IO.File functions behave differently in VSCode vs PS ISE

Created on 13 Mar 2020  路  11Comments  路  Source: PowerShell/vscode-powershell

I discovered much to my surprise that System.IO.File functions like Exists, WriteAllLines, Delete, ReadAllLines et al. behave DIFFERENTLY in VSCode Powershell Integrated Console versus the PowerShell ISE.

VSCode IGNORES any calls to Set-Location (or the DOS equivalent "cd") and the IO.File functions seem to believe that the current working directory is %USERPROFILE% = C:\Users\username. So if you use RELATIVE filename paths it looks in / writes to the wrong place. You have to use a Fully Qualified Filename with explicit path.

PowerShell ISE, on the other hand, respects the Set-Location call and the IO.File functions DO look in / write to the correct relative location.

See attached code to demonstrate the issue. You will likely want to change $script:ScriptDir on line 6 to a local path of your choice (NOT in your user profile) and set $bRunningInVSCode to $true or $false depending on which debugger you're running. I loaded the file into both debuggers and pressed F5 to run. (You'll have to rename it to *.ps1 - GitHub doesn't tolerate *.ps1 files.)
VSCodeBugWith.NetFunctionRelativePaths.ps1.txt

I can't afford the time needed to re-test ALL of my PowerShell scripts to see what OTHER incompatibilities are lurking. VS Code is a huge improvement over PS ISE (which doesn't say much) but I can't trust it.

Am I missing a configuration somewhere???

Resolution-Answered

Most helpful comment

Oh wow. I didn't know that even the ISE is not consistent with the PS console!!

I agree using Resolve-Path or $PSScriptRoot or specifying a Fully Qualified Path would all solve this issue. Now that I KNOW this affects all .Net function calls I can be vigilant.

And it sounds very possible my invocation of the PS ISE could be involved here.

But good Lord I don't dare trust any of my existing scripts that were developed in the PS ISE (using a similar shortcut) to run without completely retesting them in VS Code!! I would have to change HUNDREDS of places to fix all this.

So for now the existing scripts need to be left alone and I'll have to continue to run them in PS ISE until I have time to run V&V on them.

For all new development moving forward I'll use VS Code which at least brings the dev environment into the new millennium, kinda. Still not as powerful as the full blown Visual Studio.

Thanks for your help!!!!

All 11 comments

This behavior is consistent with the PowerShell console. Related issue (and explanation): PowerShell/PowerShell#9829

The explanation is fine for what it is, but my issue is that VS Code and PS ISE execute the SAME CODE differently.

I can see how e.g. the .Net functions would have a different concept of "current directory" from the PowerShell Set-Location cmdlet, but this should not change when you run it in different environments. That frightens me.

Unless of course there is something inherent in the VS Code environment setup / launch that is setting my >> DOT NET << current directory to my user directory whereas PS ISE is setting it to the current directory in the desktop shortcut.

In particular, my PS ISE desktop shortcut is
%windir%\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe BackupVMServeVMs.ps1
with a "Start in" value of
C:\Project\vSphereBackup

I am launching VS Code standalone (no workspace) using another shortcut:
"C:\Program Files\Microsoft VS Code\Code.exe"

Is there something I'm missing here in the environment setup / launch that is setting the .Net current directory differently?

The explanation is fine for what it is, but my issue is that VS Code and PS ISE execute the SAME CODE differently.

To clarify, I mean that the ISE is inconsistent with the behavior of the PowerShell console. So developing in the ISE and then actually invoking in powershell.exe/pwsh will cause the same confusion as ISE to this extension.

I can see how e.g. the .Net functions would have a different concept of "current directory" from the PowerShell Set-Location cmdlet, but this should not change when you run it in different environments. That frightens me.

Yeah I agree. I don't know the reasons behind the decision to make the ISE work differently than the console. If VSCode does the same thing though, that just makes the script a lot more likely to break when it's actually deployed.

In particular, my PS ISE desktop shortcut is
%windir%\system32\WindowsPowerShell\v1.0\PowerShell_ISE.exe BackupVMServeVMs.ps1
with a "Start in" value of
C:\Project\vSphereBackup

I am launching VS Code standalone (no workspace) using another shortcut:
"C:\Program Files\Microsoft VS Code\Code.exe"

Is there something I'm missing here in the environment setup / launch that is setting the .Net current directory differently?

For the ISE, your shortcut is setting (with Start in) the process level current directory (which is what [Environment]::CurrentDirectory reports and what the System.IO.* API's use for resolution). For VSCode if you open a workspace, that will also set the process level current directory.

Really though, I would recommend using PowerShell's path resolution (e.g. Resolve-Path) before passing to a .NET (or other) API. Also consider using automatic variables like $PSScriptRoot which will contain the path to the directory where the script itself is located.

Actually now that I check, the ISE doesn't seem follow Set-Location/cd for me. I think it's just the shortcut you're using.

Oh wow. I didn't know that even the ISE is not consistent with the PS console!!

I agree using Resolve-Path or $PSScriptRoot or specifying a Fully Qualified Path would all solve this issue. Now that I KNOW this affects all .Net function calls I can be vigilant.

And it sounds very possible my invocation of the PS ISE could be involved here.

But good Lord I don't dare trust any of my existing scripts that were developed in the PS ISE (using a similar shortcut) to run without completely retesting them in VS Code!! I would have to change HUNDREDS of places to fix all this.

So for now the existing scripts need to be left alone and I'll have to continue to run them in PS ISE until I have time to run V&V on them.

For all new development moving forward I'll use VS Code which at least brings the dev environment into the new millennium, kinda. Still not as powerful as the full blown Visual Studio.

Thanks for your help!!!!

@SeeminglyScience thank you so much for helping @billcumming!

But good Lord I don't dare trust any of my existing scripts that were developed in the PS ISE (using a similar shortcut) to run without completely retesting them in VS Code!! I would have to change HUNDREDS of places to fix all this.

It sounds like this could be a nice PSSA rule, especially since it's an effect in a static .NET API. We could even implement a correction to automate conversion.

I have pretty simple scripts for deploying onesie VMs from my developer desktop, and none of them spawn other processes. It sounds like it's not best practice to call [System.IO.Directory]::SetCurrentDirectory($PSScriptRoot) for concern over affecting other processes. But I just had PS console, PS ISE and VS Code windows all open at the same time and calling it in one session did not affect the others.

It would be a MUCH simpler fix to my existing scripts to use SetCurrentDirectory up front so that VS Code and PS console will behave the same as the (ahem, less than optimal) PS ISE, rather than patching the scripts all over the place to set explicit paths, and risk missing a spot.

I'm not running scripts on a production server, so again the "multiple processes" issue is moot in my case.

What are the risks of using SetCurrentDirectory at the top of my scripts?

[System.IO.Directory]::SetCurrentDirectory($PSScriptRoot) for concern over affecting other processes.

The concern is other runspaces, not other processes. It will affect any other runspaces (like things running in jobs) in the same runspace.

SetCurrentDirectory will set an environment variable within the process, so anything depending on that (including any .NET APIs) will be affected.

I'm not using runspaces. As long as I'm using separate PS ISE / PS console / VS Code instances, it SEEMS like (from very brief testing) the 3 are isolated from each other in terms of SetCurrentDirectory.

Is that correct?

@billcumming It's very difficult for any of us to give you a direct yes or no on if you will have any issues. It's entirely dependent on what type of tools you use, and to be honest most of us just don't write code that way. That makes it hard for us to tell you exactly what might burn you in the long run.

Sometimes you gotta do what you gotta do. If you decide to go that route, test a lot, and keep it in the back of your mind when issues come up.

Was this page helpful?
0 / 5 - 0 ratings