diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml
index 2c504a075..959d482ec 100644
--- a/.github/workflows/ci-test.yml
+++ b/.github/workflows/ci-test.yml
@@ -30,8 +30,7 @@ jobs:
         with:
           cache: true
           cache-dependency-path: '**/*.csproj'
-          dotnet-version: 6.0.x
-          global-json-file: "./global.json"
+          global-json-file: ./global.json
 
       - name: Install PSResources
         shell: pwsh
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 0640253e9..00db279bc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,5 +1,12 @@
 # PowerShell Editor Services Release History
 
+## v4.2.0
+### Thursday, January 16, 2025
+
+See more details at the GitHub Release for [v4.2.0](https://github.com/PowerShell/PowerShellEditorServices/releases/tag/v4.2.0).
+
+Support PSScriptAnalyzer config in multi-root workspaces
+
 ## v4.1.0
 ### Wednesday, December 04, 2024
 
diff --git a/Directory.Packages.props b/Directory.Packages.props
index d854d6c51..428e28735 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -1,10 +1,10 @@
 <Project>
   <ItemGroup>
     <PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
-    <PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="8.0.0" />
-    <PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.0" />
-    <PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="9.0.0" />
-    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.10.0" />
+    <PackageVersion Include="Microsoft.Extensions.FileSystemGlobbing" Version="9.0.1" />
+    <PackageVersion Include="Microsoft.Extensions.Logging" Version="9.0.1" />
+    <PackageVersion Include="Microsoft.Extensions.Logging.Debug" Version="9.0.1" />
+    <PackageVersion Include="Microsoft.NET.Test.Sdk" Version="17.12.0" />
     <PackageVersion Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0" />
     <PackageVersion Include="Microsoft.PowerShell.SDK" Version="7.4.6" />
     <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
@@ -13,13 +13,25 @@
     <PackageVersion Include="OmniSharp.Extensions.LanguageClient" Version="0.19.9" />
     <PackageVersion Include="OmniSharp.Extensions.LanguageServer" Version="0.19.9" />
     <PackageVersion Include="PowerShellStandard.Library" Version="5.1.1" />
+    <PackageVersion Include="Roslynator.Analyzers" Version="4.12.10">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageVersion>
+    <PackageVersion Include="Roslynator.CodeAnalysis.Analyzers" Version="4.12.10">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageVersion>
+    <PackageVersion Include="Roslynator.Formatting.Analyzers" Version="4.12.10">
+      <IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
+      <PrivateAssets>all</PrivateAssets>
+    </PackageVersion>
     <PackageVersion Include="System.IO.Pipes.AccessControl" Version="5.0.0" />
     <PackageVersion Include="System.Runtime.InteropServices.RuntimeInformation" Version="4.3.0" />
     <PackageVersion Include="System.Security.Principal" Version="4.3.0" />
     <PackageVersion Include="System.Security.Principal.Windows" Version="5.0.0" />
     <PackageVersion Include="System.ValueTuple" Version="4.5.0" />
-    <PackageVersion Include="xunit" Version="2.9.0" />
+    <PackageVersion Include="xunit" Version="2.9.3" />
     <PackageVersion Include="xunit.runner.visualstudio" Version="2.8.2" />
-    <PackageVersion Include="Xunit.SkippableFact" Version="1.4.13" />
+    <PackageVersion Include="Xunit.SkippableFact" Version="1.5.23" />
   </ItemGroup>
 </Project>
diff --git a/PowerShellEditorServices.Common.props b/PowerShellEditorServices.Common.props
index 010fe2a8c..d61f9a96e 100644
--- a/PowerShellEditorServices.Common.props
+++ b/PowerShellEditorServices.Common.props
@@ -1,6 +1,6 @@
 <Project>
   <PropertyGroup>
-    <VersionPrefix>4.1.0</VersionPrefix>
+    <VersionPrefix>4.2.0</VersionPrefix>
     <VersionSuffix></VersionSuffix>
     <Company>Microsoft</Company>
     <Copyright>© Microsoft Corporation.</Copyright>
diff --git a/global.json b/global.json
index 892db14b0..4141e1966 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
 {
   "sdk": {
-    "version": "8.0.110",
+    "version": "8.0.405",
     "rollForward": "latestFeature",
     "allowPrerelease": false
   }
diff --git a/module/PowerShellEditorServices/PowerShellEditorServices.psd1 b/module/PowerShellEditorServices/PowerShellEditorServices.psd1
index c71dc1dfe..9f4ca3920 100644
--- a/module/PowerShellEditorServices/PowerShellEditorServices.psd1
+++ b/module/PowerShellEditorServices/PowerShellEditorServices.psd1
@@ -19,7 +19,7 @@ RootModule = if ($PSEdition -eq 'Core')
     }
 
 # Version number of this module.
-ModuleVersion = '4.1.0'
+ModuleVersion = '4.2.0'
 
 # ID used to uniquely identify this module
 GUID = '9ca15887-53a2-479a-9cda-48d26bcb6c47'
diff --git a/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs b/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs
index bebb7e2b9..1c8617341 100644
--- a/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs
+++ b/src/PowerShellEditorServices.Hosting/Configuration/HostLogger.cs
@@ -214,7 +214,6 @@ public void LogException(
     /// <param name="ui">The PowerShell host user interface object to log output to.</param>
     internal class PSHostLogger(PSHostUserInterface ui) : IObserver<(PsesLogLevel logLevel, string message)>
     {
-
         public void OnCompleted()
         {
             // No-op since there's nothing to close or dispose,
diff --git a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj
index 7b73ff8a8..1c30a93df 100644
--- a/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj
+++ b/src/PowerShellEditorServices.Hosting/PowerShellEditorServices.Hosting.csproj
@@ -1,5 +1,6 @@
 ﻿<Project Sdk="Microsoft.NET.Sdk">
-  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), PowerShellEditorServices.Common.props))\PowerShellEditorServices.Common.props" />
+  <Import
+    Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), PowerShellEditorServices.Common.props))\PowerShellEditorServices.Common.props" />
 
   <PropertyGroup>
     <TargetFrameworks>net8.0;net462</TargetFrameworks>
