diff --git a/.azure-pipelines-ci/ci.yaml b/.azure-pipelines-ci/ci.yaml
index 19634eac9..6d110335f 100644
--- a/.azure-pipelines-ci/ci.yaml
+++ b/.azure-pipelines-ci/ci.yaml
@@ -1,51 +1,47 @@
 variables:
-  pwsh: true
   # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds
   DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
 
-jobs:
-  - job: 'Ubuntu_16_04'
-    pool:
-      vmImage: ubuntu-16.04
-    steps:
-    - template: templates/unix.yaml
-    
-  - job: 'Ubuntu_18_04'
-    pool:
-      vmImage: ubuntu-18.04
-    steps:
-    - template: templates/unix.yaml
-    
-  - job: macOS
-    pool:
-      vmImage: macos-latest
-    steps:
-    - template: templates/unix.yaml
-
-  - job: 'Windows_PowerShell_5_1'
-    pool:
-      vmImage: windows-latest
-    steps:
-    - powershell: |
-        Import-Module .\tools\appveyor.psm1
-        Invoke-AppveyorInstall
-        ./build.ps1 -Configuration 'Release' -PSVersion 5
-        ./PSCompatibilityCollector/build.ps1 -Configuration 'Release' -Framework 'net452'
-      displayName: 'Build'
-    - template: templates/test.yaml
-      parameters:
-        pwsh: false
-
-  - job: 'Windows_PowerShell_Core'
-    pool:
-      vmImage: windows-latest
-    steps:
-    - pwsh: |
-        Import-Module .\tools\appveyor.psm1
-        Invoke-AppveyorInstall
-        ./build.ps1 -Configuration 'Release' -All
-        ./PSCompatibilityCollector/build.ps1 -Configuration 'Release' -Framework 'netstandard2.0'
-      displayName: 'Full Build'
-    - template: templates/test.yaml
-      parameters:
-        pwsh: true
+stages:
+  - stage: Build
+    jobs:
+      - job: 'Full_Build'
+        pool:
+          vmImage: windows-latest
+        steps:
+        - pwsh: |
+            Import-Module .\tools\appveyor.psm1
+            Invoke-AppveyorInstall -SkipPesterInstallation
+            ./build.ps1 -Configuration 'Release' -All
+            ./PSCompatibilityCollector/build.ps1 -Configuration 'Release'
+          displayName: 'Full Build'
+        - task: PublishPipelineArtifact@1
+          displayName: 'Publish Pipeline Artifact: out Folder'
+          inputs:
+            targetPath: '$(Build.SourcesDirectory)/out'
+            artifactName: out
+  - stage: Test
+    jobs:
+      - job:
+        strategy:
+          matrix:
+            Ubuntu_16_04:
+              vmImage: ubuntu-16.04
+            Ubuntu_18_04:
+              vmImage: ubuntu-18.04
+            macOS:
+              vmImage: macos-latest
+            Windows_Server2016_PowerShell_Core:
+              vmImage: windows-2019
+            Windows_Server2019_PowerShell_Core:
+              vmImage: windows-2019
+            Windows_Server2016_PowerShell_5_1:
+              vmImage: vs2017-win2016
+              pwsh: false
+            Windows_Server2019_PowerShell_5_1:
+              vmImage: vs2017-win2016
+              pwsh: false
+        pool:
+          vmImage: $[ variables['vmImage'] ]
+        steps:
+        - template: templates/test.yaml
diff --git a/.azure-pipelines-ci/templates/test.yaml b/.azure-pipelines-ci/templates/test.yaml
index 708352b79..2acdcc6f5 100644
--- a/.azure-pipelines-ci/templates/test.yaml
+++ b/.azure-pipelines-ci/templates/test.yaml
@@ -1,4 +1,14 @@
+parameters:
+- name: pwsh
+  type: boolean
+  default: true
+
 steps:
+- task: DownloadPipelineArtifact@2
+  displayName: 'Download Pipeline Artifact: out Folder'
+  inputs:
+    artifactName: out
+    targetPath: '$(Build.SourcesDirectory)/out'
 - task: PowerShell@2
   displayName: 'Test'
   inputs:
