Preamble: this is not about "fixing the code", as I already fixed it. This is about "understanding what went wrong, so to avoid similar mistakes in future"
Situation:
Powershell 7.4.1.
I use THIS piece of code(which I got from some website I cannot recall) in my $Profile to delay-load modules and scripts. The live one has more code but not relevant: I've tested this is where the trouble is.
Specifically, I use it to load a Module I wrote for personal use.
(I know I don't actually need to load modules in my $Profile script as long as they are in my $env:PSModulePath; I'm sure there was a reason I did it but honestly cannot remember what.)
True contents of the original module do not matter as the Minimum Reproducible Example is:
scirpt in $profile
$OutputEncoding = [console]::InputEncoding = [console]::OutputEncoding = [Text.Encoding]::UTF8
# https://seeminglyscience.github.io/powershell/2017/09/30/invocation-operators-states-and-scopes
$GlobalState = [psmoduleinfo]::new($false)
$GlobalState.SessionState = $ExecutionContext.SessionState
$Job = Start-ThreadJob -Name TestJob -ArgumentList $GlobalState -ScriptBlock {
$GlobalState = $args[0]
. $GlobalState {
# We always need to wait so that Get-Command itself is available
do {
Start-Sleep -Milliseconds 200
} until (Get-Command Import-Module -ErrorAction Ignore)
# other dot-sourced scripts...
# . "$ProfileDirectory\CustomAlias.ps1"
# . "$ProfileDirectory\CustomConstants.ps1"
# . "$ProfileDirectory\CustomVariables.ps1"
# . "$ProfileDirectory\CustomPrompt.ps1"
# Import-Module -Name Sirtao
Import-Module -Name Get-DirectoryItem
}
}
$null = Register-ObjectEvent -InputObject $Job -EventName StateChanged -SourceIdentifier Job.Monitor -Action {
# JobState: NotStarted = 0, Running = 1, Completed = 2, etc.
if ($Event.SourceEventArgs.JobStateInfo.State -eq 'Completed') {
$Result = $Event.Sender | Receive-Job
if ($Result) {
$Result | Out-String | Write-Host
}
$Event.Sender | Remove-Job
Unregister-Event Job.Monitor
Get-Job Job.Monitor | Remove-Job
}
elseif ($Event.SourceEventArgs.JobStateInfo.State -gt 2) {
$Event.Sender | Receive-Job | Out-String | Write-Host
}
}
Module loaded
function Get-DirectoryItem {
[CmdletBinding(DefaultParameterSetName = 'BaseSet')]
[Alias('Get-Dir', 'GD')]
param (
)
process {
1..3 | Where-Object { $_ }
1..3 | ForEach-Object { $_ }
$a = @('a', 'b', 'c')
$a | ForEach-Object { $_ }
$a | Where-Object { $_ }
}
}
What I did try: simply running the command.
What I was expecting: the script returning the values of the arrays
What I got: the errors ForEach-Object: Object reference not set to an instance of an object. and
Where-Object: Object reference not set to an instance of an object.
Please note that Get-Item, Get-ChildItem and Get-FileHash, the only other examples of piping I used in my modules, do work as expected
How i did fix it: removing the import from the Job. The module was still imported automagically and everything worked as expected. But as i said, this is not about fixing, but understanding.
So... any ideas?