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:
Summary:
**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
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
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
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
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
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:
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.
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.