Private/New-HDTConsoleShareReader.ps1
|
function New-HDTConsoleShareReader { <# .SYNOPSIS Builds the script block the console runs, once its window is up, to read the shares and turn them into the tree's root rows. .DESCRIPTION THIS EXISTS BECAUSE OF TWO SCOPING TRAPS, and it exists as its own function because that is the only way to avoid both at once. A PLAIN SCRIPT BLOCK READS THE CALLER'S VARIABLES. Handed to the window host and invoked from inside its ContentRendered handler, an unbound block resolves names against the scope that INVOKED it - so `$share.Add(...)` found the host's own `$share`, which is the banner TextBlock, and failed with "does not contain a method named 'Add'". A window that opened and never filled, saying nothing. AND GetNewClosure COPIES EVERY VARIABLE IN SCOPE, attributes included, re-validating each as it goes - so calling it inside Show-HDTConsole throws on whichever parameter belongs to the OTHER parameter set and is sitting there null under a [ValidateNotNull()]. The message names an attribute rather than a parameter set. SO THE CLOSURE IS MADE HERE, where the only variables in scope are this function's own parameters and they carry no attributes to re-validate. The block that comes back is bound to those, and to nothing a caller happens to have named the same. .PARAMETER Path The shares to read, in the order they should appear. .PARAMETER FileSystem An IFileSystem, passed through to Get-HDTConsoleWorkspace. .PARAMETER Share The list the shares are added to. The caller keeps it: what the console returns includes the shares it showed. .PARAMETER Carried A dictionary the block writes Node into, for the same reason - the row count is only known once the read has happened. .INPUTS None. This command does not accept pipeline input. .OUTPUTS System.Management.Automation.ScriptBlock - returns the depth-0 rows. .EXAMPLE $fill = New-HDTConsoleShareReader -Path $Path -FileSystem $FileSystem -Share $share -Carried $carried #> [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseShouldProcessForStateChangingFunctions', '', Justification = 'Builds a script block; nothing is read or written until the window invokes it.')] # EVERY PARAMETER IS USED INSIDE THE CLOSURE, which is the whole point of # the function - and which PSReviewUnusedParameter does not follow. [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSReviewUnusedParameter', '', Justification = 'Used inside a closure, which PSReviewUnusedParameter does not follow.')] [CmdletBinding()] [OutputType([scriptblock])] param( [Parameter(Mandatory = $true, Position = 0)] [string[]] $Path, [Parameter(Position = 1)] [object] $FileSystem = $null, [Parameter(Mandatory = $true, Position = 2)] [object] $Share, [Parameter(Mandatory = $true, Position = 3)] [object] $Carried ) Set-StrictMode -Version Latest $ErrorActionPreference = 'Stop' # THE COMMAND ITSELF, NOT ITS NAME. The block below is invoked by the window # host - and, in the tests, by a fake defined outside this module - and a # name resolved at that moment is resolved against THEIR session state, # where a private function of this module does not exist. The failure showed # up as "the term 'New-HDTConsoleShareFailure' is not recognized", on the # one path that is only taken when a share will not open. # # A CommandInfo captured HERE is bound to this module and works wherever it # is called from. The two public commands need no such treatment, which is # why only this one gets it. $failureRow = Get-Command -Name 'New-HDTConsoleShareFailure' -Module 'Hephaestus' -ErrorAction SilentlyContinue if ($null -eq $failureRow) { $failureRow = Get-Command -Name 'New-HDTConsoleShareFailure' -CommandType Function } return { foreach ($current in @($Path)) { try { # A SHARE THAT WILL NOT OPEN BECOMES A ROW, not an exception: # three good shares must not disappear because of a fourth. if ($null -eq $FileSystem) { [void] $Share.Add((Get-HDTConsoleWorkspace -Path $current)) } else { [void] $Share.Add((Get-HDTConsoleWorkspace -Path $current -FileSystem $FileSystem)) } } catch { [void] $Share.Add((& $failureRow -Path $current -Message ([string] $_.Exception.Message))) } } $Carried['Node'] = @(Get-HDTConsoleTreeNode -Workspace ([object[]] @($Share))) return [object[]] @($Carried['Node'] | Where-Object { $_.Depth -eq 0 }) }.GetNewClosure() } |