Powershell: Get-ChieldItem fails with "Cannot find a provider ..." on version 6.2.1

Created on 6 Jun 2019  路  14Comments  路  Source: PowerShell/PowerShell

I have a module that loads a nested binary module (due to support for desktop and core editions). The binary module defines a provider that has a default PSDrive.
When calling Get-ChieldItem <qualified path> it fails with "Cannot find a provider with the name '...'". This has changed since 6.0 when it used to work.

I have created a sample repro module:

ReproProviderNameMismatch.zip

Summary:

  • The module must be nested to get this to reproduce
  • The provider must do something at initialization time that triggers a capture of the Provider.FullName (or something like that). In my case this is the PSDriveInfo constructor probably:
    ```c#
    protected override Collection InitializeDefaultDrives() {
    var drive = new PSDriveInfo(
    "defaultSampleDrive",
    ProviderInfo,
    "/",
    "Sample default drive",
    null);
    var result = new Collection {drive};
    return result;
    }
**If the InitializeDefaultDrives in the sample is removed, then the issue would not be reproduced.**

# Steps to reproduce
1. Build the sample module with `dotnet build`
2. Load the module from the build output and run the following:
```powershell
import-module "...ReproModule.psd1"

New-PSDrive -Name "prv1" -Root "/" -PSProvider "SamplePrv"

$item = get-item "prv1:\test.txt"
$item | fl *

Get-ChildItem $item.PSPath
  1. Observe the PSPath value

Expected behavior

The command to return the item like this:

PSPath                          PSProvider            PSIsContainer Name
------                          ----------            ------------- ----
ReproModule\SamplePrv::test.txt ReproModule\SamplePrv         False test.txt

Probably the PSPath value should be:

PSPath        : ReproModule\SamplePrv::test.txt

Actual behavior

PSPath value is:

PSPath        : module\SamplePrv::test.txt

The command fails with:

Get-ChildItem : Cannot find a provider with the name 'module\SamplePrv'.
At line:1 char:1
+ Get-ChildItem $item.PSPath
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo          : ObjectNotFound: (module\SamplePrv:String) [Get-ChildItem], ProviderNotFoundException
+ FullyQualifiedErrorId : ProviderNotFound,Microsoft.PowerShell.Commands.GetChildItemCommand

Environment data

Name                           Value
----                           -----
PSVersion                      6.2.1
PSEdition                      Core
GitCommitId                    6.2.1
OS                             Microsoft Windows 10.0.17763
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0
Issue-Code Cleanup Resolution-Fixed WG-Engine-Providers

Most helpful comment

I pulled direct fix. It is not nice but the code is tricky too :-)
@SeeminglyScience Thanks for pointing where nested module name updated.

All 14 comments

This is probably also affecting other provider-related cmdlets. We are seeing that when calling New-PSDrive -Name someName -Root 'drive:/...' -PSProvider ... the call to the provider implementation (PSDriveInfo NewDrive(PSDriveInfo requestedDrive)) receives the root in the form of a PSPath instead of the root in the provider path which was the case before. Looking at the code of GetProviderRootFromSpecifiedRoot, it looks like the provider full name might be involved in the resolution of the PSPath to the provider path.

Is there some way to enable the tracing that is present in the path resolution code?

See LocationGlobber and PathResolution from Get-TraceSource

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

This is not a question but a report of an issue. The issue has not been solved, please reopen the issue.

Can you repo with latest 7.0 build?

It still reproduces with preview 4:

Name                           Value
----                           -----
PSVersion                      7.0.0-preview.4
PSEdition                      Core
GitCommitId                    7.0.0-preview.4
OS                             Microsoft Windows 10.0.18362
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

@atanasa I compiled your sample module and do not see the issue with latest PowerShell 7.0 build..

I am able to reproduce it with rc2. I am testing on Windows 10.

The error output is:
Get-ChildItem: Cannot find a provider with the name 'module\SamplePrv'.

Stack trace:

PS C:\Program Files\PowerShell\7-preview> $e = $error[0]
PS C:\Program Files\PowerShell\7-preview> $e.Exception