@@ -16,6 +17,12 @@
     <PackageReference Include="System.Runtime.InteropServices.RuntimeInformation" />
   </ItemGroup>
 
+  <ItemGroup Label="Roslynator">
+    <PackageReference Include="Roslynator.Analyzers" />
+    <PackageReference Include="Roslynator.CodeAnalysis.Analyzers" />
+    <PackageReference Include="Roslynator.Formatting.Analyzers" />
+  </ItemGroup>
+
   <ItemGroup>
     <ProjectReference Include="..\PowerShellEditorServices\PowerShellEditorServices.csproj" PrivateAssets="all" />
   </ItemGroup>
diff --git a/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs b/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs
index 0b22ddd95..5d368f912 100644
--- a/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs
+++ b/src/PowerShellEditorServices/Logging/LanguageServerLogger.cs
@@ -137,7 +137,6 @@ internal class LanguageServerLoggerProvider(ILanguageServerFacade languageServer
     public void Dispose() { }
 }
 
-
 public static class LanguageServerLoggerExtensions
 {
     /// <summary>
diff --git a/src/PowerShellEditorServices/PowerShellEditorServices.csproj b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
index bf90a93ae..18948aabc 100644
--- a/src/PowerShellEditorServices/PowerShellEditorServices.csproj
+++ b/src/PowerShellEditorServices/PowerShellEditorServices.csproj
@@ -1,5 +1,6 @@
 <Project Sdk="Microsoft.NET.Sdk">
-  <Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), PowerShellEditorServices.Common.props))\PowerShellEditorServices.Common.props" />
+  <Import
+    Project="$([MSBuild]::GetDirectoryNameOfFileAbove($(MSBuildThisFileDirectory), PowerShellEditorServices.Common.props))\PowerShellEditorServices.Common.props" />
 
   <PropertyGroup>
     <AssemblyTitle>PowerShell Editor Services</AssemblyTitle>
