1717namespace Microsoft . Azure . Functions . PowerShellWorker . PowerShell
1818{
1919 using System . Management . Automation ;
20+ using System . Reflection ;
2021
2122 internal class PowerShellManager
2223 {
23- // This script handles when the user adds something to the pipeline.
24- // It logs the item that comes and stores it as the $return out binding.
25- // The last item stored as $return will be returned to the function host.
26-
27- readonly static string s_LogAndSetReturnValueScript = @"
28- param([Parameter(ValueFromPipeline=$true)]$return)
29-
30- Write-Information $return
31-
32- Set-Variable -Name '$return' -Value $return -Scope global
33- " ;
34-
35- readonly static string s_SetExecutionPolicyOnWindowsScript = @"
36- if ($IsWindows)
37- {
38- Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Scope Process
39- }
40- " ;
41-
4224 readonly static string s_TriggerMetadataParameterName = "TriggerMetadata" ;
25+ readonly static bool s_UseLocalScope = true ;
4326
4427 RpcLogger _logger ;
4528 PowerShell _pwsh ;
4629
47- PowerShellManager ( RpcLogger logger )
30+ PowerShellManager ( PowerShell pwsh , RpcLogger logger )
4831 {
49- _pwsh = System . Management . Automation . PowerShell . Create ( InitialSessionState . CreateDefault ( ) ) ;
32+ _pwsh = pwsh ;
5033 _logger = logger ;
5134
5235 // Setup Stream event listeners
@@ -60,63 +43,33 @@ internal class PowerShellManager
6043 }
6144
6245 public static PowerShellManager Create ( RpcLogger logger )
63- {
64- var manager = new PowerShellManager ( logger ) ;
65-
66- // Add HttpResponseContext namespace so users can reference
67- // HttpResponseContext without needing to specify the full namespace
68- manager . ExecuteScriptAndClearCommands ( $ "using namespace { typeof ( HttpResponseContext ) . Namespace } ") ;
69- manager . ExecuteScriptAndClearCommands ( s_SetExecutionPolicyOnWindowsScript ) ;
70- return manager ;
71- }
72-
73- static string BuildBindingHashtableScript ( IDictionary < string , BindingInfo > outBindings )
7446 {
75- // Since all of the out bindings are stored in variables at this point,
76- // we must construct a script that will return those output bindings in a hashtable
77- StringBuilder script = new StringBuilder ( ) ;
78- script . AppendLine ( "@{" ) ;
79- foreach ( KeyValuePair < string , BindingInfo > binding in outBindings )
47+ // Set up initial session state: set execution policy, import helper module, and using namespace
48+ var initialSessionState = InitialSessionState . CreateDefault ( ) ;
49+ if ( Platform . IsWindows )
8050 {
81- script . Append ( "'" ) ;
82- script . Append ( binding . Key ) ;
83-
84- // since $return has a dollar sign, we have to treat it differently
85- if ( binding . Key == "$return" )
86- {
87- script . Append ( "' = " ) ;
88- }
89- else
90- {
91- script . Append ( "' = $" ) ;
92- }
93- script . AppendLine ( binding . Key ) ;
51+ initialSessionState . ExecutionPolicy = Microsoft . PowerShell . ExecutionPolicy . Unrestricted ;
9452 }
95- script . AppendLine ( "}" ) ;
96-
97- return script . ToString ( ) ;
98- }
99-
100- void ResetRunspace ( )
101- {
102- // Reset the runspace to the Initial Session State
103- _pwsh . Runspace . ResetRunspaceState ( ) ;
104- }
105-
106- void ExecuteScriptAndClearCommands ( string script )
107- {
108- _pwsh . AddScript ( script ) . Invoke ( ) ;
109- _pwsh . Commands . Clear ( ) ;
110- }
53+ var pwsh = PowerShell . Create ( initialSessionState ) ;
11154
112- public Collection < T > ExecuteScriptAndClearCommands < T > ( string script )
113- {
114- var result = _pwsh . AddScript ( script ) . Invoke < T > ( ) ;
115- _pwsh . Commands . Clear ( ) ;
116- return result ;
55+ // Add HttpResponseContext namespace so users can reference
56+ // HttpResponseContext without needing to specify the full namespace
57+ // and also import the Azure Functions binding helper module
58+ string modulePath = System . IO . Path . Join (
59+ AppDomain . CurrentDomain . BaseDirectory ,
60+ "Azure.Functions.PowerShell.Worker.Module" ,
61+ "Azure.Functions.PowerShell.Worker.Module.psd1" ) ;
62+ pwsh . AddScript ( $ "using namespace { typeof ( HttpResponseContext ) . Namespace } ")
63+ . AddStatement ( )
64+ . AddCommand ( "Import-Module" )
65+ . AddParameter ( "Name" , modulePath )
66+ . AddParameter ( "Scope" , "Global" )
67+ . InvokeAndClearCommands ( ) ;
68+
69+ return new PowerShellManager ( pwsh , logger ) ;
11770 }
11871
119- public PowerShellManager InvokeFunctionAndSetGlobalReturn (
72+ public Hashtable InvokeFunction (
12073 string scriptPath ,
12174 string entryPoint ,
12275 Hashtable triggerMetadata ,
@@ -135,15 +88,23 @@ public PowerShellManager InvokeFunctionAndSetGlobalReturn(
13588 {
13689 if ( entryPoint != "" )
13790 {
138- ExecuteScriptAndClearCommands ( $@ ". { scriptPath } ") ;
139- parameterMetadata = ExecuteScriptAndClearCommands < FunctionInfo > ( $@ "Get-Command { entryPoint } ") [ 0 ] . Parameters ;
140- _pwsh . AddScript ( $@ ". { entryPoint } @args") ;
91+ parameterMetadata = _pwsh
92+ . AddScript ( $@ ". { scriptPath } ", s_UseLocalScope )
93+ . AddStatement ( )
94+ . AddCommand ( "Get-Command" , s_UseLocalScope ) . AddParameter ( "Name" , entryPoint )
95+ . InvokeAndClearCommands < FunctionInfo > ( ) [ 0 ] . Parameters ;
96+
97+ _pwsh
98+ . AddScript ( $@ ". { scriptPath } ", s_UseLocalScope )
99+ . AddStatement ( )
100+ . AddCommand ( entryPoint , s_UseLocalScope ) ;
141101
142102 }
143103 else
144104 {
145- parameterMetadata = ExecuteScriptAndClearCommands < ExternalScriptInfo > ( $@ "Get-Command { scriptPath } ") [ 0 ] . Parameters ;
146- _pwsh . AddScript ( $@ ". { scriptPath } @args") ;
105+ parameterMetadata = _pwsh . AddCommand ( "Get-Command" , s_UseLocalScope ) . AddParameter ( "Name" , scriptPath )
106+ . InvokeAndClearCommands < ExternalScriptInfo > ( ) [ 0 ] . Parameters ;
107+ _pwsh . AddCommand ( scriptPath , s_UseLocalScope ) ;
147108 }
148109 }
149110
@@ -160,35 +121,47 @@ public PowerShellManager InvokeFunctionAndSetGlobalReturn(
160121 _logger . LogDebug ( $ "TriggerMetadata found. Value:{ Environment . NewLine } { triggerMetadata . ToString ( ) } ") ;
161122 }
162123
163- // This script handles when the user adds something to the pipeline.
124+ PSObject returnObject = null ;
164125 using ( ExecutionTimer . Start ( _logger , "Execution of the user's function completed." ) )
165126 {
166- ExecuteScriptAndClearCommands ( s_LogAndSetReturnValueScript ) ;
127+ // Log everything we received from the pipeline and set the last one to be the ReturnObject
128+ Collection < PSObject > pipelineItems = _pwsh . InvokeAndClearCommands < PSObject > ( ) ;
129+ foreach ( var psobject in pipelineItems )
130+ {
131+ _logger . LogInformation ( psobject . ToString ( ) ) ;
132+ }
133+
134+ returnObject = pipelineItems [ pipelineItems . Count - 1 ] ;
167135 }
168- return this ;
169- }
170- catch ( Exception e )
171- {
172- ResetRunspace ( ) ;
173- throw e ;
174- }
175- }
136+
137+ var result = _pwsh . AddCommand ( "Get-OutputBinding" , s_UseLocalScope ) . InvokeAndClearCommands < Hashtable > ( ) [ 0 ] ;
176138
177- public Hashtable ReturnBindingHashtable ( IDictionary < string , BindingInfo > outBindings )
178- {
179- try
180- {
181- // This script returns a hashtable that contains the
182- // output bindings that we will return to the function host.
183- var result = ExecuteScriptAndClearCommands < Hashtable > ( BuildBindingHashtableScript ( outBindings ) ) [ 0 ] ;
139+ if ( returnObject != null )
140+ {
141+ result . Add ( "$return" , returnObject ) ;
142+ }
184143 ResetRunspace ( ) ;
185144 return result ;
186145 }
187146 catch ( Exception e )
188147 {
189148 ResetRunspace ( ) ;
190- throw e ;
149+ throw ;
191150 }
192151 }
152+
153+ void ResetRunspace ( )
154+ {
155+ // Reset the runspace to the Initial Session State
156+ _pwsh . Runspace . ResetRunspaceState ( ) ;
157+
158+ // TODO: Change this to clearing the variable by running in the module
159+ string modulePath = System . IO . Path . Join ( AppDomain . CurrentDomain . BaseDirectory , "Azure.Functions.PowerShell.Worker.Module" , "Azure.Functions.PowerShell.Worker.Module.psd1" ) ;
160+ _pwsh . AddCommand ( "Import-Module" )
161+ . AddParameter ( "Name" , modulePath )
162+ . AddParameter ( "Scope" , "Global" )
163+ . AddParameter ( "Force" )
164+ . InvokeAndClearCommands ( ) ;
165+ }
193166 }
194167}
0 commit comments