66using System ;
77using System . Collections . Generic ;
88using System . ComponentModel ;
9- using System . Globalization ;
109using System . IO ;
1110using System . Linq ;
1211using System . Management . Automation . Host ;
@@ -23,6 +22,7 @@ namespace Microsoft.PowerShell.EditorServices.Services
2322{
2423 using System . Diagnostics . CodeAnalysis ;
2524 using System . Management . Automation ;
25+ using System . Runtime . InteropServices ;
2626 using Microsoft . PowerShell . EditorServices . Handlers ;
2727 using Microsoft . PowerShell . EditorServices . Hosting ;
2828 using Microsoft . PowerShell . EditorServices . Logging ;
@@ -367,10 +367,9 @@ public void Initialize(
367367 powerShellVersion . ToString ( ) ) ;
368368 }
369369
370- if ( this . LocalPowerShellVersion . Edition != "Linux" )
370+ if ( VersionUtils . IsWindows )
371371 {
372- // TODO: Should this be configurable?
373- this . SetExecutionPolicy ( ExecutionPolicy . RemoteSigned ) ;
372+ this . SetExecutionPolicy ( ) ;
374373 }
375374
376375 // Set up the runspace
@@ -2086,56 +2085,70 @@ private static string GetStringForPSCommand(PSCommand psCommand)
20862085 return stringBuilder . ToString ( ) ;
20872086 }
20882087
2089- private void SetExecutionPolicy ( ExecutionPolicy desiredExecutionPolicy )
2088+ private void SetExecutionPolicy ( )
20902089 {
2091- var currentPolicy = ExecutionPolicy . Undefined ;
2090+ // We want to get the list hierarchy of execution policies
2091+ // Calling the cmdlet is the simplest way to do that
2092+ IReadOnlyList < PSObject > policies = this . powerShell
2093+ . AddCommand ( "Microsoft.PowerShell.Security\\ Get-ExecutionPolicy" )
2094+ . AddParameter ( "-List" )
2095+ . Invoke ( ) ;
20922096
2093- // Get the current execution policy so that we don't set it higher than it already is
2094- this . powerShell . Commands . AddCommand ( "Get-ExecutionPolicy" ) ;
2097+ this . powerShell . Commands . Clear ( ) ;
20952098
2096- var result = this . powerShell . Invoke < ExecutionPolicy > ( ) ;
2097- if ( result . Count > 0 )
2099+ // The policies come out in the following order:
2100+ // - MachinePolicy
2101+ // - UserPolicy
2102+ // - Process
2103+ // - CurrentUser
2104+ // - LocalMachine
2105+ // This is the order of precedence we want to follow, skipping the Process scope
2106+ //
2107+ // Get-ExecutionPolicy -List emits PSObjects with Scope and ExecutionPolicy note properties
2108+ // set to expected values, so we must sift through those.
2109+ ExecutionPolicy policyToSet = ExecutionPolicy . Bypass ;
2110+ for ( int i = policies . Count - 1 ; i >= 0 ; i -- )
20982111 {
2099- currentPolicy = result . FirstOrDefault ( ) ;
2100- }
2112+ PSObject policyObject = policies [ i ] ;
21012113
2102- if ( desiredExecutionPolicy < currentPolicy ||
2103- desiredExecutionPolicy == ExecutionPolicy . Bypass ||
2104- currentPolicy == ExecutionPolicy . Undefined )
2105- {
2106- this . logger . LogTrace (
2107- string . Format (
2108- "Setting execution policy:\r \n Current = ExecutionPolicy.{0}\r \n Desired = ExecutionPolicy.{1}" ,
2109- currentPolicy ,
2110- desiredExecutionPolicy ) ) ;
2111-
2112- this . powerShell . Commands . Clear ( ) ;
2113- this . powerShell
2114- . AddCommand ( "Set-ExecutionPolicy" )
2115- . AddParameter ( "ExecutionPolicy" , desiredExecutionPolicy )
2116- . AddParameter ( "Scope" , ExecutionPolicyScope . Process )
2117- . AddParameter ( "Force" ) ;
2118-
2119- try
2114+ if ( ( ExecutionPolicyScope ) policyObject . Members [ "Scope" ] . Value == ExecutionPolicyScope . Process )
21202115 {
2121- this . powerShell . Invoke ( ) ;
2116+ break ;
21222117 }
2123- catch ( CmdletInvocationException e )
2118+
2119+ var executionPolicy = ( ExecutionPolicy ) policyObject . Members [ "ExecutionPolicy" ] . Value ;
2120+ if ( executionPolicy != ExecutionPolicy . Undefined )
21242121 {
2125- this . logger . LogException (
2126- $ "An error occurred while calling Set-ExecutionPolicy, the desired policy of { desiredExecutionPolicy } may not be set.",
2127- e ) ;
2122+ policyToSet = executionPolicy ;
2123+ break ;
21282124 }
2129-
2130- this . powerShell . Commands . Clear ( ) ;
21312125 }
2132- else
2126+
2127+ // If there's nothing to do, save ourselves a PowerShell invocation
2128+ if ( policyToSet == ExecutionPolicy . Bypass )
21332129 {
2134- this . logger . LogTrace (
2135- string . Format (
2136- "Current execution policy: ExecutionPolicy.{0}" ,
2137- currentPolicy ) ) ;
2130+ this . logger . LogTrace ( "Execution policy already set to Bypass. Skipping execution policy set" ) ;
2131+ return ;
2132+ }
21382133
2134+ // Finally set the inherited execution policy
2135+ this . logger . LogTrace ( "Setting execution policy to {Policy}" , policyToSet ) ;
2136+ try
2137+ {
2138+ this . powerShell
2139+ . AddCommand ( "Microsoft.PowerShell.Security\\ Set-ExecutionPolicy" )
2140+ . AddParameter ( "Scope" , ExecutionPolicyScope . Process )
2141+ . AddParameter ( "ExecutionPolicy" , policyToSet )
2142+ . AddParameter ( "Force" )
2143+ . Invoke ( ) ;
2144+ }
2145+ catch ( CmdletInvocationException e )
2146+ {
2147+ this . logger . LogError ( e , "Error occurred calling 'Set-ExecutionPolicy -Scope Process -ExecutionPolicy {Policy} -Force'" , policyToSet ) ;
2148+ }
2149+ finally
2150+ {
2151+ this . powerShell . Commands . Clear ( ) ;
21392152 }
21402153 }
21412154
0 commit comments