@@ -41,6 +42,12 @@
     <PackageReference Include="System.Security.Principal.Windows" />
   </ItemGroup>
 
+  <ItemGroup Label="Roslynator">
+    <PackageReference Include="Roslynator.Analyzers" />
+    <PackageReference Include="Roslynator.CodeAnalysis.Analyzers" />
+    <PackageReference Include="Roslynator.Formatting.Analyzers" />
+  </ItemGroup>
+
   <Choose>
     <When Condition=" '$(LocalOmniSharp)' == 'true' ">
       <ItemGroup>
diff --git a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
index f6b25c5f7..f346cb6c9 100644
--- a/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
+++ b/src/PowerShellEditorServices/Services/Analysis/AnalysisService.cs
@@ -322,7 +322,7 @@ private bool TryFindSettingsFile(out string settingsFilePath)
                 return false;
             }
 
-            settingsFilePath = _workspaceService?.ResolveWorkspacePath(configuredPath);
+            settingsFilePath = _workspaceService?.FindFileInWorkspace(configuredPath);
 
             if (settingsFilePath is null
                 || !File.Exists(settingsFilePath))
@@ -332,6 +332,8 @@ private bool TryFindSettingsFile(out string settingsFilePath)
                 return false;
             }
 
+            _logger.LogInformation($"Found PSSA settings file at '{settingsFilePath}'");
+
             return true;
         }
 
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs
index 97bd6cca7..67b2c1021 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/LaunchAndAttachHandler.cs
@@ -301,7 +301,6 @@ void RunspaceChangedHandler(object s, RunspaceChangedEventArgs _)
                 throw new RpcErrorException(0, null, "Invalid configuration with no process ID nor custom pipe name!");
             }
 
-
             // Execute the Debug-Runspace command but don't await it because it
             // will block the debug adapter initialization process. The
             // InitializedEvent will be sent as soon as the RunspaceChanged
@@ -328,7 +327,6 @@ void RunspaceChangedHandler(object s, RunspaceChangedEventArgs _)
 
             if (request.RunspaceId < 1)
             {
-
                 throw new RpcErrorException(0, null, "A positive integer must be specified for the RunspaceId!");
             }
 
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs
index 84d23a8b6..858f6a815 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/StackTraceHandler.cs
@@ -128,6 +128,4 @@ public static StackFrame CreateStackFrame(StackFrameDetails stackFrame, long id)
         Column = invocationInfo.OffsetInLine,
         PresentationHint = StackFramePresentationHint.Label
     };
-
 }
-
diff --git a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs
index 58fb4d5ef..55c5f85ff 100644
--- a/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs
+++ b/src/PowerShellEditorServices/Services/DebugAdapter/Handlers/VariablesHandler.cs
@@ -34,10 +34,12 @@ public async Task<VariablesResponse> Handle(VariablesArguments request, Cancella
                             .ToArray()
                 };
             }
+            #pragma warning disable RCS1075
             catch (Exception)
             {
                 // TODO: This shouldn't be so broad
             }
+            #pragma warning restore RCS1075
 
             return variablesResponse;
         }
diff --git a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs
index a7f36aab1..2cfb57cd4 100644
--- a/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/Handlers/ConfigurationHandler.cs
@@ -100,7 +100,6 @@ public override async Task<Unit> Handle(DidChangeConfigurationParams request, Ca
             return await Unit.Task.ConfigureAwait(false);
         }
 
-
         public event EventHandler<LanguageServerSettings> ConfigurationUpdated;
     }
 }
diff --git a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
index 941fcf736..efd7f82d7 100644
--- a/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
+++ b/src/PowerShellEditorServices/Services/Workspace/WorkspaceService.cs
@@ -335,6 +335,35 @@ public string GetRelativePath(ScriptFile scriptFile)
             return fileUri.ToString();
         }
 
