New-Module m {
class c {
[object] Invoke () { return Invoke-Something }
}
function Invoke-Something { 'Invoke-Something' }
function New-InstanceOfC { [c]::new() }
function Invoke-MethodOfC { (New-InstanceOfC).Invoke() }
Export-ModuleMember *OfC
} | Out-Null
(New-InstanceOfC).Invoke()
Invoke-MethodOfC
I expected both calls to Invoke-Something to succeed and output
Invoke-Something
Invoke-Something
Neither call to Invoke-Something succeeds.
Invoke-Something : The term 'Invoke-Something' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At C:\Users\un1\Desktop\test.ps1:3 char:37
+ [object] Invoke () { return Invoke-Something }
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Invoke-Something:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
Invoke-Something : The term 'Invoke-Something' is not recognized as the name of a cmdlet, function, script file, or
operable program. Check the spelling of the name, or if a path was included, verify that the path is correct and try
again.
At C:\Users\un1\Desktop\test.ps1:3 char:37
+ [object] Invoke () { return Invoke-Something }
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : ObjectNotFound: (Invoke-Something:String) [], CommandNotFoundException
+ FullyQualifiedErrorId : CommandNotFoundException
> $PSVersionTable
Name Value
---- -----
PSVersion 6.0.0-beta
PSEdition Core
GitCommitId v6.0.0-beta.6
OS Microsoft Windows 6.3.9600
Platform Win32NT
PSCompatibleVersions {1.0, 2.0, 3.0, 4.0...}
PSRemotingProtocolVersion 2.3
SerializationVersion 1.1.0.1
WSManStackVersion 3.0
I can't speak to the underlying design issues (how things _should_ work in this case), but I can offer a pointer:
Your code would work if you put the module code into a *.psm1 file instead and import it with Import-Module or using module.
Note that only with using module is the module's custom class truly imported into the caller's scope and accessible as [c] (modules neither by default export custom classes nor allow their explicit exporting; they're imported (implicitly) only with a using module statement, which is used at _parse_ time and must be the very 1st statement in the script).
Your code would work if you put the module code into a *.psm1 file instead and import it with Import-Module...
Interesting. I confirmed this behavior. I wonder if there is a good reason for the discrepancy in behaviors between the .psm1-backed and dynamic modules.
@daxian-dbw I remember discussing this with you. What are the exact mechanics here?
This issue is a duplicate of #2841
All classes in a script block, including those in the nested script blocks, are emitted when the top level script block (scriptblockast.Parent == null) is compiled. After emitting the dyanmic types, the compiler will generate code to initialize the produced types when the top-level script block runs, of which one task is to associate thsoe types with the current active session state, so instances of those types can run methods using that session state.
This casues a problem to New-Module m { class c { ... } }, where the class c is supposed to be associated with the module session state when it's evaluated within New-Module, but it has already been associated with the active session state when running the top-level scirpt block New-Module.
The instance of foo cannot find Invoke-Something because it's not using the module session state when running Invoke().
When Invoke() runs, it's actually using the outer session state to resolve the command, and in this case, if Invoke-Something is defined in the scope chain in the outer session state, then it will find it. See the below code for comparison.
& {
function Invoke-Something { "Something" }
New-Module m {
class c {
[object] Invoke () { return Invoke-Something }
}
function New-InstanceOfC { [c]::new() }
} | Out-Null
(New-InstanceOfC).Invoke()
}
Something
Most helpful comment
I can't speak to the underlying design issues (how things _should_ work in this case), but I can offer a pointer:
Your code would work if you put the module code into a
*.psm1file instead and import it withImport-Moduleorusing module.Note that only with
using moduleis the module's custom class truly imported into the caller's scope and accessible as[c](modules neither by default export custom classes nor allow their explicit exporting; they're imported (implicitly) only with ausing modulestatement, which is used at _parse_ time and must be the very 1st statement in the script).