diff --git a/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptBootstrapper.cs b/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptBootstrapper.cs
index 0e92786e7b..b59b802ee8 100644
--- a/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptBootstrapper.cs
+++ b/source/Calamari.Common/Features/Scripting/DotnetScript/DotnetScriptBootstrapper.cs
@@ -102,11 +102,31 @@ public static string FormatCommandArguments(string bootstrapFile, string? script
var source = string.IsNullOrWhiteSpace(nugetSource) ? "https://api.nuget.org/v3/index.json" : nugetSource;
var commandArguments = new StringBuilder();
commandArguments.Append($"-s {source} ");
+ // dotnet-script 2.0 turned the isolated assembly load context on by default, which
+ // changes which assembly a script gets when it references a package that dotnet-script
+ // also carries: a script asking for Newtonsoft.Json 9.0.1 used to bind to the 13.0.3
+ // dotnet-script bundles, and under isolation it gets 9.0.1. That is arguably more
+ // correct, but it is a silent change to what customer scripts run against, so hold the
+ // existing behaviour here and treat adopting isolation as its own decision.
+ //
+ // Unless the customer asked for isolation themselves. When both flags are passed,
+ // --disable-isolated-load-context wins, so adding it unconditionally would override
+ // the one group of customers who made a deliberate choice here.
+ if (!HasIsolatedLoadContextFlag(scriptCommandArguments))
+ commandArguments.Append("--disable-isolated-load-context ");
if (!string.IsNullOrWhiteSpace(scriptCommandArguments)) commandArguments.Append($"{scriptCommandArguments} ");
commandArguments.AppendFormat("\"{0}\" -- {1} \"{2}\"", bootstrapFile, scriptArguments, encryptionKey);
return commandArguments.ToString();
}
+ ///
+ /// True when the caller already passed --isolated-load-context. Note that
+ /// --disable-isolated-load-context does not match: "--isolated-load-context" is not a
+ /// substring of it, because the character before "isolated" there is a single dash.
+ ///
+ static bool HasIsolatedLoadContextFlag(string? scriptCommandArguments)
+ => scriptCommandArguments?.IndexOf("--isolated-load-context", StringComparison.OrdinalIgnoreCase) >= 0;
+
[return: NotNullIfNotNull("scriptParameters")]
static (string? scriptCommandArguments, string? scriptArguments) RetrieveParameterValues(string? scriptParameters)
{
diff --git a/source/Calamari.Scripting/DotnetScript/dotnet-script.1.6.0.zip b/source/Calamari.Scripting/DotnetScript/dotnet-script.1.6.0.zip
deleted file mode 100644
index 88cda61773..0000000000
Binary files a/source/Calamari.Scripting/DotnetScript/dotnet-script.1.6.0.zip and /dev/null differ
diff --git a/source/Calamari.Scripting/DotnetScript/dotnet-script.2.0.1.zip b/source/Calamari.Scripting/DotnetScript/dotnet-script.2.0.1.zip
new file mode 100644
index 0000000000..65024309a4
Binary files /dev/null and b/source/Calamari.Scripting/DotnetScript/dotnet-script.2.0.1.zip differ
diff --git a/source/Calamari.Scripting/DotnetScript/dotnet-script.runtimeconfig.json b/source/Calamari.Scripting/DotnetScript/dotnet-script.runtimeconfig.json
new file mode 100644
index 0000000000..5b614377bb
--- /dev/null
+++ b/source/Calamari.Scripting/DotnetScript/dotnet-script.runtimeconfig.json
@@ -0,0 +1,14 @@
+{
+ "runtimeOptions": {
+ "tfm": "net8.0",
+ "rollForward": "LatestMajor",
+ "framework": {
+ "name": "Microsoft.NETCore.App",
+ "version": "8.0.0"
+ },
+ "configProperties": {
+ "System.Reflection.Metadata.MetadataUpdater.IsSupported": false,
+ "System.Runtime.Serialization.EnableUnsafeBinaryFormatterSerialization": false
+ }
+ }
+}
diff --git a/source/Calamari.Tests/Fixtures/DotnetScript/DotnetScriptBootstrapperFixture.cs b/source/Calamari.Tests/Fixtures/DotnetScript/DotnetScriptBootstrapperFixture.cs
index ba81b3c9a9..fe4a59b45a 100644
--- a/source/Calamari.Tests/Fixtures/DotnetScript/DotnetScriptBootstrapperFixture.cs
+++ b/source/Calamari.Tests/Fixtures/DotnetScript/DotnetScriptBootstrapperFixture.cs
@@ -22,6 +22,23 @@ public void FormatCommandArgumentsTest([CanBeNull] string scriptParameters, [Can
formattedCommandArgument.Should().Contain($"{commandArguments}\"{bootstrapFile}\" -- {scriptArguments}");
}
+ [Test]
+ public void FormatCommandArguments_DisablesIsolatedLoadContext_ByDefault()
+ {
+ var result = DotnetScriptBootstrapper.FormatCommandArguments("Bootstrap.csx", null);
+ result.Should().Contain("--disable-isolated-load-context ");
+ }
+
+ [TestCase("--isolated-load-context -- \"Parameter 1\"")]
+ [TestCase("--isolated-load-context -d -- \"Parameter 1\"")]
+ public void FormatCommandArguments_LeavesIsolationOn_WhenTheCallerAskedForIt(string scriptParameters)
+ {
+ // Both flags together resolve to disabled, so we must not add ours on top of theirs.
+ var result = DotnetScriptBootstrapper.FormatCommandArguments("Bootstrap.csx", scriptParameters);
+ result.Should().NotContain("--disable-isolated-load-context");
+ result.Should().Contain("--isolated-load-context ");
+ }
+
[Test]
public void FormatCommandArguments_UsesCustomNuGetSource_WhenProvided()
{
diff --git a/source/IncludeDotNetScript.targets b/source/IncludeDotNetScript.targets
index 1f6ed73182..dfa02786b5 100644
--- a/source/IncludeDotNetScript.targets
+++ b/source/IncludeDotNetScript.targets
@@ -3,6 +3,15 @@
+
+
@@ -10,6 +19,7 @@
+
@@ -18,6 +28,7 @@
+
\ No newline at end of file