+        /// <summary>
+        /// Finds a file in the first workspace folder where it exists, if possible.
+        /// Used as a backwards-compatible way to find files in the workspace.
+        /// </summary>
+        /// <param name="filePath"></param>
+        /// <returns>Best possible path.</returns>
+        public string FindFileInWorkspace(string filePath)
+        {
+            // If the file path is already an absolute path, just return it.
+            if (Path.IsPathRooted(filePath))
+            {
+                return filePath;
+            }
+
+            // If the file path is relative, try to find it in the workspace folders.
+            foreach (WorkspaceFolder workspaceFolder in WorkspaceFolders)
+            {
+                string folderPath = workspaceFolder.Uri.GetFileSystemPath();
+                string combinedPath = Path.Combine(folderPath, filePath);
+                if (File.Exists(combinedPath))
+                {
+                    return combinedPath;
+                }
+            }
+
+            // If the file path is not found in the workspace folders, return the original path.
+            return filePath;
+        }
+
         /// <summary>
         /// Enumerate all the PowerShell (ps1, psm1, psd1) files in the workspace in a recursive manner, using default values.
         /// </summary>
@@ -409,57 +438,6 @@ internal static string ReadFileContents(DocumentUri uri)
             return reader.ReadToEnd();
         }
 
-        internal string ResolveWorkspacePath(string path) => ResolveRelativeScriptPath(InitialWorkingDirectory, path);
-
-        internal string ResolveRelativeScriptPath(string baseFilePath, string relativePath)
-        {
-            // TODO: Sometimes the `baseFilePath` (even when its `WorkspacePath`) is null.
-            string combinedPath = null;
-            Exception resolveException = null;
-
-            try
-            {
-                // If the path is already absolute there's no need to resolve it relatively
-                // to the baseFilePath.
-                if (Path.IsPathRooted(relativePath))
-                {
-                    return relativePath;
-                }
-
-                // Get the directory of the original script file, combine it
-                // with the given path and then resolve the absolute file path.
-                combinedPath =
-                    Path.GetFullPath(
-                        Path.Combine(
-                            baseFilePath,
-                            relativePath));
-            }
-            catch (NotSupportedException e)
-            {
-                // Occurs if the path is incorrectly formatted for any reason.  One
-                // instance where this occurred is when a user had curly double-quote
-                // characters in their source instead of normal double-quotes.
-                resolveException = e;
-            }
-            catch (ArgumentException e)
-            {
-                // Occurs if the path contains invalid characters, specifically those
-                // listed in System.IO.Path.InvalidPathChars.
-                resolveException = e;
-            }
-
-            if (resolveException != null)
-            {
-                logger.LogError(
-                    "Could not resolve relative script path\r\n" +
-                    $"    baseFilePath = {baseFilePath}\r\n    " +
-                    $"    relativePath = {relativePath}\r\n\r\n" +
-                    $"{resolveException}");
-            }
-
-            return combinedPath;
-        }
-
         /// <summary>
         /// Returns a normalized string for a given documentUri to be used as key name.
         /// Case-sensitive uri on Linux and lowercase for other platforms.
diff --git a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs
index bb794516f..523ced631 100644
--- a/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs
+++ b/test/PowerShellEditorServices.Test.E2E/DebugAdapterProtocolMessageTests.cs
@@ -306,7 +306,6 @@ await PsesDebugAdapterClient.SetBreakpoints(
             await PsesDebugAdapterClient.RequestConfigurationDone(new ConfigurationDoneArguments());
             await PsesDebugAdapterClient.LaunchScript(filePath, Started);
 
-
             // Get the stacktrace for the breakpoint
             await Assert.ThrowsAsync<JsonRpcException>(() => PsesDebugAdapterClient.RequestStackTrace(
                 new StackTraceArguments { }
diff --git a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
index 05386d43a..d9656c855 100644
--- a/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
+++ b/test/PowerShellEditorServices.Test/Debugging/DebugServiceTests.cs
@@ -76,7 +76,6 @@ public async Task InitializeAsync()
             variableScriptFile = GetDebugScript("VariableTest.ps1");
         }
 
-
         public async Task DisposeAsync()
         {
             debugService.Abort();
