1+ function New-PSObject ([hashtable ]$Property ) {
2+ New-Object - Type PSObject - Property $Property
3+ }
4+
5+ function Invoke-WithContext {
6+ param (
7+ [Parameter (Mandatory = $true )]
8+ [ScriptBlock ] $ScriptBlock ,
9+ [Parameter (Mandatory = $true )]
10+ [hashtable ] $Variables )
11+
12+ # this functions is a psv2 compatible version of
13+ # ScriptBlock InvokeWithContext that is not available
14+ # in that version of PowerShell
15+
16+ # this is what the code below does
17+ # which in effect sets the context without detaching the
18+ # scriptblock from the original scope
19+ # & {
20+ # # context
21+ # $a = 10
22+ # $b = 20
23+ # # invoking our original scriptblock
24+ # & $sb
25+ # }
26+
27+ # a similar solution was $SessionState.PSVariable.Set('a', 10)
28+ # but that sets the variable for all "scopes" in the current
29+ # scope so the value persist after the original has run which
30+ # is not correct,
31+
32+ $scriptBlockWithContext = {
33+ param ($context )
34+
35+ foreach ($pair in $context.Variables.GetEnumerator ()) {
36+ New-Variable - Name $pair.Key - Value $pair.Value
37+ }
38+
39+ # this cleans up the variable from the session
40+ # the subexpression outputs the value of the variable
41+ # and then deletes the variable, so the value is still passed
42+ # but the variable no longer exists when the scriptblock executes
43+ & $ ($context.ScriptBlock ; Remove-Variable - Name ' context' - Scope Local)
44+ }
45+
46+ $flags = [System.Reflection.BindingFlags ]' Instance,NonPublic'
47+ $SessionState = $ScriptBlock.GetType ().GetProperty(" SessionState" , $flags ).GetValue($ScriptBlock , $null )
48+ $SessionStateInternal = $SessionState.GetType ().GetProperty(' Internal' , $flags ).GetValue($SessionState , $null )
49+
50+ # attach the original session state to the wrapper scriptblock
51+ # making it invoke in the same scope as $ScriptBlock
52+ $scriptBlockWithContext.GetType ().GetProperty(' SessionStateInternal' , $flags ).SetValue($scriptBlockWithContext , $SessionStateInternal , $null )
53+
54+ & $scriptBlockWithContext @ { ScriptBlock = $ScriptBlock ; Variables = $Variables }
55+ }
56+
57+ function Test-NullOrWhiteSpace ($Value ) {
58+ # psv2 compatibility, on newer .net we would simply use
59+ # [string]::isnullorwhitespace
60+ $null -eq $Value -or $Value -match " ^\s*$"
61+ }
62+
63+ function Get-Type ($InputObject ) {
64+ try {
65+ $ErrorActionPreference = ' Stop'
66+ # normally this would not ever throw
67+ # but in psv2 when datatable is deserialized then
68+ # [Deserialized.System.Data.DataTable] does not contain
69+ # .GetType()
70+ $InputObject.GetType ()
71+ }
72+ catch [Exception ] {
73+ return [Object ]
74+ }
75+
76+ }
0 commit comments