Powershell: Use forward slashes by default in Windows

Created on 11 Sep 2019  ·  49Comments  ·  Source: PowerShell/PowerShell

Summary of the new feature/enhancement

PowerShell aims to be cross-platform, but I have been having many issues operating on paths across both Windows and Linux. I understand the need to support \ in Windows for the foreseeable future, but I would at least like the default path character to be the same on both Windows and *nix, presumably by setting the default path delimiter to /. The current alternative is forcing users to normalize paths themselves with -replace "\\", "/" in their paths.

Issue-Enhancement Resolution-By Design

Most helpful comment

I think it would be nice if path completion used the path separator that appears explicitly in the completion text, and if there is none, then default to the platform native separator.

So on Windows, c:\w completes to c:\Windows\ and c:/w completes to 'c:/Windows/'.

I think this would cover a majority of the annoyances without requiring a configuration option, and is actually preferable because you occasionally might need the other form for whatever reason.

All 49 comments

The current alternative is forcing users to normalize paths

PowerShell already does the work for you and you have no need to normalize paths.
PowerShell is very user-friendly here - users can use slashes which they are comfortable regardless of platform.
Best practice is to avoid using literal paths and use path cmdlets.

Best practice is to avoid using literal paths and use path cmdlets.

@iSazonov Yes and no.

Sure, if you are combining path segments, you can use path cmdlets. But if you are writing a script that references a relative path with multiple segments, and if you intend for your script to work cross platform, you're not going to do that.

In PowerShell 7 preview 3 on Windows, tab completion completes paths using a backslash. That is the one place where I think we're doing it wrong now that PowerShell is cross platform. There should at least be an option to select the directory separator character you want used on Windows as part of tab completion: either [System.IO.Path]::DirectorySeparatorChar or [System.IO.Path]::AltDirectorySeparatorChar. Given where we are today, I suspect most folks who do any cross platform work would want tab completion of paths to use AltDirectorySeparatorChar on Windows by default, but as far as I know there is no way to make it do that.

@chriskuech: Aside from tab completion of paths, are there other places where you feel AltDirectorySeparatorChar isn't being used where you would like to have an option for it to be used instead of DirectorySeparatorChar? I can't think of any.

@KirkMunro , are you saying that there is an (at least partially implemented) way to normalize paths in PowerShell today? If so, will it work on latest 6.x? The use cases I was having an issue with were automatic variables and *-Path commands.

@iSazonov, the proposed solution would not have worked for my scenario because I generated a list of paths on Windows, generated a list of paths on Linux, then attempted to compare them, which failed due to the separators.

The automatic variables consistently lack a trailing directory separator, so PowerShell beautifully allows creating paths with literals. Ex:

$RepoRoot = "$PSScriptRoot/../.."
$SourceRoot = "$RepoRoot/src"
$BuildRoot = "$RepoRoot/.build"

I think this is much more clear than

$RepoRoot = Join-Path $PSScriptRoot "../.."
$SourceRoot = Join-Path $RepoRoot "src"
$BuildRoot = Join-Path $RepoRoot ".build"

so I hope it can work in the future, even if not by default.

@chriskuech my personal habit has become something like:

$SourceRoot = $RepoRoot | Join-Path -ChildPath 'src'

It's a little clearer but yeah it's not perfect.

Join-Path has AdditionalChildPath which accept string array.

@chriskuech Thanks for the additional information.

I wasn't suggesting that PowerShell partially supports normalization of paths. I was simply calling out that I personally dislike that tab completion uses a backward slash by default on Windows, and a forward slash by default on Linux or macOS.

If I could tweak some setting to change that so that forward slash is used even on Windows paths by default, I would make that change, and this is one place where I think there may be an opportunity to make cross platform PowerShell work easier. Join-Path uses [System.IO.Path]::DirectorySeparatorChar as the path separator as well. Ideally if there were a setting to set the desired path separator when writing scripts (because we should be able to easily write scripts the way we want regardless of the platform we choose to write them on), it would be reflected in both tab completion of paths and Join-Path as well.

