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.
///