diff --git a/.editorconfig b/.editorconfig
index efe9133c8ff..d2ac76dc9cd 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -49,6 +49,9 @@ indent_style = tab
# Dotnet code style settings:
[*.cs]
+# Ignore xUnit analyzer rule "Do not use blocking task operations in test method"
+dotnet_diagnostic.xUnit1031.severity = none
+
# Sort using and Import directives with System.* appearing first
dotnet_sort_system_directives_first = true
diff --git a/Analyzers.props b/Analyzers.props
index 2608f972630..6f906496c73 100644
--- a/Analyzers.props
+++ b/Analyzers.props
@@ -1,6 +1,6 @@
-
+
diff --git a/CHANGELOG/7.4.md b/CHANGELOG/7.4.md
index 5dd5481c919..1d62bb6f61f 100644
--- a/CHANGELOG/7.4.md
+++ b/CHANGELOG/7.4.md
@@ -1,5 +1,41 @@
# 7.4 Changelog
+## [7.4.1] - 2024-01-11
+
+### General Cmdlet Updates and Fixes
+
+- Fix `Group-Object` output using interpolated strings (#20745) (Thanks @mawosoft!)
+- Fix `Start-Process -PassThru` to make sure the `ExitCode` property is accessible for the returned `Process` object (#20749) (#20866) (Thanks @CodeCyclone!)
+- Fix rendering of DisplayRoot for network PSDrive (#20793) (#20863)
+
+### Engine Updates and Fixes
+
+- Ensure filename is not null when logging WDAC ETW events (#20910) (Thanks @jborean93!)
+- Fix four regressions introduced by WDAC audit logging feature (#20913)
+
+### Build and Packaging Improvements
+
+
+
+
+
+Bump .NET 8 to version 8.0.101
+
+
+
+
+- Update .NET SDK and dependencies for v7.4.1 (Internal 29142)
+- Update cgmanifest for v7.4.1 (#20874)
+- Update package dependencies for v7.4.1 (#20871)
+- Set the
rollForwardOnNoCandidateFx in runtimeconfig.json to roll forward only on minor and patch versions (#20689) (#20865)
+- Remove RHEL7 publishing to packages.microsoft.com as it's no longer supported (#20849) (#20864)
+- Fix the tab completion tests (#20867)
+
+
+
+
+[7.4.1]: https://github.com/PowerShell/PowerShell/compare/v7.4.0...v7.4.1
+
## [7.4.0] - 2023-11-16
### General Cmdlet Updates and Fixes
diff --git a/DotnetRuntimeMetadata.json b/DotnetRuntimeMetadata.json
index 0eca4cf79f4..a2bec0cdc03 100644
--- a/DotnetRuntimeMetadata.json
+++ b/DotnetRuntimeMetadata.json
@@ -4,12 +4,12 @@
"quality": "daily",
"qualityFallback": "preview",
"packageVersionPattern": "8.0.0",
- "sdkImageVersion": "8.0.100",
+ "sdkImageVersion": "8.0.101",
"nextChannel": "8.0.1xx",
"azureFeed": "",
- "sdkImageOverride": "8.0.100-rtm.23551.15"
+ "sdkImageOverride": ""
},
"internalfeed": {
- "url": "https://pkgs.dev.azure.com/powershell-rel/PowerShell/_packaging/powershell-7.4-ga/nuget/v2"
+ "url": ""
}
}
diff --git a/global.json b/global.json
index 5ce84955149..d54915e8d4d 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,5 @@
{
"sdk": {
- "version": "8.0.100"
+ "version": "8.0.101"
}
}
diff --git a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs
index c5df76c0445..e445b60986e 100644
--- a/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs
+++ b/src/Microsoft.PowerShell.Commands.Management/commands/management/Process.cs
@@ -2126,6 +2126,13 @@ protected override void BeginProcessing()
jobAssigned = jobObject.AssignProcessToJobObject(processInfo.Process);
}
+ // Since the process wasn't spawned by .NET, we need to trigger .NET to get a lock on the handle of the process.
+ // Otherwise, accessing properties like `ExitCode` will throw the following exception:
+ // "Process was not started by this object, so requested information cannot be determined."
+ // Fetching the process handle will trigger the `Process` object to update its internal state by calling `SetProcessHandle`,
+ // the result is discarded as it's not used later in this code.
+ _ = process.Handle;
+
// Resume the process now that is has been set up.
processInfo.Resume();
#endif
diff --git a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
index fc5a61d44b8..e582c08ab89 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
+++ b/src/Microsoft.PowerShell.Commands.Utility/Microsoft.PowerShell.Commands.Utility.csproj
@@ -32,10 +32,13 @@
-
+
-
-
+
+
+
+
+
diff --git a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs
index 0f0a9951967..1f527258939 100644
--- a/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs
+++ b/src/Microsoft.PowerShell.Commands.Utility/commands/utility/Group-Object.cs
@@ -153,7 +153,7 @@ private static string BuildName(List propValues)
foreach (object item in propertyValueItems)
{
- sb.AppendFormat(CultureInfo.CurrentCulture, $"{item}, ");
+ sb.Append(CultureInfo.CurrentCulture, $"{item}, ");
}
sb = sb.Length > length ? sb.Remove(sb.Length - 2, 2) : sb;
@@ -161,7 +161,7 @@ private static string BuildName(List propValues)
}
else
{
- sb.AppendFormat(CultureInfo.CurrentCulture, $"{propValuePropertyValue}, ");
+ sb.Append(CultureInfo.CurrentCulture, $"{propValuePropertyValue}, ");
}
}
}
diff --git a/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json b/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json
index 8ba6dc2eba9..4a5e3e367ec 100644
--- a/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json
+++ b/src/Microsoft.PowerShell.GlobalTool.Shim/runtimeconfig.template.json
@@ -1,4 +1,4 @@
-// This is required to roll forward to runtime 3.x when 2.x is not installed
+// This is required to roll forward to supported minor.patch versions of the runtime.
{
- "rollForwardOnNoCandidateFx": 2
+ "rollForwardOnNoCandidateFx": 1
}
diff --git a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
index c6e8bf10326..5945b00b2b4 100644
--- a/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
+++ b/src/Microsoft.PowerShell.SDK/Microsoft.PowerShell.SDK.csproj
@@ -17,7 +17,7 @@
-
+
@@ -33,8 +33,10 @@
+
-
+
+
diff --git a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj
index 4cc9ed73321..3adf1cc62ed 100644
--- a/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj
+++ b/src/System.Management.Automation/SourceGenerators/PSVersionInfoGenerator/PSVersionInfoGenerator.csproj
@@ -13,7 +13,9 @@
-
+
+
+
diff --git a/src/System.Management.Automation/System.Management.Automation.csproj b/src/System.Management.Automation/System.Management.Automation.csproj
index a13051797df..12247e78313 100644
--- a/src/System.Management.Automation/System.Management.Automation.csproj
+++ b/src/System.Management.Automation/System.Management.Automation.csproj
@@ -40,7 +40,7 @@
-
+
diff --git a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs
index bf7742526f1..fcdaeb65d3c 100644
--- a/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs
+++ b/src/System.Management.Automation/engine/Interop/Windows/WNetGetConnection.cs
@@ -13,8 +13,8 @@ internal static unsafe partial class Windows
{
private static bool s_WNetApiNotAvailable;
- [LibraryImport("mpr.dll", EntryPoint = "WNetGetConnectionW")]
- internal static partial int WNetGetConnection(ReadOnlySpan localName, Span remoteName, ref uint remoteNameLength);
+ [LibraryImport("mpr.dll", EntryPoint = "WNetGetConnectionW", StringMarshalling = StringMarshalling.Utf16)]
+ internal static partial int WNetGetConnection(ReadOnlySpan localName, Span remoteName, ref uint remoteNameLength);
internal static int GetUNCForNetworkDrive(char drive, out string? uncPath)
{
@@ -33,11 +33,8 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath)
bufferSize = 3;
#endif
- // TODO: change ushort with char after LibraryImport will support 'ref char'
- // without applying the 'System.Runtime.CompilerServices.DisableRuntimeMarshallingAttribute'
- // to the assembly.
- ReadOnlySpan driveName = stackalloc ushort[] { drive, ':', '\0' };
- Span uncBuffer = stackalloc ushort[(int)bufferSize];
+ ReadOnlySpan driveName = stackalloc char[] { drive, ':', '\0' };
+ Span uncBuffer = stackalloc char[(int)bufferSize];
int errorCode = ERROR_NO_NETWORK;
try
@@ -52,26 +49,28 @@ internal static int GetUNCForNetworkDrive(char drive, out string? uncPath)
if (errorCode == ERROR_SUCCESS)
{
- uncPath = uncBuffer.Slice((int)bufferSize).ToString();
+ // exclude null terminator
+ uncPath = uncBuffer.Slice(0, (int)bufferSize - 1).ToString();
}
else if (errorCode == ERROR_MORE_DATA)
{
- ushort[]? rentedArray = null;
+ char[]? rentedArray = null;
try
{
- uncBuffer = rentedArray = ArrayPool.Shared.Rent((int)bufferSize);
+ uncBuffer = rentedArray = ArrayPool.Shared.Rent((int)bufferSize);
errorCode = WNetGetConnection(driveName, uncBuffer, ref bufferSize);
if (errorCode == ERROR_SUCCESS)
{
- uncPath = uncBuffer.Slice((int)bufferSize).ToString();
+ // exclude null terminator
+ uncPath = uncBuffer.Slice(0, (int)bufferSize - 1).ToString();
}
}
finally
{
if (rentedArray is not null)
{
- ArrayPool.Shared.Return(rentedArray);
+ ArrayPool.Shared.Return(rentedArray);
}
}
}
diff --git a/src/System.Management.Automation/engine/LanguagePrimitives.cs b/src/System.Management.Automation/engine/LanguagePrimitives.cs
index ac78e5e80d5..87a6dcb7804 100644
--- a/src/System.Management.Automation/engine/LanguagePrimitives.cs
+++ b/src/System.Management.Automation/engine/LanguagePrimitives.cs
@@ -3986,44 +3986,46 @@ internal object Convert(object valueToConvert,
// - It's in FullLanguage but not because it's part of a parameter binding that is transitioning from ConstrainedLanguage to FullLanguage
// When this is invoked from a parameter binding in transition from ConstrainedLanguage environment to FullLanguage command, we disallow
// the property conversion because it's dangerous.
- if (ecFromTLS == null || (ecFromTLS.LanguageMode == PSLanguageMode.FullLanguage && !ecFromTLS.LanguageModeTransitionInParameterBinding))
+ bool canProceedWithConversion = ecFromTLS == null || (ecFromTLS.LanguageMode == PSLanguageMode.FullLanguage && !ecFromTLS.LanguageModeTransitionInParameterBinding);
+ if (!canProceedWithConversion)
{
- result = _constructor();
- var psobject = valueToConvert as PSObject;
- if (psobject != null)
- {
- // Use PSObject properties to perform conversion.
- SetObjectProperties(result, psobject, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, formatProvider, recursion, ignoreUnknownMembers);
- }
- else
+ if (SystemPolicy.GetSystemLockdownPolicy() != SystemEnforcementMode.Audit)
{
- // Use provided property dictionary to perform conversion.
- // The method invocation is disabled for "Hashtable to Object conversion" (Win8:649519), but we need to keep it enabled for New-Object for compatibility to PSv2
- IDictionary properties = valueToConvert as IDictionary;
- SetObjectProperties(result, properties, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: false);
+ throw InterpreterError.NewInterpreterException(
+ valueToConvert,
+ typeof(RuntimeException),
+ errorPosition: null,
+ "HashtableToObjectConversionNotSupportedInDataSection",
+ ParserStrings.HashtableToObjectConversionNotSupportedInDataSection,
+ resultType.ToString());
}
- typeConversion.WriteLine("Constructor result: \"{0}\".", result);
- }
- else
- {
- if (SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Audit)
- {
- SystemPolicy.LogWDACAuditMessage(
+ // When in audit mode, we report but don't enforce, so we will proceed with the conversion.
+ SystemPolicy.LogWDACAuditMessage(
context: ecFromTLS,
title: ExtendedTypeSystem.WDACHashTypeLogTitle,
message: StringUtil.Format(ExtendedTypeSystem.WDACHashTypeLogMessage, resultType.FullName),
fqid: "LanguageHashtableConversionNotAllowed",
dropIntoDebugger: true);
- }
- else
- {
- RuntimeException rte = InterpreterError.NewInterpreterException(valueToConvert, typeof(RuntimeException), null,
- "HashtableToObjectConversionNotSupportedInDataSection", ParserStrings.HashtableToObjectConversionNotSupportedInDataSection, resultType.ToString());
- throw rte;
- }
}
+ result = _constructor();
+ var psobject = valueToConvert as PSObject;
+ if (psobject != null)
+ {
+ // Use PSObject properties to perform conversion.
+ SetObjectProperties(result, psobject, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, formatProvider, recursion, ignoreUnknownMembers);
+ }
+ else
+ {
+ // Use provided property dictionary to perform conversion.
+ // The method invocation is disabled for "Hashtable to Object conversion" (Win8:649519), but we need to keep it enabled for New-Object for compatibility to PSv2
+ IDictionary properties = valueToConvert as IDictionary;
+ SetObjectProperties(result, properties, resultType, CreateMemberNotFoundError, CreateMemberSetValueError, enableMethodCall: false);
+ }
+
+ typeConversion.WriteLine("Constructor result: \"{0}\".", result);
+
return result;
}
catch (TargetInvocationException ex)
diff --git a/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs b/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs
index b3bfbe9a0d9..f76b836885a 100644
--- a/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs
+++ b/src/System.Management.Automation/engine/remoting/client/RunspaceRef.cs
@@ -5,6 +5,7 @@
using System.Management.Automation.Internal;
using System.Management.Automation.Runspaces;
using System.Management.Automation.Runspaces.Internal;
+using System.Management.Automation.Security;
using Dbg = System.Management.Automation.Diagnostics;
@@ -94,7 +95,22 @@ private PSCommand ParsePsCommandUsingScriptBlock(string line, bool? useLocalScop
// to be parsed and evaluated on the remote session (not in the current local session).
RemoteRunspace remoteRunspace = _runspaceRef.Value as RemoteRunspace;
bool isConfiguredLoopback = remoteRunspace != null && remoteRunspace.IsConfiguredLoopBack;
- bool isTrustedInput = !isConfiguredLoopback && (localRunspace.ExecutionContext.LanguageMode == PSLanguageMode.FullLanguage);
+
+ bool inFullLanguage = context.LanguageMode == PSLanguageMode.FullLanguage;
+ if (context.LanguageMode == PSLanguageMode.ConstrainedLanguage
+ && SystemPolicy.GetSystemLockdownPolicy() == SystemEnforcementMode.Audit)
+ {
+ // In audit mode, report but don't enforce.
+ inFullLanguage = true;
+ SystemPolicy.LogWDACAuditMessage(
+ context: context,
+ title: RemotingErrorIdStrings.WDACGetPowerShellLogTitle,
+ message: RemotingErrorIdStrings.WDACGetPowerShellLogMessage,
+ fqid: "GetPowerShellMayFail",
+ dropIntoDebugger: true);
+ }
+
+ bool isTrustedInput = !isConfiguredLoopback && inFullLanguage;
// Create PowerShell from ScriptBlock.
ScriptBlock scriptBlock = ScriptBlock.Create(context, line);
@@ -350,7 +366,7 @@ internal void Override(RemoteRunspace remoteRunspace, object syncObject, out boo
///
private void HandleHostCall(object sender, RemoteDataEventArgs eventArgs)
{
- System.Management.Automation.Runspaces.Internal.ClientRemotePowerShell.ExitHandler(sender, eventArgs);
+ ClientRemotePowerShell.ExitHandler(sender, eventArgs);
}
#region Robust Connection Support
diff --git a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
index c633fd9fe5c..3c38a3b5bdc 100644
--- a/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
+++ b/src/System.Management.Automation/engine/remoting/commands/PSRemotingCmdlet.cs
@@ -2278,7 +2278,7 @@ private System.Management.Automation.PowerShell GetPowerShellForPSv3OrLater(stri
// Semantic checks on the using statement have already validated that there are no arbitrary expressions,
// so we'll allow these expressions in everything but NoLanguage mode.
- bool allowUsingExpressions = (Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage);
+ bool allowUsingExpressions = Context.SessionState.LanguageMode != PSLanguageMode.NoLanguage;
object[] usingValuesInArray = null;
IDictionary usingValuesInDict = null;
@@ -2428,7 +2428,7 @@ private List