diff --git a/src/ElectronNET.IntegrationTests/Tests/MigrationChecksTargetsTests.cs b/src/ElectronNET.IntegrationTests/Tests/MigrationChecksTargetsTests.cs
new file mode 100644
index 00000000..93b18173
--- /dev/null
+++ b/src/ElectronNET.IntegrationTests/Tests/MigrationChecksTargetsTests.cs
@@ -0,0 +1,193 @@
+using System.Diagnostics;
+
+namespace ElectronNET.IntegrationTests.Tests;
+
+///
+/// Unit tests for ElectronNET.MigrationChecks.targets - no Electron runtime required.
+/// Covers GitHub issue #1035: System.IO.File.ReadAllLines is not available as an MSBuild
+/// property function on all platforms (e.g. macOS GitHub Actions), causing MSB4185.
+///
+public class MigrationChecksTargetsTests
+{
+ private static readonly string TargetsFilePath = FindTargetsFile();
+
+ ///
+ /// Walks up the directory tree from until it finds
+ /// the migration checks targets file. This is robust against varying output paths
+ /// (with or without RID subfolder, debug/release, etc.).
+ ///
+ private static string FindTargetsFile()
+ {
+ const string RelativeFromRepoRoot =
+ "src/ElectronNET/build/ElectronNET.MigrationChecks.targets";
+ const string RelativeFromSrc =
+ "ElectronNET/build/ElectronNET.MigrationChecks.targets";
+
+ var dir = new DirectoryInfo(AppContext.BaseDirectory);
+ while (dir != null)
+ {
+ var fromRepoRoot = Path.Combine(dir.FullName, RelativeFromRepoRoot);
+ if (File.Exists(fromRepoRoot))
+ {
+ return Path.GetFullPath(fromRepoRoot);
+ }
+
+ var fromSrc = Path.Combine(dir.FullName, RelativeFromSrc);
+ if (File.Exists(fromSrc))
+ {
+ return Path.GetFullPath(fromSrc);
+ }
+
+ dir = dir.Parent;
+ }
+
+ throw new FileNotFoundException(
+ "Could not locate ElectronNET.MigrationChecks.targets by walking up from " +
+ $"'{AppContext.BaseDirectory}'.");
+ }
+
+ // -----------------------------------------------------------------------
+ // Content-level test (RED before fix, GREEN after fix on ALL platforms)
+ // -----------------------------------------------------------------------
+
+ [Fact]
+ public void MigrationChecksTargets_ShouldNotUseReadAllLines()
+ {
+ // The file must exist - if this fails the path constant above is wrong.
+ File.Exists(TargetsFilePath).Should().BeTrue(
+ $"targets file must exist at '{TargetsFilePath}'");
+
+ var content = File.ReadAllText(TargetsFilePath);
+
+ // System.IO.File::ReadAllLines is not in the MSBuild property-function
+ // whitelist on all platforms (MSB4185 on macOS GitHub Actions, see #1035).
+ // ReadAllText must be used instead.
+ content.Should().NotContain(
+ "::ReadAllLines(",
+ "because ReadAllLines is not available as an MSBuild property function on all " +
+ "platforms. Use ReadAllText instead (GitHub issue #1035).");
+ }
+
+ // -----------------------------------------------------------------------
+ // Functional build test - verifies no MSB4185 at runtime
+ // (RED on platforms where ReadAllLines is restricted, GREEN after fix)
+ // -----------------------------------------------------------------------
+
+ [Fact]
+ public async Task MigrationChecksTargets_BuildWithCleanPackageJson_ShouldSucceedWithoutMSB4185()
+ {
+ // Positive case: a package.json that does NOT mention electron.
+ // The migration check must successfully read the file via ReadAllText
+ // (the code path fixed by issue #1035) without producing MSB4185.
+
+ var tempDir = CreateTempProjectDirectory();
+ try
+ {
+ await File.WriteAllTextAsync(
+ Path.Combine(tempDir, "package.json"),
+ """{ "devDependencies": { "vite": "^5.0.0" } }""");
+
+ await WriteMinimalCsprojAsync(tempDir);
+
+ var (exitCode, output) = await RunDotnetBuildAsync(tempDir);
+
+ exitCode.Should().Be(0,
+ $"the build must succeed when the package.json contains no electron references. " +
+ $"Full build output:\n{output}");
+
+ output.Should().NotContain(
+ "MSB4185",
+ $"ReadAllLines must not be used as an MSBuild property function. " +
+ $"Full build output:\n{output}");
+ }
+ finally
+ {
+ Directory.Delete(tempDir, recursive: true);
+ }
+ }
+
+ [Fact]
+ public async Task MigrationChecksTargets_BuildWithPackageJsonContainingElectron_ShouldEmitELECTRON008WarningWithoutMSB4185()
+ {
+ // Negative case: a package.json that DOES contain "electron".
+ // The migration check must still read the file successfully (no MSB4185)
+ // and must emit the expected ELECTRON008 warning. ELECTRON008 is a
+ // , not an , so the build itself still succeeds.
+
+ var tempDir = CreateTempProjectDirectory();
+ try
+ {
+ await File.WriteAllTextAsync(
+ Path.Combine(tempDir, "package.json"),
+ """{ "devDependencies": { "electron": "^30.0.0" } }""");
+
+ await WriteMinimalCsprojAsync(tempDir);
+
+ var (exitCode, output) = await RunDotnetBuildAsync(tempDir);
+
+ exitCode.Should().Be(0,
+ $"ELECTRON008 is a Warning (not an Error) so the build itself must still " +
+ $"succeed. Full build output:\n{output}");
+
+ output.Should().NotContain(
+ "MSB4185",
+ $"ReadAllLines must not be used as an MSBuild property function. " +
+ $"Full build output:\n{output}");
+
+ output.Should().Contain(
+ "ELECTRON008",
+ $"the migration check must still detect electron references in package.json " +
+ $"after the ReadAllText migration. Full build output:\n{output}");
+ }
+ finally
+ {
+ Directory.Delete(tempDir, recursive: true);
+ }
+ }
+
+ // -----------------------------------------------------------------------
+ // Helpers
+ // -----------------------------------------------------------------------
+
+ private static string CreateTempProjectDirectory()
+ {
+ var tempDir = Path.Combine(Path.GetTempPath(), $"electron-net-test-{Guid.NewGuid():N}");
+ Directory.CreateDirectory(tempDir);
+ return tempDir;
+ }
+
+ private static Task WriteMinimalCsprojAsync(string tempDir)
+ {
+ // A minimal csproj that only imports the migration checks targets to keep the
+ // build fast. Note: MSBuildProjectDirectory is a reserved MSBuild property and
+ // must not be redefined manually; MSBuild sets it automatically to the folder
+ // of the csproj (which is tempDir here).
+ var targetsPathEscaped = TargetsFilePath.Replace("'", "'");
+ return File.WriteAllTextAsync(
+ Path.Combine(tempDir, "TestApp.csproj"),
+ $"""
+
+
+
+
+ """);
+ }
+
+ private static async Task<(int ExitCode, string Output)> RunDotnetBuildAsync(string workingDirectory)
+ {
+ var psi = new ProcessStartInfo("dotnet", "build --nologo -v:minimal")
+ {
+ WorkingDirectory = workingDirectory,
+ RedirectStandardOutput = true,
+ RedirectStandardError = true,
+ UseShellExecute = false,
+ };
+
+ using var process = Process.Start(psi)!;
+ var stdOut = await process.StandardOutput.ReadToEndAsync();
+ var stdErr = await process.StandardError.ReadToEndAsync();
+ await process.WaitForExitAsync();
+
+ return (process.ExitCode, stdOut + stdErr);
+ }
+}
diff --git a/src/ElectronNET/build/ElectronNET.MigrationChecks.targets b/src/ElectronNET/build/ElectronNET.MigrationChecks.targets
index 666c1785..ab138a5d 100644
--- a/src/ElectronNET/build/ElectronNET.MigrationChecks.targets
+++ b/src/ElectronNET/build/ElectronNET.MigrationChecks.targets
@@ -73,12 +73,11 @@ EXCEPTION:
-
- <_RootPackageJsonLines Include="$([System.IO.File]::ReadAllLines('$(MSBuildProjectDirectory)\package.json'))" />
-
-
- <_RootPackageJsonContent>@(_RootPackageJsonLines, ' ')
+
+ <_RootPackageJsonContent>$([System.IO.File]::ReadAllText('$(MSBuildProjectDirectory)\package.json'))
<_RootPackageJsonHasElectron>false
<_RootPackageJsonHasElectron Condition="$([System.Text.RegularExpressions.Regex]::IsMatch('$(_RootPackageJsonContent)', 'electron', System.Text.RegularExpressions.RegexOptions.IgnoreCase))">true