diff --git a/src/Cli/Microsoft.DotNet.FileBasedPrograms/MSBuildUtilities.cs b/src/Cli/Microsoft.DotNet.FileBasedPrograms/MSBuildUtilities.cs
deleted file mode 100644
index 0b556f86daee..000000000000
--- a/src/Cli/Microsoft.DotNet.FileBasedPrograms/MSBuildUtilities.cs
+++ /dev/null
@@ -1,71 +0,0 @@
-// Licensed to the .NET Foundation under one or more agreements.
-// The .NET Foundation licenses this file to you under the MIT license.
-
-// https://github.com/dotnet/sdk/issues/51487: avoid this extra copy of the file.
-#nullable enable
-using System;
-
-namespace Microsoft.DotNet.FileBasedPrograms
-{
- ///
- /// Internal utilities copied from microsoft/MSBuild repo.
- ///
- class MSBuildUtilities
- {
- ///
- /// Converts a string to a bool. We consider "true/false", "on/off", and
- /// "yes/no" to be valid boolean representations in the XML.
- /// Modified from its original version to not throw, but return a default value.
- ///
- /// The string to convert.
- /// Boolean true or false, corresponding to the string.
- internal static bool ConvertStringToBool(string? parameterValue, bool defaultValue = false)
- {
- if (string.IsNullOrEmpty(parameterValue))
- {
- return defaultValue;
- }
- else if (ValidBooleanTrue(parameterValue))
- {
- return true;
- }
- else if (ValidBooleanFalse(parameterValue))
- {
- return false;
- }
- else
- {
- // Unsupported boolean representation.
- return defaultValue;
- }
- }
-
- ///
- /// Returns true if the string represents a valid MSBuild boolean true value,
- /// such as "on", "!false", "yes"
- ///
- private static bool ValidBooleanTrue(string? parameterValue)
- {
- return ((string.Compare(parameterValue, "true", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "on", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "yes", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "!false", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "!off", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "!no", StringComparison.OrdinalIgnoreCase) == 0));
- }
-
- ///
- /// Returns true if the string represents a valid MSBuild boolean false value,
- /// such as "!on" "off" "no" "!true"
- ///
- private static bool ValidBooleanFalse(string? parameterValue)
- {
- return ((string.Compare(parameterValue, "false", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "off", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "no", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "!true", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "!on", StringComparison.OrdinalIgnoreCase) == 0) ||
- (string.Compare(parameterValue, "!yes", StringComparison.OrdinalIgnoreCase) == 0));
- }
- }
-}
diff --git a/src/Cli/Microsoft.DotNet.FileBasedPrograms/Microsoft.DotNet.FileBasedPrograms.projitems b/src/Cli/Microsoft.DotNet.FileBasedPrograms/Microsoft.DotNet.FileBasedPrograms.projitems
index 4ee12260067b..9ca6536ca148 100644
--- a/src/Cli/Microsoft.DotNet.FileBasedPrograms/Microsoft.DotNet.FileBasedPrograms.projitems
+++ b/src/Cli/Microsoft.DotNet.FileBasedPrograms/Microsoft.DotNet.FileBasedPrograms.projitems
@@ -10,6 +10,8 @@
+
+
Designer
diff --git a/src/Common/MSBuildUtilities.cs b/src/Common/MSBuildUtilities.cs
index d1ad0ea46959..ab7318d6d724 100644
--- a/src/Common/MSBuildUtilities.cs
+++ b/src/Common/MSBuildUtilities.cs
@@ -1,7 +1,23 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.
+// This file is shared between the SDK MSBuild build tasks and the Microsoft.DotNet.FileBasedPrograms source
+// package (which is also consumed by Roslyn and the dotnet CLI) to avoid a duplicate copy. See
+// https://github.com/dotnet/sdk/issues/51487. The build-tasks projects that link this file define
+// MSBUILD_BUILD_TASKS to select the Microsoft.DotNet.Cli namespace; every other consumer (the source
+// package, its external consumers, and ProjectTools) gets the Microsoft.DotNet.FileBasedPrograms form,
+// which matches the file as it originally shipped. The build tasks enable nullable and provide System via
+// ImplicitUsings, so emitting the directive and using there would be flagged as redundant (IDE0240/IDE0005).
+#if !MSBUILD_BUILD_TASKS
+#nullable enable
+using System;
+#endif
+
+#if MSBUILD_BUILD_TASKS
namespace Microsoft.DotNet.Cli
+#else
+namespace Microsoft.DotNet.FileBasedPrograms
+#endif
{
///
/// Internal utilities copied from microsoft/MSBuild repo.
diff --git a/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj b/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj
index 5c1d9241ce78..90145792d19f 100644
--- a/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj
+++ b/src/Tasks/Microsoft.NET.Build.Extensions.Tasks/Microsoft.NET.Build.Extensions.Tasks.csproj
@@ -30,7 +30,7 @@
$(BaseOutputPath)
- $(DefineConstants);EXTENSIONS
+ $(DefineConstants);EXTENSIONS;MSBUILD_BUILD_TASKS
true
$(ArtifactsBinDir)$(Configuration)\Sdks\$(PackageId)\
@@ -53,6 +53,8 @@
+
diff --git a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj
index 446bb0841c31..d6184662ff7b 100644
--- a/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj
+++ b/src/Tasks/Microsoft.NET.Build.Tasks/Microsoft.NET.Build.Tasks.csproj
@@ -93,6 +93,12 @@
+
+
+ $(DefineConstants);MSBUILD_BUILD_TASKS
+
+