diff --git a/.azure-pipelines-ci/templates/unix.yaml b/.azure-pipelines-ci/templates/unix.yaml
deleted file mode 100644
index 6d4ba43b9..000000000
--- a/.azure-pipelines-ci/templates/unix.yaml
+++ /dev/null
@@ -1,8 +0,0 @@
-steps:
-- pwsh: |
-    Import-Module .\tools\appveyor.psm1
-    Invoke-AppveyorInstall
-    ./build.ps1 -Configuration 'Release' -PSVersion 6
-    ./PSCompatibilityCollector/build.ps1 -Configuration 'Release' -Framework 'netstandard2.0'
-  displayName: 'Build'
-- template: test.yaml
\ No newline at end of file
diff --git a/Rules/MissingModuleManifestField.cs b/Rules/MissingModuleManifestField.cs
index 78deb38ab..180767766 100644
--- a/Rules/MissingModuleManifestField.cs
+++ b/Rules/MissingModuleManifestField.cs
@@ -115,10 +115,9 @@ private List<CorrectionExtent> GetCorrectionExtent(HashtableAst ast)
                 Strings.MissingModuleManifestFieldCorrectionDescription,
                 fieldName,
                 fieldValue);
-            var correctionTextTemplate = @"
-# Version number of this module.
-{0} = '{1}'
-";
+            var correctionTextTemplate = string.Concat(Environment.NewLine,
+                "# Version number of this module.", Environment.NewLine,
+                "{0} = '{1}'", Environment.NewLine);
             var correctionText = string.Format(
                 correctionTextTemplate,
                 fieldName,
diff --git a/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1 b/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1
index 55d6dc593..2198fa178 100644
--- a/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1
+++ b/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1
@@ -32,14 +32,12 @@ Describe "MissingRequiredFieldModuleManifest" {
             $violations.SuggestedCorrections.Count | Should -Be $numExpectedCorrections
         }
 
-    # On Linux, mismatch in line endings cause this to fail
-	It "has the right suggested correction" -Skip:($IsLinux) {
-	   $expectedText = @'
-# Version number of this module.
-ModuleVersion = '1.0.0.0'
-'@
-            $violations[0].SuggestedCorrections[0].Text | Should -Match $expectedText
-            Get-ExtentText $violations[0].SuggestedCorrections[0] $violationFilepath | Should -BeNullOrEmpty
+	It "has the right suggested correction" {
+        $expectedText = [System.Environment]::NewLine + '# Version number of this module.' +
+            [System.Environment]::NewLine + "ModuleVersion = '1.0.0.0'" + [System.Environment]::NewLine
+
+        $violations[0].SuggestedCorrections[0].Text | Should -BeExactly $expectedText
+        Get-ExtentText $violations[0].SuggestedCorrections[0] $violationFilepath | Should -BeNullOrEmpty
     }
 }
 
diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1
index c7146f50f..ffbcc415f 100644
--- a/tools/appveyor.psm1
+++ b/tools/appveyor.psm1
@@ -3,9 +3,8 @@
 
 $ErrorActionPreference = 'Stop'
 
-# Implements the AppVeyor 'install' step and installs the required versions of Pester, platyPS and the .Net Core SDK if needed.
-function Invoke-AppVeyorInstall {
-    $requiredPesterVersion = '4.4.4'
+function Install-Pester {
+    $requiredPesterVersion = '4.10.0'
     $pester = Get-Module Pester -ListAvailable | Where-Object { $_.Version -eq $requiredPesterVersion }
     if ($null -eq $pester) {
         if ($null -eq (Get-Module -ListAvailable PowershellGet)) {
@@ -19,6 +18,16 @@ function Invoke-AppVeyorInstall {
             Install-Module -Name Pester -Force -SkipPublisherCheck -Scope CurrentUser -Repository PSGallery
         }
     }
+}
+
+# Implements the AppVeyor 'install' step and installs the required versions of Pester, platyPS and the .Net Core SDK if needed.
+function Invoke-AppVeyorInstall {
+    param(
+        # For the multi-stage build in Azure DevOps, Pester is not needed for bootstrapping the build environment
+        [switch] $SkipPesterInstallation
+    )
+
+    if (-not $SkipPesterInstallation.IsPresent) { Install-Pester }
 
     if ($null -eq (Get-Module -ListAvailable PowershellGet)) {
         # WMF 4 image build
@@ -72,6 +81,8 @@ function Invoke-AppveyorTest {
         $CheckoutPath
     )
 
+    Install-Pester
+
     # enforce the language to utf-8 to avoid issues
     $env:LANG = "en_US.UTF-8"
     Write-Verbose -Verbose ("Running tests on PowerShell version " + $PSVersionTable.PSVersion)