You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Allow Convert-Path to convert paths that don't exist [yet] and allow specifying the target provider #7197
#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')
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.
[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.
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).
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.
:-) 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.
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
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.
Activity
iSazonov commentedon Jun 28, 2018
Do cmd.exe and .Net keep current path state internally or get from OS?
mklement0 commentedon Jun 28, 2018
Ilya (@iSazonov):
My understanding is that every process has a current directory (working directory) associated with it, which .NET reflects in
[Environment]::CurrentDirectoryand 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.
iSazonov commentedon Jun 28, 2018
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.mklement0 commentedon Jun 28, 2018
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
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-Pathfunctionality.[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).
iSazonov commentedon Jun 28, 2018
:-) Why bad? If we want keep the state in every runspace - want? - we have not two but many cwd. It is simple and clear.
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.
mklement0 commentedon Jun 28, 2018
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:
.Split()vs.-split).[System.IO.*]types.For the same reason that the
Convert-Pathcmdlet 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.
That's a separate issue - well worth pursuing - but a false dichotomy in the context of this discussion.
[-]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[/+]mklement0 commentedon Nov 26, 2018
Just realized that this is a duplicate of the much older #2993.
Ilya (@iSazonov), can you please mark this as a duplicate?
iSazonov commentedon Nov 27, 2018
Michael Klement (@mklement0) I think we would get more progress if we added Pester test prototypes to issue text description :-)
mklement0 commentedon Nov 27, 2018
Thanks for labeling, Ilya (@iSazonov), but I don't understand your comment.
iSazonov commentedon Nov 27, 2018
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.