Those personal needs aside, I wonder if a Compare-Path cmdlet would be useful. It could normalize the path separators, and even compare absolute paths with relative paths by resolving relative paths before the comparison is made if one of the paths is absolute.

Well, we do get _platform-specific_ normalization in Convert-Path and Resolve-Path:

PS> Convert-Path C:/Windows
C:\Windows # normalized to Windows-native "\"

So, perhaps as an alternative to introducing a Compare-Path cmdlet, Convert-Path and Resolve-Path could be extended to support a -UseSlash switch (name negotiable).

Separately and complementarily, the opt-in preference mechanism for using / on Windows that Kirk suggests could then also apply to Convert-Path and Resolve-Path (in addition to tab completion and Join-Path).

The catch at the moment is that Convert-Path and Resolve-Path only work with _existing_ paths, but that is something well worth changing in its own right, as @jaykul suggested a looong time ago - see #2993

I think it would be nice if path completion used the path separator that appears explicitly in the completion text, and if there is none, then default to the platform native separator.

So on Windows, c:\w completes to c:\Windows\ and c:/w completes to 'c:/Windows/'.

I think this would cover a majority of the annoyances without requiring a configuration option, and is actually preferable because you occasionally might need the other form for whatever reason.

@lzybkr, I like the idea, also in light of a concern regarding a configuration- / preference-variable-based solution that I neglected to mention: the scoping issue; with the usual _dynamic_ scoping, code that makes fixed assumptions about path separators may break (which has echoes of https://github.com/PowerShell/PowerShell-RFC/issues/7).

@lzybkr and when both slashes are used? C:\Program Files/A -> ?

So many options - random, alternate each one, always forward slash b/c it's the one true path separator, etc.

More seriously, maybe just pick the last one used, that is probably typed by the user whereas others might not be.

@lzybkr: There's one catch, though:

If you start _without_ a path separator, in order to reference a file/folder in the _current directory_, PowerShell will have to make the choice for you, at least based on the current completion algorithm that expands to .\<filename> or ./<filename> / .\<folder>\ or ./<folder>/, platform-appropriately.

For _files_ as _arguments_, we could sidestep that problem by expanding fil to just file, for instance (no .\ / ./ prefix).

However:

  • for _executables_ , the automatically added .\ / ./ prefix is a valuable convenience if the intent is indeed to execute a script located in the current directory.

  • for _directories_, similarly, expanding to something with a _trailing path separator_ (<folder>\ or <folder>/) is valuable too.

In both cases there's no user action to imply the preferred separator.

That said, perhaps the solution is: if you want to control the separator, _manually start with_ ./ or .\ and make tab completion respect that.

This issue has been marked as answered and has not had any activity for 1 day. It has been closed for housekeeping purposes.

@iSazonov: This isn't really answered, and should be reopened to allow the ongoing discussion to continue working this out. The OP hasn't even had a chance to respond to questions asked back to him.

I think I addressed all the questions to me, but let me know if I didn't. I too am not sure why this issue is closed. It wasn't meant as a discussion thread, rather a feature request.

The root issue at hand:

  • Should a cross-platform tool have non-cross-platform behavior by default?
  • If so, should there be a way to globally run PowerShell in a "cross-platform" mode?

I think forcing devs to manually normalize strings with cmdlets is a definite wrong move. I don't see any scenarios where using / by default would cause issues on Windows because PowerShell, as previously mentioned, is very good about handling both kinds of slashes. Unless anyone can provide compelling situations where this would cause error, why not just use / by default? Perhaps this issue needs to move to an RFC.

As more people migrate to the cloud, more and more people develop PowerShell code on Windows and run it on Linux. There will certainly be a point in the future (if not already passed) where the number of users preferring true cross-platform behavior exceeds any who feel strongly about keeping \ on Windows.

@chriskuech: My bad, I didn't specifically pose the question to you. I was wondering if you felt a Conpare-Path cmdlet would help you out. That question aside though, I would like to see normalization options as well.

@KirkMunro I'm not sure Compare-Path would help, because in the original use case (comparing paths on Linux and Windows), the root file system is different, so I have to call Resolve-Path -Relative. At that point the comparison use case is just a one-liner: | ? {($_ -replace "\\", "/") -in $ExpectedPaths}.

However, I am very hesitant to endorse any cmdlet-based solution, as it doesn't solve the root issue and will either disallow string interpolation for paths or require code changes to every path string definition. Specifically, Compare-Path won't fix all my logged paths with mixed slashes.

@KirkMunro @mklement0 The issue is not locked and everyone can pull comments.
We have a lot of issues without new comments and progress. Open status has lost its meaning.
As a maintainer, I intend to be more exacting in order to encourage discussions to become more rigorous specifications that can easily turn into PRs.
As for the issue, it turns into infinite - initial request was "use forward slash on Windows", then "compare paths". What is next? Remoting? It is open to continue but will be closed.
While only one real proposal from Jason was above (to enhance completion) and we could open a tracking issue and close it by real PR.

To be clear, the issue is still "use forward slash on Windows". "Compare paths" was only brought up as one (of multiple) motivating examples.

Proposal
Implement true cross-platform behavior, where the path delimiter defaults to / on all platforms unless the user is tab-completing a path already containing \. I would expect this to be hidden as an experimental feature for now, but I should at least be able to enable a "maximize cross-platform behavior" feature in my code for optimizing the dev experience of Windows devs targeting Linux.

If this is unreasonable, I would like to know why and if there is documentation guiding when PowerShell design diverges across platforms.

@iSazonov: Maintainers of the PS repo shouldn't be dismissive to users issues without discussion. You originally replied without taking the time to understand the needs of the OP, marking the issue as answered, but the issue was not posted as a question, it was posted as a feature request, and as can be seen by the discussion it is clearly not "answered".

Open status has lost its meaning.

Who says? That's absolutely not true. An open issue is open, and a closed issue is closed. Those two distinctions have very clear meaning. I only look at closed issues if they are my own and I want to go back to check something. On a rare occasion I may go searching closed issues for discussions on a certain topic. But 90% or more of my time in issues is in open issues, as it should be. The only thing blurring the line between the two and making open issues lose their meaning is summarily closing them before they are resolved, like you have done with this issue.

(The discussion) is open to continue but will be closed.

Based on this approach to managing issues, you're forcing people to lose the distinction between open and closed, such that they have to search all issues rather than focus on the open issues, which means checking the 2K open issues plus the 4K closed issues for discussions relevant to them instead of just focusing on the open issues. That is a broken, flawed issue management strategy.

As for the issue, it turns into infinite - initial request was "use forward slash on Windows", then "compare paths". What is next? Remoting?

That is ridiculous. The discussion is focused on dealing with Windows having a backslash as the default when you are writing scripts for cross platform. It has remained focused on that topic. You're trying to make it sound like it isn't focused at all.

@iSazonov, I agree that there are too many open issues; however, the fact that there are too many open issues does not mean we should be dismissive and shut conversation down prematurely on new issues. We must continue to encourage feedback and be open to discussion about PowerShell in open issues, and only close them once they are truly resolved. The volume of open issues must be dealt with differently.

Loyal linux users?Incomprehensible advice.
You can convince Microsoft. Ask them to use backslashes as system file paths.

I'd like to chime in here that there are usecases where literal paths with forward slashes are needed, even on Windows.

I was just writing a script where I was using .net APIs to manipulate and create zip archives. Adding entries to the zip file with this API:

    [System.IO.Compression.ZipFileExtensions]::CreateEntryFromFile(
        $zip, $file, $entry,
        [System.IO.Compression.CompressionLevel]::Optimal
    ) > $null

In this particular case, $entry is a path within the zip archive. If I simply pass the windows path as returned by various path cmdlets, every zip utility on the planet will spew warnings about my zip file having the wrong slashes.

Also as a long time linux user and developer, I love powershell and I've been having lots of fun learning it. I've been having fun playing with my new windows server core over ssh into powershell 7 too, and I have published scripts that work perfectly with powershell on linux. I was surprised how well that works. In fact, powershell is going to be my first choice for some programs/scripts that I want to be cross-platform.

But it still makes me sad seeing all my tab completions be rewritten with backslashes.

I use paths like /users/foo/somefile on windows all the time and that is what I want to use.

Most of the windows APIs support forward slashes just fine. I realize there are a few exceptions, with utilities and maybe APIs, namely some cmd.exe invocations, but I just want to set something in my $profile so that by default all my paths have forward slashes, unless I am using backslashes explicitly.

This would be inoffensive to windows users and developers used to the backslashes because they would simply not use this setting, and it would default to off. Of course, they may decide to use it too if for example they decide to write cross-platform scripts and modules more.

I want this setting for my scripts and modules too, so that I don't have unexpected problems like the one I showed above.

@iSazonov users can use slashes which they are comfortable regardless of platform.

Does this mean I can configure PowerShell to use forward slashes since that's more comfortable for me as a user? I would like to change the path displayed in the prompt as well as the tab autocompletion which currently changes forward slashes into backslashes.

@aaronfranke, no, there is currently no way to configure PowerShell this way; I think what @iSazonov was trying to say is that when you manually type a path, you're free to choose between \ and / (and you can even mix them in a single path).

Considering versatility, a new path symbol should be enabled instead of / and ,Traditional symbols increase the difficulty of conversion across platforms

I think what @iSazonov was trying to say is that when you manually type a path, you're free to choose between and / (and you can even mix them in a single path).

Yes, It is PowerShell design.

This is not a resolution of the issues that have been raised here, such as the forcible replacement of your path separators during completion, or the ability to configure path cmdlets to use your path separator of choice, should we open separate, specific issues for them?

@rkitover I asked about such scenarios years ago (you can find the issue) without any resolution. This convinces me that this is a cosmetic change, although it requires a lot of effort. If you are ready to invest in this area and pull a PR, then only it makes sense to open a new discussion.

CP/M and clones use / for options, examples: DIR/P, CMD/CECHO. These are valid commands. If we replace \ with / everywhere, I am afraid bad misunderstandings could happen.

  1. Nobody uses CP/M anymore.

  2. Using / for both options and paths at the same time works just fine on Windows in my testing.

  3. Modern tools use - for options instead, including PowerShell tools and other Microsoft tools such as .NET. Using / for options should be kept for backwards compatibility, but users will not have any confusion with modern tools.

Also, I would like to note that the forward slash / is an invalid character name in Win32 file names:

https://gist.github.com/doctaphred/d01d05291546186941e1b7ddc02034d3

Gist
Invalid characters for Windows filenames. GitHub Gist: instantly share code, notes, and snippets.

I just want to point out I started using forward slashes only in cross-platform scripts etc and hit a problem with symbolic links.

As an example, run

new-item -itemtype SymbolicLink -path TestScript8.ps1 -target ./TestScript.ps1

on Windows and you will not be able to open TestScript8.ps1 in VS Code on Windows.

@markm77, you've discovered a _bug_ - can you please create a new issue for it? [_update_: see #13064]

Not that it is an argument against an opt-in mechanism for defaulting to /, @aaronfranke, but note that there are few edge cases where / instead of \ still breaks things on Windows; e.g.:

PS> cmd /c dir C:/
Invalid switch - ""

Double-quoting the path only helps with _directory_ paths, curiously - see https://stackoverflow.com/a/43297482/45375, which also shows that the Excel COM Automation library doesn't support /.

Stack Overflow
$Path = 'D:/ETL_Data/TwitchTVData.xlsx' $csvPath = 'D:/ETL_Data/TwitchTVData2.csv' # Open the Excel document and pull in the 'Sheet1' worksheet $Excel = New-Object -Com Excel.Application $Workbook...

@markm77, you've discovered a bug - can you please create a new issue for it?

But is this a PowerShell bug? PowerShell creates the correct sym-link with specified slash as verified by examining the sym-link using dir. It seems though that a sym-link created with the wrong slash type can then be unusable in apps such as VS Code. Which is also understandable perhaps.

NB it's quite easy to work around this issue by running convert-item on sym-link targets which has the added benefit of ensuring sym-links point to absolute paths (probably appropriate).

NB it's quite easy to work around this issue by running convert-item on sym-link targets which has the added benefit of ensuring sym-links point to absolute paths (probably appropriate).

Inappropriate, will break upon remounting 😞

Inappropriate, will break upon remounting 😞

Fair comment, I don't remount (this is for local dev work) and I have a script for link re-generation I can run at any time. join-path is obviously the other solution or even better would be a new-item option to ensure links are platform-appropriate.

See #12797

But is this a PowerShell bug?

While you could argue that on _Windows_ it is a WinAPI bug, given that \ and / are usually supported interchangeably, it is definitely a bug on Unix-like platforms if you do the reverse and pass a \ based path as the -Target path - on such platforms, only / is natively supported (it is only PowerShell that allows you to use \ as an alternative, which comes with its own problems - see #9244), and it is PowerShell's responsibility to translate something like .\TestScript.ps1 to ./TestScript.ps1 when creating the symlink.

Fixing this - by making PowerShell normalize the path to use the (primary) _platform-native_ separator - will also fix the issue on Windows.

@iSazonov, #12797 fundamentally enabled support for _relative_ paths as symlink targets, but the problem at hand is the lack of platform-native separator normalization, which renders the resulting symlinks broken.

@iSazonov Please see #13064 for what is still broken as of PowerShell Core 7.1.0-preview.4 (which should include #12797, right)?

Thanks @mklement0 for what looks to be a thorough investigation of relative symlink behaviour and raising of issue https://github.com/PowerShell/PowerShell/issues/13064. I had made a note to follow-up further the particular issue I had and this discussion but in fact it seems you've covered everything in https://github.com/PowerShell/PowerShell/issues/13064 and in fact taught me how to write PowerShell tests (I'm new to PowerShell).... Cheers!

I did not follow this issue in every detail so excuse me if I miss something. The initial issue was a cross platform standarized path separator (potentially a forward slashes). @iSazonov now closed this issue. Can you please give an overview why you think this is no longer valid so that the people who were subscribed on issue close events can follow along?

Something like what @lzybkr proposed above is still a perfectly reasonable - and presumably easy - thing to implement; to recap:

I think it would be nice if path completion used the path separator that appears explicitly in the completion text, and if there is none, then default to the platform native separator.

It is then the user's responsibility to avoid the - rare - edge cases where / still breaks on Windows (see above).

This causes a real headache when running wsl bash scripts via powershell. Like:

bash .\updateTemplate.sh

This should be autocompleted to

bash ./updateTemplate.sh

Is there any other workaround for this problem? specifically I'd be totally okay if PS autocompletes path with forward slashes on bash/WSL context only.

Is there any other workaround for this problem?

Create custom completor for bash.

Is there any other workaround for this problem?

Create custom completor for bash.

How do you do this?

Are we not getting any more discussion on the baseless closure of this issue? This is a major annoyance for cross-platform work. Every single time I auto-complete paths that are fed to cross-platform tools or indirectly through wsl to Linux tools, I have to march my cursor backwards through the whole path and individually replace every single backslash with a slash. No one should ever have to work this way, and it genuinely makes Powershell as a command line nearly untenable.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

concentrateddon picture concentrateddon  ·  3Comments

ajensenwaud picture ajensenwaud  ·  3Comments

SteveL-MSFT picture SteveL-MSFT  ·  3Comments

alx9r picture alx9r  ·  3Comments

andschwa picture andschwa  ·  3Comments