Skip to content

Allow Convert-Path to convert paths that don't exist [yet] and allow specifying the target provider #7197

Closed

Description

#3428 discusses the perennial point of PowerShell's current filesystem location not being in sync with .NET's, which causes surprising behavior whenever relative paths are passed to .NET methods.
(Sadly, there seems to be no good fundamental solution to this problem.)

The pain could be alleviated if there were an easy way to convert relative filesystem paths to absolute ones, so that the latter can be passed to the .NET methods for predictable behavior.

While Convert-Path's purpose is to convert (relative or not) paths to provider-native absolute paths (e.g., by resolving custom-PS-drive-based paths to their underlying filesystem paths), Convert-Path currently requires that the input path already exist.

However, you may find yourself wanting to convert a path about to be created to Convert-Path, e.g. when trying to use [io.file]::WriteAllText() with the name of a new file to be created in the current location.

To that end, a new switch such as -NoCheck could be introduced that simply converts the path formally, whether or not it ends up referring to an existing item.

Note: Arguably, Convert-Path should always have defaulted to this behavior, but I presume that changing this now would be considered an unacceptable breaking change.

This could be complemented with a -PSProvider parameter that would allow you to target a specific provider irrespective of the current location's, thus allowing the use of -PSProvider FileSystem in order to reliably target the filesystem provider.

For example, you could then use the following code to reliably create a new file in the current PS filesystem location:

# Wishful thinking
# Add -PSProvider FileSystem if there's a chance that the current location is 
# not a filesystem one.
[io.file]::WriteAllText((Convert-Path -NoCheck fileInCurrentDir.txt), 'file content') 

Environment data

Written as of:

PowerShell Core v6.1.0-preview.3

Activity

  1. iSazonov commented on Jun 28, 2018

    @iSazonov
    Collaborator

    Do cmd.exe and .Net keep current path state internally or get from OS?

  2. mklement0 commented on Jun 28, 2018

    @mklement0
    ContributorAuthor

    Ilya (@iSazonov):

    My understanding is that every process has a current directory (working directory) associated with it, which .NET reflects in [Environment]::CurrentDirectory and cmd.exe in %CD%.

    My guess is that cmd.exe and .NET both rely directly on the process's current directory and that it is only PowerShell that "does its own thing" where its notion of the current filesystem directory can deviate from the process's.

  3. iSazonov commented on Jun 28, 2018

    @iSazonov
    Collaborator

    PowerShell that "does its own thing"

    Then it is a problem of documenting and learning.

    [io.file]::WriteAllText and cmdlets use string as paths. But first uses .Net path, second uses filesystem path - it is different things. They are the same for full paths, but may differ for relative paths. We should treat it as two different namespaces otherwise we have to fix then other possible scenarios.

    If someone wants to use methods ([io.file]::WriteAllText) instead of cmdlets why would he want to use the cmdlet to get the full path? It can use [System.IO.FileInfo]::new(...).FullPath.

  4. mklement0 commented on Jun 28, 2018

    @mklement0
    ContributorAuthor

    Then it is a problem of documenting and learning.

    It's a matter of convenience that is rooted in already knowing the underlying problem of not being able to assume that relative paths work the same in both worlds.
    That said, documenting is obviously also needed - see MicrosoftDocs/PowerShell-Docs#2626

    why would he want to use the cmdlet to get the full path? It can use [System.IO.FileInfo]::new(...).FullPath

    Because it offers a predictable, robust way to pass a PS path to .NET, whether the path is relative or not, whether it is based on a custom PS drive or not, and because it is a natural extension of the existing Convert-Path functionality.

    [System.IO.FileInfo]::new(...).FullName, aside from being awkward to type, suffers the very same problem as the one this proposal is trying to solve: if you pass it a relative path, it will be resolved relative to [Environment]::CurrentDir, not to PowerShell's current filesystem location.

    It is really too bad that the two directory locations cannot be kept in sync, but it sounds like PowerShell's multiple-runspaces-per-process feature prevents a good solution (see the linked issue).

  5. iSazonov commented on Jun 28, 2018

    @iSazonov
    Collaborator

    It is really too bad that the two directory locations cannot be kept in sync

    :-) Why bad? If we want keep the state in every runspace - want? - we have not two but many cwd. It is simple and clear.

    [System.IO.FileInfo]::new(...).FullName, aside from being awkward to type, suffers the very same problem as the one this proposal is trying to solve: if you pass it a relative path, it will be resolved relative to [Environment]::CurrentDir, not to PowerShell's current filesystem location.

    I meant that the user should stay within the same namespace.
    Why would anybody want to convert PowerShell path to .Net path? If we have scenarios where we really can't do without it, it's more useful to enhance the capabilities of PowerShell. Otherwise, we're opening an infinite path to fix PowerShell behaviors. For example, someone will want a reverse operation - convert .Net path to a PowerShell path, etc.

  6. mklement0 commented on Jun 28, 2018

    @mklement0
    ContributorAuthor

    :-) Why bad? If we want keep the state in every runspace [...]

    Yes, I recognize that the multiple runspaces are a good reason not to attempt to syncing the current directories, and that the best we can do is to offer a clear and reliable method for handling the discrepancy.

    The reasons the the issue isn't clear and simple from the end user's perspective are:

    • Most users aren't even aware of multiple runspaces and how they relate to processes.
    • They are used to a given process having a single current directory, not least because that's how it works when you call an external program.
    • They are used to thinking of the .NET framework as a readily available lower layer they can call at their convenience, often (loosely) interchangeably with native PS functionality (e.g, .Split() vs. -split).
    • With the advent of UTF-8 as the default, the problem has lessened, but there are many workarounds out there that rely on calling [System.IO.*] types.

    Why would anybody want to convert PowerShell path to .Net path?

    For the same reason that the Convert-Path cmdlet exists in the first place:

    To translate PS-specific paths into paths understood by the outside world - which, by the way, is not limited to calling .NET.

    What I'm proposing is a natural extension of this functionality.

    it's more useful to enhance the capabilities of PowerShell.

    That's a separate issue - well worth pursuing - but a false dichotomy in the context of this discussion.

  7. changed the title [-]Allow Convert-Path to convert paths don't exist [yet] and allow specifying the target provider[/-] [+]Allow Convert-Path to convert paths that don't exist [yet] and allow specifying the target provider[/+] on Jun 28, 2018
  8. mklement0 commented on Nov 26, 2018

    @mklement0
    ContributorAuthor

    Just realized that this is a duplicate of the much older #2993.

    Ilya (@iSazonov), can you please mark this as a duplicate?

  9. iSazonov commented on Nov 27, 2018

    @iSazonov
    Collaborator

    Michael Klement (@mklement0) I think we would get more progress if we added Pester test prototypes to issue text description :-)

  10. mklement0 commented on Nov 27, 2018

    @mklement0
    ContributorAuthor

    Thanks for labeling, Ilya (@iSazonov), but I don't understand your comment.

  11. iSazonov commented on Nov 27, 2018

    @iSazonov
    Collaborator

    Sorry. We need tests before merge a PR. The Pester tests is exact contracts. If we create the tests in an issue discussion time we will speed up the fix creation. If there is an approved contract, even a novice developer can prepare fix.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    Issue-Discussionthe issue may not have a clear classification yet. The issue may generate an RFC or may be reclassifResolution-DuplicateThe issue is a duplicate.WG-Cmdletsgeneral cmdlet issues

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions