Note: There may be no straightforward solution, but the user experience is certainly confusing.
If you try to target a nonexistent drive, PowerShell doesn't invoke the FileSystem-provider implementation of Get-ChildItem (since no provider can be inferred from the path), and since switches -Directory and -File are specific to that provider, an error message complaining about nonexistent _parameters_ is reported rather than the nonexistent _drive_.
Assume that there's no drive N: (on Windows)
Get-ChildItem 'N:/foo'
Get-ChildItem 'N:/foo' -File
Get-ChildItem 'N:/foo' -Directory
Get-ChildItem : Cannot find drive. A drive with the name 'N' does not exist.
Get-ChildItem : Cannot find drive. A drive with the name 'N' does not exist.
Get-ChildItem : Cannot find drive. A drive with the name 'N' does not exist.
Get-ChildItem : Cannot find drive. A drive with the name 'N' does not exist.
Get-ChildItem : A parameter cannot be found that matches parameter name 'File'.
Get-ChildItem : A parameter cannot be found that matches parameter name 'Directory'.
That is, if -File or -Directory are also specified, the error message changes from complaining about a nonexistent _drive_ to a nonexistent _parameter_.
PowerShell Core v6.0.2 on macOS 10.13.4
PowerShell Core v6.0.2 on Ubuntu 16.04.4 LTS
PowerShell Core v6.0.2 on Microsoft Windows 10 Pro (64-bit; Version 1709, OS Build: 16299.371)
Windows PowerShell v5.1.16299.251 on Microsoft Windows 10 Pro (64-bit; Version 1709, OS Build: 16299.371)
Does it make sense for us to assume a filesystem drive by default in error scenarios? Or would that break things?
The non-performant implementation would be to go and look through other provider *-*Item cmdlets and see if they have the particular parameters given and then throw the relevant error from whichever we hit first? But there could be a whole host of challenges associated with that.
Does it make sense for us to assume a filesystem drive by default in error scenarios?
Pragmatically speaking, I'd say yes.
The generalized drive metaphor never really gained traction, is my sense (although that could be considered unfortunate).
In the Unix world, in the absence of the registry provider, the only provider that really matters is the filesystem provider (what the alias:, env:, function: and variable: drives provide is easily covered by other features)
I would disagree that the generalized drive metaphor didn't gain traction. I've seen dozens of modules that implement it including SQL Server. After SHIPs was released, tons more popped up.
As for the fix, the issue happens when specifying other parameters too such as -Attributes, -ReadOnly but it works for -Recurse.
My guess is that the parameters that don't work are all for the filesystem. If so, then it needs the drive to determine if it is hitting the filesystem provider to enable them which would explain why it gave the unexpected error. So I wonder if the drive check just needs to happen sooner or catch the parameter error and check if the invalid drive was the cause and throw that instead.
@dragonwolf83:
I would disagree that the generalized drive metaphor didn't gain traction.
I've seen dozens of modules that implement it including SQL Server
Fair enough - my personal sense was just that.
Would you agree that filesystem use is by far the most common use, however?
but it works for -Recurse.
that the parameters that don't work are all for the filesystem.
Yes, the problem is that you cannot infer from a nonexistent drive what the target provider is, so it isn't the filesystem provider's cmdlet implementation that is called.
The path may _look_ like a filesystem path (on Windows), but if the drive isn't defined, it could be anything (given that you can define PS drives such as New-PSdrive -PSProvider alias -name N -root alias).
So I wonder if the drive check just needs to happen sooner
Good idea.
@rjmholt, Given that at least a _formal_ check of the path must already be happening in order to determine the appropriate provider cmdlet, would it be feasible to check the drive's existence at that point?
I don't know the provider code, but checking the path and sending an error earlier seems feasible and I don't imagine changing one error for a more descriptive one will hurt anyone.
But two possible complications are:
I'll look into it.
I'm hoping it can be as simple as adding a ValidationAttribute to the -Path parameter but I don't know if ParamaterBinding happens first or not.
@dragonwolf83 Parameter binding happens first which is why this error happens. Without the provider metadata, the command knows nothing about "-File" and so you get an invalid parameter exception long before the command code gets control. But I would think the call to get the parameter metadata should generate an error if the provider can't be resolved. Perhaps that's where we can introduce a more useful error.
I had a feeling that was the case. It makes sense.
Most helpful comment
@dragonwolf83 Parameter binding happens first which is why this error happens. Without the provider metadata, the command knows nothing about "-File" and so you get an invalid parameter exception long before the command code gets control. But I would think the call to get the parameter metadata should generate an error if the provider can't be resolved. Perhaps that's where we can introduce a more useful error.