ScriptProperty can't access script's cmdlets when invoked as a command

110 Views Asked by At

Given code such as this MRE:

function Get-One {1}
Update-TypeData -TypeName 'Demo' -MemberType 'ScriptProperty' -MemberName 'Test1' -Value {Get-Date}
Update-TypeData -TypeName 'Demo' -MemberType 'ScriptProperty' -MemberName 'Test2' -Value {Get-One}
$example = [PSCustomObject]@{PSTypeName = 'Demo'}
$example

If I invoke it as pwsh -File '.\Demo.ps1' then all works as you'd expect / I get this output:

Test1               Test2
-----               -----
2021-04-17 21:35:55     1

However, if I invoke the same command as pwsh -Command '.\Demo.ps1' I get this (i.e. Test2 is blank); whilst I'd expect to get the same as the above:

Test1               Test2
-----               -----
2021-04-17 21:35:55     

i.e. When I invoke via the -Command parameter, the ScriptProperty can't access cmdlets/functions defined within the script itself; though can access standard ones (e.g. Get-Date).

I'd assume this was a bug; only the same behaviour's seem in both PWSH and PowerShell; which makes that a little less likely.

Is this a bug; or am I missing something in my understanding.

1

There are 1 best solutions below

2
On BEST ANSWER

The difference in behavior is explained by the fact that -File implicitly dot-sources the target script file, which means that it runs in the global scope.

Typically, this detail is of little consequence (except if you also pass -NoExit to request staying in the session after the script terminates).

Here, it makes the crucial difference:

  • With -File, Get-One ends up defined in the global scope, which is the prerequisite for the ScriptProperty-defining { Get-One } script block being able to see it.

  • By contrast, running the script file with -Command does not dot-source it, making the Get-One command effectively invisible to the { Get-One } script block - and errors occurring inside such ScriptProperty-defining script blocks are quietly ignored.

There are two solutions:

  • Either: Explicitly define your Get-One function as global:

    function global:Get-One { 1 }
    
  • Or: When using -Command, explicitly dot-source the script:

     pwsh -Command '. .\Demo.ps1'