ErrorRecord                 : Cannot find a provider with the name 'module\SamplePrv'.
ItemName                    : module\SamplePrv
SessionStateCategory        : CmdletProvider
WasThrownFromThrowStatement : False
TargetSite                  : System.Management.Automation.ProviderInfo GetSingleProvider(System.String)
StackTrace                  :    at System.Management.Automation.SessionStateInternal.GetSingleProvider(String name)
                                 at System.Management.Automation.LocationGlobber.GetProviderPath(String path,
                              CmdletProviderContext context, Boolean isTrusted, ProviderInfo& provider, PSDriveInfo&
                              drive)
                                 at System.Management.Automation.SessionStateInternal.GetChildItems(String path,
                              Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                 at System.Management.Automation.ChildItemCmdletProviderIntrinsics.Get(String path,
                              Boolean recurse, UInt32 depth, CmdletProviderContext context)
                                 at Microsoft.PowerShell.Commands.GetChildItemCommand.ProcessRecord()
Message                     : Cannot find a provider with the name 'module\SamplePrv'.
Data                        : {}
InnerException              :
HelpLink                    :
Source                      : System.Management.Automation
HResult                     : -2146233087

The $PSTableVersion:

Name                           Value
----                           -----
PSVersion                      7.0.0-rc.2
PSEdition                      Core
GitCommitId                    7.0.0-rc.2
OS                             Microsoft Windows 10.0.18363
Platform                       Win32NT
PSCompatibleVersions           {1.0, 2.0, 3.0, 4.0鈥
PSRemotingProtocolVersion      2.3
SerializationVersion           1.1.0.1
WSManStackVersion              3.0

This is the compiled version of the module:
ReproModule.zip

@atanasa Thanks! I can repo. It comes from SnapIn history. The name module\SamplePrv looks like SnapIn name and not all code was leaned up from SnapIn support.

Error starts here:
https://github.com/PowerShell/PowerShell/blob/c4e144b13e1209a6a723160d38be9f11ab45b8da/src/System.Management.Automation/engine/SessionStateProviderAPIs.cs#L786
and
https://github.com/PowerShell/PowerShell/blob/c4e144b13e1209a6a723160d38be9f11ab45b8da/src/System.Management.Automation/engine/MshSnapinQualifiedName.cs#L65-L81

The GetInstance() method has 11 references so it's very risky to change.
@atanasa I suggest to find a workaround and/or redesign your module. Perhaps @SeeminglyScience know a workaround.

@SteveL-MSFT I think the old SnapIn code could be removed in next milestone. It seems it currently is a source of tricky issues for users and developers.

@iSazonov the class is named snapin, but it's just provider code. Also this is actually a side effect of #8831. Since the full name is cached now, creating those drives on initialization locks in the name at the wrong time.

You can verify this by clearing the cached field via reflection:

```powershell
$provider = Get-PSProvider SamplePrv
$provider.GetType().GetField('_fullName', 60).SetValue($provider, $null)
$item = get-item "prv1:\test.txt"
$item.PSPath

ReproModule\SamplePrv::test.txt

Also this is actually a side effect of #8831.

The ProviderInfo class is immutable. It makes me think that a root reason of the issue is still different.

I agree with @SeeminglyScience. The "immutability" does not contradict that explanation. The issue is triggered by the early initialization of ProviderInfo.FullName that calls into ModuleInfo.Name. ModuleInfo.Name is not immutable and its name is updated at a later point for some reason. As ProviderInfo.FullName is immutable, it is not update to reflect the new name of the module.

@iSazonov does have a point, it's puzzling. So I took a deeper look.

First, this actually has a much simpler repro and isn't related to nested modules at all. All you need is a RootModule dll with a file name different from the name declared in the module manifest.

The problem is that provider drive initialization happens before the module is renamed to match the manifest here:

https://github.com/PowerShell/PowerShell/blob/a34d0f3e808659b0c07b8fdac83aaae1dae43c21/src/System.Management.Automation/engine/Modules/ModuleCmdletBase.cs#L3085-L3086

The caching is still why it happens, but not in the way I expected.

I pulled direct fix. It is not nice but the code is tricky too :-)
@SeeminglyScience Thanks for pointing where nested module name updated.

Was this page helpful?
0 / 5 - 0 ratings