diff --git a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs index 19bb79977e7..e2b7bd7b8ba 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs +++ b/src/Microsoft.PowerShell.ConsoleHost/host/msh/ConsoleHost.cs @@ -180,7 +180,7 @@ internal static int Start( // Alternatively, we could call s_theConsoleHost.UI.WriteLine(s_theConsoleHost.Version.ToString()); // or start up the engine and retrieve the information via $psversiontable.GitCommitId // but this returns the semantic version and avoids executing a script - s_theConsoleHost.UI.WriteLine("PowerShell " + PSVersionInfo.GitCommitId); + s_theConsoleHost.UI.WriteLine($"PowerShell {PSVersionInfo.GitCommitId}"); return 0; } @@ -1831,8 +1831,29 @@ private void DoRunspaceInitialization(RunspaceCreationEventArgs args) const string shellId = "Microsoft.PowerShell"; // If the system lockdown policy says "Enforce", do so. Do this after types / formatting, default functions, etc - // are loaded so that they are trusted. (Validation of their signatures is done in F&O) - Utils.EnforceSystemLockDownLanguageMode(_runspaceRef.Runspace.ExecutionContext); + // are loaded so that they are trusted. (Validation of their signatures is done in F&O). + var languageMode = Utils.EnforceSystemLockDownLanguageMode(_runspaceRef.Runspace.ExecutionContext); + // When displaying banner, also display the language mode if running in any restricted mode. + if (s_cpp.ShowBanner) + { + switch (languageMode) + { + case PSLanguageMode.ConstrainedLanguage: + s_theConsoleHost.UI.WriteLine(ManagedEntranceStrings.ShellBannerCLMode); + break; + + case PSLanguageMode.NoLanguage: + s_theConsoleHost.UI.WriteLine(ManagedEntranceStrings.ShellBannerNLMode); + break; + + case PSLanguageMode.RestrictedLanguage: + s_theConsoleHost.UI.WriteLine(ManagedEntranceStrings.ShellBannerRLMode); + break; + + default: + break; + } + } string allUsersProfile = HostUtilities.GetFullProfileFileName(null, false); string allUsersHostSpecificProfile = HostUtilities.GetFullProfileFileName(shellId, false); diff --git a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx index df68fb8e70a..65d5ebe041d 100644 --- a/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx +++ b/src/Microsoft.PowerShell.ConsoleHost/resources/ManagedEntranceStrings.resx @@ -120,6 +120,15 @@ PowerShell {0} + + [Constrained Language Mode] + + + [No Language Mode] + + + [Restricted Language Mode] + Warning: PowerShell detected that you might be using a screen reader and has disabled PSReadLine for compatibility purposes. If you want to re-enable it, run 'Import-Module PSReadLine'. diff --git a/src/System.Management.Automation/engine/Utils.cs b/src/System.Management.Automation/engine/Utils.cs index 295b7f931ed..61f10ab6930 100644 --- a/src/System.Management.Automation/engine/Utils.cs +++ b/src/System.Management.Automation/engine/Utils.cs @@ -1457,22 +1457,18 @@ internal static bool IsComObject(object obj) /// NoLanguage -> NoLanguage. /// /// ExecutionContext. - /// Previous language mode or null for no language mode change. - internal static PSLanguageMode? EnforceSystemLockDownLanguageMode(ExecutionContext context) + /// The current ExecutionContext language mode. + internal static PSLanguageMode EnforceSystemLockDownLanguageMode(ExecutionContext context) { - PSLanguageMode? oldMode = null; - if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Enforce) { switch (context.LanguageMode) { case PSLanguageMode.FullLanguage: - oldMode = context.LanguageMode; context.LanguageMode = PSLanguageMode.ConstrainedLanguage; break; case PSLanguageMode.RestrictedLanguage: - oldMode = context.LanguageMode; context.LanguageMode = PSLanguageMode.NoLanguage; break; @@ -1482,13 +1478,12 @@ internal static bool IsComObject(object obj) default: Diagnostics.Assert(false, "Unexpected PSLanguageMode"); - oldMode = context.LanguageMode; context.LanguageMode = PSLanguageMode.NoLanguage; break; } } - return oldMode; + return context.LanguageMode; } internal static string DisplayHumanReadableFileSize(long bytes) diff --git a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs index d59e8828830..b9c599d53e5 100644 --- a/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs +++ b/src/System.Management.Automation/engine/remoting/common/PSETWTracer.cs @@ -159,6 +159,7 @@ internal enum PSEventId : int Settings = 0x1F04, Engine_Trace = 0x1F06, Amsi_Init = 0x4001, + WDAC_Query = 0x4002, // Experimental Features ExperimentalFeature_InvalidName = 0x3001, @@ -241,7 +242,8 @@ internal enum PSTask : int ScheduledJob = 0x6E, NamedPipe = 0x6F, ISEOperation = 0x78, - Amsi = 0X82 + Amsi = 0X82, + WDAC = 0x83 } /// diff --git a/src/System.Management.Automation/logging/LogProvider.cs b/src/System.Management.Automation/logging/LogProvider.cs index bca5d5fb930..b7de1f60b4e 100644 --- a/src/System.Management.Automation/logging/LogProvider.cs +++ b/src/System.Management.Automation/logging/LogProvider.cs @@ -109,6 +109,19 @@ internal LogProvider() /// The amsiContext handled - Session pair. internal abstract void LogAmsiUtilStateEvent(string state, string context); + /// + /// Provider interface function for logging WDAC query event. + /// + /// Name of the WDAC query. + /// Name of script file for policy query. Can be null value. + /// Query call succeed code. + /// Result code of WDAC query. + internal abstract void LogWDACQueryEvent( + string queryName, + string fileName, + int querySuccess, + int queryResult); + /// /// True if the log provider needs to use logging variables. /// @@ -386,6 +399,21 @@ internal override void LogAmsiUtilStateEvent(string state, string context) { } + /// + /// Provider interface function for logging WDAC query event. + /// + /// Name of the WDAC query. + /// Name of script file for policy query. Can be null value. + /// Query call succeed code. + /// Result code of WDAC query. + internal override void LogWDACQueryEvent( + string queryName, + string fileName, + int querySuccess, + int queryResult) + { + } + #endregion } } diff --git a/src/System.Management.Automation/security/wldpNativeMethods.cs b/src/System.Management.Automation/security/wldpNativeMethods.cs index 970abe541f6..730db922a00 100644 --- a/src/System.Management.Automation/security/wldpNativeMethods.cs +++ b/src/System.Management.Automation/security/wldpNativeMethods.cs @@ -6,9 +6,10 @@ // #if !UNIX +using System.Diagnostics.CodeAnalysis; using System.Management.Automation.Internal; +using System.Management.Automation.Tracing; using System.Runtime.InteropServices; -using System.Diagnostics.CodeAnalysis; namespace System.Management.Automation.Security { @@ -110,6 +111,7 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( SafeHandle fileHandle = fileStream.SafeFileHandle; // First check latest WDAC APIs if available. + Exception errorException = null; if (s_wldpCanExecuteAvailable) { try @@ -124,6 +126,8 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( auditInfo: auditMsg, result: out WLDP_EXECUTION_POLICY canExecuteResult); + PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile", filePath, hr, (int)canExecuteResult); + if (hr >= 0) { switch (canExecuteResult) @@ -146,15 +150,22 @@ public static SystemScriptFileEnforcement GetFilePolicyEnforcement( // If HResult is unsuccessful (such as E_NOTIMPL (0x80004001)), fall through to legacy system checks. } - catch (DllNotFoundException) + catch (DllNotFoundException ex) { // Fall back to legacy system policy checks. s_wldpCanExecuteAvailable = false; + errorException = ex; } - catch (EntryPointNotFoundException) + catch (EntryPointNotFoundException ex) { // Fall back to legacy system policy checks. s_wldpCanExecuteAvailable = false; + errorException = ex; + } + + if (errorException != null) + { + PSEtwLog.LogWDACQueryEvent("WldpCanExecuteFile_Failed", filePath, errorException.HResult, 0); } } @@ -263,6 +274,7 @@ private static SystemEnforcementMode GetWldpPolicy(string path, SafeHandle handl uint pdwLockdownState = 0; int result = WldpNativeMethods.WldpGetLockdownPolicy(ref hostInformation, ref pdwLockdownState, 0); + PSEtwLog.LogWDACQueryEvent("WldpGetLockdownPolicy", path, result, (int)pdwLockdownState); if (result >= 0) { SystemEnforcementMode resultingLockdownPolicy = GetLockdownPolicyForResult(pdwLockdownState); @@ -281,9 +293,10 @@ private static SystemEnforcementMode GetWldpPolicy(string path, SafeHandle handl return SystemEnforcementMode.Enforce; } } - catch (DllNotFoundException) + catch (DllNotFoundException ex) { s_hadMissingWldpAssembly = true; + PSEtwLog.LogWDACQueryEvent("WldpGetLockdownPolicy_Failed", path, ex.HResult, 0); return s_cachedWldpSystemPolicy.GetValueOrDefault(SystemEnforcementMode.None); } } diff --git a/src/System.Management.Automation/utils/tracing/PSEtwLog.cs b/src/System.Management.Automation/utils/tracing/PSEtwLog.cs index 8212cf55cd8..438d7b5f059 100644 --- a/src/System.Management.Automation/utils/tracing/PSEtwLog.cs +++ b/src/System.Management.Automation/utils/tracing/PSEtwLog.cs @@ -128,6 +128,22 @@ internal static void LogAmsiUtilStateEvent(string state, string context) provider.LogAmsiUtilStateEvent(state, context); } + /// + /// Provider interface function for logging WDAC query event. + /// + /// Name of the WDAC query. + /// Name of script file for policy query. Can be null value. + /// Query call succeed code. + /// Result code of WDAC query. + internal static void LogWDACQueryEvent( + string queryName, + string fileName, + int querySuccess, + int queryResult) + { + provider.LogWDACQueryEvent(queryName, fileName, querySuccess, queryResult); + } + /// /// Provider interface function for logging settings event. /// diff --git a/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs b/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs index 09b1cd9b0f0..9b56da1ae72 100755 --- a/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs +++ b/src/System.Management.Automation/utils/tracing/PSEtwLogProvider.cs @@ -202,6 +202,22 @@ internal override void LogAmsiUtilStateEvent(string state, string context) WriteEvent(PSEventId.Amsi_Init, PSChannel.Analytic, PSOpcode.Method, PSLevel.Informational, PSTask.Amsi, (PSKeyword)0x0, state, context); } + /// + /// Provider interface function for logging WDAC query event. + /// + /// Name of the WDAC query. + /// Name of script file for policy query. Can be null value. + /// Query call succeed code. + /// Result code of WDAC query. + internal override void LogWDACQueryEvent( + string queryName, + string fileName, + int querySuccess, + int queryResult) + { + WriteEvent(PSEventId.WDAC_Query, PSChannel.Analytic, PSOpcode.Method, PSLevel.Informational, PSTask.WDAC, (PSKeyword)0x0, queryName, fileName, querySuccess, queryResult); + } + /// /// Provider interface function for logging provider lifecycle event. /// diff --git a/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs b/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs index 629cdd64476..e7accd6978c 100755 --- a/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs +++ b/src/System.Management.Automation/utils/tracing/PSSysLogProvider.cs @@ -102,6 +102,22 @@ internal override void LogAmsiUtilStateEvent(string state, string context) WriteEvent(PSEventId.Amsi_Init, PSChannel.Analytic, PSOpcode.Method, PSLevel.Informational, PSTask.Amsi, (PSKeyword)0x0, state, context); } + /// + /// Provider interface function for logging WDAC query event. + /// + /// Name of the WDAC query. + /// Name of script file for policy query. Can be null value. + /// Query call succeed code. + /// Result code of WDAC query. + internal override void LogWDACQueryEvent( + string queryName, + string fileName, + int querySuccess, + int queryResult) + { + WriteEvent(PSEventId.WDAC_Query, PSChannel.Analytic, PSOpcode.Method, PSLevel.Informational, PSTask.WDAC, (PSKeyword)0x0, queryName, fileName, querySuccess, queryResult); + } + /// /// Provider interface function for logging engine lifecycle event. ///