diff --git a/.azure-pipelines-ci/ci.yaml b/.azure-pipelines-ci/ci.yaml
deleted file mode 100644
index 7cf89937a..000000000
--- a/.azure-pipelines-ci/ci.yaml
+++ /dev/null
@@ -1,53 +0,0 @@
-variables:
-  # Avoid expensive initialization of dotnet cli, see: https://donovanbrown.com/post/Stop-wasting-time-during-NET-Core-builds
-  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: 1
-
-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'
-        - pwsh: |
-            Write-Host "##vso[artifact.upload containerfolder=out;artifactname=out;]${env:Build_SourcesDirectory}/out"
-  - stage: Test
-    jobs:
-      - job:
-        strategy:
-          matrix:
-            Ubuntu_16_04:
-              vmImage: ubuntu-16.04
-            Ubuntu_18_04:
-              vmImage: ubuntu-18.04
-            macOS_10_14_Mojave:
-              vmImage: macOS-10.14
-            macOS_10_15_Catalina:
-              vmImage: macOS-10.15
-            Windows_Server2016_PowerShell_Core:
-              vmImage: vs2017-win2016
-            Windows_Server2019_PowerShell_Core:
-              vmImage: windows-2019
-        pool:
-          vmImage: $[ variables['vmImage'] ]
-        steps:
-        - template: templates/test-pwsh.yaml
-      - job:
-        strategy:
-          matrix:
-            Windows_Server2016_PowerShell_5_1:
-              vmImage: vs2017-win2016
-              pwsh: false
-            Windows_Server2019_PowerShell_5_1:
-              vmImage: windows-2019
-              pwsh: false
-        pool:
-          vmImage: $[ variables['vmImage'] ]
-        steps:
-        - template: templates/test-powershell.yaml
diff --git a/.azure-pipelines-ci/templates/test-powershell.yaml b/.azure-pipelines-ci/templates/test-powershell.yaml
deleted file mode 100644
index e832f04e4..000000000
--- a/.azure-pipelines-ci/templates/test-powershell.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-steps:
-- task: DownloadPipelineArtifact@2
-  displayName: 'Download Pipeline Artifact: out Folder'
-  inputs:
-    artifactName: out
-    targetPath: '$(Build.SourcesDirectory)/out'
-- task: PowerShell@2
-  displayName: 'Test'
-  inputs:
-    targetType: inline
-    pwsh: false
-    script: |
-      Import-Module .\tools\appveyor.psm1
-      Invoke-AppveyorTest -CheckoutPath $env:BUILD_SOURCESDIRECTORY
-- task: PublishTestResults@2
-  inputs:
-    testRunner: NUnit
-    testResultsFiles: 'TestResults.xml'
-  condition: succeededOrFailed()
diff --git a/.azure-pipelines-ci/templates/test-pwsh.yaml b/.azure-pipelines-ci/templates/test-pwsh.yaml
deleted file mode 100644
index 2661b2157..000000000
--- a/.azure-pipelines-ci/templates/test-pwsh.yaml
+++ /dev/null
@@ -1,19 +0,0 @@
-steps:
-- task: DownloadPipelineArtifact@2
-  displayName: 'Download Pipeline Artifact: out Folder'
-  inputs:
-    artifactName: out
-    targetPath: '$(Build.SourcesDirectory)/out'
-- task: PowerShell@2
-  displayName: 'Test'
-  inputs:
-    targetType: inline
-    pwsh: true
-    script: |
-      Import-Module .\tools\appveyor.psm1
-      Invoke-AppveyorTest -CheckoutPath $env:BUILD_SOURCESDIRECTORY
-- task: PublishTestResults@2
-  inputs:
-    testRunner: NUnit
-    testResultsFiles: 'TestResults.xml'
-  condition: succeededOrFailed()
diff --git a/.config/tsaoptions.json b/.config/tsaoptions.json
new file mode 100644
index 000000000..a0887d850
--- /dev/null
+++ b/.config/tsaoptions.json
@@ -0,0 +1,10 @@
+{
+    "instanceUrl": "https://msazure.visualstudio.com",
+    "projectName": "One",
+    "areaPath": "One\\MGMT\\Compute\\Powershell\\Powershell\\PowerShell Core",
+    "notificationAliases": [
+        "andschwa@microsoft.com",
+        "slee@microsoft.com"
+    ],
+    "codebaseName": "PSSA_202403"
+}
diff --git a/.devcontainer/Dockerfile b/.devcontainer/Dockerfile
index 0b85b17b1..cc17c531c 100644
--- a/.devcontainer/Dockerfile
+++ b/.devcontainer/Dockerfile
@@ -1,31 +1,6 @@
-#-------------------------------------------------------------------------------------------------------------
 # Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License. See https://go.microsoft.com/fwlink/?linkid=2090316 for license information.
-#-------------------------------------------------------------------------------------------------------------
+# Licensed under the MIT License.
 
-FROM mcr.microsoft.com/dotnet/core/sdk:3.1
-
-# This Dockerfile adds a non-root user with sudo access. Use the "remoteUser"
-# property in devcontainer.json to use it. On Linux, the container user's GID/UIDs
-# will be updated to match your local UID/GID (when using the dockerFile property).
-# See https://aka.ms/vscode-remote/containers/non-root-user for details.
-
-# Avoid warnings by switching to noninteractive
-ENV DEBIAN_FRONTEND=noninteractive
-
-# Configure apt and install packages
-RUN apt-get update \
-    && apt-get -y install --no-install-recommends apt-utils dialog 2>&1 \
-    #
-    # Verify git, process tools, lsb-release (common in install instructions for CLIs) installed
-    && apt-get -y install git iproute2 procps apt-transport-https gnupg2 curl lsb-release \
-    #
-    # Clean up
-    && apt-get autoremove -y \
-    && apt-get clean -y \
-    && rm -rf /var/lib/apt/lists/*
+FROM mcr.microsoft.com/dotnet/sdk:8.0
     
-RUN pwsh -c Install-Module platyPS,Pester -Force
-
-# Switch back to dialog for any ad-hoc use of apt-get
-ENV DEBIAN_FRONTEND=dialog
+RUN pwsh --command Install-Module platyPS,Pester -Force
\ No newline at end of file
diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json
index d59606e96..dbbc9c7ee 100644
--- a/.devcontainer/devcontainer.json
+++ b/.devcontainer/devcontainer.json
@@ -1,14 +1,16 @@
-// For format details, see https://aka.ms/vscode-remote/devcontainer.json or the definition README at
-// https://github.com/microsoft/vscode-dev-containers/tree/master/containers/dotnetcore-3.0
+// For format details, see https://aka.ms/vscode-remote/devcontainer.json
 {
-	"name": "C# (.NET Core 3.1)",
-	"dockerFile": "Dockerfile",
-	"settings": {
-		"terminal.integrated.shell.linux": "/usr/bin/pwsh"
-	},
-	"postCreateCommand": "dotnet restore",
-	"extensions": [
-		"ms-dotnettools.csharp",
-		"ms-vscode.powershell"
-	]
+    "name": "C# (.NET 8.0)",
+    "dockerFile": "Dockerfile",
+    "customizations": {
+        "vscode": {
+            "settings": {
+                "terminal.integrated.defaultProfile.linux": "pwsh"
+            },
+            "extensions": [
+                "ms-dotnettools.csharp",
+                "ms-vscode.powershell"
+            ]
+        }
+    }
 }
\ No newline at end of file
diff --git a/.gitattributes b/.gitattributes
new file mode 100644
index 000000000..6313b56c5
--- /dev/null
+++ b/.gitattributes
@@ -0,0 +1 @@
+* text=auto eol=lf
diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS
new file mode 100644
index 000000000..983234361
--- /dev/null
+++ b/.github/CODEOWNERS
@@ -0,0 +1,6 @@
+# Default owners
+* @andyleejordan @bergmeister
+
+# Version bumps and documentation updates
+Directory.Build.props @sdwheeler @michaeltlombardi
+/docs/ @sdwheeler @michaeltlombardi
diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml
new file mode 100644
index 000000000..048d20ef0
--- /dev/null
+++ b/.github/ISSUE_TEMPLATE/config.yml
@@ -0,0 +1,5 @@
+blank_issues_enabled: false
+contact_links:
+  - name: Report a User documentation issue
+    url: https://github.com/MicrosoftDocs/PowerShell-Docs-Modules/issues/new/choose
+    about: Report issues about the user documentation available on learn.microsoft.com.
diff --git a/.github/dependabot.yml b/.github/dependabot.yml
new file mode 100644
index 000000000..f0ba62a3e
--- /dev/null
+++ b/.github/dependabot.yml
@@ -0,0 +1,15 @@
+version: 2
+updates:
+- package-ecosystem: nuget
+  directory: "/"
+  schedule:
+    interval: daily
+    time: "13:00"
+    timezone: America/Los_Angeles
+  open-pull-requests-limit: 10
+  reviewers:
+    - "JamesWTruher"
+    - "bergmeister"
+  ignore:
+    - dependency-name: "System.Management.Automation"
+    - dependency-name: "PowerShellStandard.Library"
diff --git a/.github/policies/resourceManagement.yml b/.github/policies/resourceManagement.yml
new file mode 100644
index 000000000..c5262aa28
--- /dev/null
+++ b/.github/policies/resourceManagement.yml
@@ -0,0 +1,92 @@
+id: 
+name: GitOps.PullRequestIssueManagement
+description: GitOps.PullRequestIssueManagement primitive
+owner: 
+resource: repository
+disabled: false
+where: 
+configuration:
+  resourceManagementConfiguration:
+    scheduledSearches:
+    - description: 
+      frequencies:
+      - hourly:
+          hour: 3
+      filters:
+      - isIssue
+      - isOpen
+      - hasLabel:
+          label: Resolution - Duplicate
+      - noActivitySince:
+          days: 1
+      actions:
+      - addReply:
+          reply: This issue has been marked as duplicate and has not had any activity for **1 day**. It will be closed for housekeeping purposes.
+      - closeIssue
+    - description: 
+      frequencies:
+      - hourly:
+          hour: 6
+      filters:
+      - isOpen
+      - hasLabel:
+          label: Resolution - Answered
+      - noActivitySince:
+          days: 7
+      actions:
+      - closeIssue
+    - description: 
+      frequencies:
+      - hourly:
+          hour: 6
+      filters:
+      - isOpen
+      - hasLabel:
+          label: Resolution - External
+      - noActivitySince:
+          days: 7
+      actions:
+      - closeIssue
+    - description: 
+      frequencies:
+      - hourly:
+          hour: 6
+      filters:
+      - isOpen
+      - hasLabel:
+          label: Resolution - Fixed
+      - noActivitySince:
+          days: 7
+      actions:
+      - closeIssue
+    - description: 
+      frequencies:
+      - hourly:
+          hour: 6
+      filters:
+      - isOpen
+      - hasLabel:
+          label: Resolution - Won't Fix
+      - noActivitySince:
+          days: 7
+      actions:
+      - closeIssue
+    - description: 
+      frequencies:
+      - hourly:
+          hour: 6
+      filters:
+      - isOpen
+      - hasLabel:
+          label: Need Repro Info
+      - noActivitySince:
+          days: 14
+      - isNotLabeledWith:
+          label: Issue - Bug
+      actions:
+      - addReply:
+          reply: Closing due to inactivity
+      - closeIssue
+    eventResponderTasks: []
+onFailure: 
+onSuccess: 
diff --git a/.github/workflows/ci-test.yml b/.github/workflows/ci-test.yml
new file mode 100644
index 000000000..5469c54a5
--- /dev/null
+++ b/.github/workflows/ci-test.yml
@@ -0,0 +1,83 @@
+name: CI Tests
+
+on:
+  push:
+    branches: [ main ]
+  pull_request:
+    branches: [ main ]
+
+jobs:
+  ci:
+    name: pester
+    strategy:
+      matrix:
+        os: [ windows-latest, macos-latest, ubuntu-latest ]
+    runs-on: ${{ matrix.os }}
+    env:
+      DOTNET_NOLOGO: true
+      DOTNET_GENERATE_ASPNET_CERTIFICATE: false
+    steps:
+      - name: Checkout repository
+        uses: actions/checkout@v4
+
+      - name: Install dotnet
+        uses: actions/setup-dotnet@v4
+        with:
+          cache: true
+          cache-dependency-path: '**/*.csproj'
+
+      - name: Install PSResources
+        run: ./tools/installPSResources.ps1
+        shell: pwsh
+
+      - name: Build
+        run: ./build.ps1 -Configuration Release -All -Verbose
+        shell: pwsh
+
+      - name: Package
+        run: ./build.ps1 -BuildNupkg -Verbose
+        shell: pwsh
+
+      - name: Test
+        run: ./build.ps1 -Test -Verbose
+        shell: pwsh
+
+      - name: Test Windows PowerShell
+        if: matrix.os == 'windows-latest'
+        run: |
+           Install-Module Pester -Scope CurrentUser -Force -SkipPublisherCheck
+           ./build.ps1 -Test -Verbose
+        shell: powershell
+
+      - name: Download PowerShell install script
+        uses: actions/checkout@v4
+        with:
+          repository: PowerShell/PowerShell
+          path: pwsh
+          sparse-checkout: tools/install-powershell.ps1
+          sparse-checkout-cone-mode: false
+
+      - name: Install preview
+        continue-on-error: true
+        run: ./pwsh/tools/install-powershell.ps1 -Preview -Destination ./preview
+        shell: pwsh
+
+      - name: Test preview
+        run: |
+          $PwshPreview = if ($isWindows) { "./preview/pwsh.exe" } else { "./preview/pwsh" }
+          ./build.ps1 -Test -WithPowerShell:$PwshPreview -Verbose
+        shell: pwsh
+
+      - name: Upload build artifacts
+        uses: actions/upload-artifact@v4
+        if: always()
+        with:
+          name: PSScriptAnalyzer-package-${{ matrix.os }}
+          path: out/**/*.nupkg
+
+      - name: Upload test results
+        uses: actions/upload-artifact@v4
+        if: always()
+        with:
+          name: PSScriptAnalyzer-tests-${{ matrix.os }}
+          path: testResults.xml
diff --git a/.gitignore b/.gitignore
index 4f674094d..fdf91a4bf 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,223 +1,5 @@
-## Ignore Visual Studio temporary files, build results, and
-## files generated by popular Visual Studio add-ons.
-
-# User-specific files
-*.suo
-*.user
-*.userosscache
-*.sln.docstates
-
-# User-specific files (MonoDevelop/Xamarin Studio)
-*.userprefs
-
-# Build results
-[Dd]ebug/
-[Dd]ebugPublic/
-[Rr]elease/
-[Rr]eleases/
-x64/
-x86/
-build/
-bld/
-[Bb]in/
-[Oo]bj/
-
-# Visual Studo 2015 cache/options directory
-.vs/
-
-# VSCode configuration directory
-.vscode/
-
-# MSTest test Results
-[Tt]est[Rr]esult*/
-[Bb]uild[Ll]og.*
-
-# NUNIT
-*.VisualState.xml
-TestResult.xml
-
-# Build Results of an ATL Project
-[Dd]ebugPS/
-[Rr]eleasePS/
-dlldata.c
-
-# .Net Core CLI
-project.lock.json
-artifacts/
-
-*_i.c
-*_p.c
-*_i.h
-*.ilk
-*.meta
-*.obj
-*.pch
-*.pdb
-*.pgc
-*.pgd
-*.rsp
-*.sbr
-*.tlb
-*.tli
-*.tlh
-*.tmp
-*.tmp_proj
-*.log
-*.vspscc
-*.vssscc
-.builds
-*.pidb
-*.svclog
-*.scc
-
-# Chutzpah Test files
-_Chutzpah*
-
-# Visual C++ cache files
-ipch/
-*.aps
-*.ncb
-*.opensdf
-*.sdf
-*.cachefile
-
-# Visual Studio profiler
-*.psess
-*.vsp
-*.vspx
-
-# TFS 2012 Local Workspace
-$tf/
-
-# Guidance Automation Toolkit
-*.gpState
-
-# ReSharper is a .NET coding add-in
-_ReSharper*/
-*.[Rr]e[Ss]harper
-*.DotSettings.user
-
-# JustCode is a .NET coding addin-in
-.JustCode
-
-# TeamCity is a build add-in
-_TeamCity*
-
-# DotCover is a Code Coverage Tool
-*.dotCover
-
-# NCrunch
-_NCrunch_*
-.*crunch*.local.xml
-
-# MightyMoose
-*.mm.*
-AutoTest.Net/
-
-# Web workbench (sass)
-.sass-cache/
-
-# Installshield output folder
-[Ee]xpress/
-
-# DocProject is a documentation generator add-in
-DocProject/buildhelp/
-DocProject/Help/*.HxT
-DocProject/Help/*.HxC
-DocProject/Help/*.hhc
-DocProject/Help/*.hhk
-DocProject/Help/*.hhp
-DocProject/Help/Html2
-DocProject/Help/html
-
-# Click-Once directory
-publish/
-
-# Publish Web Output
-*.[Pp]ublish.xml
-*.azurePubxml
-# TODO: Comment the next line if you want to checkin your web deploy settings 
-# but database connection strings (with potential passwords) will be unencrypted
-*.pubxml
-*.publishproj
-
-# NuGet Packages
-*.nupkg
-# The packages folder can be ignored because of Package Restore
-**/packages/*
-# except build/, which is used as an MSBuild target.
-!**/packages/build/
-# Uncomment if necessary however generally it will be regenerated when needed
-#!**/packages/repositories.config
-
-# Windows Azure Build Output
-csx/
-*.build.csdef
-
-# Windows Store app package directory
-AppPackages/
-
-# Visual Studio cache files
-# files ending in .cache can be ignored
-*.[Cc]ache
-# but keep track of directories ending in .cache
-!*.[Cc]ache/
-
-# Others
-ClientBin/
-[Ss]tyle[Cc]op.*
-~$*
-*~
-*.dbmdl
-*.dbproj.schemaview
-*.pfx
-*.publishsettings
-node_modules/
-bower_components/
-
-# RIA/Silverlight projects
-Generated_Code/
-
-# Backup & report files from converting an old project file
-# to a newer Visual Studio version. Backup files are not needed,
-# because we have git ;-)
-_UpgradeReport_Files/
-Backup*/
-UpgradeLog*.XML
-UpgradeLog*.htm
-
-# SQL Server files
-*.mdf
-*.ldf
-
-# Business Intelligence projects
-*.rdl.data
-*.bim.layout
-*.bim_*.settings
-
-# Microsoft Fakes
-FakesAssemblies/
-
-# Node.js Tools for Visual Studio
-.ntvs_analysis.dat
-
-# Visual Studio 6 build log
-*.plg
-
-# Visual Studio 6 workspace options file
-*.opt
-
-##Our project binplace location
-PSScriptAnalyzer/
-
-# Vim swap files
-*.swp
-
-# Test result file
-TestResults.xml
-
-# PSCompatibilityCollector module
-PSCompatibilityCollector/out/
-
-# Folder of build module 
-out
+bin/
+obj/
+/module/
+/out/
+testResults.xml
diff --git a/.pipelines/PSScriptAnalyzer-Official.yml b/.pipelines/PSScriptAnalyzer-Official.yml
new file mode 100644
index 000000000..abea9ab3c
--- /dev/null
+++ b/.pipelines/PSScriptAnalyzer-Official.yml
@@ -0,0 +1,174 @@
+#################################################################################
+#                               OneBranch Pipelines                             #
+# This pipeline was created by EasyStart from a sample located at:              #
+#   https://aka.ms/obpipelines/easystart/samples                                #
+# Documentation:  https://aka.ms/obpipelines                                    #
+# Yaml Schema:    https://aka.ms/obpipelines/yaml/schema                        #
+# Retail Tasks:   https://aka.ms/obpipelines/tasks                              #
+# Support:        https://aka.ms/onebranchsup                                   #
+#################################################################################
+
+trigger:
+- main
+
+schedules:
+- cron: '20 16 * * 4'
+  displayName: Weekly CodeQL
+  branches:
+    include:
+    - main
+  always: true
+
+parameters:
+- name: debug
+  displayName: Enable debug output
+  type: boolean
+  default: false
+
+variables:
+  system.debug: ${{ parameters.debug }}
+  BuildConfiguration: Release
+  WindowsContainerImage: onebranch.azurecr.io/windows/ltsc2022/vse2022:latest
+  DOTNET_NOLOGO: true
+  DOTNET_GENERATE_ASPNET_CERTIFICATE: false
+
+resources:
+  repositories:
+    - repository: templates
+      type: git
+      name: OneBranch.Pipelines/GovernedTemplates
+      ref: refs/heads/main
+
+extends:
+  # https://aka.ms/obpipelines/templates
+  template: v2/OneBranch.Official.CrossPlat.yml@templates
+  parameters:
+    globalSdl: # https://aka.ms/obpipelines/sdl
+      asyncSdl:
+        enabled: true
+        forStages: [build]
+    featureFlags:
+      EnableCDPxPAT: false
+      WindowsHostVersion:
+        Version: 2022
+        Network: KS3
+    release:
+      category: NonAzure
+    stages:
+    - stage: build
+      jobs:
+      - job: main
+        displayName: Build package
+        pool:
+          type: windows
+        variables:
+          ob_outputDirectory: $(Build.SourcesDirectory)/out
+        steps:
+          - pwsh: |
+              [xml]$xml = Get-Content ./Directory.Build.props
+              $version = $xml.Project.PropertyGroup.ModuleVersion
+              Write-Output "##vso[task.setvariable variable=version;isOutput=true]$version"
+            name: package
+            displayName: Get version from project properties
+          - task: onebranch.pipeline.version@1
+            displayName: Set OneBranch version
+            inputs:
+              system: Custom
+              customVersion: $(package.version)
+          - task: UseDotNet@2
+            displayName: Use .NET SDK
+            inputs:
+              packageType: sdk
+              useGlobalJson: true
+          - pwsh: ./tools/installPSResources.ps1 -PSRepository CFS
+            displayName: Install PSResources
+          - pwsh: ./build.ps1 -Configuration Release -All
+            displayName: Build
+          - task: onebranch.pipeline.signing@1
+            displayName: Sign 1st-party files
+            inputs:
+              command: sign
+              signing_profile: external_distribution
+              search_root: $(Build.SourcesDirectory)/out
+              files_to_sign: |
+                **/Microsoft.*.dll;
+                **/*.psd1;
+                **/*.psm1;
+                **/*.ps1xml;
+          - task: onebranch.pipeline.signing@1
+            displayName: Sign 3rd-party files
+            inputs:
+              command: sign
+              signing_profile: 135020002
+              search_root: $(Build.SourcesDirectory)/out
+              files_to_sign: |
+                **/Newtonsoft.Json.dll;
+                **/Pluralize.NET.dll;
+          - pwsh: ./build.ps1 -BuildNupkg
+            displayName: Package module
+          - task: onebranch.pipeline.signing@1
+            displayName: Sign NuGet package
+            inputs:
+              command: sign
+              signing_profile: external_distribution
+              search_root: $(Build.SourcesDirectory)/out
+              files_to_sign: |
+                *.nupkg
+    - stage: release
+      dependsOn: build
+      condition: eq(variables['Build.Reason'], 'Manual')
+      variables:
+        ob_release_environment: Production
+        version: $[ stageDependencies.build.main.outputs['package.version'] ]
+      jobs:
+      - job: github
+        displayName: Publish draft to GitHub
+        pool:
+          type: release
+        templateContext:
+          inputs:
+          - input: pipelineArtifact
+            artifactName: drop_build_main
+        steps:
+        - task: GitHubRelease@1
+          displayName: Create GitHub release
+          inputs:
+            gitHubConnection: GitHub
+            repositoryName: PowerShell/PSScriptAnalyzer
+            target: main
+            assets: $(Pipeline.Workspace)/PSScriptAnalyzer.$(version).nupkg
+            tagSource: userSpecifiedTag
+            tag: $(version)
+            isDraft: true
+            addChangeLog: false
+            releaseNotesSource: inline
+            releaseNotesInline: "<!-- TODO: Generate release notes on GitHub! -->"
+      - job: validation
+        displayName: Manual validation
+        pool:
+          type: server
+        timeoutInMinutes: 1440
+        steps:
+        - task: ManualValidation@0
+          displayName: Wait 24 hours for validation
+          inputs:
+            notifyUsers: $(Build.RequestedForEmail)
+            instructions: Please validate the release and then publish it!
+            timeoutInMinutes: 1440
+      - job: publish
+        dependsOn: validation
+        displayName: Publish to PowerShell Gallery
+        pool:
+          type: release
+        templateContext:
+          inputs:
+          - input: pipelineArtifact
+            artifactName: drop_build_main
+        steps:
+        - task: NuGetCommand@2
+          displayName: Publish module to PowerShell Gallery
+          inputs:
+            command: push
+            packagesToPush: $(Pipeline.Workspace)/PSScriptAnalyzer.$(version).nupkg
+            nuGetFeedType: external
+            publishFeedCredentials: PowerShellGallery
diff --git a/.vscode/extensions.json b/.vscode/extensions.json
index 098ed86e6..bf1b08715 100644
--- a/.vscode/extensions.json
+++ b/.vscode/extensions.json
@@ -3,7 +3,6 @@
     // for the documentation about the extensions.json format
     "recommendations": [
         "ms-vscode.PowerShell",
-        "ms-dotnettools.csharp",
-        "ms-vscode-remote.remote-containers"
+        "ms-dotnettools.csharp"
     ]
-}
\ No newline at end of file
+}
diff --git a/.vscode/launch.json b/.vscode/launch.json
index 9beb418df..a352eafc2 100644
--- a/.vscode/launch.json
+++ b/.vscode/launch.json
@@ -1,18 +1,55 @@
 {
     "version": "0.2.0",
     "configurations": [
-
         {
-            "name": ".NET Core Launch (console)",
-            "type": "coreclr",
+            "type": "PowerShell",
+            "request": "launch",
+            "name": "Build",
+            "script": "./build.ps1",
+            "args": [
+                ""
+            ],
+            "cwd": "${workspaceFolder}",
+            "createTemporaryIntegratedConsole": true
+        },
+        {
+            "type": "PowerShell",
+            "request": "launch",
+            "name": "Build & Import PSSA",
+            "script": "./build.ps1; Import-Module ./out/PSScriptAnalyzer/*/PSScriptAnalyzer.psd1",
+            "args": [
+                ""
+            ],
+            "cwd": "${workspaceFolder}",
+            "createTemporaryIntegratedConsole": true
+        },
+        {
+            "type": "PowerShell",
             "request": "launch",
-            "preLaunchTask": "build",
-            "program": "${workspaceRoot}/bin/Debug/<target-framework>/<project-name.dll>",
-            "args": [],
-            "cwd": "${workspaceRoot}",
-            "externalConsole": false,
-            "stopAtEntry": false,
-            "internalConsoleOptions": "openOnSessionStart"
+            "name": "Build & Run all tests",
+            "script": "./build.ps1; ./build.ps1 -Test",
+            "args": [
+                ""
+            ],
+            "cwd": "${workspaceFolder}",
+            "createTemporaryIntegratedConsole": true
+        },
+        {
+            "type": "PowerShell",
+            "request": "launch",
+            "name": "Run current Pester file with PSScriptAnalyzer development build",
+            "script": "Import-Module ./out/PSScriptAnalyzer/*/PSScriptAnalyzer.psd1; Invoke-Pester -Path '${file}'; $PID",
+            "args": [
+                ""
+            ],
+            "cwd": "${workspaceFolder}",
+            "createTemporaryIntegratedConsole": true
+        },
+        {
+            "name": "PowerShell Attach to Host Process",
+            "type": "PowerShell",
+            "request": "attach",
+            "runspaceId": 1
         },
         {
             "name": ".NET Core Attach",
diff --git a/CHANGELOG.MD b/CHANGELOG.MD
index 9e8067f3b..76352e7c7 100644
--- a/CHANGELOG.MD
+++ b/CHANGELOG.MD
@@ -1,5 +1,333 @@
 ﻿# CHANGELOG
 
+## [1.24.0](https://github.com/PowerShell/PSScriptAnalyzer/releases/tag/1.24.0)
+
+### What's Changed
+#### Breaking Changes
+
+Minimum required PowerShell version raised from 3 to 5.1
+* Drop v3 and v4 support from build by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2081
+
+#### New Features
+
+* Add new options (enabled by default) to formatting rule `UseCorrectCasing` to also correct operators, keywords and commands - Add UseConsistentCasing by @Jaykul in https://github.com/PowerShell/PSScriptAnalyzer/pull/1704
+
+#### Enhancements
+
+* PSAlignAssignmentStatement: Ignore hashtables with a single key-value pair by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/1986
+* Use `RequiredResource` hashtable to specify PowerShell module versions by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2053
+* Set exit code of `Invoke-ScriptAnalyzer -EnableExit` to total number of diagnostics (#2054) by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2055
+* PSAvoidAssignmentToAutomaticVariable: Ignore when a Parameter has an Attribute that contains a Variable expression by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/1988
+* Trim unnecessary trailing spaces from string resources in Strings.resx by @XPlantefeve in https://github.com/PowerShell/PSScriptAnalyzer/pull/1972
+* Do not print summary repeatedly for each logger by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2058
+* Make Settings type detection more robust by @Tadas in https://github.com/PowerShell/PSScriptAnalyzer/pull/1967
+* Add foreach Assignment to AvoidAssignmentToAutomaticVariable by @PoshAJ in https://github.com/PowerShell/PSScriptAnalyzer/pull/2021
+* Invoke-ScriptAnalyzer: Stream diagnostics instead of batching by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2062
+* Invoke-ScriptAnalyzer: Print summary only once per invocation by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2063
+* Invoke-ScriptAnalyzer: Include parse errors in reported error count by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2069
+* Add exception message for missing rules by @Tadas in https://github.com/PowerShell/PSScriptAnalyzer/pull/1968
+
+#### Bug Fixes
+
+* Update links in module manifest by @martincostello in https://github.com/PowerShell/PSScriptAnalyzer/pull/2034
+* Fix incorrect `-ReportSummary` Pester test grouping by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2057
+* Fixed erroneous PSUseDeclaredVarsMoreThanAssignments for some globals variables by @John-Leitch in https://github.com/PowerShell/PSScriptAnalyzer/pull/2013
+* PSReservedParams: Make severity Error instead of Warning by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/1989
+* PSUseConsistentIndentation: Check indentation of lines where first token is a LParen not followed by comment or new line by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/1995
+* PSUseConsistentWhitespace: Correctly fix whitespace between command parameters when parameter value spans multiple lines  by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/2064
+* PSAvoidTrailingWhitespace: Rule not applied when using formatter + single character lines with trailing whitespace are truncated by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/1993
+* PSUseConsistentWhitespace: Ignore whitespace between separator and comment by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/2065
+* PSReviewUnusedParameter false positive for ValueFromPipeline by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/2072
+* Change severity of UseCorrectCasing to be Information by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2082
+
+#### Process Changes
+
+* Copy more files to module root by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2037
+* Upgrade to .NET 8 since .NET 6 is past EOL by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2073
+* Use -NoProfile when invoking pwsh in Pester tests by @MatejKafka in https://github.com/PowerShell/PSScriptAnalyzer/pull/2061
+* Add GitHub Actions Ubuntu's dotnet path by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2080
+* Update README.md with recent upgrade to .NET 8 by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2076
+* Update CHANGELOG.MD with 1.23.0 release notes by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2078
+* Bring back Codespaces by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2077
+* Update SMA version to 7.4.7 by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2075
+* Test PowerShell Preview in CI by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2070
+* Backport MSDocs changes by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2085
+* Document new optional parameters added to UseCorrectCasing by @bergmeister in https://github.com/PowerShell/PSScriptAnalyzer/pull/2086
+
+### New Contributors
+* @martincostello made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/2034
+* @MatejKafka made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/2055
+* @XPlantefeve made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/1972
+* @John-Leitch made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/2013
+* @Tadas made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/1967
+* @PoshAJ made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/2021
+* @Jaykul made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/1704
+
+**Full Changelog**: https://github.com/PowerShell/PSScriptAnalyzer/compare/1.23.0...1.24.0
+
+## [1.23.0](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.23.0) - 2024-10-09
+
+### What's Changed
+* Adding OneBranch pipeline YAML config file for OSS_Microsoft_PSSA-Official by @adityapatwardhan in https://github.com/PowerShell/PSScriptAnalyzer/pull/1981
+* Update format and grammar of AvoidUsingAllowUnencryptedAuthentication by @sdwheeler in https://github.com/PowerShell/PSScriptAnalyzer/pull/1974
+* Move to OneBranch Signing and SBOM generation by @TravisEz13 in https://github.com/PowerShell/PSScriptAnalyzer/pull/1982
+* Sync rule docs changes by @sdwheeler in https://github.com/PowerShell/PSScriptAnalyzer/pull/1985
+* Sync docs changes from MicrosoftDocs/PowerShell-Docs-Modules#213 by @sdwheeler in https://github.com/PowerShell/PSScriptAnalyzer/pull/1987
+* Update CHANGELOG for 1.22.0 release by @sdwheeler in https://github.com/PowerShell/PSScriptAnalyzer/pull/1990
+* Update Code of Conduct by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2002
+* Update default type definition of `RuleInfo` by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/2011
+* PSUseConsistentWhitespace: Handle redirect operators which are not in stream order by @liamjpeters in https://github.com/PowerShell/PSScriptAnalyzer/pull/2001
+* Setup GitHub Actions CI by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2018
+* Setup new OneBranch pipeline by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2027
+* Bump SMA version by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2028
+* Package updates by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2030
+* v1.23.0: Update version for new release by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2032
+* Migrate release pipeline to DeployBox by @andyleejordan in https://github.com/PowerShell/PSScriptAnalyzer/pull/2033
+
+### New Contributors
+* @adityapatwardhan made their first contribution in https://github.com/PowerShell/PSScriptAnalyzer/pull/1981
+
+**Full Changelog**: https://github.com/PowerShell/PSScriptAnalyzer/compare/1.22.0...1.23.0
+
+## [1.22.0](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.22.0) - 2024-03-05
+
+Minimum required version when using PowerShell 7 is now `7.2.11`.
+
+### New Rule
+
+- Add AvoidUsingAllowUnencryptedAuthentication by @MJVL in (#1857)
+- Add the AvoidExclaimOperator rule to warn about the use of the ! negation operator. Fixes (#1826) by
+  @liamjpeters in (#1922)
+
+### Enhancements
+
+- Enable suppression of PSAvoidAssignmentToAutomaticVariable for specific variable or parameter by
+  @fflaten in (#1896)
+- Upgrade to use .NET 6 since PowerShell 7.0 is now out out of support by @bergmeister in (#1873)
+- Convert UseSingularNouns to configurable rule and add Windows to allowlist by @MJVL in (#1858)
+- Add ErrorView to SpecialVars.cs by @ewisniew0 in (#1865)
+- Allow suppression of  PSUseSingularNouns for specific function by @fflaten in (#1903)
+- Adding ToString() methods to [CorrectionExtent] and [DiagnosticRecord] by @StartAutomating in (#1946)
+- Add PSNativeCommandUseErrorActionPreference preference variable by @aelij in (#1954)
+- AvoidUsingPositionalParameter: Check if command has parameters to avoid having az in default
+  CommandAllowList by @bergmeister in (#1850)
+- PSReviewUnusedParameter: Add CommandsToTraverse option by @FriedrichWeinmann in (#1921)
+
+### Fixes
+
+- Prevent NullReferenceException for null analysis type. by @hubuk in (#1949)
+
+### Build & Test, Documentation and Maintenance
+
+- UseApprovedVerbs.md: Backport minor change of PR 104 in PowerShell-Docs-Modules by @bergmeister in
+  (#1849)
+- Improve Pester bootstrap logic for CI by @bergmeister in (#1853)
+- Bump .NET SDK from 3.1.419 to 3.1.424 by @bergmeister in (#1852)
+- AvoidLongLines: Make internal function DiagnosticSeverity private by @bergmeister in (#1851)
+- SupportsShouldProcess.md: Fix Typo - MicrosoftDocs backport of PR 121 there by @sdwheeler in (#1869)
+- Minor test fix for UseCorrectCasing rule by @kilasuit in (#1885)
+- Make Invoke-Formatter test case assertion fail in case of incorrect casing by @alexandear in (#1888)
+- Fix `AvoidUsingDoubleQuotesForConstantString` information in overview README by @michaeltlombardi
+  in (#1883)
+- Update dependabot reviewers to remove Rob by @fflaten in (#1897)
+- Fix typo in AvoidUsingPlainTextForPassword error message: 'to' being repeated two times by
+  @ALiwoto in (#1902)
+- CI: Use new Ubuntu 22.04  image and remove deprecated Ubuntu 18.04 by @bergmeister in (#1847)
+- Change double quotes to single where possible by @sdwheeler in (#1911)
+- Backport MicrosoftDocs PR 143 by @sdwheeler in (#1910)
+- Fix typos in rules documentation by @sdwheeler in (#1913)
+- add demand for compliance job by @TravisEz13 in (#1920)
+- FabricBot: Onboarding to GitOps.ResourceManagement because of FabricBot decommissioning by
+  @microsoft-github-policy-service in (#1925)
+- Sync changes from Docs repository by @sdwheeler in (#1929)
+- Developer documentation fix and message fix of
+  PossibleIncorrectUsageOfRedirectionOperatorDescription by @JoelTipke in (#1928)
+- Documentation corrections for AvoidUsingPositionalParameters by @ImportTaste in (#1917)
+- Update minimum PowerShell Core version to 7.2.11 as 7.0 is now EOL by @bergmeister in (#1872)
+- Remove dead code and simplify by @bergmeister in (#1856)
+- PSReservedParams - link about_CommonParameters by @petervandivier in (#1908)
+- Generate strongly typed resources as part of build by @bergmeister in (#1855)
+- Bump Newtonsoft.Json to 13.0.3 by @dependabot in (#1866)
+- Use latest .NET 6.0 SDK patch version and update devcontainer to use .NET 6 as well by
+  @bergmeister in (#1955)
+- Bump Microsoft.Management.Infrastructure from 1.0.0 to 3.0.0 for PowerShell 7 only by @dependabot
+  in (#1947)
+- Bump version from 1.21.0 to 1.22.0 by @bergmeister in (#1965)
+- Remove Appveyor badge from main README by @bergmeister in (#1962)
+- Do not hard code common parameters in module help test any more by @bergmeister in (#1963)
+
+### New Contributors
+
+- @fflaten made their first contribution in (#1897)
+- @ALiwoto made their first contribution in (#1902)
+- @microsoft-github-policy-service made their first contribution in (#1925)
+- @JoelTipke made their first contribution in (#1928)
+- @ImportTaste made their first contribution in (#1917)
+- @liamjpeters made their first contribution in (#1922)
+- @petervandivier made their first contribution in (#1908)
+- @ewisniew0 made their first contribution in (#1865)
+- @StartAutomating made their first contribution in (#1946)
+- @aelij made their first contribution in (#1954)
+- @FriedrichWeinmann made their first contribution in (#1921)
+
+**Full Changelog**: <https://github.com/PowerShell/PSScriptAnalyzer/compare/1.21.0...1.22.0>
+
+## [1.21.0](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.21.0) - 2022-09-27
+
+### New Rule
+
+- Add AvoidMultipleTypeAttributes rule (#1705) (thanks @hankyi95)
+- Add the AvoidSemicolonsAsLineTerminators rule to warn about lines ending with a semicolon. Fix
+  (#824) (#1806) (thanks @tempora-mutantur)
+- Add AvoidUsingBrokenHashAlgorithms (#1787) (thanks @MJVL)
+
+### Enhancements
+
+- Also return suggestion to use PSCredential for AvoidUsingPlainTextForPassword rule (#1782) (by @bergmeister)
+- Invoke-Formatter: Accept input from pipeline (#1763) (by @bergmeister)
+- Make messages of UseCorrectCasing more detailed (#1843)
+- Exclude automatic variable FormatEnumerationLimit from analysis by PSAvoidGlobalVars and
+  PSUseDeclaredVarsMoreThanAssignments (#1836) (by @bergmeister)
+- PSAvoidUsingPositionalParameters: Do not warn on AZ CLI (#1846) (by @bergmeister)
+
+### Fixes
+
+- Fix PSUseConsistentIndentation.PipelineIndentation.None to not remove code when the previous line ended with a pipe (#1746) (by @bergmeister)
+- Fix edge case of UseConsistentIndentation where child pipeline is on the same line as hashtable (#1838) (by @bergmeister)
+- Skip OpenBrace check when preceded by Dot token (#1750) (by @bergmeister)
+- Fix NRE (NullReferenceException) when custom rules omit optional properties in diagnostics (#1715) (by @rjmholt)
+
+### Build, Documenation and Maintenance
+
+- Tweak documentation for AvoidUsingBrokenHashAlgorithms (#1829) (thanks @michaeltlombardi)
+- Set MaxDepth in JsonSerializerSettings for more secure handling of exceptional conditions in Newtonsoft.Json (#1824) (by @bergmeister)
+- Use latest Newtonsoft.Json version for Windows PowerShell builds and not exclude it any more in Dependabot (#1825) (by @bergmeister)
+- Correct pipeline acceptance docs for Invoke-Formatter.md (#1833) (by @bergmeister)
+- Sync remaining docs changes from Microsoft docs (#1835) (by @bergmeister)
+- (MAINT) Update URLs for site rebrand from docs.microsoft.com to learn.microsoft.com (#1844) (by @sdwheeler)
+- Reformat note block (#1837) (by @sdwheeler)
+- Update AvoidMultipleTypeAttributes.md with example that has runtime error (#1831) (by @bergmeister)
+- Fix minimum PowerShell version to be 7.0.11 instead of 7.1.7 (#1830) (by @bergmeister)
+- Add `.github/fabricbot.json` (#1812)
+- Sync changes from docs repo (#1814) (by @sdwheeler)
+- Fix name of PowerShell 5.1 test stage in CI (#1820) (by @bergmeister)
+- CI: Retry test tasks in cas1e of failure to reduce sporadic failures (#1770)
+- Upgrade from net452 to net462 for Windows PowerShell (#1789)
+- Move issue template config into folder (#1804) (thanks @michaeltlombardi)
+- Bump version from 1.20.0 to 1.21.0 (#1796) (by @bergmeister)
+- Bump .NET SDK and SMA patch version (#1795) (by @bergmeister)
+- Be sure not to clobber existing files when installing dotnet. (#1788) (by @JamesWTruher)
+- Add link to issues chooser for reporting docs issues (#1794) (by @sdwheeler)
+- Update README and delete docs that were migrated (#1790) (by @sdwheeler)
+- Fix errors in ShouldProcess rule document (#1766) (thanks @masaru-iritani)
+- Replicate changes from docs repo (#1781) (by @sdwheeler)
+- Update Windows CI images as windows-2016 has been deprecated (#1784) (by @bergmeister)
+- Use latest mac image rather than a specific version. (#1777) (by @JamesWTruher)
+- Add docs migration notice & fix formatting (#1779) (by @sdwheeler)
+- use compliant build environment for release build. (#1776) (by @JamesWTruher)
+- Enable SBOM creation for script analyzer (#1762) (by @JamesWTruher)
+- Fix links to work on GitHub (#1738) (by @andschwa)
+- Update AvoidUsingWMICmdlet.md (#1737) (thanks @C0smin)
+- Fix broken doc link in README (#1735) (thanks @AndrewRathbun)
+- Add metadata to docs (#1731) (by @sdwheeler)
+- Remove Ubuntu 16.04 from test matrix (#1733) (by @rjmholt)
+- Use PowerShell1ES pool for official build (#1719) (by @JamesWTruher)
+- Update cmdlet docs for 1.20.0 (#1726) (by @sdwheeler)
+- Fixes (#1720) - move rule docs and update tests (#1724) (by @sdwheeler)
+- Update rule docs (#1711)  (by @sdwheeler)
+
+## [1.20.0](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.20.0) - 2021-08-20
+
+### Fixes
+
+- Replace unhelpful warning around `process` aliasing `Get-Process` with warning about misused syntax (#1638) (by @bergmeister)
+- Fix `FunctionInfo` fallback AST attribute analysis for UseShouldProcessCorrectly (#1659) (thanks @hubuk)
+- Do not increase indentation after a left parenthesis if the previous token is a newline and the next token is not a newline (#1469) (by @bergmeister)
+- UseConsistentWhitespace - CheckOpenBrace setting: Do not warn when being preceded by open parenthesis (#1633) (by @bergmeister)
+
+### New Rule
+
+- Make UseSingularNouns rule work in PowerShell 7 (#1627) (by @bergmeister)
+- UseConsistentWhitespace: Create option to ignore assignment operator inside hashtable (#1566) (thanks @daviesj)
+
+### Miscellaneous
+
+- Implement -IncludeSuppressions parameter (#1701) (by @rjmholt)
+- Combine multiple suppressions applied to the same diagnostic (#1699) (by @rjmholt)
+- Use dependabot to keep dependencies up to date (#1664) (by @rjmholt)
+- Add reviewers and explicit dependency exclusions to dependabot (#1676) (by @rjmholt)
+- Remove explicit registries in dependabot (#1671) (by @rjmholt)
+
+### Documentation
+
+- Link to PSScriptAnalyzer rule documentation from the README (#1642) (thanks @bbodenmiller)
+- Add HelpInfoUri to module manifest (#1651) (by @sdwheeler)
+- Add documentation around CustomRulePath in Settings file to README.md (#1636) (thanks @johlju)
+- Use allowlist and blocklist terminology, supply alternate configuration key for PSAvoidUsingCmdletAliases (#1604) (by @bergmeister)
+- Fix suppression example errors in README (#1593) (by @rjmholt)
+- Fix AvoidLongLines documentation example (#1554) (thanks @floh96)
+- Remove broken waffle.io links from readme.md (#1558) (thanks @clcaldwell)
+- Fix typo in AvoidUsingCmdletAliases documentation (#1590) (thanks @rubengonzalez-dev)
+
+### Testing
+
+- Fix compatibility rule tests (#1697) (by @rjmholt)
+- Fix missing space in AvoidPositionalParameter test asset (#1573) (by @jameswtruher)
+
+### Development/Build Improvements
+
+- Fix build module tests (#1654) (thanks @clcaldwell)
+- Move to new signing process for release build and prep for 1.20.0 (#1625) (by @jameswtruher)
+- Handle cases where the signature generator fails (#1661) (by @jameswtruher)
+- Update .NET SDK to 3.1.408 (#1630) (by @bergmeister)
+- Simplify devcontainer setup and resolve git line ending conflicts (#1637) (by @bergmeister)
+- Speedup CI by bootstrapping PowerShell module installations in background and in parallel, whilst the .NET SDK is being installed (#1634) (by @bergmeister)
+- Upgrade release Dockerfile from Ubuntu 16.04 to 20.04 (#1631) (by @bergmeister)
+- Remove old powershell-core NuGet feed, which sometimes causes build failures (#1632) (by @bergmeister)
+- Remove reference to myget.org as a package resource (#1640) (by @jameswtruher)
+- Add Ubuntu 20.04 to build matrix (#1628) (by @bergmeister)
+- Remove conditional compilation for PSv6/netstandard2.0 for Engine and Rules projects (#1600) (by @bergmeister)
+- Upgrade Microsoft.CSharp, Microsoft.Win32.Registry and System.Reflection.TypeExtensions from 4.5.0 to 4.7.0 (#1599) (by @bergmeister)
+- Use PowerShell preview extension for Github Codespaces (#1596) (by @bergmeister)
+- Update SMA reference for netcoreapp3.1 to from 7.0.0 to 7.0.3 (#1597) (by @bergmeister)
+- 🧹 Make usage of Microsoft.Management.Infrastructure consistent and reference it only once in CrossCompatibility project (#1601) (by @bergmeister)
+- Update launch.json (#1603) (by @bergmeister)
+- Make CI fail if tests fail and fix failing tests by making them Pester v5 compatible (#1553) (coauthored by @bergmeister)
+
+## [1.19.1](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.19.1) - 2020-07-28
+
+### Fixes
+
+- `UseCorrectCasing`: Do not use CommandInfoCache when CommandInfoParameters property throws due to runspace affinity problem of PowerShell engine (#1523) (by @bergmeister)
+- `ReviewUnusedParameter`: Do not trigger when MyInvocation.BoundParameters or PSCmdlet.MyInvocation.BoundParameters is used (#1520) (Thanks @jegannathanmaniganadan!)
+- `PipelineIndentationStyle.None`: Fix bug that caused incorrect formatting in hashtables (#1497) (by @bergmeister)
+- `UseUsingScopeModifierInNewRunspaces`: Fix ArgumentException when the same variable name is used in 2 different sessions. (#1493) (by @bergmeister)
+- `UseConsistentWhitespace`
+  - Check previous token only if it starts on the same line (#1491) (by @bergmeister)
+  - Fix CheckParameter bug when using interpolated string (#1498) (by @bergmeister)
+
+### New Rule
+
+- New rule (disabled by default): [AvoidUsingDoubleQuotesForConstantString](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingDoubleQuotesForConstantString.md) (#1470) (by @bergmeister)
+
+### Miscellaneous
+
+- Set Assembly version attribute (#1549) (by @JamesWTruher)
+
+### Documentation
+
+- Remove references to Windows in Introduction of Readme.md (#1509) (Thanks @hjorslev!)
+
+### Testing
+
+- Pester v5 (#1444) (by @bergmeister)
+
+### Development improvements
+
+- Include PDB files in Debug build (#1535) (by @bergmeister)
+- Add more useful launch configurations (#1499) (by @bergmeister)
+- Make .Net Core version in Docker image of .devcontainer match the one in global.json (#1494) (by @bergmeister)
+
 ## [1.19.0](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.19.0)
 
 ### New Rules
@@ -16,7 +344,7 @@
 
 ### Compatibility Rules
 
-- Make CompatibilityCollector able to parse a single version String #1446 (by @bergmeister)
+- Make CompatibilityCollector able to parse a single version String (#1446) (by @bergmeister)
 - Update compatibility profiles for PowerShell 7 (#1429) (by @rjmholt)
 - Ps7 syntax (#1426) (by @rjmholt)
 - Fix ps3 syntax check (#1395) (by @rjmholt)
@@ -117,7 +445,7 @@ The PRs for those improvements are:
 
 ## [1.18.3](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.18.3) - 2019-09-13
 
-This release adds one more important fix, which prevents a leak of runspaces when repeatedly invoking the PSScriptAnalyzer cmdlets. Furthermore it ups the minimum version of PowerShell Core to `6.2.0` due to `6.1` reaching its [end of life](https://docs.microsoft.com/en-us/powershell/scripting/powershell-support-lifecycle?view=powershell-6#powershell-releases-end-of-life) this month.
+This release adds one more important fix, which prevents a leak of runspaces when repeatedly invoking the PSScriptAnalyzer cmdlets. Furthermore it ups the minimum version of PowerShell Core to `6.2.0` due to `6.1` reaching its [end of life](https://learn.microsoft.com/powershell/scripting/install/PowerShell-Support-Lifecycle#powershell-end-of-support-dates) this month.
 
 - Change CommandInfoCache to implement IDisposable and clean up the runspace pool (#1335) (by @JamesWTruher)
 - Update Newtonsoft json to 12.0.1 due to PowerShell 6.1 going out of support (#1336) (by @bergmeister)
@@ -183,11 +511,11 @@ The benefit to the user will be some enhancements and fixes in the formatter, es
   - Convert compatibility module to binary module, fix compatibility with Azure environments (#1212) (by @rjmholt)
   - Prevent .NET members with names differing only by case from crashing the compatibility profiler (#1195) (by @rjmholt)
   - Fix compatibility profile query API so that aliases referring to other modules appear (#1194) (by @rjmholt)
-  
+
 - DSC
   - Instead of using the first cimClass and then having no superClass, use the first cimClass that has a non-null superClass (#1200) (by @bergmeister, thanks to @ykuijs! for the great collaboration)
   - Make `-SaveDscDependency` work on Linux (#1246) (by @bergmeister)
-  
+
 - Enable suppression of custom rules when used together with `-IncludeDefaultRules` to allow all possible scenarios from 1.17.1 and 1.18.0. This removes also the check if the rule name in the suppression attribute can be found because this check is technically not possible in all scenarios (#1245) (by @bergmeister)
 - Fix NullReferenceException for class type (#1182) (by @bergmeister)
 
@@ -400,7 +728,7 @@ Multi-threading efficiency was highly improved leading to a speedup whilst keepi
 - Add simple GitHub Pull Request template based off the one for PowerShell Core (#866) (by @bergmeister)
 - Add a simple GitHub issue template based on the one of PowerShell Core. (#865, #884) (by @bergmeister)
 - Fix Example 7 in Invoke-ScriptAnalyzer.md (#862) (Thanks @sethvs!)
-- Use the typewriter apostrophe instead the typographic apostrophe (#855) (Thanks @alexandear!) 
+- Use the typewriter apostrophe instead the typographic apostrophe (#855) (Thanks @alexandear!)
 - Add justification to ReadMe (#848) (Thanks @KevinMarquette!)
 - Fix typo in README (#845) (Thanks @misterGF!)
 
@@ -469,7 +797,7 @@ Many thanks to @rkeithhill for contributing the _Stroustrup_ style code formatti
 ## [1.11.1](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.11.1) - 2017-04-04
 ### Fixed
 - CodeFormatting settings file (#727, #728).
-- Whitelisted aliases comparison in AvoidUsingCmdletAliases rule (#739).
+- Allowlist aliases comparison in AvoidUsingCmdletAliases rule (#739).
 - PlaceCloseBrace rule behavior for NewLineAfter option (#741).
 - UseConsistentIndentation rule to ignore open brace in magic methods (#744).
 
@@ -566,7 +894,7 @@ Here are some improvements since the last release.
 - Fix `SaveDscDependency` switch implementation, which use fail if more than one parameter is given to `Import-DSCResource` dynamic keyword.
 - Add support for external AST based rule suppression
 - Fix rule suppression caused by inavlid offsets
-- Whitelist `Data` in `PSUseSingularNoun` rule
+- Allowlist `Data` in `PSUseSingularNoun` rule
 - Fix rule documentation of `PSDSCExamplesPresent`
 - Fix false positives caused by PSD1 files which are not module manifests
     - affects `PSUseToExportFieldsInManifest`, `PSMissingModuleManifestField` and `PSAvoidUsingDeprecatedManifestFields` rules
@@ -574,10 +902,10 @@ Here are some improvements since the last release.
 - Add build script to automate building and testing the solution
 
 A big **Thank You!** to the following folks for making PSScriptAnalyzer even better:
-- [Kieran Jacobsen (@kjacobsen)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=kjacobsen): Fix rule documentation of `PSDSCExamplesPresent` [PR #591](https://github.com/PowerShell/PSScriptAnalyzer/pull/591)
-- [Charlie Schmidt (@charlieschmidt)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=charlieschmidt): Suppress External Rules [PR #585](https://github.com/PowerShell/PSScriptAnalyzer/pull/585)
+- [Kieran Jacobsen (@kjacobsen)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=kjacobsen): Fix rule documentation of `PSDSCExamplesPresent` [PR #591](#591)
+- [Charlie Schmidt (@charlieschmidt)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=charlieschmidt): Suppress External Rules [PR #585](#585)
 - [June Blender (@juneb)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=juneb): Add tests for module help [058f65e1](https://github.com/PowerShell/PSScriptAnalyzer/commit/058f65e1f6278222378fedf444eecb2e32865b1e)
-- [Shayde Nofziger (@Blackbaud-ShaydeNofziger)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=Blackbaud-ShaydeNofziger): Fix rule name typo and comment [PR #560](https://github.com/PowerShell/PSScriptAnalyzer/pull/560)
+- [Shayde Nofziger (@Blackbaud-ShaydeNofziger)](https://github.com/PowerShell/PSScriptAnalyzer/commits/development?author=Blackbaud-ShaydeNofziger): Fix rule name typo and comment [PR #560](#560)
 
 ## [1.6.0](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.6.0) - 2016-06-07
 
@@ -676,7 +1004,8 @@ A big **Thank You!** to the following folks for making PSScriptAnalyzer even bet
 ### Fixes:
 #### Engine:
 - Engine update to prevent script based injection attacks
-- CustomizedRulePath is now called CustomRulePath â€“ Fixes to handle folder paths
+- CustomizedRulePath is now called CustomRulePath
+- Fixes to handle folder paths
 - Fixes for RecurseCustomRulePath functionality
 - Fix to binplace cmdlet help file as part of build process
 - ScriptAnalyzer Profile is now called Settings
@@ -694,7 +1023,8 @@ A big **Thank You!** to the following folks for making PSScriptAnalyzer even bet
 - Update to Credential based rules to validate the presence of CredentialAttribute and PSCredential type
 
 ### Documentation:
-- Rule & Cmdlet documentation updates â€“ Cmdlet help file addition
+- Rule & Cmdlet documentation updates
+- Cmdlet help file addition
 
 ## [1.1.1](https://github.com/PowerShell/PSScriptAnalyzer/tree/1.1.1) - 2015-11-03
 ### Features:
@@ -735,7 +1065,7 @@ A big **Thank You!** to the following folks for making PSScriptAnalyzer even bet
 
 ### Rules:
 - New rule to validate the presence of deprecated module manifest fields.
-- Removed PSAvoidTrapStatement rule from the builtin set â€“ since this is not deprecated and using trap is a better choice in certain scenarios.
+- Removed PSAvoidTrapStatement rule from the builtin set since this is not deprecated and using trap is a better choice in certain scenarios.
 
 ### Fixes:
 - Verbose Message rule applies to only DSC cmdlet based resources.
diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md
new file mode 100644
index 000000000..686e5e7a0
--- /dev/null
+++ b/CODE_OF_CONDUCT.md
@@ -0,0 +1,10 @@
+# Microsoft Open Source Code of Conduct
+
+This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
+
+Resources:
+
+- [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/)
+- [Microsoft Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/)
+- Contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with questions or concerns
+- Employees can reach out at [aka.ms/opensource/moderation-support](https://aka.ms/opensource/moderation-support)
diff --git a/Directory.Build.props b/Directory.Build.props
new file mode 100644
index 000000000..f7d809c1d
--- /dev/null
+++ b/Directory.Build.props
@@ -0,0 +1,7 @@
+<Project>
+  <!-- See https://aka.ms/dotnet/msbuild/customize for more details on customizing your build -->
+  <PropertyGroup>
+    <ModuleVersion>1.24.0</ModuleVersion>
+    <ManagePackageVersionsCentrally>true</ManagePackageVersionsCentrally>
+  </PropertyGroup>
+</Project>
diff --git a/Directory.Packages.props b/Directory.Packages.props
new file mode 100644
index 000000000..d79bb8840
--- /dev/null
+++ b/Directory.Packages.props
@@ -0,0 +1,16 @@
+<Project>
+  <ItemGroup>
+    <!-- Newtonsoft.Json brings in an old version of CSharp. So, we are forcing a newer version. -->
+    <PackageVersion Include="Microsoft.CSharp" Version="4.7.0" />
+    <PackageVersion Include="Microsoft.Management.Infrastructure" Version="3.0.0" />
+    <PackageVersion Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0" />
+    <PackageVersion Include="Microsoft.Win32.Registry" Version="5.0.0" />
+    <!--  The version of Newtonsoft.Json needs to be newer than the version in the oldest supported version of PowerShell 7: https://github.com/PowerShell/PowerShell/blob/v7.2.17/src/System.Management.Automation/System.Management.Automation.csproj#L15 -->
+    <PackageVersion Include="Newtonsoft.Json" Version="13.0.3" />
+    <PackageVersion Include="Pluralize.NET" Version="1.0.2" />
+    <PackageVersion Include="PowerShellStandard.Library" Version="5.1.1" />
+    <!-- Please update minimumPowerShellCoreVersion in PSScriptAnalyzer.psm1 when updating below SMA version for better user-facing error message -->
+    <PackageVersion Include="System.Management.Automation" Version="7.4.7" />
+    <PackageVersion Include="System.Reflection.TypeExtensions" Version="4.7.0" />
+  </ItemGroup>
+</Project>
diff --git a/Engine/CommandInfoCache.cs b/Engine/CommandInfoCache.cs
index 02e926b53..71c37d83c 100644
--- a/Engine/CommandInfoCache.cs
+++ b/Engine/CommandInfoCache.cs
@@ -15,17 +15,15 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
     internal class CommandInfoCache : IDisposable
     {
         private readonly ConcurrentDictionary<CommandLookupKey, Lazy<CommandInfo>> _commandInfoCache;
-        private readonly Helper _helperInstance;
         private readonly RunspacePool _runspacePool;
         private bool disposed = false;
 
         /// <summary>
         /// Create a fresh command info cache instance.
         /// </summary>
-        public CommandInfoCache(Helper pssaHelperInstance)
+        public CommandInfoCache()
         {
             _commandInfoCache = new ConcurrentDictionary<CommandLookupKey, Lazy<CommandInfo>>();
-            _helperInstance = pssaHelperInstance;
             _runspacePool = RunspaceFactory.CreateRunspacePool(1, 10);
             _runspacePool.Open();
         }
@@ -57,8 +55,9 @@ protected virtual void Dispose(bool disposing)
         /// </summary>
         /// <param name="commandName">Name of the command to get a commandinfo object for.</param>
         /// <param name="commandTypes">What types of command are needed. If omitted, all types are retrieved.</param>
+        /// <param name="bypassCache">When needed due to runspace affinity problems of some PowerShell objects.</param>
         /// <returns></returns>
-        public CommandInfo GetCommandInfo(string commandName, CommandTypes? commandTypes = null)
+        public CommandInfo GetCommandInfo(string commandName, CommandTypes? commandTypes = null, bool bypassCache = false)
         {
             if (string.IsNullOrWhiteSpace(commandName))
             {
@@ -66,6 +65,10 @@ public CommandInfo GetCommandInfo(string commandName, CommandTypes? commandTypes
             }
 
             var key = new CommandLookupKey(commandName, commandTypes);
+            if (bypassCache)
+            {
+                return GetCommandInfoInternal(commandName, commandTypes);
+            }
             // Atomically either use PowerShell to query a command info object, or fetch it from the cache
             return _commandInfoCache.GetOrAdd(key, new Lazy<CommandInfo>(() => GetCommandInfoInternal(commandName, commandTypes))).Value;
         }
diff --git a/Engine/Commands/GetScriptAnalyzerRuleCommand.cs b/Engine/Commands/GetScriptAnalyzerRuleCommand.cs
index 7a9d50561..3219affa7 100644
--- a/Engine/Commands/GetScriptAnalyzerRuleCommand.cs
+++ b/Engine/Commands/GetScriptAnalyzerRuleCommand.cs
@@ -84,13 +84,12 @@ protected override void BeginProcessing()
 
             // Initialize helper
             Helper.Instance = new Helper(
-                SessionState.InvokeCommand,
-                this);
+                SessionState.InvokeCommand);
             Helper.Instance.Initialize();
 
             string[] rulePaths = Helper.ProcessCustomRulePaths(customRulePath,
                 this.SessionState, recurseCustomRulePath);
-            ScriptAnalyzer.Instance.Initialize(this, rulePaths, null, null, null, null == rulePaths ? true : false);
+            ScriptAnalyzer.Instance.Initialize(this, rulePaths, null, null, null, null == rulePaths);
         }
 
         /// <summary>
diff --git a/Engine/Commands/InvokeFormatterCommand.cs b/Engine/Commands/InvokeFormatterCommand.cs
index c0d9fd168..25a2d364e 100644
--- a/Engine/Commands/InvokeFormatterCommand.cs
+++ b/Engine/Commands/InvokeFormatterCommand.cs
@@ -25,14 +25,14 @@ public class InvokeFormatterCommand : PSCmdlet, IOutputWriter
         ///
         /// *NOTE*: Unlike ScriptBlock parameter, the ScriptDefinition parameter require a string value.
         /// </summary>
-        [ParameterAttribute(Mandatory = true, Position = 1)]
+        [ParameterAttribute(Mandatory = true, ValueFromPipeline = true, ValueFromPipelineByPropertyName = true, Position = 1)]
         [ValidateNotNull]
         public string ScriptDefinition { get; set; }
 
         /// <summary>
         /// A settings hashtable or a path to a PowerShell data file (.psd1) file that contains the settings.
         /// </summary>
-        [Parameter(Mandatory = false, Position = 2)]
+        [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, Position = 2)]
         [ValidateNotNull]
         public object Settings { get; set; } = defaultSettingsPreset;
 
@@ -44,7 +44,7 @@ public class InvokeFormatterCommand : PSCmdlet, IOutputWriter
         /// end column number. These numbers must be greater than 0.
         /// </summary>
         /// <returns></returns>
-        [Parameter(Mandatory = false, Position = 3)]
+        [Parameter(Mandatory = false, ValueFromPipelineByPropertyName = true, Position = 3)]
         [ValidateNotNull]
         [ValidateCount(4, 4)]
         public int[] Range { get; set; }
@@ -124,11 +124,5 @@ protected override void StopProcessing()
             ScriptAnalyzer.Instance.CleanUp();
             base.StopProcessing();
         }
-
-        private void ValidateInputSettings()
-        {
-            // todo implement this
-            return;
-        }
     }
 }
diff --git a/Engine/Commands/InvokeScriptAnalyzerCommand.cs b/Engine/Commands/InvokeScriptAnalyzerCommand.cs
index f5598d5bd..a444327e0 100644
--- a/Engine/Commands/InvokeScriptAnalyzerCommand.cs
+++ b/Engine/Commands/InvokeScriptAnalyzerCommand.cs
@@ -21,15 +21,22 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands
     /// </summary>
     [Cmdlet(VerbsLifecycle.Invoke,
         "ScriptAnalyzer",
-        DefaultParameterSetName = "File",
+        DefaultParameterSetName = ParameterSet_Path_SuppressedOnly,
         SupportsShouldProcess = true,
         HelpUri = "https://go.microsoft.com/fwlink/?LinkId=525914")]
-    [OutputType(typeof(DiagnosticRecord))]
-    [OutputType(typeof(SuppressedRecord))]
+    [OutputType(typeof(DiagnosticRecord), typeof(SuppressedRecord))]
     public class InvokeScriptAnalyzerCommand : PSCmdlet, IOutputWriter
     {
+        private const string ParameterSet_Path_SuppressedOnly = nameof(Path) + "_" + nameof(SuppressedOnly);
+        private const string ParameterSet_Path_IncludeSuppressed = nameof(Path) + "_" + nameof(IncludeSuppressed);
+        private const string ParameterSet_ScriptDefinition_SuppressedOnly = nameof(ScriptDefinition) + "_" + nameof(SuppressedOnly);
+        private const string ParameterSet_ScriptDefinition_IncludeSuppressed = nameof(ScriptDefinition) + "_" + nameof(IncludeSuppressed);
+
         #region Private variables
         List<string> processedPaths;
+        // initialize to zero for all severity enum values
+        private Dictionary<DiagnosticSeverity, int> diagnosticCounts =
+                Enum.GetValues(typeof(DiagnosticSeverity)).Cast<DiagnosticSeverity>().ToDictionary(s => s, _ => 0);
         #endregion // Private variables
 
         #region Parameters
@@ -37,7 +44,12 @@ public class InvokeScriptAnalyzerCommand : PSCmdlet, IOutputWriter
         /// Path: The path to the file or folder to invoke PSScriptAnalyzer on.
         /// </summary>
         [Parameter(Position = 0,
-            ParameterSetName = "File",
+            ParameterSetName = ParameterSet_Path_IncludeSuppressed,
+            Mandatory = true,
+            ValueFromPipeline = true,
+            ValueFromPipelineByPropertyName = true)]
+        [Parameter(Position = 0,
+            ParameterSetName = ParameterSet_Path_SuppressedOnly,
             Mandatory = true,
             ValueFromPipeline = true,
             ValueFromPipelineByPropertyName = true)]
@@ -54,7 +66,12 @@ public string Path
         /// ScriptDefinition: a script definition in the form of a string to run rules on.
         /// </summary>
         [Parameter(Position = 0,
-            ParameterSetName = "ScriptDefinition",
+            ParameterSetName = ParameterSet_ScriptDefinition_IncludeSuppressed,
+            Mandatory = true,
+            ValueFromPipeline = true,
+            ValueFromPipelineByPropertyName = true)]
+        [Parameter(Position = 0,
+            ParameterSetName = ParameterSet_ScriptDefinition_SuppressedOnly,
             Mandatory = true,
             ValueFromPipeline = true,
             ValueFromPipelineByPropertyName = true)]
@@ -84,7 +101,6 @@ public string[] CustomRulePath
         /// RecurseCustomRulePath: Find rules within subfolders under the path
         /// </summary>
         [Parameter(Mandatory = false)]
-        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
         public SwitchParameter RecurseCustomRulePath
         {
             get { return recurseCustomRulePath; }
@@ -96,7 +112,6 @@ public SwitchParameter RecurseCustomRulePath
         /// IncludeDefaultRules: Invoke default rules along with Custom rules
         /// </summary>
         [Parameter(Mandatory = false)]
-        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
         public SwitchParameter IncludeDefaultRules
         {
             get { return includeDefaultRules; }
@@ -143,11 +158,15 @@ public string[] Severity
         }
         private string[] severity;
 
+        // TODO: This should be only in the Path parameter sets, and is ignored otherwise,
+        //       but we already have a test that depends on it being otherwise
+        //[Parameter(ParameterSetName = ParameterSet_Path_IncludeSuppressed)]
+        //[Parameter(ParameterSetName = ParameterSet_Path_SuppressedOnly)]
+        //
         /// <summary>
         /// Recurse: Apply to all files within subfolders under the path
         /// </summary>
-        [Parameter(Mandatory = false)]
-        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
+        [Parameter]
         public SwitchParameter Recurse
         {
             get { return recurse; }
@@ -158,19 +177,22 @@ public SwitchParameter Recurse
         /// <summary>
         /// ShowSuppressed: Show the suppressed message
         /// </summary>
-        [Parameter(Mandatory = false)]
-        [SuppressMessage("Microsoft.Performance", "CA1819:PropertiesShouldNotReturnArrays")]
-        public SwitchParameter SuppressedOnly
-        {
-            get { return suppressedOnly; }
-            set { suppressedOnly = value; }
-        }
-        private bool suppressedOnly;
+        [Parameter(ParameterSetName = ParameterSet_Path_SuppressedOnly)]
+        [Parameter(ParameterSetName = ParameterSet_ScriptDefinition_SuppressedOnly)]
+        public SwitchParameter SuppressedOnly { get; set; }
+
+        /// <summary>
+        /// Include suppressed diagnostics in the output.
+        /// </summary>
+        [Parameter(ParameterSetName = ParameterSet_Path_IncludeSuppressed, Mandatory = true)]
+        [Parameter(ParameterSetName = ParameterSet_ScriptDefinition_IncludeSuppressed, Mandatory = true)]
+        public SwitchParameter IncludeSuppressed { get; set; }
 
         /// <summary>
         /// Resolves rule violations automatically where possible.
         /// </summary>
-        [Parameter(Mandatory = false, ParameterSetName = "File")]
+        [Parameter(Mandatory = false, ParameterSetName = ParameterSet_Path_IncludeSuppressed)]
+        [Parameter(Mandatory = false, ParameterSetName = ParameterSet_Path_SuppressedOnly)]
         public SwitchParameter Fix
         {
             get { return fix; }
@@ -266,8 +288,7 @@ protected override void BeginProcessing()
             }
 #endif
             Helper.Instance = new Helper(
-                SessionState.InvokeCommand,
-                this);
+                SessionState.InvokeCommand);
             Helper.Instance.Initialize();
 
             var psVersionTable = this.SessionState.PSVariable.GetValue("PSVersionTable") as Hashtable;
@@ -334,6 +355,12 @@ protected override void BeginProcessing()
                         this.settings));
             }
 
+            SuppressionPreference suppressionPreference = SuppressedOnly
+                ? SuppressionPreference.SuppressedOnly
+                : IncludeSuppressed
+                    ? SuppressionPreference.Include
+                    : SuppressionPreference.Omit;
+
             ScriptAnalyzer.Instance.Initialize(
                 this,
                 combRulePaths,
@@ -341,7 +368,7 @@ protected override void BeginProcessing()
                 this.excludeRule,
                 this.severity,
                 combRulePaths == null || combIncludeDefaultRules,
-                this.suppressedOnly);
+                suppressionPreference);
         }
 
         /// <summary>
@@ -388,6 +415,37 @@ protected override void EndProcessing()
         {
             ScriptAnalyzer.Instance.CleanUp();
             base.EndProcessing();
+
+            var diagnosticCount = diagnosticCounts.Values.Sum();
+
+            if (ReportSummary.IsPresent)
+            {
+                if (diagnosticCount == 0)
+                {
+                    Host.UI.WriteLine("0 rule violations found.");
+                }
+                else
+                {
+                    var infoCount = diagnosticCounts[DiagnosticSeverity.Information];
+                    var warningCount = diagnosticCounts[DiagnosticSeverity.Warning];
+                    var errorCount = diagnosticCounts[DiagnosticSeverity.Error] + diagnosticCounts[DiagnosticSeverity.ParseError];
+                    var severeDiagnosticCount = diagnosticCount - infoCount;
+
+                    var colorPropertyPrefix = severeDiagnosticCount == 0 ? "Warning" : "Error";
+                    var pluralS = diagnosticCount > 1 ? "s" : string.Empty;
+                    ConsoleHostHelper.DisplayMessageUsingSystemProperties(
+                            Host, colorPropertyPrefix + "ForegroundColor", colorPropertyPrefix + "BackgroundColor",
+                            $"{diagnosticCount} rule violation{pluralS} found. Severity distribution: " +
+                            $"{DiagnosticSeverity.Error} = {errorCount}, " +
+                            $"{DiagnosticSeverity.Warning} = {warningCount}, " +
+                            $"{DiagnosticSeverity.Information} = {infoCount}");
+                }
+            }
+
+            if (EnableExit)
+            {
+                this.Host.SetShouldExit(diagnosticCount);
+            }
         }
 
         protected override void StopProcessing()
@@ -402,89 +460,50 @@ protected override void StopProcessing()
 
         private void ProcessInput()
         {
-            IEnumerable<DiagnosticRecord> diagnosticsList = Enumerable.Empty<DiagnosticRecord>();
-            if (IsFileParameterSet())
+            foreach (var diagnostic in RunAnalysis())
             {
-                foreach (var p in processedPaths)
+                diagnosticCounts[diagnostic.Severity]++;
+
+                foreach (var logger in ScriptAnalyzer.Instance.Loggers)
                 {
-                    if (fix)
-                    {
-                        ShouldProcess(p, $"Analyzing and fixing path with Recurse={this.recurse}");
-                        diagnosticsList = ScriptAnalyzer.Instance.AnalyzeAndFixPath(p, this.ShouldProcess, this.recurse);
-                    }
-                    else
-                    {
-                        ShouldProcess(p, $"Analyzing path with Recurse={this.recurse}");
-                        diagnosticsList = ScriptAnalyzer.Instance.AnalyzePath(p, this.ShouldProcess, this.recurse);
-                    }
-                    WriteToOutput(diagnosticsList);
+                    logger.LogObject(diagnostic, this);
                 }
             }
-            else if (String.Equals(this.ParameterSetName, "ScriptDefinition", StringComparison.OrdinalIgnoreCase))
-            {
-                diagnosticsList = ScriptAnalyzer.Instance.AnalyzeScriptDefinition(scriptDefinition, out _, out _);
-                WriteToOutput(diagnosticsList);
-            }
         }
 
-        private void WriteToOutput(IEnumerable<DiagnosticRecord> diagnosticRecords)
+        private IEnumerable<DiagnosticRecord> RunAnalysis()
         {
-            foreach (ILogger logger in ScriptAnalyzer.Instance.Loggers)
+            if (!IsFileParameterSet())
             {
-                var errorCount = 0;
-                var warningCount = 0;
-                var infoCount = 0;
-                var parseErrorCount = 0;
+                foreach (var record in ScriptAnalyzer.Instance.AnalyzeScriptDefinition(scriptDefinition, out _, out _))
+                {
+                    yield return record;
+                }
+                yield break;
+            }
 
-                foreach (DiagnosticRecord diagnostic in diagnosticRecords)
+            foreach (var path in this.processedPaths)
+            {
+                if (!ShouldProcess(path, $"Analyzing path with Fix={this.fix} and Recurse={this.recurse}"))
                 {
-                    logger.LogObject(diagnostic, this);
-                    switch (diagnostic.Severity)
-                    {
-                        case DiagnosticSeverity.Information:
-                            infoCount++;
-                            break;
-                        case DiagnosticSeverity.Warning:
-                            warningCount++;
-                            break;
-                        case DiagnosticSeverity.Error:
-                            errorCount++;
-                            break;
-                        case DiagnosticSeverity.ParseError:
-                            parseErrorCount++;
-                            break;
-                        default:
-                            throw new ArgumentOutOfRangeException(nameof(diagnostic.Severity), $"Severity '{diagnostic.Severity}' is unknown");
-                    }
+                    continue;
                 }
 
-                if (ReportSummary.IsPresent)
+                if (fix)
                 {
-                    var numberOfRuleViolations = infoCount + warningCount + errorCount;
-                    if (numberOfRuleViolations == 0)
+                    foreach (var record in ScriptAnalyzer.Instance.AnalyzeAndFixPath(path, this.ShouldProcess, this.recurse))
                     {
-                        Host.UI.WriteLine("0 rule violations found.");
+                        yield return record;
                     }
-                    else
+                }
+                else
+                {
+                    foreach (var record in ScriptAnalyzer.Instance.AnalyzePath(path, this.ShouldProcess, this.recurse))
                     {
-                        var pluralS = numberOfRuleViolations > 1 ? "s" : string.Empty;
-                        var message = $"{numberOfRuleViolations} rule violation{pluralS} found.    Severity distribution:  {DiagnosticSeverity.Error} = {errorCount}, {DiagnosticSeverity.Warning} = {warningCount}, {DiagnosticSeverity.Information} = {infoCount}";
-                        if (warningCount + errorCount == 0)
-                        {
-                            ConsoleHostHelper.DisplayMessageUsingSystemProperties(Host, "WarningForegroundColor", "WarningBackgroundColor", message);
-                        }
-                        else
-                        {
-                            ConsoleHostHelper.DisplayMessageUsingSystemProperties(Host, "ErrorForegroundColor", "ErrorBackgroundColor", message);
-                        }
+                        yield return record;
                     }
                 }
             }
-
-            if (EnableExit.IsPresent)
-            {
-                this.Host.SetShouldExit(diagnosticRecords.Count());
-            }
         }
 
         private void ProcessPath()
@@ -497,10 +516,7 @@ private void ProcessPath()
             }
         }
 
-        private bool IsFileParameterSet()
-        {
-            return String.Equals(this.ParameterSetName, "File", StringComparison.OrdinalIgnoreCase);
-        }
+        private bool IsFileParameterSet() => Path is not null;
 
         private bool OverrideSwitchParam(bool paramValue, string paramName)
         {
@@ -511,4 +527,4 @@ private bool OverrideSwitchParam(bool paramValue, string paramName)
 
         #endregion // Private Methods
     }
-}
+}
\ No newline at end of file
diff --git a/Engine/Engine.csproj b/Engine/Engine.csproj
index 1f8d6b6e0..63b9a1b9c 100644
--- a/Engine/Engine.csproj
+++ b/Engine/Engine.csproj
@@ -1,26 +1,28 @@
 ﻿<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <VersionPrefix>1.19.0</VersionPrefix>
-    <TargetFrameworks>netcoreapp3.1;netstandard2.0;net452</TargetFrameworks>
+    <VersionPrefix>$(ModuleVersion)</VersionPrefix>
+    <TargetFrameworks>net8;net462</TargetFrameworks>
     <AssemblyName>Microsoft.Windows.PowerShell.ScriptAnalyzer</AssemblyName>
+    <AssemblyVersion>$(ModuleVersion)</AssemblyVersion>
     <PackageId>Engine</PackageId>
     <RootNamespace>Microsoft.Windows.PowerShell.ScriptAnalyzer</RootNamespace> <!-- Namespace needs to match Assembly name for ressource binding -->
+    <LangVersion>9.0</LangVersion>
   </PropertyGroup>
 
-  <ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
     <Reference Include="System.ComponentModel.Composition" />
   </ItemGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'net452' ">
+  <PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
     <DebugType>portable</DebugType>
   </PropertyGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'netcoreapp3.1' ">
+  <PropertyGroup Condition=" '$(TargetFramework)' == 'net8' ">
     <DefineConstants>$(DefineConstants);CORECLR</DefineConstants>
   </PropertyGroup>
 
-  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'netcoreapp3.1' ">
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net8' ">
     <Compile Remove="SafeDirectoryCatalog.cs" />
   </ItemGroup>
 
@@ -43,63 +45,39 @@
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
-  </ItemGroup>
-
-  <ItemGroup>
-    <Compile Update="Strings.Designer.cs">
-      <DesignTime>True</DesignTime>
-      <AutoGen>True</AutoGen>
-      <DependentUpon>Strings.resx</DependentUpon>
-    </Compile>
+    <PackageReference Include="Microsoft.CSharp" />
   </ItemGroup>
 
+  <!--
+       This ItemGroup and PropertyGroup block is required for resource generation to work for
+       .NET CLI, Visual Studio and VS-Code: https://github.com/dotnet/msbuild/issues/4751
+  -->
   <ItemGroup>
     <EmbeddedResource Update="Strings.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
+      <!-- Tell Visual Studio that MSBuild will do the generation and run a build if resx file changes. -->
+      <Generator>MSBuild:Compile</Generator>
       <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+      <StronglyTypedFileName>$(IntermediateOutputPath)\Strings.Designer.cs</StronglyTypedFileName>
+      <StronglyTypedLanguage>CSharp</StronglyTypedLanguage>
+      <StronglyTypedNamespace>Microsoft.Windows.PowerShell.ScriptAnalyzer</StronglyTypedNamespace>
+      <StronglyTypedClassName>Strings</StronglyTypedClassName>
     </EmbeddedResource>
   </ItemGroup>
-
-  <ItemGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
-    <PackageReference Include="System.Management.Automation" Version="7.0.0" />
-  </ItemGroup>
-  <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
-    <DefineConstants>$(DefineConstants);PSV7;CORECLR</DefineConstants>
-  </PropertyGroup>
-  <PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
-    <DefineConstants>$(DefineConstants);PSV6;CORECLR</DefineConstants>
+  <!-- For VS Code/OmniSharp support, ensure that CoreResGen runs before CoreCompile -->
+  <PropertyGroup>
+    <CoreCompileDependsOn>PrepareResources;$(CompileDependsOn)</CoreCompileDependsOn>
   </PropertyGroup>
-  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
-    <PackageReference Include="System.Management.Automation" Version="6.1.0" />
-  </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == 'net452' AND '$(Configuration)' == 'PSV3Release' AND '$(Configuration)' != 'PSV4Release'">
-    <PackageReference Include="Microsoft.PowerShell.3.ReferenceAssemblies" Version="1.0.0" />
-  </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == 'net452' AND '$(Configuration)' == 'PSV4Release'">
-    <PackageReference Include="Microsoft.PowerShell.4.ReferenceAssemblies" Version="1.0.0" />
+  <ItemGroup Condition="'$(TargetFramework)' == 'net8'">
+    <PackageReference Include="System.Management.Automation" />
   </ItemGroup>
+  <PropertyGroup Condition="'$(TargetFramework)' == 'net8'">
+    <DefineConstants>$(DefineConstants);PSV7;CORECLR</DefineConstants>
+  </PropertyGroup>
    
-  <ItemGroup Condition="'$(TargetFramework)' == 'net452' AND '$(Configuration)' != 'PSV3Release'">
-    <PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" Version="1.1.0" />
+  <ItemGroup Condition="'$(TargetFramework)' == 'net462' ">
+    <PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" />
   </ItemGroup>
-   
-  <PropertyGroup Condition=" '$(Configuration)' == 'PSV3Release' ">
-    <DefineConstants>$(DefineConstants);PSV3</DefineConstants>
-  </PropertyGroup>
-  
-  <PropertyGroup Condition=" '$(Configuration)' == 'PSV4Release' ">
-    <DefineConstants>$(DefineConstants);PSV3;PSV4</DefineConstants>
-  </PropertyGroup>
-
-  <PropertyGroup Condition=" '$(Configuration)' == 'PSV3Debug' ">
-    <DefineConstants>$(DefineConstants);PSV3</DefineConstants>
-  </PropertyGroup>
-  
-  <PropertyGroup Condition=" '$(Configuration)' == 'PSV4Debug' ">
-    <DefineConstants>$(DefineConstants);PSV3;PSV4</DefineConstants>
-  </PropertyGroup>
 
 </Project>
diff --git a/Engine/Extensions.cs b/Engine/Extensions.cs
index 5e10b1d78..46b67bf65 100644
--- a/Engine/Extensions.cs
+++ b/Engine/Extensions.cs
@@ -178,5 +178,19 @@ public static bool GetValue(this NamedAttributeArgumentAst attrAst, out Expressi
 
             return false;
         }
+
+        internal static bool TryGetPropertyValue(this PSObject psObject, string propertyName, out object value)
+        {
+            PSMemberInfo property = psObject.Properties[propertyName];
+
+            if (property is null)
+            {
+                value = default;
+                return false;
+            }
+
+            value = property.Value;
+            return true;
+        }
     }
 }
diff --git a/Engine/FindAstPositionVisitor.cs b/Engine/FindAstPositionVisitor.cs
new file mode 100644
index 000000000..459581cbc
--- /dev/null
+++ b/Engine/FindAstPositionVisitor.cs
@@ -0,0 +1,369 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System.Management.Automation.Language;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
+{
+    /// <summary>
+    /// Provides an efficient way to find the position in the AST corresponding to a given script position.
+    /// </summary>
+#if !(PSV3 || PSV4)
+    internal class FindAstPositionVisitor : AstVisitor2
+#else
+    internal class FindAstPositionVisitor : AstVisitor
+#endif
+    {
+        private IScriptPosition searchPosition;
+
+        /// <summary>
+        /// Contains the position in the AST corresponding to the provided <see cref="IScriptPosition"/> upon completion of the <see cref="Ast.Visit(AstVisitor)"/> method.
+        /// </summary>
+        public Ast AstPosition { get; private set; }
+
+        /// <summary>
+        /// Initializes a new instance of the <see cref="FindAstPositionVisitor"/> class with the postition to search for.
+        /// </summary>
+        /// <param name="position">The script position to search for.</param>
+        public FindAstPositionVisitor(IScriptPosition position)
+        {
+            this.searchPosition = position;
+        }
+
+        public override AstVisitAction VisitArrayExpression(ArrayExpressionAst arrayExpressionAst)
+         {
+             return Visit(arrayExpressionAst);
+         }
+
+         public override AstVisitAction VisitArrayLiteral(ArrayLiteralAst arrayLiteralAst)
+         {
+             return Visit(arrayLiteralAst);
+         }
+
+         public override AstVisitAction VisitAssignmentStatement(AssignmentStatementAst assignmentStatementAst)
+         {
+             return Visit(assignmentStatementAst);
+         }
+
+         public override AstVisitAction VisitAttribute(AttributeAst attributeAst)
+         {
+             return Visit(attributeAst);
+         }
+
+         public override AstVisitAction VisitAttributedExpression(AttributedExpressionAst attributedExpressionAst)
+         {
+             return Visit(attributedExpressionAst);
+         }
+
+         public override AstVisitAction VisitBinaryExpression(BinaryExpressionAst binaryExpressionAst)
+         {
+             return Visit(binaryExpressionAst);
+         }
+
+         public override AstVisitAction VisitBlockStatement(BlockStatementAst blockStatementAst)
+         {
+             return Visit(blockStatementAst);
+         }
+
+         public override AstVisitAction VisitBreakStatement(BreakStatementAst breakStatementAst)
+         {
+             return Visit(breakStatementAst);
+         }
+
+         public override AstVisitAction VisitCatchClause(CatchClauseAst catchClauseAst)
+         {
+             return Visit(catchClauseAst);
+         }
+
+         public override AstVisitAction VisitCommand(CommandAst commandAst)
+         {
+             return Visit(commandAst);
+         }
+
+         public override AstVisitAction VisitCommandExpression(CommandExpressionAst commandExpressionAst)
+         {
+             return Visit(commandExpressionAst);
+         }
+
+         public override AstVisitAction VisitCommandParameter(CommandParameterAst commandParameterAst)
+         {
+             return Visit(commandParameterAst);
+         }
+
+         public override AstVisitAction VisitConstantExpression(ConstantExpressionAst constantExpressionAst)
+         {
+             return Visit(constantExpressionAst);
+         }
+
+         public override AstVisitAction VisitContinueStatement(ContinueStatementAst continueStatementAst)
+         {
+             return Visit(continueStatementAst);
+         }
+
+         public override AstVisitAction VisitConvertExpression(ConvertExpressionAst convertExpressionAst)
+         {
+             return Visit(convertExpressionAst);
+         }
+
+         public override AstVisitAction VisitDataStatement(DataStatementAst dataStatementAst)
+         {
+             return Visit(dataStatementAst);
+         }
+
+         public override AstVisitAction VisitDoUntilStatement(DoUntilStatementAst doUntilStatementAst)
+         {
+             return Visit(doUntilStatementAst);
+         }
+
+         public override AstVisitAction VisitDoWhileStatement(DoWhileStatementAst doWhileStatementAst)
+         {
+             return Visit(doWhileStatementAst);
+         }
+
+         public override AstVisitAction VisitErrorExpression(ErrorExpressionAst errorExpressionAst)
+         {
+             return Visit(errorExpressionAst);
+         }
+
+         public override AstVisitAction VisitErrorStatement(ErrorStatementAst errorStatementAst)
+         {
+             return Visit(errorStatementAst);
+         }
+
+         public override AstVisitAction VisitExitStatement(ExitStatementAst exitStatementAst)
+         {
+             return Visit(exitStatementAst);
+         }
+
+         public override AstVisitAction VisitExpandableStringExpression(ExpandableStringExpressionAst expandableStringExpressionAst)
+         {
+             return Visit(expandableStringExpressionAst);
+         }
+
+         public override AstVisitAction VisitFileRedirection(FileRedirectionAst fileRedirectionAst)
+         {
+             return Visit(fileRedirectionAst);
+         }
+
+         public override AstVisitAction VisitForEachStatement(ForEachStatementAst forEachStatementAst)
+         {
+             return Visit(forEachStatementAst);
+         }
+
+         public override AstVisitAction VisitForStatement(ForStatementAst forStatementAst)
+         {
+             return Visit(forStatementAst);
+         }
+
+         public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst functionDefinitionAst)
+         {
+             return Visit(functionDefinitionAst);
+         }
+
+         public override AstVisitAction VisitHashtable(HashtableAst hashtableAst)
+         {
+             return Visit(hashtableAst);
+         }
+
+         public override AstVisitAction VisitIfStatement(IfStatementAst ifStatementAst)
+         {
+             return Visit(ifStatementAst);
+         }
+
+         public override AstVisitAction VisitIndexExpression(IndexExpressionAst indexExpressionAst)
+         {
+             return Visit(indexExpressionAst);
+         }
+
+         public override AstVisitAction VisitInvokeMemberExpression(InvokeMemberExpressionAst invokeMemberExpressionAst)
+         {
+             return Visit(invokeMemberExpressionAst);
+         }
+
+         public override AstVisitAction VisitMemberExpression(MemberExpressionAst memberExpressionAst)
+         {
+             return Visit(memberExpressionAst);
+         }
+
+         public override AstVisitAction VisitMergingRedirection(MergingRedirectionAst mergingRedirectionAst)
+         {
+             return Visit(mergingRedirectionAst);
+         }
+
+         public override AstVisitAction VisitNamedAttributeArgument(NamedAttributeArgumentAst namedAttributeArgumentAst)
+         {
+             return Visit(namedAttributeArgumentAst);
+         }
+
+         public override AstVisitAction VisitNamedBlock(NamedBlockAst namedBlockAst)
+         {
+             return Visit(namedBlockAst);
+         }
+
+         public override AstVisitAction VisitParamBlock(ParamBlockAst paramBlockAst)
+         {
+             return Visit(paramBlockAst);
+         }
+
+         public override AstVisitAction VisitParameter(ParameterAst parameterAst)
+         {
+             return Visit(parameterAst);
+         }
+
+         public override AstVisitAction VisitParenExpression(ParenExpressionAst parenExpressionAst)
+         {
+             return Visit(parenExpressionAst);
+         }
+
+         public override AstVisitAction VisitPipeline(PipelineAst pipelineAst)
+         {
+             return Visit(pipelineAst);
+         }
+
+         public override AstVisitAction VisitReturnStatement(ReturnStatementAst returnStatementAst)
+         {
+             return Visit(returnStatementAst);
+         }
+
+         public override AstVisitAction VisitScriptBlock(ScriptBlockAst scriptBlockAst)
+         {
+             return Visit(scriptBlockAst);
+         }
+
+         public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionAst scriptBlockExpressionAst)
+         {
+             return Visit(scriptBlockExpressionAst);
+         }
+
+         public override AstVisitAction VisitStatementBlock(StatementBlockAst statementBlockAst)
+         {
+             return Visit(statementBlockAst);
+         }
+
+         public override AstVisitAction VisitStringConstantExpression(StringConstantExpressionAst stringConstantExpressionAst)
+         {
+             return Visit(stringConstantExpressionAst);
+         }
+
+         public override AstVisitAction VisitSubExpression(SubExpressionAst subExpressionAst)
+         {
+             return Visit(subExpressionAst);
+         }
+
+         public override AstVisitAction VisitSwitchStatement(SwitchStatementAst switchStatementAst)
+         {
+             return Visit(switchStatementAst);
+         }
+
+         public override AstVisitAction VisitThrowStatement(ThrowStatementAst throwStatementAst)
+         {
+             return Visit(throwStatementAst);
+         }
+
+         public override AstVisitAction VisitTrap(TrapStatementAst trapStatementAst)
+         {
+             return Visit(trapStatementAst);
+         }
+
+         public override AstVisitAction VisitTryStatement(TryStatementAst tryStatementAst)
+         {
+             return Visit(tryStatementAst);
+         }
+
+         public override AstVisitAction VisitTypeConstraint(TypeConstraintAst typeConstraintAst)
+         {
+             return Visit(typeConstraintAst);
+         }
+
+         public override AstVisitAction VisitTypeExpression(TypeExpressionAst typeExpressionAst)
+         {
+             return Visit(typeExpressionAst);
+         }
+
+         public override AstVisitAction VisitUnaryExpression(UnaryExpressionAst unaryExpressionAst)
+         {
+             return Visit(unaryExpressionAst);
+         }
+
+         public override AstVisitAction VisitUsingExpression(UsingExpressionAst usingExpressionAst)
+         {
+             return Visit(usingExpressionAst);
+         }
+
+         public override AstVisitAction VisitVariableExpression(VariableExpressionAst variableExpressionAst)
+         {
+             return Visit(variableExpressionAst);
+         }
+
+         public override AstVisitAction VisitWhileStatement(WhileStatementAst whileStatementAst)
+         {
+             return Visit(whileStatementAst);
+         }
+
+#if !(PSV3 || PSV4)
+         public override AstVisitAction VisitBaseCtorInvokeMemberExpression(BaseCtorInvokeMemberExpressionAst baseCtorInvokeMemberExpressionAst)
+         {
+             return Visit(baseCtorInvokeMemberExpressionAst);
+         }
+
+         public override AstVisitAction VisitConfigurationDefinition(ConfigurationDefinitionAst configurationDefinitionAst)
+         {
+             return Visit(configurationDefinitionAst);
+         }
+
+         public override AstVisitAction VisitDynamicKeywordStatement(DynamicKeywordStatementAst dynamicKeywordStatementAst)
+         {
+             return Visit(dynamicKeywordStatementAst);
+         }
+
+         public override AstVisitAction VisitFunctionMember(FunctionMemberAst functionMemberAst)
+         {
+             return Visit(functionMemberAst);
+         }
+
+         public override AstVisitAction VisitPropertyMember(PropertyMemberAst propertyMemberAst)
+         {
+             return Visit(propertyMemberAst);
+         }
+
+         public override AstVisitAction VisitTypeDefinition(TypeDefinitionAst typeDefinitionAst)
+         {
+             return Visit(typeDefinitionAst);
+         }
+
+         public override AstVisitAction VisitUsingStatement(UsingStatementAst usingStatementAst)
+         {
+             return AstVisitAction.Continue;
+         }
+#endif
+
+#if !(NET462 || PSV7) // net462 includes V3,4,5
+         public override AstVisitAction VisitPipelineChain(PipelineChainAst pipelineChainAst)
+         {
+             return Visit(pipelineChainAst);
+         }
+
+         public override AstVisitAction VisitTernaryExpression(TernaryExpressionAst ternaryExpressionAst)
+         {
+             return Visit(ternaryExpressionAst);
+         }
+#endif
+
+        /// <summary>
+        /// Traverses the AST based on offests to find the leaf-most node which contains the provided <see cref="IScriptPosition"/>.
+        /// This method implements the entire functionality of this visitor. All <see cref="AstVisitor2"/> methods are overridden to simply invoke this one.
+        /// </summary>
+        /// <param name="ast">Current AST node to process.</param>
+        /// <returns>An <see cref="AstVisitAction"/> indicating whether to visit children of the current node.</returns>
+        private AstVisitAction Visit(Ast ast)
+        {
+            if (ast.Extent.StartOffset > searchPosition.Offset || ast.Extent.EndOffset <= searchPosition.Offset)
+            {
+                return AstVisitAction.SkipChildren;
+            }
+            AstPosition = ast;
+            return AstVisitAction.Continue;
+        }
+
+    }
+}
\ No newline at end of file
diff --git a/Engine/Formatter.cs b/Engine/Formatter.cs
index 15db1b39d..a6a25f0fb 100644
--- a/Engine/Formatter.cs
+++ b/Engine/Formatter.cs
@@ -32,7 +32,7 @@ public static string Format<TCmdlet>(
             ValidateNotNull(settings, "settings");
             ValidateNotNull(cmdlet, "cmdlet");
 
-            Helper.Instance = new Helper(cmdlet.SessionState.InvokeCommand, cmdlet);
+            Helper.Instance = new Helper(cmdlet.SessionState.InvokeCommand);
             Helper.Instance.Initialize();
 
             var ruleOrder = new string[]
@@ -44,6 +44,10 @@ public static string Format<TCmdlet>(
                 "PSAlignAssignmentStatement",
                 "PSUseCorrectCasing",
                 "PSAvoidUsingCmdletAliases",
+                "PSAvoidUsingDoubleQuotesForConstantString",
+                "PSAvoidSemicolonsAsLineTerminators",
+                "PSAvoidExclaimOperator",
+                "PSAvoidTrailingWhitespace",
             };
 
             var text = new EditableText(scriptDefinition);
@@ -59,7 +63,7 @@ public static string Format<TCmdlet>(
 
                 var currentSettings = GetCurrentSettings(settings, rule);
                 ScriptAnalyzer.Instance.UpdateSettings(currentSettings);
-                ScriptAnalyzer.Instance.Initialize(cmdlet, null, null, null, null, true, false);
+                ScriptAnalyzer.Instance.Initialize(cmdlet, null, null, null, null, true, SuppressionPreference.Omit);
 
                 text = ScriptAnalyzer.Instance.Fix(text, range, skipParsing, out Range updatedRange, out bool fixesWereApplied, ref scriptAst, ref scriptTokens, skipVariableAnalysis: true);
                 skipParsing = !fixesWereApplied;
diff --git a/Engine/Generic/CorrectionExtent.cs b/Engine/Generic/CorrectionExtent.cs
index caad49cdb..f92070844 100644
--- a/Engine/Generic/CorrectionExtent.cs
+++ b/Engine/Generic/CorrectionExtent.cs
@@ -104,5 +104,13 @@ public CorrectionExtent(
         {
 
         }
+
+        /// <summary>
+        /// Outputs a CorrectionExtent as a string.
+        /// </summary>
+        /// <returns>Returns the text in a CorrectionExtent.</returns>
+        public override string ToString() {
+            return this.Text;
+        }
     }
 }
diff --git a/Engine/Generic/DiagnosticRecord.cs b/Engine/Generic/DiagnosticRecord.cs
index a02f8a273..41eb86a05 100644
--- a/Engine/Generic/DiagnosticRecord.cs
+++ b/Engine/Generic/DiagnosticRecord.cs
@@ -74,7 +74,7 @@ public string ScriptPath
         }
 
         /// <summary>
-        /// Returns the rule id for this record
+        /// Returns the rule suppression id for this record
         /// </summary>
         public string RuleSuppressionID
         {
@@ -88,18 +88,19 @@ public string RuleSuppressionID
         /// </summary>
         public IEnumerable<CorrectionExtent> SuggestedCorrections
         {
-            get { return suggestedCorrections;  }            
+            get { return suggestedCorrections;  }
             set { suggestedCorrections = value; }
         }
 
+        public bool IsSuppressed { get; protected set; } = false;
+
         /// <summary>
         /// DiagnosticRecord: The constructor for DiagnosticRecord class.
         /// </summary>
         public DiagnosticRecord()
         {
-
         }
-        
+
         /// <summary>
         /// DiagnosticRecord: The constructor for DiagnosticRecord class that takes in suggestedCorrection
         /// </summary>
@@ -107,9 +108,17 @@ public DiagnosticRecord()
         /// <param name="extent">The place in the script this diagnostic refers to</param>
         /// <param name="ruleName">The name of the rule that created this diagnostic</param>
         /// <param name="severity">The severity of this diagnostic</param>
+        /// <param name="ruleId">The rule suppression ID of this diagnostic</param>
         /// <param name="scriptPath">The full path of the script file being analyzed</param>
         /// <param name="suggestedCorrections">The correction suggested by the rule to replace the extent text</param>
-        public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, DiagnosticSeverity severity, string scriptPath, string ruleId = null, IEnumerable<CorrectionExtent> suggestedCorrections = null)
+        public DiagnosticRecord(
+            string message,
+            IScriptExtent extent,
+            string ruleName,
+            DiagnosticSeverity severity,
+            string scriptPath,
+            string ruleId = null,
+            IEnumerable<CorrectionExtent> suggestedCorrections = null)
         {
             Message  = message;
             RuleName = ruleName;
@@ -120,6 +129,13 @@ public DiagnosticRecord(string message, IScriptExtent extent, string ruleName, D
             this.suggestedCorrections = suggestedCorrections;
         }
 
+        /// <summary>
+        /// Outputs a DiagnosticRecord as a string.
+        /// </summary>
+        /// <returns>Returns the message in a DiagnosticRecord.</returns>
+        public override string ToString() {
+            return this.Message;
+        }
     }
 
 
diff --git a/Engine/Generic/ModuleDependencyHandler.cs b/Engine/Generic/ModuleDependencyHandler.cs
index 347b9a9a1..31a43d6ca 100644
--- a/Engine/Generic/ModuleDependencyHandler.cs
+++ b/Engine/Generic/ModuleDependencyHandler.cs
@@ -22,7 +22,6 @@ public class ModuleDependencyHandler : IDisposable
         private string moduleRepository;
         private string tempPath; // path to the user temporary directory 
         private string tempModulePath; // path to temp directory containing modules
-        Dictionary<string, PSObject> modulesFound;
         private string localAppdataPath;
         private string pssaAppDataPath;
         private const string symLinkName = "TempModuleDir";
@@ -271,8 +270,6 @@ public ModuleDependencyHandler(
                         ? "PSScriptAnalyzer"
                         : pssaAppDataPath);
 
-            modulesFound = new Dictionary<string, PSObject>(StringComparer.OrdinalIgnoreCase);            
-
             // TODO Add PSSA Version in the path
             symLinkPath = Path.Combine(pssaAppDataPath, symLinkName);
             SetupPSSAAppData();
diff --git a/Engine/Generic/RuleSuppression.cs b/Engine/Generic/RuleSuppression.cs
index d8a41f974..d912eee0c 100644
--- a/Engine/Generic/RuleSuppression.cs
+++ b/Engine/Generic/RuleSuppression.cs
@@ -308,7 +308,7 @@ public static List<RuleSuppression> GetSuppressions(IEnumerable<AttributeAst> at
             }
 
             IEnumerable<AttributeAst> suppressionAttribute = attrAsts.Where(
-                item => item.TypeName.GetReflectionType() == typeof(System.Diagnostics.CodeAnalysis.SuppressMessageAttribute));
+                item => item.TypeName.GetReflectionAttributeType() == typeof(System.Diagnostics.CodeAnalysis.SuppressMessageAttribute));
 
             foreach (var attributeAst in suppressionAttribute)
             {
diff --git a/Engine/Generic/SuppressedRecord.cs b/Engine/Generic/SuppressedRecord.cs
index ee50ea48b..66d1b4739 100644
--- a/Engine/Generic/SuppressedRecord.cs
+++ b/Engine/Generic/SuppressedRecord.cs
@@ -1,6 +1,9 @@
 ﻿// Copyright (c) Microsoft Corporation. All rights reserved.
 // Licensed under the MIT License.
 
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+
 namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
 {
     /// <summary>
@@ -9,22 +12,19 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic
     public class SuppressedRecord : DiagnosticRecord
     {
         /// <summary>
-        /// The rule suppression of this record
+        /// The rule suppressions applied to this record.
         /// </summary>
-        public RuleSuppression Suppression
-        {
-            get;
-            set;
-        }
+        public IReadOnlyList<RuleSuppression> Suppression { get; set; }
 
         /// <summary>
         /// Creates a suppressed record based on a diagnostic record and the rule suppression
         /// </summary>
         /// <param name="record"></param>
         /// <param name="Suppression"></param>
-        public SuppressedRecord(DiagnosticRecord record, RuleSuppression suppression)
+        public SuppressedRecord(DiagnosticRecord record, IReadOnlyList<RuleSuppression> suppressions)
         {
-            Suppression = suppression;
+            Suppression = new ReadOnlyCollection<RuleSuppression>(new List<RuleSuppression>(suppressions));
+            IsSuppressed = true;
             if (record != null)
             {
                 RuleName = record.RuleName;
diff --git a/Engine/Helper.cs b/Engine/Helper.cs
index cbd8d0cd3..82948a4fc 100644
--- a/Engine/Helper.cs
+++ b/Engine/Helper.cs
@@ -24,7 +24,6 @@ public class Helper
         #region Private members
 
         private CommandInvocationIntrinsics invokeCommand;
-        private IOutputWriter outputWriter;
         private readonly static Version minSupportedPSVersion = new Version(3, 0);
         private Dictionary<string, Dictionary<string, object>> ruleArguments;
         private PSVersionTable psVersionTable;
@@ -115,7 +114,7 @@ internal set
         /// </summary>
         private Helper()
         {
-            _commandInfoCacheLazy = new Lazy<CommandInfoCache>(() => new CommandInfoCache(pssaHelperInstance: this));
+            _commandInfoCacheLazy = new Lazy<CommandInfoCache>(() => new CommandInfoCache());
         }
 
         /// <summary>
@@ -125,16 +124,11 @@ private Helper()
         /// A CommandInvocationIntrinsics instance for use in gathering
         /// information about available commands and aliases.
         /// </param>
-        /// <param name="outputWriter">
-        /// An IOutputWriter instance for use in writing output
-        /// to the PowerShell environment.
-        /// </param>
         public Helper(
-            CommandInvocationIntrinsics invokeCommand,
-            IOutputWriter outputWriter) : this()
+            CommandInvocationIntrinsics invokeCommand
+            ): this()
         {
             this.invokeCommand = invokeCommand;
-            this.outputWriter = outputWriter;
         }
 
         #region Methods
@@ -615,14 +609,15 @@ public bool HasSplattedVariable(CommandAst cmdAst)
         /// </summary>
         /// <param name="cmdAst"></param>
         /// <returns></returns>
-        public bool IsKnownCmdletFunctionOrExternalScript(CommandAst cmdAst)
+        public bool IsKnownCmdletFunctionOrExternalScript(CommandAst cmdAst, out CommandInfo commandInfo)
         {
+            commandInfo = null;
             if (cmdAst == null)
             {
                 return false;
             }
 
-            var commandInfo = GetCommandInfo(cmdAst.GetCommandName());
+            commandInfo = GetCommandInfo(cmdAst.GetCommandName());
             if (commandInfo == null)
             {
                 return false;
@@ -673,10 +668,11 @@ public bool PositionalParameterUsed(CommandAst cmdAst, bool moreThanTwoPositiona
         /// </summary>
         /// <param name="name"></param>
         /// <param name="commandType"></param>
+        /// <param name="bypassCache"></param>
         /// <returns></returns>
-        public CommandInfo GetCommandInfo(string name, CommandTypes? commandType = null)
+        public CommandInfo GetCommandInfo(string name, CommandTypes? commandType = null, bool bypassCache = false)
         {
-            return CommandInfoCache.GetCommandInfo(name, commandTypes: commandType);
+            return CommandInfoCache.GetCommandInfo(name, commandTypes: commandType, bypassCache: bypassCache);
         }
 
         /// <summary>
@@ -874,19 +870,13 @@ public bool IsUninitialized(VariableExpressionAst varAst, Ast ast)
         }
 
         /// <summary>
-        /// Returns true if varaible is either a global variable or an environment variable
+        /// Returns true if variable is either a global variable or an environment variable
         /// </summary>
         /// <param name="varAst"></param>
-        /// <param name="ast"></param>
         /// <returns></returns>
-        public bool IsVariableGlobalOrEnvironment(VariableExpressionAst varAst, Ast ast)
+        public bool IsVariableGlobalOrEnvironment(VariableExpressionAst varAst)
         {
-            if (!VariableAnalysisDictionary.ContainsKey(ast) || VariableAnalysisDictionary[ast] == null)
-            {
-                return false;
-            }
-
-            return VariableAnalysisDictionary[ast].IsGlobalOrEnvironment(varAst);
+            return VariableAnalysis.IsGlobalOrEnvironment(varAst);
         }
 
 
@@ -1322,156 +1312,177 @@ internal List<RuleSuppression> GetSuppressionsConfiguration(ConfigurationDefinit
         /// Suppress the rules from the diagnostic records list.
         /// Returns a list of suppressed records as well as the ones that are not suppressed
         /// </summary>
-        /// <param name="ruleSuppressions"></param>
-        /// <param name="diagnostics"></param>
+        /// <param name="ruleName">The name of the rule possibly being suppressed.</param>
+        /// <param name="ruleSuppressionsDict">A lookup table from rule name to suppressions of that rule.</param>
+        /// <param name="diagnostics">The list of all diagnostics emitted by the given rule.</param>
+        /// <param name="errors">Any errors that arise due to misconfigured suppression settings.</param>
+        /// <returns>A pair, with the first item being the list of suppressed diagnostics, and the second the list of unsuppressed diagnostics.</returns>
         public Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> SuppressRule(
             string ruleName,
             Dictionary<string, List<RuleSuppression>> ruleSuppressionsDict,
             List<DiagnosticRecord> diagnostics,
-            out List<ErrorRecord> errorRecords)
+            out List<ErrorRecord> errors)
         {
-            List<SuppressedRecord> suppressedRecords = new List<SuppressedRecord>();
-            List<DiagnosticRecord> unSuppressedRecords = new List<DiagnosticRecord>();
-            Tuple<List<SuppressedRecord>, List<DiagnosticRecord>> result = Tuple.Create(suppressedRecords, unSuppressedRecords);
-            errorRecords = new List<ErrorRecord>();
-            if (diagnostics == null || diagnostics.Count == 0)
+            var suppressedRecords = new List<SuppressedRecord>();
+            var unsuppressedRecords = new List<DiagnosticRecord>();
+            errors = new List<ErrorRecord>();
+            var result = new Tuple<List<SuppressedRecord>, List<DiagnosticRecord>>(suppressedRecords, unsuppressedRecords);
+
+            if (diagnostics is null || diagnostics.Count == 0)
             {
                 return result;
             }
 
-            if (ruleSuppressionsDict == null || !ruleSuppressionsDict.ContainsKey(ruleName)
-                || ruleSuppressionsDict[ruleName].Count == 0)
+            if (ruleSuppressionsDict is null
+                || !ruleSuppressionsDict.TryGetValue(ruleName, out List<RuleSuppression> ruleSuppressions)
+                || ruleSuppressions.Count == 0)
             {
-                unSuppressedRecords.AddRange(diagnostics);
+                unsuppressedRecords.AddRange(diagnostics);
                 return result;
             }
 
-            List<RuleSuppression> ruleSuppressions = ruleSuppressionsDict[ruleName];
-            var offsetArr = GetOffsetArray(diagnostics);
-            int recordIndex = 0;
-            int startRecord = 0;
-            bool[] suppressed = new bool[diagnostics.Count];
-            foreach (RuleSuppression ruleSuppression in ruleSuppressions)
+            // We need to report errors for any rule suppressions with IDs that are not applied to anything
+            // Start by assuming all suppressions are unapplied and then we'll remove them as we apply them later
+            var unappliedSuppressions = new HashSet<RuleSuppression>();
+            foreach (RuleSuppression suppression in ruleSuppressions)
             {
-                int suppressionCount = 0;
-                while (startRecord < diagnostics.Count
-                    // && diagnostics[startRecord].Extent.StartOffset < ruleSuppression.StartOffset)
-                    // && diagnostics[startRecord].Extent.StartLineNumber < ruleSuppression.st)
-                    && offsetArr[startRecord] != null && offsetArr[startRecord].Item1 < ruleSuppression.StartOffset)
+                if (!string.IsNullOrWhiteSpace(suppression.RuleSuppressionID))
                 {
-                    startRecord += 1;
+                    unappliedSuppressions.Add(suppression);
                 }
-
-                // at this point, start offset of startRecord is greater or equals to rulesuppression.startoffset
-                recordIndex = startRecord;
-
-                while (recordIndex < diagnostics.Count)
+            }
+            
+            // We have suppressions and diagnostics
+            // For each diagnostic, collect all the suppressions that apply to it
+            // and if there are any, record the diagnostic as suppressed
+            foreach (DiagnosticRecord diagnostic in diagnostics)
+            {
+                Tuple<int, int> offsetPair = GetOffset(diagnostic);
+                
+                var appliedSuppressions = new List<RuleSuppression>();
+                foreach (RuleSuppression suppression in ruleSuppressions)
                 {
-                    DiagnosticRecord record = diagnostics[recordIndex];
-                    var curOffset = offsetArr[recordIndex];
-
-                    //if (record.Extent.EndOffset > ruleSuppression.EndOffset)
-                    if (curOffset != null && curOffset.Item2 > ruleSuppression.EndOffset)
+                    // Check that the diagnostic is within the suppressed extent, if we have such an extent
+                    if (!(offsetPair is null)
+                        && (offsetPair.Item1 < suppression.StartOffset || offsetPair.Item2 > suppression.EndOffset))
                     {
-                        break;
+                        continue;
                     }
-
-                    // we suppress if there is no suppression id or if there is suppression id and it matches
-                    if (string.IsNullOrWhiteSpace(ruleSuppression.RuleSuppressionID)
-                        || (!String.IsNullOrWhiteSpace(record.RuleSuppressionID) &&
-                            string.Equals(ruleSuppression.RuleSuppressionID, record.RuleSuppressionID, StringComparison.OrdinalIgnoreCase)))
+                    
+                    // If there's a rule suppression ID, check that it matches the diagnostic
+                    if (!string.IsNullOrWhiteSpace(suppression.RuleSuppressionID)
+                        && !string.Equals(diagnostic.RuleSuppressionID, suppression.RuleSuppressionID, StringComparison.OrdinalIgnoreCase))
                     {
-                        suppressed[recordIndex] = true;
-                        suppressedRecords.Add(new SuppressedRecord(record, ruleSuppression));
-                        suppressionCount += 1;
+                        continue;
                     }
-
-                    recordIndex += 1;
+                    
+                    unappliedSuppressions.Remove(suppression);
+                    appliedSuppressions.Add(suppression);
                 }
-
-                // If we cannot found any error but the rulesuppression has a rulesuppressionid then it must be used wrongly
-                if (!String.IsNullOrWhiteSpace(ruleSuppression.RuleSuppressionID) && suppressionCount == 0)
+                
+                if (appliedSuppressions.Count > 0)
                 {
-                    // checks whether are given a string or a file path
-                    if (String.IsNullOrWhiteSpace(diagnostics.First().Extent.File))
-                    {
-                        ruleSuppression.Error = String.Format(CultureInfo.CurrentCulture, Strings.RuleSuppressionErrorFormatScriptDefinition, ruleSuppression.StartAttributeLine,
-                                String.Format(Strings.RuleSuppressionIDError, ruleSuppression.RuleSuppressionID));
-                    }
-                    else
-                    {
-                        ruleSuppression.Error = String.Format(CultureInfo.CurrentCulture, Strings.RuleSuppressionErrorFormat, ruleSuppression.StartAttributeLine,
-                                System.IO.Path.GetFileName(diagnostics.First().Extent.File), String.Format(Strings.RuleSuppressionIDError, ruleSuppression.RuleSuppressionID));
-                    }
-                    errorRecords.Add(new ErrorRecord(new ArgumentException(ruleSuppression.Error), ruleSuppression.Error, ErrorCategory.InvalidArgument, ruleSuppression));
-                    //this.outputWriter.WriteError(new ErrorRecord(new ArgumentException(ruleSuppression.Error), ruleSuppression.Error, ErrorCategory.InvalidArgument, ruleSuppression));
+                    suppressedRecords.Add(new SuppressedRecord(diagnostic, appliedSuppressions));
+                }
+                else
+                {
+                    unsuppressedRecords.Add(diagnostic);
                 }
             }
-
-            for (int i = 0; i < suppressed.Length; i += 1)
+            
+            // Do any error reporting for misused RuleSuppressionIDs here.
+            // If the user applied a suppression qualified by a suppression ID,
+            // but that suppression didn't apply only because the suppression ID didn't match
+            // we let the user know in the form of an error.
+            string analyzedFile = diagnostics[0]?.Extent?.File;
+            bool appliedToFile = !string.IsNullOrEmpty(analyzedFile);
+            string analyzedFileName = appliedToFile ? Path.GetFileName(analyzedFile) : null;
+            foreach (RuleSuppression unappliedSuppression in unappliedSuppressions)
             {
-                if (!suppressed[i])
+                string suppressionIDError = string.Format(Strings.RuleSuppressionIDError, unappliedSuppression.RuleSuppressionID);
+
+                if (appliedToFile)
+                {
+                    unappliedSuppression.Error = string.Format(
+                        CultureInfo.CurrentCulture,
+                        Strings.RuleSuppressionErrorFormat,
+                        unappliedSuppression.StartAttributeLine,
+                        analyzedFileName,
+                        suppressionIDError);
+                }
+                else
                 {
-                    unSuppressedRecords.Add(diagnostics[i]);
+                    unappliedSuppression.Error = string.Format(
+                        CultureInfo.CurrentCulture,
+                        Strings.RuleSuppressionErrorFormatScriptDefinition,
+                        unappliedSuppression.StartAttributeLine,
+                        suppressionIDError);
                 }
+                
+                errors.Add(
+                    new ErrorRecord(
+                        new ArgumentException(unappliedSuppression.Error),
+                        unappliedSuppression.Error,
+                        ErrorCategory.InvalidArgument,
+                        unappliedSuppression));
             }
 
             return result;
         }
 
-        private Tuple<int,int>[] GetOffsetArray(List<DiagnosticRecord> diagnostics)
+        private Tuple<int, int> GetOffset(DiagnosticRecord diagnostic)
         {
-            Func<int,int,Tuple<int,int>> GetTuple = (x, y) => new Tuple<int, int>(x, y);
-            Func<Tuple<int, int>> GetDefaultTuple = () => GetTuple(0, 0);
-            var offsets = new Tuple<int, int>[diagnostics.Count];
-            for (int k = 0; k < diagnostics.Count; k++)
+            IScriptExtent extent = diagnostic.Extent;
+
+            if (extent is null)
             {
-                var ext = diagnostics[k].Extent;
-                if (ext == null)
-                {
-                    continue;
-                }
-                if (ext.StartOffset == 0 && ext.EndOffset == 0)
+                return null;
+            }
+
+            if (extent.StartOffset != 0 && extent.EndOffset != 0)
+            {
+                return Tuple.Create(extent.StartOffset, extent.EndOffset);
+            }
+
+            // We're forced to determine the offset ourselves from the lines and columns now
+            // Rather than counting every line in the file, we scan through the tokens looking for ones matching the offset
+
+            Token startToken = null;
+            int i = 0;
+            for (; i < Tokens.Length; i++)
+            {
+                Token curr = Tokens[i];
+                if (curr.Extent.StartLineNumber == extent.StartLineNumber
+                    && curr.Extent.StartColumnNumber == extent.StartColumnNumber)
                 {
-                    // check if line and column number correspond to 0 offsets
-                    if (ext.StartLineNumber == 1
-                        && ext.StartColumnNumber == 1
-                        && ext.EndLineNumber == 1
-                        && ext.EndColumnNumber == 1)
-                    {
-                        offsets[k] = GetDefaultTuple();
-                        continue;
-                    }
-                    // created using the ScriptExtent constructor, which sets
-                    // StartOffset and EndOffset to 0
-                    // find the token the corresponding start line and column number
-                    var startToken = Tokens.Where(x
-                        => x.Extent.StartLineNumber == ext.StartLineNumber
-                        && x.Extent.StartColumnNumber == ext.StartColumnNumber)
-                        .FirstOrDefault();
-                    if (startToken == null)
-                    {
-                        offsets[k] = GetDefaultTuple();
-                        continue;
-                    }
-                    var endToken = Tokens.Where(x
-                        => x.Extent.EndLineNumber == ext.EndLineNumber
-                        && x.Extent.EndColumnNumber == ext.EndColumnNumber)
-                        .FirstOrDefault();
-                    if (endToken == null)
-                    {
-                        offsets[k] = GetDefaultTuple();
-                        continue;
-                    }
-                    offsets[k] = GetTuple(startToken.Extent.StartOffset, endToken.Extent.EndOffset);
+                    startToken = curr;
+                    break;
                 }
-                else
+            }
+
+            if (startToken is null)
+            {
+                return Tuple.Create(0, 0);
+            }
+
+            Token endToken = null;
+            for (; i < Tokens.Length; i++)
+            {
+                Token curr = Tokens[i];
+                if (curr.Extent.EndLineNumber == extent.EndLineNumber
+                    && curr.Extent.EndColumnNumber == extent.EndColumnNumber)
                 {
-                    // Extent has valid offsets
-                    offsets[k] = GetTuple(ext.StartOffset, ext.EndOffset);
+                    endToken = curr;
+                    break;
                 }
             }
-            return offsets;
+
+            if (endToken is null)
+            {
+                return Tuple.Create(0, 0);
+            }
+
+            return Tuple.Create(startToken.Extent.StartOffset, endToken.Extent.EndOffset);
         }
 
         public static string[] ProcessCustomRulePaths(string[] rulePaths, SessionState sessionState, bool recurse = false)
diff --git a/Engine/PSScriptAnalyzer.psd1 b/Engine/PSScriptAnalyzer.psd1
index 716464e34..49fb93227 100644
--- a/Engine/PSScriptAnalyzer.psd1
+++ b/Engine/PSScriptAnalyzer.psd1
@@ -11,7 +11,7 @@ Author = 'Microsoft Corporation'
 RootModule = 'PSScriptAnalyzer.psm1'
 
 # Version number of this module.
-ModuleVersion = '1.19.0'
+ModuleVersion = '{{ModuleVersion}}'
 
 # ID used to uniquely identify this module
 GUID = 'd6245802-193d-4068-a631-8863a4342a18'
@@ -20,13 +20,13 @@ GUID = 'd6245802-193d-4068-a631-8863a4342a18'
 CompanyName = 'Microsoft Corporation'
 
 # Copyright statement for this module
-Copyright = '(c) Microsoft Corporation 2016. All rights reserved.'
+Copyright = '(c) Microsoft Corporation 2025. All rights reserved.'
 
 # Description of the functionality provided by this module
 Description = 'PSScriptAnalyzer provides script analysis and checks for potential code defects in the scripts by applying a group of built-in or customized rules on the scripts being analyzed.'
 
 # Minimum version of the Windows PowerShell engine required by this module
-PowerShellVersion = '3.0'
+PowerShellVersion = '5.1'
 
 # Name of the Windows PowerShell host required by this module
 # PowerShellHostName = ''
@@ -83,15 +83,15 @@ AliasesToExport = @()
 PrivateData = @{
     PSData = @{
         Tags = 'lint', 'bestpractice'
-        LicenseUri = 'https://github.com/PowerShell/PSScriptAnalyzer/blob/master/LICENSE'
+        LicenseUri = 'https://github.com/PowerShell/PSScriptAnalyzer/blob/main/LICENSE'
         ProjectUri = 'https://github.com/PowerShell/PSScriptAnalyzer'
-        IconUri = 'https://raw.githubusercontent.com/powershell/psscriptanalyzer/master/logo.png'
+        IconUri = 'https://raw.githubusercontent.com/powershell/psscriptanalyzer/main/logo.png'
         ReleaseNotes = ''
     }
 }
 
 # HelpInfo URI of this module
-# HelpInfoURI = ''
+HelpInfoURI = 'https://aka.ms/ps-modules-help'
 
 # Default prefix for commands exported from this module. Override the default prefix using Import-Module -Prefix.
 # DefaultCommandPrefix = ''
diff --git a/Engine/PSScriptAnalyzer.psm1 b/Engine/PSScriptAnalyzer.psm1
index e98e1c88a..121e96d6f 100644
--- a/Engine/PSScriptAnalyzer.psm1
+++ b/Engine/PSScriptAnalyzer.psm1
@@ -9,15 +9,13 @@ $PSModuleRoot = $PSModule.ModuleBase
 
 # Import the appropriate nested binary module based on the current PowerShell version
 $binaryModuleRoot = $PSModuleRoot
-if ($PSVersionTable.PSVersion.Major -eq 7 ) {
-    $binaryModuleRoot = Join-Path -Path $PSModuleRoot -ChildPath "PSv$($PSVersionTable.PSVersion.Major)"
-}
-elseif ($PSVersionTable.PSVersion.Major -eq 6 ) {
+[Version] $minimumPowerShellCoreVersion = '7.4.7'
+if ($PSVersionTable.PSVersion.Major -ge 6) {
     $binaryModuleRoot = Join-Path -Path $PSModuleRoot -ChildPath "PSv$($PSVersionTable.PSVersion.Major)"
     # Minimum PowerShell Core version given by PowerShell Core support itself and
-    # also the version of NewtonSoft.Json implicitly that PSSA ships with,
-    # which cannot be higher than the one that PowerShell ships with.
-    [Version] $minimumPowerShellCoreVersion = '6.2.4'
+    # the version of Nuget references, such as e.g. Newtonsoft.Json inside PowerShell itself
+    # or the version of the System.Management.Automation NuGet reference in PSSA.
+
     if ($PSVersionTable.PSVersion -lt $minimumPowerShellCoreVersion) {
         throw "Minimum supported version of PSScriptAnalyzer for PowerShell Core is $minimumPowerShellCoreVersion but current version is '$($PSVersionTable.PSVersion)'. Please update PowerShell Core."
     }
diff --git a/Engine/ScriptAnalyzer.cs b/Engine/ScriptAnalyzer.cs
index ffe277375..f250336b5 100644
--- a/Engine/ScriptAnalyzer.cs
+++ b/Engine/ScriptAnalyzer.cs
@@ -22,9 +22,17 @@
 using System.Collections;
 using System.Diagnostics;
 using System.Text;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Extensions;
 
 namespace Microsoft.Windows.PowerShell.ScriptAnalyzer
 {
+    internal enum SuppressionPreference
+    {
+        Omit = 0,
+        Include = 1,
+        SuppressedOnly = 2,
+    }
+
     public sealed class ScriptAnalyzer
     {
         #region Private members
@@ -41,7 +49,7 @@ public sealed class ScriptAnalyzer
         string[] severity;
         List<Regex> includeRegexList;
         List<Regex> excludeRegexList;
-        bool suppressedOnly;
+        private SuppressionPreference _suppressionPreference;
 #if !PSV3
         ModuleDependencyHandler moduleHandler;
 #endif
@@ -118,7 +126,7 @@ internal void Initialize<TCmdlet>(
             string[] excludeRuleNames = null,
             string[] severity = null,
             bool includeDefaultRules = false,
-            bool suppressedOnly = false)
+            SuppressionPreference suppressionPreference = SuppressionPreference.Omit)
             where TCmdlet : PSCmdlet, IOutputWriter
         {
             if (cmdlet == null)
@@ -135,7 +143,7 @@ internal void Initialize<TCmdlet>(
                 excludeRuleNames,
                 severity,
                 includeDefaultRules,
-                suppressedOnly);
+                suppressionPreference);
         }
 
         /// <summary>
@@ -150,6 +158,7 @@ public void Initialize(
             string[] severity = null,
             bool includeDefaultRules = false,
             bool suppressedOnly = false,
+            bool includeSuppression = false,
             string profile = null)
         {
             if (runspace == null)
@@ -159,10 +168,14 @@ public void Initialize(
 
             //initialize helper
             Helper.Instance = new Helper(
-                runspace.SessionStateProxy.InvokeCommand,
-                outputWriter);
+                runspace.SessionStateProxy.InvokeCommand);
             Helper.Instance.Initialize();
 
+            SuppressionPreference suppressionPreference = suppressedOnly
+                ? SuppressionPreference.SuppressedOnly
+                : includeSuppression
+                    ? SuppressionPreference.Include
+                    : SuppressionPreference.Omit;
 
             this.Initialize(
                 outputWriter,
@@ -173,7 +186,7 @@ public void Initialize(
                 excludeRuleNames,
                 severity,
                 includeDefaultRules,
-                suppressedOnly,
+                suppressionPreference,
                 profile);
         }
 
@@ -187,7 +200,7 @@ public void CleanUp()
             severity = null;
             includeRegexList = null;
             excludeRegexList = null;
-            suppressedOnly = false;
+            _suppressionPreference = SuppressionPreference.Omit;
         }
 
         /// <summary>
@@ -671,7 +684,7 @@ private void Initialize(
             string[] excludeRuleNames,
             string[] severity,
             bool includeDefaultRules = false,
-            bool suppressedOnly = false,
+            SuppressionPreference suppressionPreference = SuppressionPreference.Omit,
             string profile = null)
         {
             if (outputWriter == null)
@@ -730,7 +743,7 @@ private void Initialize(
                 }
             }
 
-            this.suppressedOnly = suppressedOnly;
+            _suppressionPreference = suppressionPreference;
             this.includeRegexList = new List<Regex>();
             this.excludeRegexList = new List<Regex>();
 
@@ -809,13 +822,13 @@ private void Initialize(
             // Ensure that rules were actually loaded
             if (rules == null || rules.Any() == false)
             {
+                string errorMessage = string.Format(CultureInfo.CurrentCulture, Strings.RulesNotFound);
+
                 this.outputWriter.ThrowTerminatingError(
                     new ErrorRecord(
-                        new Exception(),
-                        string.Format(
-                            CultureInfo.CurrentCulture,
-                            Strings.RulesNotFound),
-                        ErrorCategory.ResourceExists,
+                        new Exception(errorMessage),
+                        errorMessage,
+                        ErrorCategory.ObjectNotFound,
                         this));
             }
 
@@ -1250,13 +1263,6 @@ internal IEnumerable<DiagnosticRecord> GetExternalRecord(Ast ast, Token[] token,
 
                         foreach (var psobject in psobjects)
                         {
-                            DiagnosticSeverity severity;
-                            IScriptExtent extent;
-                            string message = string.Empty;
-                            string ruleName = string.Empty;
-                            string ruleSuppressionID = string.Empty;
-                            IEnumerable<CorrectionExtent> suggestedCorrections;
-
                             if (psobject != null && psobject.ImmediateBaseObject != null)
                             {
                                 // Because error stream is merged to output stream,
@@ -1269,28 +1275,9 @@ internal IEnumerable<DiagnosticRecord> GetExternalRecord(Ast ast, Token[] token,
                                 }
 
                                 // DiagnosticRecord may not be correctly returned from external rule.
-                                try
-                                {
-                                    severity = (DiagnosticSeverity)Enum.Parse(typeof(DiagnosticSeverity), psobject.Properties["Severity"].Value.ToString());
-                                    message = psobject.Properties["Message"].Value.ToString();
-                                    extent = (IScriptExtent)psobject.Properties["Extent"].Value;
-                                    ruleName = psobject.Properties["RuleName"].Value.ToString();
-                                    ruleSuppressionID = psobject.Properties["RuleSuppressionID"].Value?.ToString();
-                                    suggestedCorrections = (IEnumerable<CorrectionExtent>)psobject.Properties["SuggestedCorrections"].Value;
-                                }
-                                catch (Exception ex)
-                                {
-                                    this.outputWriter.WriteError(new ErrorRecord(ex, ex.HResult.ToString("X"), ErrorCategory.NotSpecified, this));
-                                    continue;
-                                }
-
-                                if (!string.IsNullOrEmpty(message))
+                                if (TryConvertPSObjectToDiagnostic(psobject, filePath, out DiagnosticRecord diagnostic))
                                 {
-                                    diagnostics.Add(new DiagnosticRecord(message, extent, ruleName, severity, filePath)
-                                    {
-                                        SuggestedCorrections = suggestedCorrections,
-                                        RuleSuppressionID = ruleSuppressionID,
-                                    });
+                                    diagnostics.Add(diagnostic);
                                 }
                             }
                         }
@@ -1501,7 +1488,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeAndFixPath(string path, Func<string,
         /// <param name="scriptTokens">Parsed tokens of <paramref name="scriptDefinition"/.></param>
         /// <param name="skipVariableAnalysis">Whether variable analysis can be skipped (applicable if rules do not use variable analysis APIs).</param>
         /// <returns></returns>
-        public IEnumerable<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefinition, out ScriptBlockAst scriptAst, out Token[] scriptTokens, bool skipVariableAnalysis = false)
+        public List<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefinition, out ScriptBlockAst scriptAst, out Token[] scriptTokens, bool skipVariableAnalysis = false)
         {
             scriptAst = null;
             scriptTokens = null;
@@ -1516,7 +1503,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefini
             catch (Exception e)
             {
                 this.outputWriter.WriteWarning(e.ToString());
-                return null;
+                return new();
             }
 
             var relevantParseErrors = RemoveTypeNotFoundParseErrors(errors, out List<DiagnosticRecord> diagnosticRecords);
@@ -1541,7 +1528,8 @@ public IEnumerable<DiagnosticRecord> AnalyzeScriptDefinition(string scriptDefini
             }
 
             // now, analyze the script definition
-            return diagnosticRecords.Concat(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, String.Empty, skipVariableAnalysis));
+            diagnosticRecords.AddRange(this.AnalyzeSyntaxTree(scriptAst, scriptTokens, null, skipVariableAnalysis));
+            return diagnosticRecords;
         }
 
         /// <summary>
@@ -1647,6 +1635,57 @@ public EditableText Fix(EditableText text, Range range, bool skipParsing, out Ra
             return text;
         }
 
+        private bool TryConvertPSObjectToDiagnostic(PSObject psObject, string filePath, out DiagnosticRecord diagnostic)
+        {
+            string message = psObject.Properties["Message"]?.Value?.ToString();
+            object extentValue = psObject.Properties["Extent"]?.Value;
+            string ruleName = psObject.Properties["RuleName"]?.Value?.ToString();
+            string ruleSuppressionID = psObject.Properties["RuleSuppressionID"]?.Value?.ToString();
+            CorrectionExtent[] suggestedCorrections = psObject.TryGetPropertyValue("SuggestedCorrections", out object correctionsValue)
+                ? LanguagePrimitives.ConvertTo<CorrectionExtent[]>(correctionsValue)
+                : null;
+            DiagnosticSeverity severity = psObject.TryGetPropertyValue("Severity", out object severityValue)
+                ? LanguagePrimitives.ConvertTo<DiagnosticSeverity>(severityValue)
+                : DiagnosticSeverity.Warning;
+
+            bool isValid = true;
+            isValid &= CheckHasRequiredProperty("Message", message);
+            isValid &= CheckHasRequiredProperty("RuleName", ruleName);
+
+            if (extentValue is not null && extentValue is not IScriptExtent)
+            {
+                this.outputWriter.WriteError(
+                    new ErrorRecord(
+                        new ArgumentException($"Property 'Extent' is expected to be of type '{typeof(IScriptExtent)}' but was instead of type '{extentValue.GetType()}'"),
+                        "CustomRuleDiagnosticPropertyInvalidType",
+                        ErrorCategory.InvalidArgument,
+                        this));
+                isValid = false;
+            }
+
+            if (!isValid)
+            {
+                diagnostic = null;
+                return false;
+            }
+
+            diagnostic = new DiagnosticRecord(message, (IScriptExtent)extentValue, ruleName, severity, filePath, ruleSuppressionID, suggestedCorrections);
+            return true;
+        }
+
+        private bool CheckHasRequiredProperty(string propertyName, object propertyValue)
+        {
+            if (propertyValue is null)
+            {
+                var exception = new ArgumentNullException(propertyName, $"The '{propertyName}' property is required on custom rule diagnostics");
+                this.outputWriter.WriteError(new ErrorRecord(exception, "CustomRuleDiagnosticPropertyMissing", ErrorCategory.InvalidArgument, this));
+                return false;
+            }
+
+            return true;
+        }
+
+
         private static Encoding GetFileEncoding(string path)
         {
             using (var stream = new FileStream(path, FileMode.Open))
@@ -2324,9 +2363,13 @@ public IEnumerable<DiagnosticRecord> AnalyzeSyntaxTree(
             // Need to reverse the concurrentbag to ensure that results are sorted in the increasing order of line numbers
             IEnumerable<DiagnosticRecord> diagnosticsList = diagnostics.Reverse();
 
-            return this.suppressedOnly ?
-                suppressed.OfType<DiagnosticRecord>() :
-                diagnosticsList;
+            return _suppressionPreference switch
+            {
+                SuppressionPreference.SuppressedOnly => suppressed.OfType<DiagnosticRecord>(),
+                SuppressionPreference.Omit => diagnosticsList,
+                SuppressionPreference.Include => diagnosticsList.Concat(suppressed.OfType<DiagnosticRecord>()),
+                _ => throw new ArgumentException($"SuppressionPreference has invalid value '{_suppressionPreference}'"),
+            };
         }
     }
 }
diff --git a/Engine/ScriptAnalyzer.types.ps1xml b/Engine/ScriptAnalyzer.types.ps1xml
index da989657e..03bf3937e 100644
--- a/Engine/ScriptAnalyzer.types.ps1xml
+++ b/Engine/ScriptAnalyzer.types.ps1xml
@@ -79,7 +79,7 @@
           <PropertySet>
             <Name>DefaultDisplayPropertySet</Name>
             <ReferencedProperties>
-              <Name>Name</Name>
+              <Name>RuleName</Name>
               <Name>Severity</Name>
               <Name>Description</Name>
               <Name>SourceName</Name>
diff --git a/Engine/Settings.cs b/Engine/Settings.cs
index b13f9405b..b0c424c64 100644
--- a/Engine/Settings.cs
+++ b/Engine/Settings.cs
@@ -285,17 +285,6 @@ private Dictionary<string, object> GetDictionaryFromHashtable(Hashtable hashtabl
             return dictionary;
         }
 
-        private bool IsStringOrStringArray(object val)
-        {
-            if (val is string)
-            {
-                return true;
-            }
-
-            var valArr = val as object[];
-            return val == null ? false : valArr.All(x => x is string);
-        }
-
         private List<string> GetData(object val, string key)
         {
             // value must be either string or or an array of strings
@@ -508,6 +497,13 @@ private static bool IsBuiltinSettingPreset(object settingPreset)
         internal static SettingsMode FindSettingsMode(object settings, string path, out object settingsFound)
         {
             var settingsMode = SettingsMode.None;
+
+            // if the provided settings argument is wrapped in an expressions then PowerShell resolves it but it will be of type PSObject and we have to operate then on the BaseObject
+            if (settings is PSObject settingsFoundPSObject)
+            {
+                settings = settingsFoundPSObject.BaseObject;
+            }
+
             settingsFound = settings;
             if (settingsFound == null)
             {
@@ -543,11 +539,6 @@ internal static SettingsMode FindSettingsMode(object settings, string path, out
                     {
                         settingsMode = SettingsMode.Hashtable;
                     }
-                    // if the provided argument is wrapped in an expressions then PowerShell resolves it but it will be of type PSObject and we have to operate then on the BaseObject
-                    else if (settingsFound is PSObject settingsFoundPSObject)
-                    {
-                        TryResolveSettingForStringType(settingsFoundPSObject.BaseObject, ref settingsMode, ref settingsFound);
-                    }
                 }
             }
 
diff --git a/Engine/Settings/CodeFormatting.psd1 b/Engine/Settings/CodeFormatting.psd1
index 0676fccf1..8b53c1ae4 100644
--- a/Engine/Settings/CodeFormatting.psd1
+++ b/Engine/Settings/CodeFormatting.psd1
@@ -40,6 +40,7 @@
             CheckPipeForRedundantWhitespace = $false
             CheckSeparator                  = $true
             CheckParameter                  = $false
+            IgnoreAssignmentOperatorInsideHashTable = $true
         }
 
         PSAlignAssignmentStatement = @{
diff --git a/Engine/Settings/CodeFormattingAllman.psd1 b/Engine/Settings/CodeFormattingAllman.psd1
index a0c649457..188b2c651 100644
--- a/Engine/Settings/CodeFormattingAllman.psd1
+++ b/Engine/Settings/CodeFormattingAllman.psd1
@@ -40,6 +40,7 @@
             CheckPipeForRedundantWhitespace = $false
             CheckSeparator                  = $true
             CheckParameter                  = $false
+            IgnoreAssignmentOperatorInsideHashTable = $true
         }
 
         PSAlignAssignmentStatement = @{
diff --git a/Engine/Settings/CodeFormattingOTBS.psd1 b/Engine/Settings/CodeFormattingOTBS.psd1
index 21f4c0995..0e966bc46 100644
--- a/Engine/Settings/CodeFormattingOTBS.psd1
+++ b/Engine/Settings/CodeFormattingOTBS.psd1
@@ -40,6 +40,7 @@
             CheckPipeForRedundantWhitespace = $false
             CheckSeparator                  = $true
             CheckParameter                  = $false
+            IgnoreAssignmentOperatorInsideHashTable = $true
         }
 
         PSAlignAssignmentStatement = @{
diff --git a/Engine/Settings/CodeFormattingStroustrup.psd1 b/Engine/Settings/CodeFormattingStroustrup.psd1
index 34ea924a5..d9bb16be5 100644
--- a/Engine/Settings/CodeFormattingStroustrup.psd1
+++ b/Engine/Settings/CodeFormattingStroustrup.psd1
@@ -41,6 +41,7 @@
             CheckPipeForRedundantWhitespace = $false
             CheckSeparator                  = $true
             CheckParameter                  = $false
+            IgnoreAssignmentOperatorInsideHashTable = $true
         }
 
         PSAlignAssignmentStatement = @{
diff --git a/Engine/SpecialVars.cs b/Engine/SpecialVars.cs
index 1e57028cf..3416a5ad2 100644
--- a/Engine/SpecialVars.cs
+++ b/Engine/SpecialVars.cs
@@ -28,6 +28,7 @@ internal class SpecialVars
         internal const string Matches = "Matches";
         internal const string PSVersionTable = "PSVersionTable";
         internal const string OFS = "OFS";
+        internal const string FormatEnumerationLimit = "FormatEnumerationLimit";
 
         internal static readonly string[] InitializedVariables;
 
@@ -59,8 +60,9 @@ static SpecialVars()
                                                                    PSCommandPath,
                                                                    ExecutionContext,
                                                                    Matches,
-                                                                   PSVersionTable,
-                                                                   OFS
+                                                                   PSVersionTable,                                                                   
+                                                                   OFS,
+                                                                   FormatEnumerationLimit,
                                                                };
         internal static readonly Type[] AutomaticVariableTypes = new Type[]  
                                                                  {  
@@ -76,7 +78,8 @@ static SpecialVars()
                                                                    /* ExecutionContext */  typeof(EngineIntrinsics),
                                                                    /* Matches */           typeof(System.Collections.Hashtable),
                                                                    /* PSVersionTable */    typeof(System.Collections.Hashtable),
-                                                                   /* OFS */               typeof(object)
+                                                                   /* OFS */               typeof(object),
+                                                                   /* FormatEnumerationLimit */ typeof(int)
                                                                  };
 
 
@@ -88,6 +91,8 @@ static SpecialVars()
         internal const string ConfirmPreference = "ConfirmPreference";
         internal const string ProgressPreference = "ProgressPreference";
         internal const string InformationPreference = "InformationPreference";
+        internal const string ErrorView = "ErrorView";
+        internal const string PSNativeCommandUseErrorActionPreference = "PSNativeCommandUseErrorActionPreference";
 
         internal static readonly string[] PreferenceVariables = new string[]
                                                                 {
@@ -98,7 +103,9 @@ static SpecialVars()
                                                                     WarningPreference,
                                                                     ConfirmPreference,
                                                                     ProgressPreference,
-                                                                    InformationPreference
+                                                                    InformationPreference,
+                                                                    ErrorView,
+                                                                    PSNativeCommandUseErrorActionPreference,
                                                                 };
 
         internal static readonly Type[] PreferenceVariableTypes = new Type[]
@@ -111,6 +118,8 @@ static SpecialVars()
                                                                     /* ConfirmPreference */ typeof(ConfirmImpact),
                                                                     /* ProgressPreference */ typeof(Enum),
                                                                     /* InformationPreference */ typeof(ActionPreference),
+                                                                    /* ErrorView */         typeof(Enum), //ErrorView type not available on PS3
+                                                                    /* PSNativeCommandUseErrorActionPreference */ typeof(bool),
                                                                 };
 
         internal enum AutomaticVariable
@@ -151,6 +160,7 @@ internal enum PreferenceVariable
         internal const string PSEmailServer = "PSEmailServer";
         internal const string PSDefaultParameterValues = "PSDefaultParameterValues";
         internal const string PSModuleAutoLoadingPreference = "PSModuleAutoLoadingPreference";
+        internal const string PSNativeCommandArgumentPassing = "PSNativeCommandArgumentPassing";
         internal const string pwd = "PWD";
         internal const string Null = "null";
         internal const string True = "true";
@@ -173,6 +183,7 @@ internal enum PreferenceVariable
                                                                     PSEmailServer,
                                                                     PSDefaultParameterValues,
                                                                     PSModuleAutoLoadingPreference,
+                                                                    PSNativeCommandArgumentPassing,
                                                                     pwd,
                                                                     Null,
                                                                     True,
diff --git a/Engine/Strings.Designer.cs b/Engine/Strings.Designer.cs
deleted file mode 100644
index 1fed6e234..000000000
--- a/Engine/Strings.Designer.cs
+++ /dev/null
@@ -1,684 +0,0 @@
-﻿//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by a tool.
-//     Runtime Version:4.0.30319.42000
-//
-//     Changes to this file may cause incorrect behavior and will be lost if
-//     the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace Microsoft.Windows.PowerShell.ScriptAnalyzer {
-    using System;
-    
-    
-    /// <summary>
-    ///   A strongly-typed resource class, for looking up localized strings, etc.
-    /// </summary>
-    // This class was auto-generated by the StronglyTypedResourceBuilder
-    // class via a tool like ResGen or Visual Studio.
-    // To add or remove a member, edit your .ResX file then rerun ResGen
-    // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    internal class Strings {
-        
-        private static global::System.Resources.ResourceManager resourceMan;
-        
-        private static global::System.Globalization.CultureInfo resourceCulture;
-        
-        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-        internal Strings() {
-        }
-        
-        /// <summary>
-        ///   Returns the cached ResourceManager instance used by this class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Resources.ResourceManager ResourceManager {
-            get {
-                if (object.ReferenceEquals(resourceMan, null)) {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Windows.PowerShell.ScriptAnalyzer.Strings", typeof(Strings).Assembly);
-                    resourceMan = temp;
-                }
-                return resourceMan;
-            }
-        }
-        
-        /// <summary>
-        ///   Overrides the current thread's CurrentUICulture property for all
-        ///   resource lookups using this strongly typed resource class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Globalization.CultureInfo Culture {
-            get {
-                return resourceCulture;
-            }
-            set {
-                resourceCulture = value;
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checking assembly file &apos;{0}&apos; ....
-        /// </summary>
-        internal static string CheckAssemblyFile {
-            get {
-                return ResourceManager.GetString("CheckAssemblyFile", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checking module &apos;{0}&apos; ....
-        /// </summary>
-        internal static string CheckModuleName {
-            get {
-                return ResourceManager.GetString("CheckModuleName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to CommandInfo not found for function: {0}.
-        /// </summary>
-        internal static string CommandInfoNotFound {
-            get {
-                return ResourceManager.GetString("CommandInfoNotFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &quot;Argument should not be null.&quot;..
-        /// </summary>
-        internal static string ConfigurableScriptRuleNRE {
-            get {
-                return ResourceManager.GetString("ConfigurableScriptRuleNRE", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &quot;Cannot find a ConfigurableRuleProperty attribute on property {0}&quot;..
-        /// </summary>
-        internal static string ConfigurableScriptRulePropertyHasNotAttribute {
-            get {
-                return ResourceManager.GetString("ConfigurableScriptRulePropertyHasNotAttribute", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to SettingsFileHasInvalidHashtable.
-        /// </summary>
-        internal static string ConfigurationFileHasInvalidHashtable {
-            get {
-                return ResourceManager.GetString("ConfigurationFileHasInvalidHashtable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to SettingsFileHasNoHashTable.
-        /// </summary>
-        internal static string ConfigurationFileHasNoHashTable {
-            get {
-                return ResourceManager.GetString("ConfigurationFileHasNoHashTable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to SettingsFileNotFound.
-        /// </summary>
-        internal static string ConfigurationFileNotFound {
-            get {
-                return ResourceManager.GetString("ConfigurationFileNotFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to SettingsKeyNotAString.
-        /// </summary>
-        internal static string ConfigurationKeyNotAString {
-            get {
-                return ResourceManager.GetString("ConfigurationKeyNotAString", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to SettingsValueNotAString.
-        /// </summary>
-        internal static string ConfigurationValueNotAString {
-            get {
-                return ResourceManager.GetString("ConfigurationValueNotAString", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to SettingsValueWrongFormat.
-        /// </summary>
-        internal static string ConfigurationValueWrongFormat {
-            get {
-                return ResourceManager.GetString("ConfigurationValueWrongFormat", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Writes all diagnostics to WriteObject..
-        /// </summary>
-        internal static string DefaultLoggerDescription {
-            get {
-                return ResourceManager.GetString("DefaultLoggerDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to WriteObjects.
-        /// </summary>
-        internal static string DefaultLoggerName {
-            get {
-                return ResourceManager.GetString("DefaultLoggerName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Edge from {0} to {1} already exists..
-        /// </summary>
-        internal static string DigraphEdgeAlreadyExists {
-            get {
-                return ResourceManager.GetString("DigraphEdgeAlreadyExists", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Vertex {0} already exists! Cannot add it to the digraph..
-        /// </summary>
-        internal static string DigraphVertexAlreadyExists {
-            get {
-                return ResourceManager.GetString("DigraphVertexAlreadyExists", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Vertex {0} does not exist in the digraph..
-        /// </summary>
-        internal static string DigraphVertexDoesNotExists {
-            get {
-                return ResourceManager.GetString("DigraphVertexDoesNotExists", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot determine line endings as the text probably contain mixed line endings..
-        /// </summary>
-        internal static string EditableTextInvalidLineEnding {
-            get {
-                return ResourceManager.GetString("EditableTextInvalidLineEnding", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to TextEdit extent not completely contained in EditableText..
-        /// </summary>
-        internal static string EditableTextRangeIsNotContained {
-            get {
-                return ResourceManager.GetString("EditableTextRangeIsNotContained", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot find file &apos;{0}&apos;..
-        /// </summary>
-        internal static string FileNotFound {
-            get {
-                return ResourceManager.GetString("FileNotFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot find the path &apos;{0}&apos;..
-        /// </summary>
-        internal static string InvalidPath {
-            get {
-                return ResourceManager.GetString("InvalidPath", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Settings file &apos;{0}&apos; is invalid because it does not contain a hashtable..
-        /// </summary>
-        internal static string InvalidProfile {
-            get {
-                return ResourceManager.GetString("InvalidProfile", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Key {0} in the settings is not a string..
-        /// </summary>
-        internal static string KeyNotString {
-            get {
-                return ResourceManager.GetString("KeyNotString", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to No loggers found..
-        /// </summary>
-        internal static string LoggersNotFound {
-            get {
-                return ResourceManager.GetString("LoggersNotFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot find rule extension &apos;{0}&apos;..
-        /// </summary>
-        internal static string MissingRuleExtension {
-            get {
-                return ResourceManager.GetString("MissingRuleExtension", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Temporary module location: {0}..
-        /// </summary>
-        internal static string ModuleDepHandlerTempLocation {
-            get {
-                return ResourceManager.GetString("ModuleDepHandlerTempLocation", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} cannot be set by both positional and named arguments..
-        /// </summary>
-        internal static string NamedAndPositionalArgumentsConflictError {
-            get {
-                return ResourceManager.GetString("NamedAndPositionalArgumentsConflictError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Named arguments must always come after positional arguments..
-        /// </summary>
-        internal static string NamedArgumentsBeforePositionalError {
-            get {
-                return ResourceManager.GetString("NamedArgumentsBeforePositionalError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to RuleName must not be null..
-        /// </summary>
-        internal static string NullRuleNameError {
-            get {
-                return ResourceManager.GetString("NullRuleNameError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Parse error in script definition:  {0} at line {1} column {2}..
-        /// </summary>
-        internal static string ParseErrorFormatForScriptDefinition {
-            get {
-                return ResourceManager.GetString("ParseErrorFormatForScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Parse error in file {0}:  {1} at line {2} column {3}..
-        /// </summary>
-        internal static string ParserErrorFormat {
-            get {
-                return ResourceManager.GetString("ParserErrorFormat", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to There are too many parser errors in {0}. Please correct them before running ScriptAnalyzer..
-        /// </summary>
-        internal static string ParserErrorMessage {
-            get {
-                return ResourceManager.GetString("ParserErrorMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to There are too many parser errors in the script definition. Please correct them before running ScriptAnalyzer..
-        /// </summary>
-        internal static string ParserErrorMessageForScriptDefinition {
-            get {
-                return ResourceManager.GetString("ParserErrorMessageForScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Column number cannot be less than 1..
-        /// </summary>
-        internal static string PositionColumnLessThanOne {
-            get {
-                return ResourceManager.GetString("PositionColumnLessThanOne", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line number cannot be less than 1..
-        /// </summary>
-        internal static string PositionLineLessThanOne {
-            get {
-                return ResourceManager.GetString("PositionLineLessThanOne", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Input position should be less than that of the invoking object..
-        /// </summary>
-        internal static string PositionRefPosLessThanInputPos {
-            get {
-                return ResourceManager.GetString("PositionRefPosLessThanInputPos", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Reference Position should begin before start Position of Range..
-        /// </summary>
-        internal static string RangeRefPosShouldStartBeforeRangeStartPos {
-            get {
-                return ResourceManager.GetString("RangeRefPosShouldStartBeforeRangeStartPos", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Start position cannot be before End position..
-        /// </summary>
-        internal static string RangeStartPosGreaterThanEndPos {
-            get {
-                return ResourceManager.GetString("RangeStartPosGreaterThanEndPos", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to RULE_ERROR.
-        /// </summary>
-        internal static string RuleErrorMessage {
-            get {
-                return ResourceManager.GetString("RuleErrorMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot find ScriptAnalyzer rules in the specified path.
-        /// </summary>
-        internal static string RulesNotFound {
-            get {
-                return ResourceManager.GetString("RulesNotFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Suppression Message Attribute error at line {0} in {1} : {2}.
-        /// </summary>
-        internal static string RuleSuppressionErrorFormat {
-            get {
-                return ResourceManager.GetString("RuleSuppressionErrorFormat", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Suppression Message Attribute error at line {0} in script definition : {1}.
-        /// </summary>
-        internal static string RuleSuppressionErrorFormatScriptDefinition {
-            get {
-                return ResourceManager.GetString("RuleSuppressionErrorFormatScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot find any DiagnosticRecord with the Rule Suppression ID {0}..
-        /// </summary>
-        internal static string RuleSuppressionIDError {
-            get {
-                return ResourceManager.GetString("RuleSuppressionIDError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Found {0}. Will use it to provide settings for this invocation..
-        /// </summary>
-        internal static string SettingsAutoDiscovered {
-            get {
-                return ResourceManager.GetString("SettingsAutoDiscovered", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot resolve settings file path &apos;{0}&apos;..
-        /// </summary>
-        internal static string SettingsCannotFindFile {
-            get {
-                return ResourceManager.GetString("SettingsCannotFindFile", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Dictionary should be indexable in a case-insensitive manner..
-        /// </summary>
-        internal static string SettingsDictionaryShouldBeCaseInsesitive {
-            get {
-                return ResourceManager.GetString("SettingsDictionaryShouldBeCaseInsesitive", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Input should be a dictionary type..
-        /// </summary>
-        internal static string SettingsInputShouldBeDictionary {
-            get {
-                return ResourceManager.GetString("SettingsInputShouldBeDictionary", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Settings should be either a file path, built-in preset or a hashtable..
-        /// </summary>
-        internal static string SettingsInvalidType {
-            get {
-                return ResourceManager.GetString("SettingsInvalidType", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot parse settings. Will abort the invocation..
-        /// </summary>
-        internal static string SettingsNotParsable {
-            get {
-                return ResourceManager.GetString("SettingsNotParsable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Settings not provided. Will look for settings file in the given path {0}..
-        /// </summary>
-        internal static string SettingsNotProvided {
-            get {
-                return ResourceManager.GetString("SettingsNotProvided", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Settings object could not be resolved..
-        /// </summary>
-        internal static string SettingsObjectCouldNotBResolved {
-            get {
-                return ResourceManager.GetString("SettingsObjectCouldNotBResolved", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Using settings file at {0}..
-        /// </summary>
-        internal static string SettingsUsingFile {
-            get {
-                return ResourceManager.GetString("SettingsUsingFile", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Using settings hashtable..
-        /// </summary>
-        internal static string SettingsUsingHashtable {
-            get {
-                return ResourceManager.GetString("SettingsUsingHashtable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} property must be of type bool..
-        /// </summary>
-        internal static string SettingsValueTypeMustBeBool {
-            get {
-                return ResourceManager.GetString("SettingsValueTypeMustBeBool", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to All the arguments of the Suppress Message Attribute should be string constants..
-        /// </summary>
-        internal static string StringConstantArgumentsSuppressionAttributeError {
-            get {
-                return ResourceManager.GetString("StringConstantArgumentsSuppressionAttributeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot find any Targets {0} that match the Scope {1} to apply the SuppressMessageAttribute..
-        /// </summary>
-        internal static string TargetCannotBeFoundError {
-            get {
-                return ResourceManager.GetString("TargetCannotBeFoundError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to If Target is specified, Scope must be specified..
-        /// </summary>
-        internal static string TargetWithoutScopeSuppressionAttributeError {
-            get {
-                return ResourceManager.GetString("TargetWithoutScopeSuppressionAttributeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line element cannot be null..
-        /// </summary>
-        internal static string TextEditNoNullItem {
-            get {
-                return ResourceManager.GetString("TextEditNoNullItem", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line element cannot be null..
-        /// </summary>
-        internal static string TextLinesNoNullItem {
-            get {
-                return ResourceManager.GetString("TextLinesNoNullItem", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Ignoring &apos;TypeNotFound&apos; parse error on type &apos;{0}&apos;. Check if the specified type is correct. This can also be due the type not being known at parse time due to types imported by &apos;using&apos; statements..
-        /// </summary>
-        internal static string TypeNotFoundParseErrorFound {
-            get {
-                return ResourceManager.GetString("TypeNotFoundParseErrorFound", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Analyzing file: {0}.
-        /// </summary>
-        internal static string VerboseFileMessage {
-            get {
-                return ResourceManager.GetString("VerboseFileMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Running {0} rule..
-        /// </summary>
-        internal static string VerboseRunningMessage {
-            get {
-                return ResourceManager.GetString("VerboseRunningMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Analyzing Script Definition..
-        /// </summary>
-        internal static string VerboseScriptDefinitionMessage {
-            get {
-                return ResourceManager.GetString("VerboseScriptDefinitionMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to WrongSettingsKey.
-        /// </summary>
-        internal static string WrongConfigurationKey {
-            get {
-                return ResourceManager.GetString("WrongConfigurationKey", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} is not a valid key in the settings hashtable: file {3}. Valid keys are ExcludeRules, IncludeRules and Severity..
-        /// </summary>
-        internal static string WrongKey {
-            get {
-                return ResourceManager.GetString("WrongKey", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Key in the settings hashtable should be a string: line {0} column {1} in file {2}.
-        /// </summary>
-        internal static string WrongKeyFormat {
-            get {
-                return ResourceManager.GetString("WrongKeyFormat", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} is not a valid key in the settings hashtable. Valid keys are CustomRulePath, ExcludeRules, IncludeRules, IncludeDefaultRules, RecurseCustomRulePath, Rules and Severity..
-        /// </summary>
-        internal static string WrongKeyHashTable {
-            get {
-                return ResourceManager.GetString("WrongKeyHashTable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Scope can only be either function or class..
-        /// </summary>
-        internal static string WrongScopeArgumentSuppressionAttributeError {
-            get {
-                return ResourceManager.GetString("WrongScopeArgumentSuppressionAttributeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Value in the settings hashtable should be a string or an array of strings: line {0} column {1} in file {2}.
-        /// </summary>
-        internal static string WrongValueFormat {
-            get {
-                return ResourceManager.GetString("WrongValueFormat", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Value {0} for key {1} has the wrong data type..
-        /// </summary>
-        internal static string WrongValueHashTable {
-            get {
-                return ResourceManager.GetString("WrongValueHashTable", resourceCulture);
-            }
-        }
-    }
-}
diff --git a/Engine/TokenOperations.cs b/Engine/TokenOperations.cs
index 0a47ab3cc..fa9a1978a 100644
--- a/Engine/TokenOperations.cs
+++ b/Engine/TokenOperations.cs
@@ -232,5 +232,18 @@ private bool OnSameLine(Token token1, Token token2)
         {
             return token1.Extent.StartLineNumber == token2.Extent.EndLineNumber;
         }
+
+        /// <summary>
+        /// Finds the position of a given token in the AST.
+        /// </summary>
+        /// <param name="token">The <see cref="Token"/> to search for.</param>
+        /// <returns>The Ast node directly containing the provided <see cref="Token"/>.</returns>
+        public Ast GetAstPosition(Token token)
+        {
+            FindAstPositionVisitor findAstVisitor = new FindAstPositionVisitor(token.Extent.StartScriptPosition);
+            ast.Visit(findAstVisitor);
+            return findAstVisitor.AstPosition;
+        }
+
     }
 }
diff --git a/Engine/VariableAnalysis.cs b/Engine/VariableAnalysis.cs
index fd66ea2c4..2870d442f 100644
--- a/Engine/VariableAnalysis.cs
+++ b/Engine/VariableAnalysis.cs
@@ -375,7 +375,7 @@ public bool IsUninitialized(VariableExpressionAst varTarget)
         /// </summary>
         /// <param name="varTarget"></param>
         /// <returns></returns>
-        public bool IsGlobalOrEnvironment(VariableExpressionAst varTarget)
+        public static bool IsGlobalOrEnvironment(VariableExpressionAst varTarget)
         {
             if (varTarget != null)
             {
diff --git a/Engine/VariableAnalysisBase.cs b/Engine/VariableAnalysisBase.cs
index b55119d7a..77c421f3c 100644
--- a/Engine/VariableAnalysisBase.cs
+++ b/Engine/VariableAnalysisBase.cs
@@ -995,7 +995,7 @@ internal static Tuple<Dictionary<string, VariableAnalysisDetails>, Dictionary<st
 
                                 #else
 
-                                TypeDefinitionAst psClass = Classes.FirstOrDefault(item => String.Equals(item.Name, analysis.Type.FullName, StringComparison.OrdinalIgnoreCase));
+                                TypeDefinitionAst psClass = Classes.FirstOrDefault(item => String.Equals(item.Name, analysis.Type?.FullName, StringComparison.OrdinalIgnoreCase));
                                 Type possibleType = AssignmentTarget.GetTypeFromMemberExpressionAst(memAst, analysis, psClass);
 
                                 #endif
diff --git a/LICENSE b/LICENSE
index cec380d8e..48ea6616b 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
-The MIT License (MIT)
+MIT License
 
-Copyright (c) 2015 Microsoft Corporation.
+Copyright (c) Microsoft Corporation.
 
 Permission is hereby granted, free of charge, to any person obtaining a copy
 of this software and associated documentation files (the "Software"), to deal
@@ -9,13 +9,13 @@ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 copies of the Software, and to permit persons to whom the Software is
 furnished to do so, subject to the following conditions:
 
-The above copyright notice and this permission notice shall be included in
-all copies or substantial portions of the Software.
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
 
 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
-OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
-THE SOFTWARE.
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE
diff --git a/NuGet.Config b/NuGet.Config
index acba4478b..f003b0fbd 100644
--- a/NuGet.Config
+++ b/NuGet.Config
@@ -1,8 +1,7 @@
-﻿<?xml version="1.0" encoding="utf-8"?>
+<?xml version="1.0" encoding="utf-8"?>
 <configuration>
   <packageSources>
     <clear />
-    <add key="nuget.org" value="https://api.nuget.org/v3/index.json" />
-    <add key="powershell-core" value="https://powershell.myget.org/F/powershell-core/api/v3/index.json" />
+    <add key="PowerShellCore_PublicPackages" value="https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/powershell/nuget/v3/index.json" />
   </packageSources>
 </configuration>
diff --git a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/PlatformInformationCollector.cs b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/PlatformInformationCollector.cs
index dfd62b806..26aa0ee7a 100644
--- a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/PlatformInformationCollector.cs
+++ b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/PlatformInformationCollector.cs
@@ -330,7 +330,7 @@ private Architecture GetProcessArchitecture()
             return (Architecture)RuntimeInformation.ProcessArchitecture;
 #else
             // We assume .NET Framework must be on an Intel architecture
-            // net452 does not reliably have the above API
+            // net462 does not reliably have the above API
             return Environment.Is64BitProcess
                 ? Architecture.X64
                 : Architecture.X86;
@@ -344,25 +344,13 @@ private Architecture GetOSArchitecture()
             return (Architecture)RuntimeInformation.OSArchitecture;
 #else
             // We assume .NET Framework must be on an Intel architecture
-            // net452 does not reliably have the above API
+            // net462 does not reliably have the above API
             return Environment.Is64BitOperatingSystem
                 ? Architecture.X64
                 : Architecture.X86;
 #endif
         }
 
-        private DotnetRuntime GetDotnetRuntime()
-        {
-#if CoreCLR
-            // Our CoreCLR is actuall .NET Standard, so we could be loaded into net47
-            return RuntimeInformation.FrameworkDescription.StartsWith(".NET Core")
-                ? DotnetRuntime.Core
-                : DotnetRuntime.Framework;
-#else
-            return DotnetRuntime.Framework;
-#endif
-        }
-
         /// <summary>
         /// Get the Windows SKU ID of the current PowerShell session.
         /// </summary>
diff --git a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/TypeDataCollector.cs b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/TypeDataCollector.cs
index 8ec0d0f03..19710dde6 100644
--- a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/TypeDataCollector.cs
+++ b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Collection/TypeDataCollector.cs
@@ -347,7 +347,9 @@ private MemberData AssembleMembers(Type type, BindingFlags memberBinding)
                 switch (member)
                 {
                     case ConstructorInfo constructor:
-                        constructors.Add(AssembleConstructor(constructor));
+                        if (TryAssembleConstructor(constructor, out string[] cInfo)) {
+                            constructors.Add(cInfo);
+                        }
                         break;
 
                     case FieldInfo field:
@@ -400,7 +402,10 @@ private MemberData AssembleMembers(Type type, BindingFlags memberBinding)
             var methodDatas = new JsonDictionary<string, MethodData>();
             foreach (KeyValuePair<string, List<MethodInfo>> method in methods)
             {
-                methodDatas[method.Key] = AssembleMethod(method.Value);
+                if (TryAssembleMethod(method.Value, out MethodData md))
+                {
+                    methodDatas[method.Key] = md;
+                }
             }
 
             return new MemberData()
@@ -457,35 +462,61 @@ private EventData AssembleEvent(EventInfo e)
             };
         }
 
-        private string[] AssembleConstructor(ConstructorInfo ctor)
+        // private string[] AssembleConstructor(ConstructorInfo ctor)
+        private bool TryAssembleConstructor(ConstructorInfo ctor, out string[] result)
         {
+            bool success = false;
             var parameters = new List<string>();
-            foreach (ParameterInfo param in ctor.GetParameters())
+            try
+            {
+                foreach (ParameterInfo param in ctor.GetParameters())
+                {
+                    parameters.Add(TypeNaming.GetFullTypeName(param.ParameterType));
+                }
+
+                result = parameters.ToArray();
+                success = true;
+            }
+            catch
             {
-                parameters.Add(TypeNaming.GetFullTypeName(param.ParameterType));
+                result = null;
             }
 
-            return parameters.ToArray();
+            return success;
         }
 
-        private MethodData AssembleMethod(List<MethodInfo> methodOverloads)
+        // private MethodData AssembleMethod(List<MethodInfo> methodOverloads)
+        private bool TryAssembleMethod(List<MethodInfo> methodOverloads, out MethodData result)
         {
             var overloads = new List<string[]>();
             foreach (MethodInfo overload in methodOverloads)
             {
                 var parameters = new List<string>();
-                foreach (ParameterInfo param in overload.GetParameters())
+                try
                 {
-                    parameters.Add(TypeNaming.GetFullTypeName(param.ParameterType));
+                    foreach (ParameterInfo param in overload.GetParameters())
+                    {
+                        parameters.Add(TypeNaming.GetFullTypeName(param.ParameterType));
+                    }
+                    overloads.Add(parameters.ToArray());
                 }
-                overloads.Add(parameters.ToArray());
+                catch
+                {
+                }
+            }
+
+            if (overloads.Count == 0)
+            {
+                result = null;
+                return false;
             }
 
-            return new MethodData()
+            result =  new MethodData()
             {
                 ReturnType = TypeNaming.GetFullTypeName(methodOverloads[0].ReturnType),
                 OverloadParameters = overloads.ToArray()
             };
+            return true;
         }
 
         private bool IsAssemblyPathExcluded(string path)
diff --git a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Commands/CommandUtilities.cs b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Commands/CommandUtilities.cs
index 3e14494f1..6a957f7cc 100644
--- a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Commands/CommandUtilities.cs
+++ b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Commands/CommandUtilities.cs
@@ -13,8 +13,6 @@ namespace Microsoft.PowerShell.CrossCompatibility.Commands
     /// </summary>
     internal static class CommandUtilities
     {
-        private const string COMPATIBILITY_ERROR_ID = "CompatibilityAnalysisError";
-
         public const string MODULE_PREFIX = "PSCompatibility";
 
         /// <summary>
diff --git a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Data/Platform/OperatingSystemData.cs b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Data/Platform/OperatingSystemData.cs
index 89fe9445a..cb0455a78 100644
--- a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Data/Platform/OperatingSystemData.cs
+++ b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Data/Platform/OperatingSystemData.cs
@@ -69,7 +69,7 @@ public class OperatingSystemData : ICloneable
         /// <summary>
         /// The Windows SKU identifier, corresponding to
         /// the GetProductInfo() sysinfo API:
-        /// https://docs.microsoft.com/en-us/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getproductinfo
+        /// https://learn.microsoft.com/windows/desktop/api/sysinfoapi/nf-sysinfoapi-getproductinfo
         /// </summary>
         [DataMember(EmitDefaultValue = false)]
         public uint? SkuId { get; set; }
diff --git a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Microsoft.PowerShell.CrossCompatibility.csproj b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Microsoft.PowerShell.CrossCompatibility.csproj
index 641cb159e..c4667a950 100644
--- a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Microsoft.PowerShell.CrossCompatibility.csproj
+++ b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Microsoft.PowerShell.CrossCompatibility.csproj
@@ -1,7 +1,9 @@
 ﻿<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <TargetFrameworks>netstandard2.0;net452</TargetFrameworks>
+    <VersionPrefix>$(ModuleVersion)</VersionPrefix>
+    <TargetFrameworks>netstandard2.0;net462</TargetFrameworks>
+    <AssemblyVersion>$(ModuleVersion)</AssemblyVersion>
   </PropertyGroup>
 
   <PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
@@ -9,18 +11,20 @@
   </PropertyGroup>
 
   <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
-    <PackageReference Include="Microsoft.Win32.Registry" Version="4.5.0" />
-    <PackageReference Include="PowerShellStandard.Library" Version="3.0.0-preview-02" />
+    <PackageReference Include="Newtonsoft.Json" />
+    <PackageReference Include="Microsoft.Win32.Registry" />
+    <PackageReference Include="Microsoft.Management.Infrastructure" />
+    <PackageReference Include="PowerShellStandard.Library" />
   </ItemGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == 'net452'">
-    <PackageReference Include="Microsoft.PowerShell.3.ReferenceAssemblies" Version="1.0.0" />
+  <ItemGroup Condition="'$(TargetFramework)' == 'net462'">
+    <PackageReference Include="Newtonsoft.Json" />
+    <PackageReference Include="Microsoft.PowerShell.5.ReferenceAssemblies" />
+    <PackageReference Include="Microsoft.Management.Infrastructure" VersionOverride="1.0.0" />
   </ItemGroup>
 
   <ItemGroup>
-    <PackageReference Include="Microsoft.CSharp" Version="4.5.0" />
-    <PackageReference Include="Microsoft.Management.Infrastructure" Version="1.0.0" />
-    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
+    <PackageReference Include="Microsoft.CSharp" />
   </ItemGroup>
 
 </Project>
diff --git a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Retrieval/JsonProfileSerializer.cs b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Retrieval/JsonProfileSerializer.cs
index 85ed9b82d..27d2e298b 100644
--- a/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Retrieval/JsonProfileSerializer.cs
+++ b/PSCompatibilityCollector/Microsoft.PowerShell.CrossCompatibility/Retrieval/JsonProfileSerializer.cs
@@ -84,6 +84,7 @@ public static JsonProfileSerializer Create(Formatting formatting)
                 Converters = GetFormatConverters(),
                 MissingMemberHandling = MissingMemberHandling.Ignore,
                 DefaultValueHandling = DefaultValueHandling.IgnoreAndPopulate,
+                MaxDepth = 128,
             };
 
             var serializer = JsonSerializer.Create(settings);
diff --git a/PSCompatibilityCollector/PSCompatibilityCollector.psm1 b/PSCompatibilityCollector/PSCompatibilityCollector.psm1
index aea680da4..0e3f6a8e4 100644
--- a/PSCompatibilityCollector/PSCompatibilityCollector.psm1
+++ b/PSCompatibilityCollector/PSCompatibilityCollector.psm1
@@ -8,5 +8,5 @@ if ($PSVersionTable.PSVersion.Major -ge 6)
 }
 else
 {
-    Import-Module ([System.IO.Path]::Combine($PSScriptRoot, 'net452', 'Microsoft.PowerShell.CrossCompatibility.dll')) -Force
+    Import-Module ([System.IO.Path]::Combine($PSScriptRoot, 'net462', 'Microsoft.PowerShell.CrossCompatibility.dll')) -Force
 }
diff --git a/PSCompatibilityCollector/Tests/UtilityApi.Tests.ps1 b/PSCompatibilityCollector/Tests/UtilityApi.Tests.ps1
index 3d0108b50..0ebcec746 100644
--- a/PSCompatibilityCollector/Tests/UtilityApi.Tests.ps1
+++ b/PSCompatibilityCollector/Tests/UtilityApi.Tests.ps1
@@ -1,52 +1,44 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
-function Get-TypeNameAstFromScript
-{
-    param([string]$Script)
+BeforeAll {
+    function Get-TypeNameAstFromScript
+    {
+        param([string]$Script)
 
-    $ast = [System.Management.Automation.Language.Parser]::ParseInput($Script, [ref]$null, [ref]$null)
-    $typeExpAst = $ast.Find({
-        $args[0] -is [System.Management.Automation.Language.TypeExpressionAst]
-    }, $true)
+        $ast = [System.Management.Automation.Language.Parser]::ParseInput($Script, [ref]$null, [ref]$null)
+        $typeExpAst = $ast.Find({
+            $args[0] -is [System.Management.Automation.Language.TypeExpressionAst]
+        }, $true)
 
-    return $typeExpAst.TypeName
-}
+        return $typeExpAst.TypeName
+    }
 
-function Get-TypeAccelerators
-{
-    [psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators', 'nonpublic')::Get.GetEnumerator()
+    function Get-TypeAccelerators
+    {
+        [psobject].Assembly.GetType('System.Management.Automation.TypeAccelerators', 'nonpublic')::Get.GetEnumerator()
+    }
 }
 
-Describe "Type name serialization" {
-    BeforeAll {
-        $typeNameTestCases = @(
-            @{ InputType = [System.Reflection.Assembly]; ExpectedName = "System.Reflection.Assembly" }
-            @{ InputType = [string]; ExpectedName = "System.String" }
-            @{ InputType = [datetime]; ExpectedName = "System.DateTime" }
-            @{ InputType = [string[]]; ExpectedName = "System.String[]" }
-            @{ InputType = [System.TimeZoneInfo+AdjustmentRule]; ExpectedName = "System.TimeZoneInfo+AdjustmentRule" }
-            @{ InputType = [System.Func`1]; ExpectedName = "System.Func``1" }
-            @{ InputType = [System.Collections.Generic.Dictionary`2]; ExpectedName = "System.Collections.Generic.Dictionary``2" }
-            @{ InputType = [System.Collections.Generic.Dictionary`2+Enumerator]; ExpectedName = "System.Collections.Generic.Dictionary``2+Enumerator" }
-            @{ InputType = [System.Collections.Generic.Dictionary[string,object]].GetNestedType('Enumerator'); ExpectedName = "System.Collections.Generic.Dictionary``2+Enumerator" }
-            @{ InputType = [System.Collections.Generic.List[object]]; ExpectedName = "System.Collections.Generic.List``1[System.Object]" }
-            @{ InputType = [System.Collections.Generic.Dictionary[string, object]]; ExpectedName = "System.Collections.Generic.Dictionary``2[System.String,System.Object]" }
-            @{ InputType = [System.Collections.Generic.Dictionary`2+Enumerator[string,object]]; ExpectedName = "System.Collections.Generic.Dictionary``2+Enumerator[System.String,System.Object]" }
-            @{ InputType = [System.Collections.Concurrent.ConcurrentDictionary`2].GetMethod('ToArray').ReturnType; ExpectedName = "System.Collections.Generic.KeyValuePair``2[]"}
-        )
-
-        $genericStrippingTests = @(
-            @{ RawTypeName = "String"; StrippedTypeName = "String" }
-            @{ RawTypeName = "Dictionary``2"; StrippedTypeName = "Dictionary" }
-            @{ RawTypeName = "Dictionary``2"; StrippedTypeName = "Dictionary" }
-            @{ RawTypeName = "Dictionary``2+Enumerator"; StrippedTypeName = "Dictionary+Enumerator" }
-        )
-    }
 
-    It "Serializes the name of type <InputType> to <ExpectedName>" -TestCases $typeNameTestCases {
-        param([type]$InputType, [string]$ExpectedName)
+Describe "Type name serialization" {
 
+    It "Serializes the name of type <InputType> to <ExpectedName>" -TestCases @(
+        @{ InputType = [System.Reflection.Assembly]; ExpectedName = "System.Reflection.Assembly" }
+        @{ InputType = [string]; ExpectedName = "System.String" }
+        @{ InputType = [datetime]; ExpectedName = "System.DateTime" }
+        @{ InputType = [string[]]; ExpectedName = "System.String[]" }
+        @{ InputType = [System.TimeZoneInfo+AdjustmentRule]; ExpectedName = "System.TimeZoneInfo+AdjustmentRule" }
+        @{ InputType = [System.Func`1]; ExpectedName = "System.Func``1" }
+        @{ InputType = [System.Collections.Generic.Dictionary`2]; ExpectedName = "System.Collections.Generic.Dictionary``2" }
+        @{ InputType = [System.Collections.Generic.Dictionary`2+Enumerator]; ExpectedName = "System.Collections.Generic.Dictionary``2+Enumerator" }
+        @{ InputType = [System.Collections.Generic.Dictionary[string, object]].GetNestedType('Enumerator'); ExpectedName = "System.Collections.Generic.Dictionary``2+Enumerator" }
+        @{ InputType = [System.Collections.Generic.List[object]]; ExpectedName = "System.Collections.Generic.List``1[System.Object]" }
+        @{ InputType = [System.Collections.Generic.Dictionary[string, object]]; ExpectedName = "System.Collections.Generic.Dictionary``2[System.String,System.Object]" }
+        @{ InputType = [System.Collections.Generic.Dictionary`2+Enumerator[string, object]]; ExpectedName = "System.Collections.Generic.Dictionary``2+Enumerator[System.String,System.Object]" }
+        @{ InputType = [System.Collections.Concurrent.ConcurrentDictionary`2].GetMethod('ToArray').ReturnType; ExpectedName = "System.Collections.Generic.KeyValuePair``2[]" }
+    ) {
+        param ( $InputType, $ExpectedName )
         $name = [Microsoft.PowerShell.CrossCompatibility.TypeNaming]::GetFullTypeName($InputType)
         $name | Should -BeExactly $ExpectedName
     }
@@ -57,86 +49,80 @@ Describe "Type name serialization" {
         } | Should -Throw -ErrorId "ArgumentNullException"
     }
 
-    It "Strips generic quantifiers from '<RawTypeName>' to return '<StrippedTypeName>'" -TestCases $genericStrippingTests {
+    It "Strips generic quantifiers from '<RawTypeName>' to return '<StrippedTypeName>'" {
         param([string]$RawTypeName, [string]$StrippedTypeName)
 
         $stripped = [Microsoft.PowerShell.CrossCompatibility.TypeNaming]::StripGenericQuantifiers($RawTypeName)
         $stripped | Should -BeExactly $StrippedTypeName
-    }
+    } -TestCases @(
+        @{ RawTypeName = "String"; StrippedTypeName = "String" }
+        @{ RawTypeName = "Dictionary``2"; StrippedTypeName = "Dictionary" }
+        @{ RawTypeName = "Dictionary``2"; StrippedTypeName = "Dictionary" }
+        @{ RawTypeName = "Dictionary``2+Enumerator"; StrippedTypeName = "Dictionary+Enumerator" }
+    )
 }
 
 Describe "Type accelerator expansion" {
     BeforeAll {
         $typeAccelerators = Get-TypeAccelerators |
             ForEach-Object { $d = New-Object 'System.Collections.Generic.Dictionary[string,string]' } { $d.Add($_.Key, $_.Value.FullName) } { $d }
-
-        $typeAcceleratorTestCases = @(
-            @{ Raw = "[System.Exception]"; Expanded = "System.Exception" }
-            @{ Raw = "[string]"; Expanded = "System.String" }
-            @{ Raw = "[psmoduleinfo]"; Expanded = "System.Management.Automation.PSModuleInfo" }
-            @{ Raw = "[System.Collections.Generic.List[int]]"; Expanded = "System.Collections.Generic.List``1[System.Int32]" }
-            @{ Raw = "[System.Collections.Generic.Dictionary[string,psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
-            @{ Raw = "[System.Collections.Generic.Dictionary[string, psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
-            @{ Raw = "[System.Collections.Generic.Dictionary  [string,  psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
-            @{ Raw = "[System.Collections.Generic.List``1[uri]]"; Expanded = "System.Collections.Generic.List``1[System.Uri]" }
-            @{ Raw = "[System.Collections.Generic.Dictionary``2[string,psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
-            @{ Raw = "[System.Collections.Generic.Dictionary``2  [string, psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
-            @{ Raw = "[object]"; Expanded = "System.Object" }
-        )
     }
 
-    It "Expands the typename in <Raw> to <Expanded>" -TestCases $typeAcceleratorTestCases {
-        param([string]$Raw, [string]$Expanded)
-
+    It "Expands the typename in <Raw> to <Expanded>" -TestCases @(
+        @{ Raw = "[System.Exception]"; Expanded = "System.Exception" }
+        @{ Raw = "[string]"; Expanded = "System.String" }
+        @{ Raw = "[psmoduleinfo]"; Expanded = "System.Management.Automation.PSModuleInfo" }
+        @{ Raw = "[System.Collections.Generic.List[int]]"; Expanded = "System.Collections.Generic.List``1[System.Int32]" }
+        @{ Raw = "[System.Collections.Generic.Dictionary[string,psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
+        @{ Raw = "[System.Collections.Generic.Dictionary[string, psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
+        @{ Raw = "[System.Collections.Generic.Dictionary  [string,  psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
+        @{ Raw = "[System.Collections.Generic.List``1[uri]]"; Expanded = "System.Collections.Generic.List``1[System.Uri]" }
+        @{ Raw = "[System.Collections.Generic.Dictionary``2[string,psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
+        @{ Raw = "[System.Collections.Generic.Dictionary``2  [string, psmoduleinfo]]"; Expanded = "System.Collections.Generic.Dictionary``2[System.String,System.Management.Automation.PSModuleInfo]" }
+        @{ Raw = "[object]"; Expanded = "System.Object" }
+    ) -Test {
+
+        param ( $Raw, $Expanded )
         $typeName = Get-TypeNameAstFromScript -Script $Raw
 
         $canonicalName = [Microsoft.PowerShell.CrossCompatibility.TypeNaming]::GetCanonicalTypeName($typeAccelerators, $typeName)
 
         $canonicalName | Should -BeExactly $Expanded
-
     }
 }
 
+$versionCreationTests = @(
+    @{ Version = '6.1'; Major = 6; Minor = 1; Patch = -1 }
+    @{ Version = '6.1.4'; Major = 6; Minor = 1; Patch = 4; }
+    @{ Version = '5.1.8-preview.2'; Major = 5; Minor = 1; Patch = 8; Label = 'preview.2' }
+    @{ Version = [version]'4.2'; Major = 4; Minor = 2; Patch = -1; Revision = -1 }
+    @{ Version = [version]'4.2.1'; Major = 4; Minor = 2; Patch = 1; Revision = -1 }
+    @{ Version = [version]'4.2.1.7'; Major = 4; Minor = 2; Patch = 1; Revision = 7 }
+)
+
+if ($PSVersionTable.PSVersion.Major -ge 6)
+{
+    $versionCreationTests += @(
+        @{ Version = [semver]'6.1.2'; Major = 6; Minor = 1; Patch = 2; Label = $null }
+        @{ Version = [semver]'6.1.2-rc.1'; Major = 6; Minor = 1; Patch = 2; Label = 'rc.1' }
+        @{ Version = [semver]'6.1-rc.1'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1' }
+        @{ Version = [semver]'6-rc.1'; Major = 6; Minor = 0; Patch = 0; Label = 'rc.1' }
+        @{ Version = [semver]'6.1.2-rc.1+duck'; Major = 6; Minor = 1; Patch = 2; Label = 'rc.1'; BuildLabel = 'duck' }
+        @{ Version = [semver]'6.1-rc.1+duck'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1'; BuildLabel = 'duck' }
+        @{ Version = [semver]'6-rc.1+duck'; Major = 6; Minor = 0; Patch = 0; Label = 'rc.1'; BuildLabel = 'duck' }
+    )
+}
+
 Describe "PowerShell version object" {
     Context "Version parsing" {
-        BeforeAll {
-            $genericVerCases = @(
-                @{ VerStr = '42'; Major = 42; Minor = -1; Patch = -1 }
-                @{ VerStr = '7'; Major = 7; Minor = -1; Patch = -1 }
-                @{ VerStr = '6.1'; Major = 6; Minor = 1; Patch = -1 }
-                @{ VerStr = '5.2.7'; Major = 5; Minor = 2; Patch = 7 }
-                @{ VerStr = '512.2124.71'; Major = 512; Minor = 2124; Patch = 71 }
-            )
-
-            $semVerCases = @(
-                @{ VerStr = '6.1.0-rc.1'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1' }
-                @{ VerStr = '6.2-preview.2'; Major = 6; Minor = 2; Patch = -1; Label = 'preview.2' }
-                @{ VerStr = '6-preview.2'; Major = 6; Minor = -1; Patch = -1; Label = 'preview.2' }
-                @{ VerStr = '6.1.0-rc.1+moo'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1'; BuildLabel = 'moo' }
-                @{ VerStr = '6.2-preview.2+horse'; Major = 6; Minor = 2; Patch = -1; Label = 'preview.2'; BuildLabel = 'horse' }
-                @{ VerStr = '6-preview.2+veryimportant'; Major = 6; Minor = -1; Patch = -1; Label = 'preview.2'; BuildLabel = 'veryimportant' }
-            )
-
-            $systemVerCases = @(
-                @{ VerStr = '5.2.1.12312'; Major = 5; Minor = 2; Patch = 1; Revision = 12312 }
-            )
-
-            $versionFailCases = @(
-                @{ VerStr = 'banana' }
-                @{ VerStr = '' }
-                @{ VerStr = '1.' }
-                @{ VerStr = '.6' }
-                @{ VerStr = '5.1.' }
-                @{ VerStr = '5.1.2.' }
-                @{ VerStr = '4.1.5.7.' }
-                @{ VerStr = '4.1.5.7.4' }
-                @{ VerStr = '4.1.5.7-rc.2' }
-                @{ VerStr = '4.1.5.-rc.2' }
-            )
-        }
 
-        It "Parses version string '<VerStr>' as <Major>.<Minor>.<Patch>" -TestCases $genericVerCases {
-            param([string]$VerStr, [int]$Major, [int]$Minor, [int]$Patch)
+        It "Parses version string '<VerStr>' as <Major>.<Minor>.<Patch>" -TestCases @(
+            @{ VerStr = '42'; Major = 42; Minor = -1; Patch = -1 }
+            @{ VerStr = '7'; Major = 7; Minor = -1; Patch = -1 }
+            @{ VerStr = '6.1'; Major = 6; Minor = 1; Patch = -1 }
+            @{ VerStr = '5.2.7'; Major = 5; Minor = 2; Patch = 7 }
+            @{ VerStr = '512.2124.71'; Major = 512; Minor = 2124; Patch = 71 }
+        ) -Test {
 
             $v = [Microsoft.PowerShell.CrossCompatibility.PowerShellVersion]$VerStr
 
@@ -145,7 +131,14 @@ Describe "PowerShell version object" {
             $v.Patch | Should -Be $Patch
         }
 
-        It "Parses version string '<VerStr>' as <Major>.<Minor>.<Patch>-<Label>+<BuildLabel>" -TestCases $semVerCases {
+        It "Parses version string '<VerStr>' as <Major>.<Minor>.<Patch>-<Label>+<BuildLabel>" -TestCases @(
+            @{ VerStr = '6.1.0-rc.1'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1' }
+            @{ VerStr = '6.2-preview.2'; Major = 6; Minor = 2; Patch = -1; Label = 'preview.2' }
+            @{ VerStr = '6-preview.2'; Major = 6; Minor = -1; Patch = -1; Label = 'preview.2' }
+            @{ VerStr = '6.1.0-rc.1+moo'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1'; BuildLabel = 'moo' }
+            @{ VerStr = '6.2-preview.2+horse'; Major = 6; Minor = 2; Patch = -1; Label = 'preview.2'; BuildLabel = 'horse' }
+            @{ VerStr = '6-preview.2+veryimportant'; Major = 6; Minor = -1; Patch = -1; Label = 'preview.2'; BuildLabel = 'veryimportant' }
+        ) -Test {
             param([string]$VerStr, [int]$Major, [int]$Minor, [int]$Patch, [string]$Label, $BuildLabel)
 
             $v = [Microsoft.PowerShell.CrossCompatibility.PowerShellVersion]$VerStr
@@ -157,7 +150,9 @@ Describe "PowerShell version object" {
             $v.BuildLabel | Should -Be $BuildLabel
         }
 
-        It "Parses version string '<VerStr>' as <Major>.<Minor>.<Patch>.<Revision>" -TestCases $systemVerCases {
+        It "Parses version string '<VerStr>' as <Major>.<Minor>.<Patch>.<Revision>"-TestCases @(
+            @{ VerStr = '5.2.1.12312'; Major = 5; Minor = 2; Patch = 1; Revision = 12312 }
+        ) -Test {
             param([string]$VerStr, [int]$Major, [int]$Minor, [int]$Patch, [int]$Revision)
 
             $v = [Microsoft.PowerShell.CrossCompatibility.PowerShellVersion]$VerStr
@@ -168,7 +163,18 @@ Describe "PowerShell version object" {
             $v.Revision | Should -Be $Revision
         }
 
-        It "Does not parse '<VerStr>' as a version" -TestCases $versionFailCases {
+        It "Does not parse '<VerStr>' as a version" -TestCases @(
+            @{ VerStr = 'banana' }
+            @{ VerStr = '' }
+            @{ VerStr = '1.' }
+            @{ VerStr = '.6' }
+            @{ VerStr = '5.1.' }
+            @{ VerStr = '5.1.2.' }
+            @{ VerStr = '4.1.5.7.' }
+            @{ VerStr = '4.1.5.7.4' }
+            @{ VerStr = '4.1.5.7-rc.2' }
+            @{ VerStr = '4.1.5.-rc.2' }
+        ) -Test {
             param([string]$VerStr)
 
             { [Microsoft.PowerShell.CrossCompatibility.PowerShellVersion]$VerStr } | Should -Throw
@@ -176,35 +182,6 @@ Describe "PowerShell version object" {
     }
 
     Context "Version creation from other versions" {
-        BeforeAll {
-            $versionCreationTests = @(
-                @{ Version = '6.1'; Major = 6; Minor = 1; Patch = -1 }
-                @{ Version = '6.1.4'; Major = 6; Minor = 1; Patch = 4; }
-                @{ Version = '5.1.8-preview.2'; Major = 5; Minor = 1; Patch = 8; Label = 'preview.2' }
-                @{ Version = [version]'4.2'; Major = 4; Minor = 2; Patch = -1; Revision = -1 }
-                @{ Version = [version]'4.2.1'; Major = 4; Minor = 2; Patch = 1; Revision = -1 }
-                @{ Version = [version]'4.2.1.7'; Major = 4; Minor = 2; Patch = 1; Revision = 7 }
-            )
-
-            if ($PSVersionTable.PSVersion.Major -ge 6)
-            {
-                $versionCreationTests += @(
-                    @{ Version = [semver]'6.1.2'; Major = 6; Minor = 1; Patch = 2; Label = $null }
-                    @{ Version = [semver]'6.1.2-rc.1'; Major = 6; Minor = 1; Patch = 2; Label = 'rc.1' }
-                    @{ Version = [semver]'6.1-rc.1'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1' }
-                    @{ Version = [semver]'6-rc.1'; Major = 6; Minor = 0; Patch = 0; Label = 'rc.1' }
-                    @{ Version = [semver]'6.1.2-rc.1+duck'; Major = 6; Minor = 1; Patch = 2; Label = 'rc.1'; BuildLabel = 'duck' }
-                    @{ Version = [semver]'6.1-rc.1+duck'; Major = 6; Minor = 1; Patch = 0; Label = 'rc.1'; BuildLabel = 'duck' }
-                    @{ Version = [semver]'6-rc.1+duck'; Major = 6; Minor = 0; Patch = 0; Label = 'rc.1'; BuildLabel = 'duck' }
-                )
-            }
-
-            $versionCreationFailTests = @(
-                @{ Version = $null }
-                @{ Version = New-Object 'object' }
-                @{ Version = 'Hello' }
-            )
-        }
 
         It "Creates a PowerShellVersion from '<Version>'" -TestCases $versionCreationTests {
             param($Version, [int]$Major, [int]$Minor, [int]$Patch, [int]$Revision, $Label, $BuildLabel)
@@ -223,10 +200,14 @@ Describe "PowerShell version object" {
             }
         }
 
-        It "Does not create a PowerShellVersion from <Version>" -TestCases $versionCreationFailTests {
+        It "Does not create a PowerShellVersion from <Version>" {
             param($Version)
 
             { [Microsoft.PowerShell.CrossCompatibility.PowerShellVersion]::Create($Version) } | Should -Throw
-        }
+        } -TestCases @(
+            @{ Version = $null }
+            @{ Version = New-Object 'object' }
+            @{ Version = 'Hello' }
+        )
     }
 }
diff --git a/PSCompatibilityCollector/build.ps1 b/PSCompatibilityCollector/build.ps1
index ec028ee08..0d1b47958 100644
--- a/PSCompatibilityCollector/build.ps1
+++ b/PSCompatibilityCollector/build.ps1
@@ -8,7 +8,7 @@ param(
     $Configuration = 'Debug',
 
     [Parameter()]
-    [ValidateSet('netstandard2.0', 'net452')]
+    [ValidateSet('netstandard2.0', 'net462')]
     [string]
     $Framework,
 
@@ -24,7 +24,7 @@ $ErrorActionPreference = 'Stop'
 if ($IsWindows -eq $false) {
     $script:TargetFrameworks = 'netstandard2.0'
 } else {
-    $script:TargetFrameworks = 'netstandard2.0','net452'
+    $script:TargetFrameworks = 'netstandard2.0','net462'
 }
 
 $script:ModuleName = Split-Path $PSScriptRoot -Leaf
@@ -36,7 +36,7 @@ $script:BinModDir = [System.IO.Path]::Combine($PSScriptRoot, 'out', "$script:Mod
 $script:BinModSrcDir = Join-Path $PSScriptRoot 'Microsoft.PowerShell.CrossCompatibility'
 
 $script:PublishDlls = @{
-    'net452' = @('Microsoft.PowerShell.CrossCompatibility.dll', 'Microsoft.PowerShell.CrossCompatibility.pdb', 'Newtonsoft.Json.dll')
+    'net462' = @('Microsoft.PowerShell.CrossCompatibility.dll', 'Microsoft.PowerShell.CrossCompatibility.pdb', 'Newtonsoft.Json.dll')
     'netstandard2.0' = @('Microsoft.PowerShell.CrossCompatibility.dll', 'Microsoft.PowerShell.CrossCompatibility.pdb', 'Newtonsoft.Json.dll')
 }
 
@@ -44,7 +44,7 @@ function Invoke-CrossCompatibilityModuleBuild
 {
     param(
         [Parameter()]
-        [ValidateSet('netstandard2.0', 'net452')]
+        [ValidateSet('netstandard2.0', 'net462')]
         [string]
         $Framework = 'netstandard2.0',
 
diff --git a/PowerShellBestPractices.md b/PowerShellBestPractices.md
deleted file mode 100644
index 717810394..000000000
--- a/PowerShellBestPractices.md
+++ /dev/null
@@ -1,146 +0,0 @@
-# PowerShell Best Practices
-
-The following guidelines come from a combined effort from both the PowerShell team and the community. We will use this guideline to define rules for `PSScriptAnalyzer`. Please feel free to propose additional guidelines and rules for `PSScriptAnalyzer`.
-**Note**: The hyperlink next to each guidelines will redirect to documentation page for the rule that is already implemented.
-
-## Cmdlet Design Rules
-
-### Severity: Error
-
-### Severity: Warning
-
-- Use Only Approved Verbs [UseApprovedVerbs](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseApprovedVerbs.md)
-- Cmdlets Names: Characters that cannot be Used [AvoidReservedCharInCmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReservedCmdletChar.md)
-- Parameter Names that cannot be Used [AvoidReservedParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReservedParams.md)
-- Support Confirmation Requests [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md) and [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md)
-- Must call ShouldProcess when ShouldProcess attribute is present and vice versa.[UseShouldProcess](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ShouldProcess.md)
-- Nouns should be singular [UseSingularNouns](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseSingularNouns.md)
-- Module Manifest Fields [MissingModuleManifestField](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/MissingModuleManifestField.md)
-  - Version
-  - Author
-  - Description
-  - LicenseUri (for PowerShell Gallery)
-- Switch parameters should not default to true  [AvoidDefaultValueSwitchParameter](https://github.com/PowetrShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidDefaultValueSwitchParameter.md)
-
-### Severity: Information
-
-### Severity: TBD
-
-- Support Force Parameter for Interactive Session
-- If your cmdlet is used interactively, always provide a Force parameter to override the interactive actions, such as prompts or reading lines of input). This is important because it allows your cmdlet to be used in non-interactive scripts and hosts. The following methods can be implemented by an interactive host.
-- Document Output Objects
-- Module must be loadable
-- No syntax errors
-- Unresolved dependencies are an error
-- Derive from the Cmdlet or PSCmdlet Classes
-- Specify the Cmdlet Attribute
-- Override an Input Processing Method
-- Specify the OutputType Attribute
-- Write Single Records to the Pipeline 
-- Make Cmdlets Case-Insensitive and Case-Preserving 
-
-## Script Functions
-
-### Severity: Error
-
-### Severity: Warning
-
-- Avoid using alias [AvoidUsingCmdletAliases](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingCmdletAliases.md)
-- Avoid using deprecated WMI cmdlets [AvoidUsingWMICmdlet](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWMICmdlet.md)
-- Empty catch block should not be used [AvoidUsingEmptyCatchBlock](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingEmptyCatchBlock.md)
-- Invoke existing cmdlet with correct parameters [UseCmdletCorrectly](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseCmdletCorrectly.md)
-- Cmdlets should have ShouldProcess/ShouldContinue and Force param if certain system-modding verbs are present (Update, Set, Remove, New): [UseShouldProcessForStateChangingFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md)
-- Positional parameters should be avoided [AvoidUsingPositionalParameters](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPositionalParameters.md)
-- Global variables should be avoided. [AvoidGlobalVars](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidGlobalVars.md)
-- Declared variables must be used in more than just their assignment. [UseDeclaredVarsMoreThanAssignments](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md)
-- No Invoke-Expression [AvoidUsingInvokeExpression](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingInvokeExpression.md)
-
-### Severity: Information
-
-### Severity: TBD
-
-- `Clear-Host` should not be used
-- File paths should not be used (UNC)
-- Error Handling
-  - Use `-ErrorAction Stop` when calling cmdlets
-  - Use $ErrorActionPreference = 'Stop'/' Continue' when calling non-cmdlets
-  - Avoid using flags to handle errors
-  - Avoid using `$?`
-  - Avoid testing for a null variable as an error condition
-  - Copy `$Error[0]` to your own variable
-- Avoid using pipelines in scripts
-- If a return type is declared, the cmdlet must return that type. If a type is returned, a return type must be declared.
-
-## Scripting Style
-
-### Severity: Error
-
-### Severity: Warning 
-
-- Don't use `Write-Host` unless writing to the host is all you want to do [AvoidUsingWriteHost](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingWriteHost.md)
-
-### Severity: Information
-
-- Write comment-based help [ProvideCommentHelp](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ProvideCommentHelp.md)
-
-### Severity: TBD
-
-- Provide usage Examples
-- Use the Notes section for detail on how the tool work
-- Should have help on every exported command (including parameter documentation
-- Document the version of PowerShell that script was written for  
-- Indent your code
-- Avoid backticks
-
-## Script Security
-
-### Severity: Error
-
-- Password should be secure string [AvoidUsingPlainTextForPassword](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingPlainTextForPassword.md)- Should never have both -Username and -Password parameters (should take credentials): [UsePSCredentialType](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UsePSCredentialType.md)
-- `-ComputerName` Parameter argument hardcoded should not be used (information disclosure): [AvoidUsingComputerNameHardcoded](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingComputerNameHardcoded.md)
-- ConvertTo-SecureString with plaintext should not be used (information disclosure): [AvoidUsingConvertToSecureStringWithPlainText](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md)
-
-### Severity: Warning
-
-- Password = 'string' should not be used. (information disclosure) [AvoidUsingUsernameAndPasswordParams](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md)
-
-### Severity: Information
-
-### Severity: TBD
-
-- APIKey and Credentials variables that are initialized (information disclosure)
-
-## DSC Related Rules
-
-### Severity: Error
-
-- Use standard DSC methods [StandardDSCFunctionsInResource](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/StandardDSCFunctionsInResource.md)
-- Use identical mandatory parameters for all DSC methods [UseIdenticalMandatoryParametersForDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalMandatoryParametersForDSC.md)
-- Use identical parameters for Set and Test DSC methods [UseIdenticalParametersForDSC](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/UseIdenticalParametersForDSC.md)
-
-### Severity: Warning
-
-### Severity: Information
-
-- All of the following three rule are grouped by: [ReturnCorrectTypesForDSCFunctions](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/ReturnCorrectTypesForDSCFunctions.md)
-- Avoid return any object from a `Set-TargetResource` or Set (Class Based) function
-- Returning a Boolean object from a `Test-TargetResource` or Test (Class Based) function
-- Returning an object from a `Get-TargetResource` or Get (Class Based) function
-- DSC resources should have DSC tests [DSCTestsPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscTestsPresent.md)
-- DSC resources should have DSC examples [DSCExamplesPresent](https://github.com/PowerShell/PSScriptAnalyzer/blob/master/RuleDocumentation/DscExamplesPresent.md)
-
-### Severity: TBD
-
-- For PowerShell V4: Resource module contains `.psd1` file and `schema.mof` for every resource
-- MOF has description for each element [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/131)
-- Resource module must contain .psd1 file (always) and schema.mof (for non-class resource). [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/116)
-- Use ShouldProcess for a Set DSC method
-- Resource module contains DscResources folder which contains the resources [IssueOpened](https://github.com/PowerShell/PSScriptAnalyzer/issues/130)
-
-### Reference
-
-* Cmdlet Development Guidelines from MSDN site (Cmdlet Development Guidelines): https://msdn.microsoft.com/en-us/library/ms714657(v=vs.85).aspx 
-* The Community Book of PowerShell Practices (Compiled by Don Jones and Matt Penny and the Windows PowerShell Community): https://powershell.org/community-book-of-powershell-practices/
-* PowerShell DSC Resource Design and Testing Checklist: https://blogs.msdn.com/b/powershell/archive/2014/11/18/powershell-dsc-resource-design-and-testing-checklist.aspx
-* DSC Guidelines can also be found in the DSC Resources Repository: https://github.com/PowerShell/DscResources
-* The Unofficial PowerShell Best Practices and Style Guide: https://github.com/PoshCode/PowerShellPracticeAndStyle
diff --git a/README.md b/README.md
index 158904dac..d038ec756 100644
--- a/README.md
+++ b/README.md
@@ -3,467 +3,225 @@
 <img src="logo.png" width="180">
 
 [![Build Status](https://dev.azure.com/powershell/psscriptanalyzer/_apis/build/status/psscriptanalyzer-ci?branchName=master)](https://dev.azure.com/powershell/psscriptanalyzer/_build/latest?definitionId=80&branchName=master)
-[![Build status](https://ci.appveyor.com/api/projects/status/h5mot3vqtvxw5d7l/branch/master?svg=true)](https://ci.appveyor.com/project/PowerShell/psscriptanalyzer/branch/master)
 [![Join the chat at https://gitter.im/PowerShell/PSScriptAnalyzer](https://badges.gitter.im/PowerShell/PSScriptAnalyzer.svg)](https://gitter.im/PowerShell/PSScriptAnalyzer?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)
 
-Table of Contents
-=================
+## Table of Contents
 
 <!-- toc -->
 
 - [Introduction](#introduction)
-- [Usage](#usage)
+- [Documentation Notice](#documentation-notice)
 - [Installation](#installation)
-    + [From PowerShell Gallery](#from-powershell-gallery)
-      - [Supported PowerShell Versions and Platforms](#supported-powerShell-versions-and-platforms)
-    + [From Source](#from-source)
-      - [Requirements](#requirements)
-      - [Steps](#steps)
-      - [Tests](#tests)
-    + [From Chocolatey](#from-chocolatey)
-- [Suppressing Rules](#suppressing-rules)
-- [Settings Support in ScriptAnalyzer](#settings-support-in-scriptanalyzer)
-  * [Built-in Presets](#built-in-presets)
-  * [Explicit](#explicit)
-  * [Implicit](#implicit)
-- [ScriptAnalyzer as a .NET library](#scriptanalyzer-as-a-net-library)
-- [Violation Correction](#violation-correction)
-- [Project Management Dashboard](#project-management-dashboard)
 - [Contributions are welcome](#contributions-are-welcome)
 - [Creating a Release](#creating-a-release)
 - [Code of Conduct](#code-of-conduct)
+- [Security Policy](#security-policy)
 
 <!-- tocstop -->
 
-Introduction
-============
-PSScriptAnalyzer is a static code checker for Windows PowerShell modules and scripts. PSScriptAnalyzer checks the quality of Windows PowerShell code by running a set of rules.
-The rules are based on PowerShell best practices identified by PowerShell Team and the community. It generates DiagnosticResults (errors and warnings) to inform users about potential
-code defects and suggests possible solutions for improvements.
+## Introduction
 
-PSScriptAnalyzer is shipped with a collection of built-in rules that checks various aspects of PowerShell code such as presence of uninitialized variables, usage of PSCredential Type,
-usage of Invoke-Expression etc. Additional functionalities such as exclude/include specific rules are also supported.
+PSScriptAnalyzer is a static code checker for PowerShell modules and scripts. PSScriptAnalyzer
+checks the quality of PowerShell code by running a [set of rules](docs/Rules). The rules are based
+on PowerShell best practices identified by PowerShell Team and the community. It generates
+DiagnosticResults (errors and warnings) to inform users about potential code defects and suggests
+possible solutions for improvements.
 
-[Back to ToC](#table-of-contents)
-
-Usage
-======================
-
-``` PowerShell
-Get-ScriptAnalyzerRule [-CustomRulePath <String[]>] [-RecurseCustomRulePath] [-Name <String[]>] [-Severity <String[]>] [<CommonParameters>]
+PSScriptAnalyzer ships with a collection of built-in rules that check various aspects of
+PowerShell code such as:
 
-Invoke-ScriptAnalyzer [-Path] <String> [-CustomRulePath <String[]>] [-RecurseCustomRulePath] [-ExcludeRule <String[]>] [-IncludeDefaultRules] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-Fix] [-EnableExit] [-ReportSummary] [-Settings <Object>] [-SaveDscDependency] [<CommonParameters>]
-
-Invoke-ScriptAnalyzer [-ScriptDefinition] <String> [-CustomRulePath <String[]>] [-RecurseCustomRulePath] [-ExcludeRule <String[]>] [-IncludeDefaultRules] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-EnableExit] [-ReportSummary] [-Settings <Object>] [-SaveDscDependency] [<CommonParameters>]
-
-Invoke-Formatter [-ScriptDefinition] <String> [[-Settings] <Object>] [[-Range] <Int32[]>] [<CommonParameters>]
-```
+- The presence of uninitialized variables
+- Use of **PSCredential** type
+- Use of `Invoke-Expression`
+- And many more
 
 [Back to ToC](#table-of-contents)
 
-Installation
-============
+## DOCUMENTATION NOTICE
 
-### From PowerShell Gallery
-```powershell
-Install-Module -Name PSScriptAnalyzer
-```
+Conceptual user documentation has been moved out of the source code repository and into the
+documentation repository so that it can be published on learn.microsoft.com.
 
-**Note**: For PowerShell version `5.1.14393.206` or newer, before installing PSScriptAnalyzer, please install the latest Nuget provider by running the following in an elevated PowerShell session.
-```powershell
-Install-PackageProvider Nuget -MinimumVersion 2.8.5.201 –Force
-Exit
-```
-
-#### Supported PowerShell Versions and Platforms
-
-- Windows PowerShell 3.0 or greater
-- PowerShell Core 6.2 or greater on Windows/Linux/macOS
-- Docker (tested only using Docker Desktop on Windows 10 1809)
-  - PowerShell 6 Windows Image tags from [mcr.microsoft.com/powershell](https://hub.docker.com/r/microsoft/powershell). Example (1 warning gets produced by `Save-Module` but can be ignored):
-
-    ```docker run -it mcr.microsoft.com/powershell:nanoserver pwsh -command "Save-Module -Name PSScriptAnalyzer -Path .; Import-Module .\PSScriptAnalyzer; Invoke-ScriptAnalyzer -ScriptDefinition 'gci'"```
-  - PowerShell 5.1 (Windows): Only the [mcr.microsoft.com/windowsservercore](https://hub.docker.com/r/microsoft/windowsservercore/) images work but not the [microsoft/nanoserver](https://hub.docker.com/r/microsoft/windowsservercore/) images because they contain a Core version of it. Example:
+The goal of this migration is to have the user documentation on learn.microsoft.com. The source code
+repository should only contain documentation for the code base, such as how to build the code or how
+to contribute to the code.
 
-    ```docker run -it mcr.microsoft.com/windowsservercore powershell -command "Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force; Install-Module PSScriptAnalyzer -Force; Invoke-ScriptAnalyzer -ScriptDefinition 'gci'"```
-  - Linux tags from  [mcr.microsoft.com/powershell](https://hub.docker.com/r/microsoft/powershell/). - Example:
+User documentation that has been migrated:
 
-     ```docker run -it mcr.microsoft.com/powershell pwsh -c "Install-Module PSScriptAnalyzer -Force; Invoke-ScriptAnalyzer -ScriptDefinition 'gci'"```
+- Most of the contents of this README can be found in the
+  [PSScriptAnalyzer overview](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/overview)
+- For cmdlet reference, see
+  [PSScriptAnalyzer](https://learn.microsoft.com/powershell/module/psscriptanalyzer)
+- For rules, see
+  [Rules overview](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/rules/readme)
+- The `PowerShellBestPractices.md` content has been moved to
+  [PSScriptAnalyzer rules and recommendations](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/rules-recommendations)
+- The `ScriptRuleDocumentation.md` content has been moved to
+  [Creating custom rules](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/create-custom-rule)
 
-### From Chocolatey
+There is one exception - the documentation for the rules and cmdlets will remain in the [docs](docs)
+folder to facilitate build testing and to be archived as part of each release. Only the
+documentation for the latest release is published on on learn.microsoft.com.
 
-If you prefer to manage PSScriptAnalyzer as a Windows package, you can use [Chocolatey](https://chocolatey.org) to install it.
+## Installation
 
-If you don't have Chocolatey, you can install it from the [Chocolately Install page](https://chocolatey.org/install).
-With Chocolatey installed, execute the following command to install PSScriptAnalyzer:
+To install **PSScriptAnalyzer** from the PowerShell Gallery, see
+[Installing PSScriptAnalyzer](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/overview#installing-psscriptanalyzer).
 
-```powershell
-choco install psscriptanalyzer
-```
+To install **PSScriptAnalyzer** from source code:
 
-Note: the PSScriptAnalyzer Chocolatey package is provided and supported by the community.
+### Requirements
 
-### From Source
+- [Latest .NET 8.0 SDK](https://dotnet.microsoft.com/en-us/download/dotnet/8.0)
+- If building for Windows PowerShell versions, then the .NET Framework 4.6.2 [targeting pack](https://dotnet.microsoft.com/en-us/download/dotnet-framework/net462) (also referred to as developer/targeting pack) need to be installed. This is only possible on Windows.
+- Optional but recommended for development: [Visual Studio 2022](https://www.visualstudio.com/downloads)
+- Or [Visual Studio Code](https://code.visualstudio.com/download)
+- [Pester v5 PowerShell module, available on PowerShell Gallery](https://github.com/pester/Pester)
+- [PlatyPS PowerShell module, available on PowerShell Gallery](https://github.com/PowerShell/platyPS/releases)
 
-#### Requirements
+### Steps
 
-* [.NET Core 3.1.102 SDK](https://www.microsoft.com/net/download/dotnet-core/3.1#sdk-3.1.102) or newer patch release
-* [Pester v4 PowerShell module, available on PowerShell Gallery](https://github.com/pester/Pester)
-* [PlatyPS PowerShell module, available on PowerShell Gallery](https://github.com/PowerShell/platyPS/releases)
-* Optionally but recommended for development: [Visual Studio 2017/2019](https://www.visualstudio.com/downloads/)
+- Obtain the source
+  - Download the latest source code from the
+    [release page](https://github.com/PowerShell/PSScriptAnalyzer/releases) OR
+  - Clone the repository (needs git)
 
-#### Steps
-* Obtain the source
-    - Download the latest source code from the [release page](https://github.com/PowerShell/PSScriptAnalyzer/releases) OR
-    - Clone the repository (needs git)
     ```powershell
     git clone https://github.com/PowerShell/PSScriptAnalyzer
     ```
-* Navigate to the source directory
-    ```powershell
-    cd path/to/PSScriptAnalyzer
-    ```
-* Building
 
-    You can either build using the `Visual Studio` solution `PSScriptAnalyzer.sln` or build using `PowerShell` specifically for your platform as follows:
-    * The default build is for the currently used version of PowerShell
+- Navigate to the source directory
+
+  ```powershell
+  cd path/to/PSScriptAnalyzer
+  ```
+
+- Building You can either build using the `Visual Studio` solution `PSScriptAnalyzer.sln` or build
+  using `PowerShell` specifically for your platform as follows:
+  - The default build is for the currently used version of PowerShell
+
     ```powershell
     .\build.ps1
     ```
-    * Windows PowerShell version 5.0
+
+  - Windows PowerShell version 5.0
+
     ```powershell
     .\build.ps1 -PSVersion 5
     ```
-    * Windows PowerShell version 4.0
-    ```powershell
-    .\build.ps1 -PSVersion 4
-    ```
-    * Windows PowerShell version 3.0
-    ```powershell
-    .\build.ps1 -PSVersion 3
-    ```
-    * PowerShell Core
-    ```powershell
-    .\build.ps1 -PSVersion 6
-    ```
-* Rebuild documentation since it gets built automatically only the first time
-    ```powershell
-    .\build.ps1 -Documentation
-    ```
-* Build all versions (PowerShell v3, v4, v5, and v6) and documentation
+
+  - PowerShell 7
+
     ```powershell
-    .\build.ps1 -All
+    .\build.ps1 -PSVersion 7
     ```
-* Import the module
-```powershell
-Import-Module .\out\PSScriptAnalyzer\PSScriptAnalyzer.psd1
-```
 
-To confirm installation: run `Get-ScriptAnalyzerRule` in the PowerShell console to obtain the built-in rules
+- Rebuild documentation since it gets built automatically only the first time
 
-* Adding/Removing resource strings
+  ```powershell
+  .\build.ps1 -Documentation
+  ```
 
-For adding/removing resource strings in the `*.resx` files, it is recommended to use `Visual Studio` since it automatically updates the strongly typed `*.Designer.cs` files. The `Visual Studio 2017 Community Edition` is free to use but should you not have/want to use `Visual Studio` then you can either manually adapt the `*.Designer.cs` files or use the `New-StronglyTypedCsFileForResx.ps1` script although the latter is discouraged since it leads to a bad diff of the `*.Designer.cs` files.
+- Build all versions (PowerShell v5 and v7) and documentation
 
-#### Tests
-Pester-based ScriptAnalyzer Tests are located in `path/to/PSScriptAnalyzer/Tests` folder.
+  ```powershell
+  .\build.ps1 -All
+  ```
 
-* Ensure [Pester 4.3.1](https://www.powershellgallery.com/packages/Pester/4.3.1) or higher is installed
-* In the root folder of your local repository, run:
-``` PowerShell
-./build -Test
-```
+- Import the module
 
-To retrieve the results of the run, you can use the tools which are part of the build module (`build.psm1`)
+  ```powershell
+  Import-Module .\out\PSScriptAnalyzer\[version]\PSScriptAnalyzer.psd1
+  ```
 
-```powershell
-Import-Module ./build.psm1
-Get-TestResults
-```
+To confirm installation: run `Get-ScriptAnalyzerRule` in the PowerShell console to obtain the
+built-in rules.
 
-To retrieve only the errors, you can use the following:
+- Adding/Removing resource strings
 
-```powershell
-Import-Module ./build.psm1
-Get-TestFailures
-```
+  For adding/removing resource strings in the `*.resx` files, it is recommended to use
+  `Visual Studio` since it automatically updates the strongly typed `*.Designer.cs` files. The
+  `Visual Studio 2017 Community Edition` is free to use but should you not have/want to use
+  `Visual Studio` then you can either manually adapt the `*.Designer.cs` files or use the
+  `New-StronglyTypedCsFileForResx.ps1` script although the latter is discouraged since it leads to a
+  bad diff of the `*.Designer.cs` files.
 
-[Back to ToC](#table-of-contents)
+### Tests
 
-Parser Errors
-=============
+Pester-based ScriptAnalyzer Tests are located in `path/to/PSScriptAnalyzer/Tests` folder.
 
-In prior versions of ScriptAnalyer, errors found during parsing were reported as errors and diagnostic records were not created.
-ScriptAnalyzer now emits parser errors as diagnostic records in the output stream with other diagnostic records.
+- Ensure [Pester](https://www.powershellgallery.com/packages/Pester) of at least version 5.3 is installed
+- In the root folder of your local repository, run:
 
 ```powershell
-PS> Invoke-ScriptAnalyzer -ScriptDefinition '"b" = "b"; function eliminate-file () { }'
-
-RuleName            Severity   ScriptName Line Message
---------            --------   ---------- ---- -------
-InvalidLeftHandSide ParseError            1    The assignment expression is not
-                                               valid. The input to an
-                                               assignment operator must be an
-                                               object that is able to accept
-                                               assignments, such as a variable
-                                               or a property.
-PSUseApprovedVerbs  Warning               1    The cmdlet 'eliminate-file' uses an
-                                               unapproved verb.
+./build -Test
 ```
 
-The RuleName is set to the `ErrorId` of the parser error.
-
-If ParseErrors would like to be suppressed, do not include it as a value in the `-Severity` parameter.
+To retrieve the results of the run, you can use the tools which are part of the build module (`build.psm1`)
 
 ```powershell
-PS> Invoke-ScriptAnalyzer -ScriptDefinition '"b" = "b"; function eliminate-file () { }' -Severity Warning
-
-RuleName           Severity ScriptName Line Message
---------           -------- ---------- ---- -------
-PSUseApprovedVerbs Warning             1    The cmdlet 'eliminate-file' uses an
-                                            unapproved verb.
-```
-
-
-
-
-Suppressing Rules
-=================
-
-You can suppress a rule by decorating a script/function or script/function parameter with .NET's [SuppressMessageAttribute](https://docs.microsoft.com/dotnet/api/system.diagnostics.codeanalysis.suppressmessageattribute).
-`SuppressMessageAttribute`'s constructor takes two parameters: a category and a check ID. Set the `categoryID` parameter to the name of the rule you want to suppress and set the `checkID` parameter to a null or empty string. You can optionally add a third named parameter with a justification for suppressing the message:
-
-``` PowerShell
-function SuppressMe()
-{
-    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Justification='Just an example')]
-    param()
-
-    Write-Verbose -Message "I'm making a difference!"
-
-}
-```
-
-All rule violations within the scope of the script/function/parameter you decorate will be suppressed.
-
-To suppress a message on a specific parameter, set the `SuppressMessageAttribute`'s `CheckId` parameter to the name of the parameter:
-``` PowerShell
-function SuppressTwoVariables()
-{
-    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'b')]
-    [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideDefaultParameterValue', 'a')]
-    param([string]$a, [int]$b)
-    {
-    }
-}
-```
-
-Use the `SuppressMessageAttribute`'s `Scope` property to limit rule suppression to functions or classes within the attribute's scope.
-
-Use the value `Function` to suppress violations on all functions within the attribute's scope. Use the value `Class` to suppress violations on all classes within the attribute's scope:
-
-``` PowerShell
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSProvideCommentHelp', '', Scope='Function')]
-param(
-)
-
-function InternalFunction
-{
-    param()
-
-    Write-Verbose -Message "I am invincible!"
-}
-```
-
-You can further restrict suppression based on a function/parameter/class/variable/object's name by setting the `SuppressMessageAttribute's` `Target` property to a regular expression or a glob pattern. Few examples are given below.
-
-Suppress `PSAvoidUsingWriteHost` rule violation in `start-bar` and `start-baz` but not in `start-foo` and `start-bam`:
-``` PowerShell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', '', Scope='Function', Target='start-ba[rz]')]
-param()
-function start-foo {
-    write-host "start-foo"
-}
-
-function start-bar {
-    write-host "start-bar"
-}
-
-function start-baz {
-    write-host "start-baz"
-}
-
-function start-bam {
-    write-host "start-bam"
-}
-```
-
-Suppress violations in all the functions:
-``` PowerShell
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', Scope='Function', Target='*')]
-Param()
-```
-
-Suppress violation in `start-bar`, `start-baz` and `start-bam` but not in `start-foo`:
-``` PowerShell
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSAvoidUsingWriteHost', Scope='Function', Target='start-b*')]
-Param()
+Import-Module ./build.psm1
+Get-TestResults
 ```
 
-**Note**: Parser Errors cannot be suppressed via the `SuppressMessageAttribute`
-
-[Back to ToC](#table-of-contents)
-
-Settings Support in ScriptAnalyzer
-==================================
-Settings that describe ScriptAnalyzer rules to include/exclude based on `Severity` can be created and supplied to
-`Invoke-ScriptAnalyzer` using the `Setting` parameter. This enables a user to create a custom configuration for a specific environment. We support the following modes for specifying the settings file.
-
-## Built-in Presets
-ScriptAnalyzer ships a set of built-in presets that can be used to analyze scripts. For example, if the user wants to run *PowerShell Gallery* rules on their module, then they use the following command.
+To retrieve only the errors, you can use the following:
 
 ```powershell
-PS> Invoke-ScriptAnalyzer -Path /path/to/module/ -Settings PSGallery -Recurse
-```
-
-Along with `PSGallery` there are a few other built-in presets, including, `DSC` and `CodeFormatting`, that can be used. These presets can be tab completed for the `Settings` parameter.
-
-## Explicit
-
-The following example excludes two rules from the default set of rules and any rule
-that does not output an Error or Warning diagnostic record.
-
-``` PowerShell
-# PSScriptAnalyzerSettings.psd1
-@{
-    Severity=@('Error','Warning')
-    ExcludeRules=@('PSAvoidUsingCmdletAliases',
-                'PSAvoidUsingWriteHost')
-}
-```
-
-Then invoke that settings file when using `Invoke-ScriptAnalyzer`:
-
-``` PowerShell
-Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1
-```
-
-The next example selects a few rules to execute instead of all the default rules.
-
-``` PowerShell
-# PSScriptAnalyzerSettings.psd1
-@{
-    IncludeRules=@('PSAvoidUsingPlainTextForPassword',
-                'PSAvoidUsingConvertToSecureStringWithPlainText')
-}
-```
-
-Then invoke that settings file:
-``` PowerShell
-Invoke-ScriptAnalyzer -Path MyScript.ps1 -Settings PSScriptAnalyzerSettings.psd1
-```
-
-## Implicit
-If you place a PSScriptAnayzer settings file named `PSScriptAnalyzerSettings.psd1` in your project root, PSScriptAnalyzer will discover it if you pass the project root as the `Path` parameter.
-
-```PowerShell
-Invoke-ScriptAnalyzer -Path "C:\path\to\project" -Recurse
-```
-
-Note that providing settings explicitly takes higher precedence over this implicit mode. Sample settings files are provided [here](https://github.com/PowerShell/PSScriptAnalyzer/tree/master/Engine/Settings).
-
-[Back to ToC](#table-of-contents)
-
-ScriptAnalyzer as a .NET library
-================================
-
-ScriptAnalyzer engine and functionality can now be directly consumed as a library.
-
-Here are the public interfaces:
-``` c#
-using Microsoft.Windows.PowerShell.ScriptAnalyzer;
-
-public void Initialize(System.Management.Automation.Runspaces.Runspace runspace,
-Microsoft.Windows.PowerShell.ScriptAnalyzer.IOutputWriter outputWriter,
-[string[] customizedRulePath = null],
-[string[] includeRuleNames = null],
-[string[] excludeRuleNames = null],
-[string[] severity = null],
-[bool suppressedOnly = false],
-[string profile = null])
-
-public System.Collections.Generic.IEnumerable<DiagnosticRecord> AnalyzePath(string path,
-    [bool searchRecursively = false])
-
-public System.Collections.Generic.IEnumerable<IRule> GetRule(string[] moduleNames, string[] ruleNames)
+Import-Module ./build.psm1
+Get-TestFailures
 ```
 
 [Back to ToC](#table-of-contents)
 
-Violation Correction
-====================
-
-Some violations can be fixed by replacing the violation causing content with a suggested alternative. You can use the `-Fix` switch to automatically apply the suggestions. Since `Invoke-ScriptAnalyzer` implements `SupportsShouldProcess`, you can additionally use `-WhatIf` or `-Confirm` to find out which corrections would be applied. It goes without saying that you should use source control when applying those corrections since some some of them such as the one for `AvoidUsingPlainTextForPassword` might require additional script modifications that cannot be made automatically. Should your scripts be sensitive to encoding you should also check that because the initial encoding can not be preserved in all cases.
+## Using PSScriptAnalyzer
 
-The initial motivation behind having the `SuggestedCorrections` property on the `ErrorRecord` (which is how the `-Fix` switch works under the hood) was to enable quick-fix like scenarios in editors like VSCode, Sublime, etc. At present, we provide valid `SuggestedCorrection` only for the following rules, while gradually adding this feature to more rules.
+The documentation in this section can be found in
+[Using PSScriptAnalyzer](https://learn.microsoft.com/powershell/utility-modules/psscriptanalyzer/using-scriptanalyzer).
 
-- AvoidAlias.cs
-- AvoidUsingPlainTextForPassword.cs
-- MisleadingBacktick.cs
-- MissingModuleManifestField.cs
-- UseToExportFieldsInManifest.cs
-
-[Back to ToC](#table-of-contents)
-
-Project Management Dashboard
-============================
-You can track issues, pull requests, backlog items here:
-
-[![Stories in progress](https://badge.waffle.io/PowerShell/PSScriptAnalyzer.png?label=In%20Progress&title=In%20Progress)](https://waffle.io/PowerShell/PSScriptAnalyzer)
-
-[![Stories in ready](https://badge.waffle.io/PowerShell/PSScriptAnalyzer.png?label=ready&title=Ready)](https://waffle.io/PowerShell/PSScriptAnalyzer)
-
-[![Stories in backlog](https://badge.waffle.io/PowerShell/PSScriptAnalyzer.png?label=BackLog&title=BackLog)](https://waffle.io/PowerShell/PSScriptAnalyzer)
-
-Throughput Graph
-
-[![Throughput Graph](https://graphs.waffle.io/powershell/psscriptanalyzer/throughput.svg)](https://waffle.io/powershell/psscriptanalyzer/metrics)
-
-[Back to ToC](#table-of-contents)
-
-Contributions are welcome
-==============================
+## Contributions are welcome
 
 There are many ways to contribute:
 
-1. Open a new bug report, feature request or just ask a question by opening a new issue [here]( https://github.com/PowerShell/PSScriptAnalyzer/issues/new/choose).
-2. Participate in the discussions of [issues](https://github.com/PowerShell/PSScriptAnalyzer/issues), [pull requests](https://github.com/PowerShell/PSScriptAnalyzer/pulls) and verify/test fixes or new features.
-3. Submit your own fixes or features as a pull request but please discuss it beforehand in an issue if the change is substantial.
+1. Open a new bug report, feature request or just ask a question by opening a
+   [new issue](https://github.com/PowerShell/PSScriptAnalyzer/issues/new/choose).
+2. Participate in the discussions of
+   [issues](https://github.com/PowerShell/PSScriptAnalyzer/issues),
+   [pull requests](https://github.com/PowerShell/PSScriptAnalyzer/pulls) and test fixes or new
+   features.
+3. Submit your own fixes or features as a pull request but please discuss it beforehand in an issue.
 4. Submit test cases.
 
 [Back to ToC](#table-of-contents)
 
-Creating a Release
-================
+## Creating a Release
 
-- Update changelog (`changelog.md`) with the new version number and change set. When updating the changelog please follow the same pattern as that of previous change sets (otherwise this may break the next step).
+- Update changelog (`changelog.md`) with the new version number and change set. When updating the
+  changelog please follow the same pattern as that of previous change sets (otherwise this may break
+  the next step).
 - Import the ReleaseMaker module and execute `New-Release` cmdlet to perform the following actions.
   - Update module manifest (engine/PSScriptAnalyzer.psd1) with the new version number and change set
   - Update the version number in `Engine/Engine.csproj` and `Rules/Rules.csproj`
   - Create a release build in `out/`
 
 ```powershell
-    PS> Import-Module .\Utils\ReleaseMaker.psm1
-    PS> New-Release
+Import-Module .\Utils\ReleaseMaker.psm1
+New-Release
 ```
 
-- Sign the binaries and PowerShell files in the release build and publish the module to [PowerShell Gallery](www.powershellgallery.com).
+- Sign the binaries and PowerShell files in the release build and publish the module to
+  [PowerShell Gallery](https://www.powershellgallery.com).
 - Draft a new release on github and tag `master` with the new version number.
 
 [Back to ToC](#table-of-contents)
 
-Code of Conduct
-===============
-This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/). For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
+## Code of Conduct
+
+Please see our [Code of Conduct](CODE_OF_CONDUCT.md) before participating in this project.
+
+[Back to ToC](#table-of-contents)
+
+## Security Policy
+
+For any security issues, please see our [Security Policy](SECURITY.md).
 
 [Back to ToC](#table-of-contents)
diff --git a/RuleDocumentation/AlignAssignmentStatement.md b/RuleDocumentation/AlignAssignmentStatement.md
deleted file mode 100644
index 1462bd035..000000000
--- a/RuleDocumentation/AlignAssignmentStatement.md
+++ /dev/null
@@ -1,48 +0,0 @@
-﻿# AlignAssignmentStatement
-
-**Severity Level: Warning**
-
-## Description
-
-Consecutive assignment statements are more readable if they are aligned. By aligned, we imply that the `equal` sign for all the assignment statements should be in the same column.
-
-The rule looks for key (property) value pairs in a hashtable (DSC configuration) to check if they are aligned or not. Consider the following example in which the key value pairs are not aligned.
-
-```powershell
-$hashtable = @{
-    property1 = "value"
-    anotherProperty = "another value"
-}
-```
-
-Alignment in this case would look like the following.
-
-```powershell
-$hashtable = @{
-    property1       = "value"
-    anotherProperty = "another value"
-}
-```
-
-The rule will ignore hashtables in which the assignment statements are on the same line. For example, the rule will ignore `$h = {a = 1; b = 2}`.
-
-## Configuration
-
-```powershell
-    Rules = @{
-        PSAlignAssignmentStatement = @{
-            Enable = $true
-            CheckHashtable = $true
-        }
-    }
-```
-
-### Parameters
-
-#### Enable: bool (Default value is `$false`)
-
-Enable or disable the rule during ScriptAnalyzer invocation.
-
-#### CheckHashtable: bool (Default value is `$false`)
-
-Enforce alignment of assignment statements in a hashtable and in a DSC Configuration. There is only one switch for hasthable and DSC configuration because the property value pairs in a DSC configuration are parsed as key value pairs of a hashtable.
diff --git a/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md b/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md
deleted file mode 100644
index d9616e418..000000000
--- a/RuleDocumentation/AvoidAssignmentToAutomaticVariable.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# AvoidAssignmentToAutomaticVariable
-
-**Severity Level: Warning**
-
-## Description
-
-`PowerShell` exposes some of its built-in variables that are known as automatic variables. Many of them are read-only and PowerShell would throw an error when trying to assign an value on those. Other automatic variables should only be assigned to in certain special cases to achieve a certain effect as a special technique.
-
-To understand more about automatic variables, see ```Get-Help about_Automatic_Variables```.
-
-## How
-
-Use variable names in functions or their parameters that do not conflict with automatic variables.
-
-## Example
-
-### Wrong
-
-The variable `$Error` is an automatic variables that exists in the global scope and should therefore never be used as a variable or parameter name.
-
-``` PowerShell
-function foo($Error){ }
-```
-
-``` PowerShell
-function Get-CustomErrorMessage($ErrorMessage){ $Error = "Error occurred: $ErrorMessage" }
-```
-
-### Correct
-
-``` PowerShell
-function Get-CustomErrorMessage($ErrorMessage){ $FinalErrorMessage = "Error occurred: $ErrorMessage" }
-```
diff --git a/RuleDocumentation/AvoidDefaultValueSwitchParameter.md b/RuleDocumentation/AvoidDefaultValueSwitchParameter.md
deleted file mode 100644
index bd1f3018d..000000000
--- a/RuleDocumentation/AvoidDefaultValueSwitchParameter.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# AvoidDefaultValueSwitchParameter
-
-**Severity Level: Warning**
-
-## Description
-
-Switch parameters for commands should default to false.
-
-## How
-
-Change the default value of the switch parameter to be false.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Test-Script
-{
-    [CmdletBinding()]
-    Param
-    (
-        [String]
-        $Param1,
-
-        [switch]
-        $Switch=$True
-    )
-    ...
-}
-```
-
-### Correct
-
-``` PowerShell
-function Test-Script
-{
-    [CmdletBinding()]
-    Param
-    (
-        [String]
-        $Param1,
-
-        [switch]
-        $Switch=$False
-    )
-    ...
-}
-```
diff --git a/RuleDocumentation/AvoidGlobalAliases.md b/RuleDocumentation/AvoidGlobalAliases.md
deleted file mode 100644
index dd4bd3807..000000000
--- a/RuleDocumentation/AvoidGlobalAliases.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# AvoidGlobalAliases
-
-**Severity Level: Warning**
-
-## Description
-
-Globally scoped aliases override existing aliases within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules and scripts.
-
-To understand more about scoping, see ```Get-Help about_Scopes```.
-
-**NOTE** This rule is not available in PowerShell version 3 and 4 due to the `StaticParameterBinder.BindCommand` API that the rule uses internally.
-
-## How
-
-Use other scope modifiers for new aliases.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-New-Alias -Name Name -Value Value -Scope "Global"
-```
-
-### Correct
-
-``` PowerShell
-New-Alias -Name Name1 -Value Value
-```
diff --git a/RuleDocumentation/AvoidGlobalFunctions.md b/RuleDocumentation/AvoidGlobalFunctions.md
deleted file mode 100644
index a28c87f69..000000000
--- a/RuleDocumentation/AvoidGlobalFunctions.md
+++ /dev/null
@@ -1,28 +0,0 @@
-# AvoidGlobalFunctions
-
-**Severity Level: Warning**
-
-## Description
-
-Globally scoped functions override existing functions within the sessions with matching names. This name collision can cause difficult to debug issues for consumers of modules.  
-
-
-To understand more about scoping, see ```Get-Help about_Scopes```.
-
-## How
-
-Use other scope modifiers for functions.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function global:functionName {}
-```
-
-### Correct
-
-``` PowerShell
-function functionName {} 
-```
diff --git a/RuleDocumentation/AvoidGlobalVars.md b/RuleDocumentation/AvoidGlobalVars.md
deleted file mode 100644
index 12e02b92b..000000000
--- a/RuleDocumentation/AvoidGlobalVars.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# AvoidGlobalVars
-
-**Severity Level: Warning**
-
-## Description
-
-A variable is a unit of memory in which values are stored. Windows PowerShell controls access to variables, functions, aliases, and drives through a mechanism known as scoping.
-Variables and functions that are present when Windows PowerShell starts have been created in the global scope.
-
-Globally scoped variables include:
-* Automatic variables
-* Preference variables
-* Variables, aliases, and functions that are in your Windows PowerShell profiles
-
-To understand more about scoping, see ```Get-Help about_Scopes```.
-
-## How
-
-Use other scope modifiers for variables.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-$Global:var1 = $null
-function Test-NotGlobal ($var)
-{
-	$a = $var + $var1
-}
-```
-
-### Correct
-
-``` PowerShell
-$var1 = $null
-function Test-NotGlobal ($var1, $var2)
-{
-		$a = $var1 + $var2
-}
-```
diff --git a/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md b/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md
deleted file mode 100644
index a9e870660..000000000
--- a/RuleDocumentation/AvoidNullOrEmptyHelpMessageAttribute.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# AvoidNullOrEmptyHelpMessageAttribute
-
-**Severity Level: Warning**
-
-## Description
-
-The value of the `HelpMessage` attribute should not be an empty string or a null value as this causes PowerShell's interpreter to throw an mirror when executing the
-function or cmdlet.
-
-## How
-
-Specify a value for the `HelpMessage` attribute.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Function BadFuncEmptyHelpMessageEmpty
-{
-	Param(
-		[Parameter(HelpMessage='')]
-		[String]
-		$Param
-	)
-
-	$Param
-}
-
-Function BadFuncEmptyHelpMessageNull
-{
-	Param(
-		[Parameter(HelpMessage=$null)]
-		[String]
-		$Param
-	)
-
-	$Param
-}
-
-Function BadFuncEmptyHelpMessageNoAssignment
-{
-	Param(
-		[Parameter(HelpMessage)]
-		[String]
-		$Param
-	)
-
-	$Param
-}
-```
-
-### Correct
-
-``` PowerShell
-Function GoodFuncHelpMessage
-{
-	Param(
-		[Parameter(HelpMessage='This is helpful')]
-		[String]
-		$Param
-	)
-
-	$Param
-}
-```
diff --git a/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md b/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md
deleted file mode 100644
index 03d6d1ca7..000000000
--- a/RuleDocumentation/AvoidOverwritingBuiltInCmdlets.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# AvoidOverwritingBuiltInCmdlets
-
-**Severity Level: Warning**
-
-## Description
-
-This rule flags cmdlets that are available in a given edition/version of PowerShell on a given operating system which are overwritten by a function declaration. It works by comparing function declarations against a set of whitelists which ship with PSScriptAnalyzer. These whitelist files are used by other PSScriptAnalyzer rules. More information can be found in the documentation for the [UseCompatibleCmdlets](./UseCompatibleCmdlets.md) rule.
-
-## Configuration
-
-To enable the rule to check if your script is compatible on PowerShell Core on Windows, put the following your settings file.
-
-
-```PowerShell
-@{
-    'Rules' = @{
-        'PSAvoidOverwritingBuiltInCmdlets' = @{
-            'PowerShellVersion' = @("core-6.1.0-windows")
-        }
-    }
-}
-```
-
-### Parameters
-
-#### PowerShellVersion
-
-The parameter `PowerShellVersion` is a list of whitelists that ship with PSScriptAnalyzer.
-
-**Note**: The default value for `PowerShellVersion` is `"core-6.1.0-windows"` if PowerShell 6 or later is installed, and `"desktop-5.1.14393.206-windows"` if it is not.
-
-Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major and minor versions of PowerShell are supplied. One can also create a custom settings file as well with the [New-CommandDataFile.ps1](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Utils/New-CommandDataFile.ps1) script and use it by placing the created `JSON` into the `Settings` folder of the `PSScriptAnalyzer` module installation folder, then the `PowerShellVersion` parameter is just its file name (that can also be changed if desired).
-Note that the `core-6.0.2-*` files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0 reached it's end of life.
diff --git a/RuleDocumentation/AvoidTrailingWhitespace.md b/RuleDocumentation/AvoidTrailingWhitespace.md
deleted file mode 100644
index 8a5a1e189..000000000
--- a/RuleDocumentation/AvoidTrailingWhitespace.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# AvoidTrailingWhitespace
-
-**Severity Level: Information**
-
-## Description
-
-Lines should not end with whitespace characters.  This can cause problems with the line-continuation backtick, and also clutters up future commits to source control.
diff --git a/RuleDocumentation/AvoidUsingCmdletAliases.md b/RuleDocumentation/AvoidUsingCmdletAliases.md
deleted file mode 100644
index 39d7437d0..000000000
--- a/RuleDocumentation/AvoidUsingCmdletAliases.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# AvoidUsingCmdletAliases
-
-**Severity Level: Warning**
-
-## Description
-
-An alias is an alternate name or nickname for a CMDLet or for a command element, such as a function, script, file, or executable file.
-You can use the alias instead of the command name in any Windows PowerShell commands. There are also implicit aliases: When PowerShell cannot find the cmdlet name, it will try to append `Get-` to the command as a last resort before, therefore e.g. `verb` will excute `Get-Verb`.
-
-Every PowerShell author learns the actual command names, but different authors learn and use different aliases. Aliases can make code difficult to read, understand and
-impact availability.
-
-When developing PowerShell content that will potentially need to be maintained over time, either by the original author or others, you should use full command names.
-
-The use of full command names also allows for syntax highlighting in sites and applications like GitHub and Visual Studio Code.
-
-## How to Fix
-
-Use the full cmdlet name and not an alias.
-
-## Alias Whitelist
-
-To prevent `PSScriptAnalyzer` from flagging your preferred aliases, create a whitelist of the aliases in your settings file and point `PSScriptAnalyzer` to use the settings file. For example, to disable `PSScriptAnalyzer` from flagging `cd`, which is an alias of `Set-Location`, set the settings file content to the following.
-
-```PowerShell
-# PSScriptAnalyzerSettings.psd1
-
-@{
-    'Rules' = @{
-        'PSAvoidUsingCmdletAliases' = @{
-            'Whitelist' = @('cd')
-        }
-    }
-}
-```
-
-## Example
-
-### Wrong?
-
-``` PowerShell
-gps | Where-Object {$_.WorkingSet -gt 20000000}
-```
-
-### Correct:
-
-``` PowerShell
-Get-Process | Where-Object {$_.WorkingSet -gt 20000000}
-```
diff --git a/RuleDocumentation/AvoidUsingComputerNameHardcoded.md b/RuleDocumentation/AvoidUsingComputerNameHardcoded.md
deleted file mode 100644
index 740d24595..000000000
--- a/RuleDocumentation/AvoidUsingComputerNameHardcoded.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# AvoidUsingComputerNameHardcoded
-
-**Severity Level: Error**
-
-## Description
-
-The names of computers should never be hard coded as this will expose sensitive information. The `ComputerName` parameter should never have a hard coded value.
-
-## How
-
-Remove hard coded computer names.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Function Invoke-MyRemoteCommand ()
-{
-	Invoke-Command -Port 343 -ComputerName "hardcoderemotehostname"
-}
-```
-
-### Correct
-
-``` PowerShell
-Function Invoke-MyCommand ($ComputerName)
-{
-	Invoke-Command -Port 343 -ComputerName $ComputerName
-}
-```
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Function Invoke-MyLocalCommand ()
-{
-	Invoke-Command -Port 343 -ComputerName "hardcodelocalhostname"
-}
-```
-
-### Correct
-
-``` PowerShell
-Function Invoke-MyLocalCommand ()
-{
-	Invoke-Command -Port 343 -ComputerName $env:COMPUTERNAME
-}
-```
diff --git a/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md b/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md
deleted file mode 100644
index e6af00af1..000000000
--- a/RuleDocumentation/AvoidUsingConvertToSecureStringWithPlainText.md
+++ /dev/null
@@ -1,32 +0,0 @@
-# AvoidUsingConvertToSecureStringWithPlainText
-
-**Severity Level: Error**
-
-## Description
-
-The use of the `AsPlainText` parameter with the `ConvertTo-SecureString` command can expose secure information.
-
-## How
-
-Use a standard encrypted variable to perform any SecureString conversions.
-
-## Recommendations
-
-If you do need an ability to retrieve the password from somewhere without prompting the user, consider using Windows Credential Store as used in the BetterCredentials module ( https://www.powershellgallery.com/packages/BetterCredentials/4.4/Content/BetterCredentials.psm1). If that does not work, consider using Azure KeyVault (https://azure.microsoft.com/en-us/services/key-vault/) or AWS KMS (https://aws.amazon.com/kms/).
-
-## Example
-
-### Wrong
-
-``` PowerShell
-$UserInput = Read-Host "Please enter your secure code"
-$EncryptedInput = ConvertTo-SecureString -String $UserInput -AsPlainText -Force
-```
-
-### Correct
-
-``` PowerShell
-$SecureUserInput = Read-Host "Please enter your secure code" -AsSecureString
-$EncryptedInput = ConvertFrom-SecureString -String $SecureUserInput
-$SecureString = Convertto-SecureString -String $EncryptedInput
-```
diff --git a/RuleDocumentation/AvoidUsingEmptyCatchBlock.md b/RuleDocumentation/AvoidUsingEmptyCatchBlock.md
deleted file mode 100644
index b08930259..000000000
--- a/RuleDocumentation/AvoidUsingEmptyCatchBlock.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# AvoidUsingEmptyCatchBlock
-
-**Severity Level: Warning**
-
-## Description
-
-Empty catch blocks are considered a poor design choice as they result in the errors occurring in a `try` block not being acted upon.
-
-While this does not inherently lead to issues, they should be avoided wherever possible.
-
-## How
-
-Use ```Write-Error``` or ```throw``` statements within the catch block.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-try
-{
-	1/0
-}
-catch [DivideByZeroException]
-{
-}
-```
-
-### Correct
-
-``` PowerShell
-try
-{
-	1/0
-}
-catch [DivideByZeroException]
-{
-	Write-Error "DivideByZeroException"
-}
-
-try
-{
-	1/0
-}
-catch [DivideByZeroException]
-{
-	Throw "DivideByZeroException"
-}
-```
diff --git a/RuleDocumentation/AvoidUsingInvokeExpression.md b/RuleDocumentation/AvoidUsingInvokeExpression.md
deleted file mode 100644
index 08329df75..000000000
--- a/RuleDocumentation/AvoidUsingInvokeExpression.md
+++ /dev/null
@@ -1,27 +0,0 @@
-# AvoidUsingInvokeExpression
-
-**Severity Level: Warning**
-
-## Description
-
-Care must be taken when using the `Invoke-Expression` command. The `Invoke-Expression` executes the specified string and returns the results.
-
-Code injection into your application or script can occur if the expression passed as a string includes any data provided from the user.
-
-## How
-
-Remove the use of `Invoke-Expression`.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Invoke-Expression "Get-Process"
-```
-
-### Correct
-
-``` PowerShell
-Get-Process
-```
diff --git a/RuleDocumentation/AvoidUsingPositionalParameters.md b/RuleDocumentation/AvoidUsingPositionalParameters.md
deleted file mode 100644
index fc31c0de7..000000000
--- a/RuleDocumentation/AvoidUsingPositionalParameters.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# AvoidUsingPositionalParameters
-
-** Severity Level: Information **
-
-## Description
-
-When developing PowerShell content that will potentially need to be maintained over time, either by the original author or others, you should use full command names and parameter names.
-
-The use of positional parameters can reduce the readability of code and potentially introduce errors. Furthermore it is possible that future signatures of a Cmdlet could change in a way that would break existing scripts if calls to the Cmdlet rely on the position of the parameters.
-
-For simple Cmdlets with only a few positional parameters, the risk is much smaller and in order for this rule to be not too noisy, this rule gets only triggered when there are 3 or more parameters supplied. A simple example where the risk of using positional parameters is negligible, is e.g. `Test-Path $Path`.
-
-## How
-
-Use full parameter names when calling commands.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Get-Command Get-ChildItem Microsoft.PowerShell.Management System.Management.Automation.Cmdlet
-```
-
-### Correct
-
-``` PowerShell
-Get-Command -Noun Get-ChildItem -Module Microsoft.PowerShell.Management -ParameterType System.Management.Automation.Cmdlet
-```
diff --git a/RuleDocumentation/AvoidUsingWMICmdlet.md b/RuleDocumentation/AvoidUsingWMICmdlet.md
deleted file mode 100644
index 379c94822..000000000
--- a/RuleDocumentation/AvoidUsingWMICmdlet.md
+++ /dev/null
@@ -1,48 +0,0 @@
-# AvoidUsingWMICmdlet
-
-**Severity Level: Warning**
-
-## Description
-
-As of PowerShell 3.0, the CIM cmdlets should be used over the WMI cmdlets.
-
-The following cmdlets should not be used:
-* `Get-WmiObject`
-* `Remove-WmiObject`
-* `Invoke-WmiObject`
-* `Register-WmiEvent`
-* `Set-WmiInstance`
-
-Use the following cmdlets instead:
-* `Get-CimInstance`
-* `Remove-CimInstance`
-* `Invoke-CimMethod`
-* `Register-CimIndicationEvent`
-* `Set-CimInstance`
-
-The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, allowing for the management of Windows and non-Windows operating systems.
-
-## How
-
-Change to the equivalent CIM based cmdlet.
-* `Get-WmiObject` -> `Get-CimInstance`
-* `Remove-WmiObject` -> `Remove-CimInstance`
-* `Invoke-WmiObject` -> `Invoke-CimMethod`
-* `Register-WmiEvent` -> `Register-CimIndicationEvent`
-* `Set-WmiInstance` -> `Set-CimInstance`
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Get-WmiObject -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-WmiObject
-Invoke-WmiMethod ?Class Win32_Process ?Name "Create" ?ArgumentList @{ CommandLine = "notepad.exe" }
-```
-
-### Correct
-
-``` PowerShell
-Get-CimInstance -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-CIMInstance
-Invoke-CimMethod ?ClassName Win32_Process ?MethodName "Create" ?Arguments @{ CommandLine = "notepad.exe" }
-```
diff --git a/RuleDocumentation/AvoidUsingWriteHost.md b/RuleDocumentation/AvoidUsingWriteHost.md
deleted file mode 100644
index e109be908..000000000
--- a/RuleDocumentation/AvoidUsingWriteHost.md
+++ /dev/null
@@ -1,46 +0,0 @@
-# AvoidUsingWriteHost
-
-**Severity Level: Warning**
-
-## Description
-
-The use of `Write-Host` is greatly discouraged unless in the use of commands with the `Show` verb. The `Show` verb explicitly means "show on the screen, with no
-other possibilities".
-
-Commands with the `Show` verb do not have this check applied.
-
-## How
-
-Replace `Write-Host` with `Write-Output` or `Write-Verbose` depending on whether the intention is logging or returning one or multiple objects.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Get-MeaningOfLife
-{
-	...
-	Write-Host "Computing the answer to the ultimate question of life, the universe and everything"
-	...
-	Write-Host 42
-}
-```
-
-### Correct
-
-``` PowerShell
-function Get-MeaningOfLife
-{
-	[CmdletBinding()]Param() # to make it possible to set the VerbosePreference when calling the function
-	...
-	Write-Verbose "Computing the answer to the ultimate question of life, the universe and everything"
-	...
-	Write-Output 42
-}
-
-function Show-Something
-{
-    Write-Host "show something on screen";
-}
-```
diff --git a/RuleDocumentation/DSCDscExamplesPresent.md b/RuleDocumentation/DSCDscExamplesPresent.md
deleted file mode 100644
index 914a76107..000000000
--- a/RuleDocumentation/DSCDscExamplesPresent.md
+++ /dev/null
@@ -1,51 +0,0 @@
-# DscExamplesPresent
-
-**Severity Level: Information**
-
-## Description
-
-Checks that DSC examples for given resource are present.
-
-## How
-
-To fix a violation of this rule, please make sure Examples directory is present:
-* For non-class based resources it should exist at the same folder level as DSCResources folder.
-* For class based resources it should be present at the same folder level as resource psm1 file.
-
-Examples folder should contain sample configuration for given resource - file name should contain resource's name.
-
-## Example
-
-### Non-class based resource
-
-Let's assume we have non-class based resource with a following file structure:
-* xAzure
-  * DSCResources
-    * MSFT_xAzureSubscription
-      * MSFT_xAzureSubscription.psm1
-      * MSFT_xAzureSubscription.schema.mof
-
-In this case, to fix this warning, we should add examples in a following way:
-* xAzure
-  * DSCResources
-    * MSFT_xAzureSubscription
-      * MSFT_xAzureSubscription.psm1
-      * MSFT_xAzureSubscription.schema.mof
-  * Examples
-    * MSFT_xAzureSubscription_AddSubscriptionExample.ps1
-    * MSFT_xAzureSubscription_RemoveSubscriptionExample.ps1
-
-### Class based resource
-
-Let's assume we have class based resource with a following file structure:
-* MyDscResource
-    * MyDscResource.psm1
-    * MyDscResource.psd1
-
-In this case, to fix this warning, we should add examples in a following way:
-* MyDscResource
-    * MyDscResource.psm1
-    * MyDscResource.psd1
-    * Examples
-      * MyDscResource_Example1.ps1
-      * MyDscResource_Example2.ps1
diff --git a/RuleDocumentation/DSCDscTestsPresent.md b/RuleDocumentation/DSCDscTestsPresent.md
deleted file mode 100644
index a988d6b5d..000000000
--- a/RuleDocumentation/DSCDscTestsPresent.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# DscTestsPresent
-
-**Severity Level: Information**
-
-## Description
-
-Checks that DSC tests for given resource are present.
-
-## How
-
-To fix a violation of this rule, please make sure Tests directory is present:
-* For non-class based resources it should exist at the same folder level as DSCResources folder.
-* For class based resources it should be present at the same folder level as resource psm1 file.
-
-Tests folder should contain test script for given resource - file name should contain resource's name.
-
-## Example
-
-### Non-class based resource
-
-Let's assume we have non-class based resource with a following file structure:
-* xAzure
-  * DSCResources
-    * MSFT_xAzureSubscription
-      * MSFT_xAzureSubscription.psm1
-      * MSFT_xAzureSubscription.schema.mof
-
-In this case, to fix this warning, we should add tests in a following way:
-* xAzure
-  * DSCResources
-    * MSFT_xAzureSubscription
-      * MSFT_xAzureSubscription.psm1
-      * MSFT_xAzureSubscription.schema.mof
-  * Tests
-    * MSFT_xAzureSubscription_Tests.ps1
-
-### Class based resource
-
-Let's assume we have class based resource with a following file structure:
-* MyDscResource
-    * MyDscResource.psm1
-    * MyDscResource.psd1
-
-In this case, to fix this warning, we should add tests in a following way:
-* MyDscResource
-    * MyDscResource.psm1
-    * MyDscResource.psd1
-    * Tests
-      * MyDscResource_Tests.ps1
diff --git a/RuleDocumentation/PossibleIncorrectComparisonWithNull.md b/RuleDocumentation/PossibleIncorrectComparisonWithNull.md
deleted file mode 100644
index bfcde4672..000000000
--- a/RuleDocumentation/PossibleIncorrectComparisonWithNull.md
+++ /dev/null
@@ -1,58 +0,0 @@
-# PossibleIncorrectComparisonWithNull
-
-**Severity Level: Warning**
-
-## Description
-
-To ensure that PowerShell performs comparisons correctly, the `$null` element should be on the left side of the operator.
-
-There are a number of reasons why this should occur:
-* `$null` is a scalar. When the input (left side) to an operator is a scalar value, comparison operators return a Boolean value. When the input is a collection of values, the comparison operators return any matching values, or an empty array if there are no matches in the collection. The only way to reliably check if a value is `$null` is to place `$null` on the left side of the operator so that a scalar comparison is performed.
-* PowerShell will perform type casting left to right, resulting in incorrect comparisons when `$null` is cast to other scalar types.
-
-## How
-
-Move `$null` to the left side of the comparison.
-
-## Example
-
-### Wrong?
-
-``` PowerShell
-function Test-CompareWithNull
-{
-	if ($DebugPreference -eq $null)
-	{
-	}
-}
-```
-
-### Correct
-
-``` PowerShell
-function Test-CompareWithNull
-{
-	if ($null -eq $DebugPreference)
-	{
-	}
-}
-```
-
-## Try it Yourself
-
-``` PowerShell
-# Both expressions below return 'false' because the comparison does not return an object and therefore the if statement always falls through:
-if (@() -eq $null) { 'true' } else { 'false' }
-if (@() -ne $null) { 'true' }else { 'false' } 
-```
-This is just the way how the comparison operator works (by design) but as demonstrated this can lead to unintuitive behaviour, especially when the intent is just a null check. The following example demonstrated the designed behaviour of the comparison operator, whereby for each element in the collection, the comparison with the right hand side is done, and where true, that element in the collection is returned.
-``` PowerShell
-PS> 1,2,3,1,2 -eq $null
-PS> 1,2,3,1,2 -eq 1    
-1
-1
-PS> (1,2,3,1,2 -eq $null).count            
-0
-PS> (1,2,$null,3,$null,1,2 -eq $null).count
-2
-```
diff --git a/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md b/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md
deleted file mode 100644
index 5089c103a..000000000
--- a/RuleDocumentation/PossibleIncorrectUsageOfAssignmentOperator.md
+++ /dev/null
@@ -1,54 +0,0 @@
-# PossibleIncorrectUsageOfAssignmentOperator
-
-**Severity Level: Information**
-
-## Description
-
-In many programming languages, the equality operator is denoted as `==` or `=` in many programming languages, but `PowerShell` uses `-eq`. Therefore it can easily happen that the wrong operator is used unintentionally and this rule catches a few special cases where the likelihood of that is quite high.
-
-The rule looks for usages of `==` and `=` operators inside `if`, `else if`, `while` and `do-while` statements but it will not warn if any kind of command or expression is used at the right hand side as this is probably by design.
-
-## Example
-
-### Wrong
-
-```` PowerShell
-if ($a = $b)
-{
-    ...
-}
-````
-
-```` PowerShell
-if ($a == $b)
-{
-
-}
-````
-
-### Correct
-
-```` PowerShell
-if ($a -eq $b) # Compare $a with $b
-{
-    ...
-}
-````
-
-```` PowerShell
-if ($a = Get-Something) # Only execute action if command returns something and assign result to variable
-{
-    Do-SomethingWith $a
-}
-````
-
-## Implicit suppresion using Clang style
-
-There are some rare cases where assignment of variable inside an if statement is by design. Instead of suppression the rule, one can also signal that assignment was intentional by wrapping the expression in extra parenthesis. An exception for this is when `$null` is used on the LHS is used because there is no use case for this.
-
-```` powershell
-if (($shortVariableName = $SuperLongVariableName['SpecialItem']['AnotherItem']))
-{
-    ...
-}
-````
\ No newline at end of file
diff --git a/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md b/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md
deleted file mode 100644
index 6af16c0a7..000000000
--- a/RuleDocumentation/PossibleIncorrectUsageOfRedirectionOperator.md
+++ /dev/null
@@ -1,29 +0,0 @@
-# PossibleIncorrectUsageOfRedirectionOperator
-
-**Severity Level: Information**
-
-## Description
-
-In many programming languages, the comparison operator for 'greater than' is `>` but `PowerShell` uses `-gt` for it and `-ge` (greater or equal) for `>=`. Therefore it can easily happen that the wrong operator is used unintentionally and this rule catches a few special cases where the likelihood of that is quite high.
-
-The rule looks for usages of `>` or `>=` operators inside if, elseif, while and do-while statements because this is likely going to be unintentional usage.
-
-## Example
-
-### Wrong
-
-```` PowerShell
-if ($a > $b)
-{
-    ...
-}
-````
-
-### Correct
-
-```` PowerShell
-if ($a -gt $b)
-{
-    ...
-}
-````
\ No newline at end of file
diff --git a/RuleDocumentation/ProvideCommentHelp.md b/RuleDocumentation/ProvideCommentHelp.md
deleted file mode 100644
index bfd922c63..000000000
--- a/RuleDocumentation/ProvideCommentHelp.md
+++ /dev/null
@@ -1,106 +0,0 @@
-# ProvideCommentHelp
-
-**Severity Level: Info**
-
-## Description
-
-Comment based help should be provided for all PowerShell commands. This test only checks for the presence of comment based help and not on the validity or format.
-
-For assistance on comment based help, use the command ```Get-Help about_comment_based_help``` or the article, "How to Write Cmdlet Help" (https://go.microsoft.com/fwlink/?LinkID=123415).
-
-## Configuration
-
-```powershell
-Rules = @{
-    PSProvideCommentHelp = @{
-        Enable = $true
-        ExportedOnly = $false
-        BlockComment = $true
-        VSCodeSnippetCorrection = $false
-        Placement = "before"
-    }
-}
-```
-
-### Parameters
-
-#### Enable: bool (Default valus is `$true`)
-
-Enable or disable the rule during ScriptAnalyzer invocation.
-
-#### ExportedOnly: bool (Default value is `$true`)
-
-If enabled, throw violation only on functions/cmdlets that are exported using the 'Export-ModuleMember' cmdlet.
-
-#### BlockComment: bool (Default value is `$true`)
-
-If enabled, returns comment help in block comment style, i.e., `<#...#>`. Otherwise returns
-comment help in line comment style, i.e., each comment line starts with `#`.
-
-#### VSCodeSnippetCorrection: bool (Default value is `$false`)
-
-If enabled, returns comment help in vscode snippet format.
-
-#### Placement: string (Default value is `before`)
-
-Represents the position of comment help with respect to the function definition.
-
-Possible values are: `before`, `begin` and `end`. If any invalid value is given, the
-property defaults to `before`.
-
-`before` means the help is placed before the function definition.
-`begin` means the help is placed at the begining of the function definition body.
-`end` means the help is places the end of the function definition body.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Get-File
-{
-    [CmdletBinding()]
-    Param
-    (
-        ...
-    )
-
-}
-```
-
-### Correct
-
-``` PowerShell
-<#
-.Synopsis
-    Short description
-.DESCRIPTION
-    Long description
-.EXAMPLE
-    Example of how to use this cmdlet
-.EXAMPLE
-    Another example of how to use this cmdlet
-.INPUTS
-    Inputs to this cmdlet (if any)
-.OUTPUTS
-    Output from this cmdlet (if any)
-.NOTES
-    General notes
-.COMPONENT
-    The component this cmdlet belongs to
-.ROLE
-    The role this cmdlet belongs to
-.FUNCTIONALITY
-    The functionality that best describes this cmdlet
-#>
-
-function Get-File
-{
-    [CmdletBinding()]
-    Param
-    (
-        ...
-    )
-
-}
-```
diff --git a/RuleDocumentation/README.md b/RuleDocumentation/README.md
deleted file mode 100644
index 2ed360e88..000000000
--- a/RuleDocumentation/README.md
+++ /dev/null
@@ -1,72 +0,0 @@
-# PSScriptAnalyzer Rules
-
-## Table of Contents
-
-| Rule | Severity | Configurable |
-|------|----------------------------------|--------------|
-|[AlignAssignmentStatement](./AlignAssignmentStatement.md) | Warning | |
-|[AvoidAssignmentToAutomaticVariable](./AvoidAssignmentToAutomaticVariable.md) | Warning | |
-|[AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md) | Warning | |
-|[AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md) | Warning | |
-|[AvoidGlobalAliases<sup>*</sup>](./AvoidGlobalAliases.md) | Warning | |
-|[AvoidGlobalFunctions](./AvoidGlobalFunctions.md) | Warning | |
-|[AvoidGlobalVars](./AvoidGlobalVars.md) | Warning | |
-|[AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md) | Warning | |
-|[AvoidLongLines](./AvoidLongLines.md) | Warning | |
-|[AvoidOverwritingBuiltInCmdlets](./AvoidOverwritingBuiltInCmdlets.md) | Warning | |
-|[AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md) | Warning | |
-|[AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md) | Warning | |
-|[UseUsingScopeModifierInNewRunspaces](./UseUsingScopeModifierInNewRunspaces.md) | Warning | |
-|[AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md) | Warning | Yes |
-|[AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md) | Error | |
-|[AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error | |
-|[AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md) | Warning | |
-|[AvoidUsingEmptyCatchBlock](./AvoidUsingEmptyCatchBlock.md) | Warning | |
-|[AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md) | Warning | |
-|[AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md) | Warning | |
-|[AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md) | Warning | |
-|[AvoidTrailingWhitespace](./AvoidTrailingWhitespace.md) | Warning | |
-|[AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md) | Error | |
-|[AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md) | Warning | |
-|[AvoidUsingWriteHost](./AvoidUsingWriteHost.md) | Warning | |
-|[DSCDscExamplesPresent](./DSCDscExamplesPresent.md) | Information | |
-|[DSCDscTestsPresent](./DSCDscTestsPresent.md) | Information | |
-|[DSCReturnCorrectTypesForDSCFunctions](./DSCReturnCorrectTypesForDSCFunctions.md) | Information | |
-|[DSCStandardDSCFunctionsInResource](./DSCStandardDSCFunctionsInResource.md) | Error | |
-|[DSCUseIdenticalMandatoryParametersForDSC](./DSCUseIdenticalMandatoryParametersForDSC.md) | Error | |
-|[DSCUseIdenticalParametersForDSC](./DSCUseIdenticalParametersForDSC.md) | Error | |
-|[DSCUseVerboseMessageInDSCResource](./DSCUseVerboseMessageInDSCResource.md) | Error | |
-|[MisleadingBacktick](./MisleadingBacktick.md) | Warning | |
-|[MissingModuleManifestField](./MissingModuleManifestField.md) | Warning | |
-|[PossibleIncorrectComparisonWithNull](./PossibleIncorrectComparisonWithNull.md) | Warning | |
-|[PossibleIncorrectUsageOfAssignmentOperator](./PossibleIncorrectUsageOfAssignmentOperator.md) | Warning | |
-|[PossibleIncorrectUsageOfRedirectionOperator](./PossibleIncorrectUsageOfRedirectionOperator.md) | Warning | |
-|[ProvideCommentHelp](./ProvideCommentHelp.md) | Information | Yes |
-|[ReservedCmdletChar](./ReservedCmdletChar.md) | Error | |
-|[ReservedParams](./ReservedParams.md) | Error | |
-|[ReviewUnusedParameter](./ReviewUnusedParameter.md) | Warning | |
-|[ShouldProcess](./ShouldProcess.md) | Error | |
-|[UseApprovedVerbs](./UseApprovedVerbs.md) | Warning | |
-|[UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md) | Warning | |
-|[UseCmdletCorrectly](./UseCmdletCorrectly.md) | Warning | |
-|[UseCorrectCasing](./UseCorrectCasing.md) | Information | |
-|[UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md) | Warning | |
-|[UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md) | Warning | |
-|[UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md) | Information | |
-|[UseProcessBlockForPipelineCommand](./UseProcessBlockForPipelineCommand.md) | Warning | |
-|[UsePSCredentialType](./UsePSCredentialType.md) | Warning | |
-|[UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md) | Warning | |
-|[UseSingularNouns<sup>*</sup>](./UseSingularNouns.md) | Warning | |
-|[UseSupportsShouldProcess](./UseSupportsShouldProcess.md) | Warning | |
-|[UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md) | Warning | |
-|[UseCompatibleCmdlets](./UseCompatibleCmdlets.md) | Warning | Yes |
-|[UseCompatibleCommands](./UseCompatibleCommands.md) | Warning | Yes |
-|[UseCompatibleSyntax](./UseCompatibleSyntax.md) | Warning | Yes |
-|[UseCompatibleTypes](./UseCompatibleTypes.md) | Warning | Yes |
-|[PlaceOpenBrace](./PlaceOpenBrace.md) | Warning | Yes |
-|[PlaceCloseBrace](./PlaceCloseBrace.md) | Warning | Yes |
-|[UseConsistentIndentation](./UseConsistentIndentation.md) | Warning | Yes |
-|[UseConsistentWhitespace](./UseConsistentWhitespace.md) | Warning | Yes |
-|[UseUTF8EncodingForHelpFile](./UseUTF8EncodingForHelpFile.md) | Warning | |
-
-<sup>*</sup> Rule is not available on all PowerShell versions, editions and/or OS platforms. See the rule's documentation for details.
diff --git a/RuleDocumentation/ReservedParams.md b/RuleDocumentation/ReservedParams.md
deleted file mode 100644
index b00f77691..000000000
--- a/RuleDocumentation/ReservedParams.md
+++ /dev/null
@@ -1,41 +0,0 @@
-# ReservedParams
-
-**Severity Level: Error**
-
-## Description
-
-You cannot use reserved common parameters in an advanced function.
-
-## How
-
-Change the name of the parameter.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Test
-{
-    [CmdletBinding]
-    Param
-    (
-        $ErrorVariable,
-        $Parameter2
-    )
-}
-```
-
-### Correct
-
-``` PowerShell
-function Test
-{
-    [CmdletBinding]
-    Param
-    (
-        $Err,
-        $Parameter2
-    )
-}
-```
diff --git a/RuleDocumentation/ReviewUnusedParameter.md b/RuleDocumentation/ReviewUnusedParameter.md
deleted file mode 100644
index 82af88c62..000000000
--- a/RuleDocumentation/ReviewUnusedParameter.md
+++ /dev/null
@@ -1,45 +0,0 @@
-# ReviewUnusedParameter
-
-**Severity Level: Warning**
-
-## Description
-
-This rule identifies parameters declared in a script, scriptblock, or function scope that have not been used in that scope. 
-
-## How
-
-Consider removing the unused parameter.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Test-Parameter
-{
-	Param (
-		$Parameter1,
-		
-		# this parameter is never called in the function
-		$Parameter2
-	)
-	
-	Get-Something $Parameter1
-}
-```
-
-### Correct
-
-``` PowerShell
-function Test-Parameter
-{
-	Param (
-		$Parameter1,
-		
-		# now this parameter is being called in the same scope
-		$Parameter2
-	)
-	
-	Get-Something $Parameter1 $Parameter2
-}
-```
diff --git a/RuleDocumentation/ShouldProcess.md b/RuleDocumentation/ShouldProcess.md
deleted file mode 100644
index aa5c74214..000000000
--- a/RuleDocumentation/ShouldProcess.md
+++ /dev/null
@@ -1,55 +0,0 @@
-# ShouldProcess
-
-**Severity Level: Warning**
-
-## Description
-
-If a cmdlet declares the `SupportsShouldProcess` attribute, then it should also call `ShouldProcess`. A violation is any function which either declares `SupportsShouldProcess` attribute but makes no calls to `ShouldProcess` or it calls `ShouldProcess` but does not declare `SupportsShouldProcess`
-
-For more information, please refer to `about_Functions_Advanced_Methods` and `about_Functions_CmdletBindingAttribute`
-
-## How
-
-To fix a violation of this rule, please call `ShouldProcess` method when a cmdlet declares `SupportsShouldProcess` attribute. Or please add `SupportsShouldProcess` attribute argument when calling `ShouldProcess`
-
-## Example
-
-### Wrong
-
-``` PowerShell
-	function Set-File
-	{
-	    [CmdletBinding(SupportsShouldProcess=$true)]
-	    Param
-	    (
-	        # Path to file
-			[Parameter(Mandatory=$true)]
-	        $Path
-	    )
-		"String" | Out-File -FilePath $FilePath
-	}
-```
-
-### Correct
-
-``` PowerShell
-	function Set-File
-	{
-	    [CmdletBinding(SupportsShouldProcess=$true)]
-	    Param
-	    (
-	        # Path to file
-			[Parameter(Mandatory=$true)]
-	        $Path
-	    )
-
-		if ($PSCmdlet.ShouldProcess("Target", "Operation"))
-		{
-			"String" | Out-File -FilePath $FilePath
-		}
-		else
-		{
-			Write-Host ('Write "String" to file {0}' -f $FilePath)
-		}
-	}
-```
diff --git a/RuleDocumentation/UseApprovedVerbs.md b/RuleDocumentation/UseApprovedVerbs.md
deleted file mode 100644
index abd159c9d..000000000
--- a/RuleDocumentation/UseApprovedVerbs.md
+++ /dev/null
@@ -1,39 +0,0 @@
-# UseApprovedVerbs
-
-**Severity Level: Warning**
-
-## Description
-
-All CMDLets must used approved verbs.
-
-Approved verbs can be found by running the command `Get-Verb`.
-
-Additional documentation on approved verbs can be found in the microsoft docs page
-[Approved Verbs for PowerShell Commands](https://docs.microsoft.com/powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands).
-Some unapproved verbs are documented on the approved verbs page and point to approved alternatives;
-try searching for the verb you used to find its approved form.
-For example, searching for `Read`, `Open`, or `Search` will lead you to `Get`.
-
-## How
-
-Change the verb in the cmdlet's name to an approved verb.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Change-Item
-{
-    ...
-}
-````
-
-### Correct
-
-``` PowerShell
-function Update-Item
-{
-    ...
-}
-```
diff --git a/RuleDocumentation/UseBOMForUnicodeEncodedFile.md b/RuleDocumentation/UseBOMForUnicodeEncodedFile.md
deleted file mode 100644
index d8353eaa2..000000000
--- a/RuleDocumentation/UseBOMForUnicodeEncodedFile.md
+++ /dev/null
@@ -1,11 +0,0 @@
-# UseBOMForUnicodeEncodedFile
-
-**Severity Level: Warning**
-
-## Description
-
-For a file encoded with a format other than ASCII, ensure Byte Order Mark (BOM) is present to ensure that any application consuming this file can interpret it correctly.
-
-## How
-
-Ensure that the file is encoded with BOM present.
diff --git a/RuleDocumentation/UseCompatibleCmdlets.md b/RuleDocumentation/UseCompatibleCmdlets.md
deleted file mode 100644
index 5eb25198e..000000000
--- a/RuleDocumentation/UseCompatibleCmdlets.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# UseCompatibleCmdlets
-
-**Severity Level: Warning**
-
-## Description
-
-This rule flags cmdlets that are not available in a given Edition/Version of PowerShell on a given Operating System. It works by comparing a cmdlet against a set of whitelists which ship with PSScriptAnalyzer. They can be found at `/path/to/PSScriptAnalyzerModule/Settings`. These files are of the form, `PSEDITION-PSVERSION-OS.json` where `PSEDITION` can be either `Core` or `Desktop`, `OS` can be either `Windows`, `Linux` or `MacOS`, and `Version` is the PowerShell version. To enable the rule to check if your script is compatible on PowerShell Core on windows, put the following your settings file:
-
-```PowerShell
-@{
-    'Rules' = @{
-        'PSUseCompatibleCmdlets' = @{
-            'compatibility' = @("core-6.1.0-windows")
-        }
-    }
-}
-```
-
-The parameter `compatibility` is a list that contain any of the following
-
-- desktop-2.0-windows
-- desktop-3.0-windows
-- desktop-4.0-windows (taken from Windows Server 2012R2)
-- desktop-5.1.14393.206-windows
-- core-6.1.0-windows (taken from Windows 10 - 1803)
-- core-6.1.0-linux (taken from Ubuntu 18.04)
-- core-6.1.0-linux-arm (taken from Raspbian)
-- core-6.1.0-macos
-
-Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major and minor versions of PowerShell are supplied. One can also create a custom settings file as well with the [New-CommandDataFile.ps1](https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Utils/New-CommandDataFile.ps1) script and use it by placing the created `JSON` into the `Settings` folder of the `PSScriptAnalyzer` module installation folder, then the `compatibility` parameter is just its file name (that can also be changed if desired).
-Note that the `core-6.0.2-*` files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0 reached it's end of life.
\ No newline at end of file
diff --git a/RuleDocumentation/UseCompatibleCommands.md b/RuleDocumentation/UseCompatibleCommands.md
deleted file mode 100644
index 86cf8b84e..000000000
--- a/RuleDocumentation/UseCompatibleCommands.md
+++ /dev/null
@@ -1,125 +0,0 @@
-# UseCompatibleCommands
-
-**Severity Level: Warning**
-
-## Description
-
-This rule identifies commands that are not available on a targeted PowerShell platform.
-
-A PowerShell platform is identified by a name in the following format:
-
-```
-<os-name>_<os-arch>_<os-version>_<ps-version>_<ps-arch>_<dotnet-version>_<dotnet-edition>
-```
-
-Where:
-
-- `<os-name>`: The name of the operating system PowerShell is running on.
-    On Windows, this includes the SKU number.
-    On Linux, this is the name of the distribution.
-- `<os-arch>`: The machine architecture the operating system is running on (this is usually `x64`).
-- `<os-version>`: The self-reported version of the operating system (on Linux, this is the distribution version).
-- `<ps-version>`: The PowerShell version (from `$PSVersionTable.PSVersion`).
-- `<ps-arch>`: The machine architecture of the PowerShell process.
-- `<dotnet-version>`: The reported version of the .NET runtime PowerShell is running on (from `System.Environment.Version`).
-- `<dotnet-edition>`: The .NET runtime flavor PowerShell is running on (currently `framework` or `core`).
-
-For example:
-
-- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on Windows 10 Enterprise (build 18312) for x64.
-- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same operating system.
-- `ubuntu_x64_18.04_6.2.0_x64_4.0.30319.42000_core` is PowerShell 6.2.0 running on Ubuntu 18.04.
-
-Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in your configuration.
-
-Platforms bundled by default are:
-
-| PowerShell Version | Operating System      | ID                                                                    |
-| -------------------|---------------------- | --------------------------------------------------------------------- |
-| 3.0                | Windows Server 2012   | `win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework`              |
-| 4.0                | Windows Server 2012R2 | `win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework`              |
-| 5.1                | Windows Server 2016   | `win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework` |
-| 5.1                | Windows Server 2019   | `win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework`  |
-| 5.1                | Windows 10 1809 (RS5) | `win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework` |
-| 6.2                | Windows Server 2016   | `win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core`               |
-| 6.2                | Windows Server 2019   | `win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core`               |
-| 6.2                | Windows 10 1809 (RS5) | `win-4_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core`               |
-| 6.2                | Ubuntu 18.04 LTS      | `ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core`                     |
-| 7.0                | Windows Server 2016   | `win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core`                         |
-| 7.0                | Windows Server 2019   | `win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core`                         |
-| 7.0                | Windows 10 1809 (RS5) | `win-4_x64_10.0.17763.0_6.2.4_x64_3.1.2_core`                         |
-| 7.0                | Ubuntu 18.04 LTS      | `ubuntu_x64_18.04_6.2.4_x64_3.1.2_core`                               |
-
-Other profiles can be found [here](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector/optional_profiles).
-
-You can also generate your own platform profile using the [PSCompatibilityCollector module](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector).
-
-The compatibility profile settings takes a list of platforms to target under `TargetProfiles`.
-A platform can be specified as:
-
-- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json` added to the end
-  and is searched for in the default profile directory.
-- A file name (like `my_custom_platform.json`), which will be searched for the in the default profile directory.
-- An absolute path to a file (like `D:\PowerShellProfiles\TargetMachine.json`).
-
-The default profile directory is under the PSScriptAnalzyer module at `$PSScriptRoot/compatibility_profiles`
-(where `$PSScriptRoot` here refers to the directory containing `PSScriptAnalyzer.psd1`).
-
-The compatibility analysis compares a command used to both a target profile
-and a "union" profile (containing all commands available in *any* profile in the profile dir).
-If a command is not present in the union profile, it is assumed to be locally created and ignored.
-Otherwise, if a command is present in the union profile but not present in a target,
-it is deemed to be incompatible with that target.
-
-## Configuration settings
-
-| Configuration key | Meaning | Accepted values | Mandatory | Example |
-| ----------------- | ------- | --------------- | --------- | ------- |
-| `Enable`          | Activates the rule | bool (`$true`/`$false`) | No (default: `$false`) | `$true` |
-| `TargetProfiles`  | The list of PowerShell profiles to target | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`) | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` |
-| `ProfileDirPath` | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles` |
-| `IgnoreCommands` | Commands to ignore compatibility of in scripts | string[]: names of commands to ignore | No (default: `@()`) | `@('Get-ChildItem','Import-Module')` |
-
-An example configuration might look like:
-
-```PowerShell
-@{
-    Rules = @{
-        PSUseCompatibleCommmands = @{
-            Enable = $true
-            TargetProfiles = @(
-                'ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core'
-                'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-                'MyProfile'
-                'another_custom_profile_in_the_profiles_directory.json'
-                'D:\My Profiles\profile1.json'
-            )
-            # You can specify commands to not check like this, which also will ignore its parameters:
-            IgnoreCommands = @(
-                'Install-Module'
-            )
-        }
-    }
-}
-```
-
-## Suppression
-
-Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a scriptblock
-as with other rules.
-
-```powershell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleCommands", "")]
-```
-
-The rule can also be suppressed only for particular commands:
-
-```powershell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleCommands", "Start-Service")]
-```
-
-And also suppressed only for parameters:
-
-```powershell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleCommands", "Import-Module/FullyQualifiedName")]
-```
diff --git a/RuleDocumentation/UseCompatibleTypes.md b/RuleDocumentation/UseCompatibleTypes.md
deleted file mode 100644
index c1a05f47d..000000000
--- a/RuleDocumentation/UseCompatibleTypes.md
+++ /dev/null
@@ -1,145 +0,0 @@
-# UseCompatibleTypes
-
-**Severity Level: Warning**
-
-## Description
-
-This rule identifies types that are not available (loaded by default) in targeted PowerShell platforms.
-
-A PowerShell platform is identified by a name in the following format:
-
-```
-<os-name>_<os-arch>_<os-version>_<ps-version>_<ps-arch>_<dotnet-version>_<dotnet-edition>
-```
-
-Where:
-
-- `<os-name>`: The name of the operating system PowerShell is running on.
-    On Windows, this includes the SKU number.
-    On Linux, this is the name of the distribution.
-- `<os-arch>`: The machine architecture the operating system is running on (this is usually `x64`).
-- `<os-version>`: The self-reported version of the operating system (on Linux, this is the distribution version).
-- `<ps-version>`: The PowerShell version (from `$PSVersionTable.PSVersion`).
-- `<ps-arch>`: The machine architecture of the PowerShell process.
-- `<dotnet-version>`: The reported version of the .NET runtime PowerShell is running on (from `System.Environment.Version`).
-- `<dotnet-edition>`: The .NET runtime flavor PowerShell is running on (currently `framework` or `core`).
-
-For example:
-
-- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on Windows 10 Enterprise (build 18312) for x64.
-- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same operating system.
-- `ubuntu_x64_18.04_6.2.0_x64_4.0.30319.42000_core` is PowerShell 6.2.0 running on Ubuntu 18.04.
-
-Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in your configuration.
-
-Platforms bundled by default are:
-
-| PowerShell Version | Operating System      | ID                                                                    |
-| -------------------|---------------------- | --------------------------------------------------------------------- |
-| 3.0                | Windows Server 2012   | `win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework`              |
-| 4.0                | Windows Server 2012R2 | `win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework`              |
-| 5.1                | Windows Server 2016   | `win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework` |
-| 5.1                | Windows Server 2019   | `win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework`  |
-| 5.1                | Windows 10 1809 (RS5) | `win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework` |
-| 6.2                | Windows Server 2016   | `win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core`               |
-| 6.2                | Windows Server 2019   | `win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core`               |
-| 6.2                | Windows 10 1809 (RS5) | `win-4_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core`               |
-| 6.2                | Ubuntu 18.04 LTS      | `ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core`                     |
-| 7.0                | Windows Server 2016   | `win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core`                         |
-| 7.0                | Windows Server 2019   | `win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core`                         |
-| 7.0                | Windows 10 1809 (RS5) | `win-4_x64_10.0.17763.0_6.2.4_x64_3.1.2_core`                         |
-| 7.0                | Ubuntu 18.04 LTS      | `ubuntu_x64_18.04_6.2.4_x64_3.1.2_core`                               |
-
-Other profiles can be found [here](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector/optional_profiles).
-
-You can also generate your own platform profile using the [PSCompatibilityCollector module](https://github.com/PowerShell/PSScriptAnalyzer/tree/development/PSCompatibilityCollector).
-
-The compatibility profile settings takes a list of platforms to target under `TargetProfiles`.
-A platform can be specified as:
-
-- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json` added to the end
-  and is searched for in the default profile directory.
-- A file name (like `my_custom_platform.json`), which will be searched for the in the default profile directory.
-- An absolute path to a file (like `D:\PowerShellProfiles\TargetMachine.json`).
-
-The default profile directory is under the PSScriptAnalzyer module at `$PSScriptRoot/PSCompatibilityCollector/profiles`
-(where `$PSScriptRoot` here refers to the directory containing `PSScriptAnalyzer.psd1`).
-
-The compatibility analysis compares a type used to both a target profile
-and a "union" profile (containing all types available in *any* profile in the profile dir).
-If a type is not present in the union profile, it is assumed to be locally created and ignored.
-Otherwise, if a type is present in the union profile but not present in a target,
-it is deemed to be incompatible with that target.
-
-## Configuration settings
-
-| Configuration key | Meaning | Accepted values | Mandatory | Example |
-| ----------------- | ------- | --------------- | --------- | ------- |
-| `Enable`          | Activates the rule | bool (`$true`/`$false`) | No (default: `$false`) | `$true` |
-| `TargetProfiles`  | The list of PowerShell profiles to target | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`) | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` |
-| `ProfileDirPath` | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles` |
-| `IgnoreTypes` | Full names of types or type accelerators to ignore compatibility of in scripts | string[]: names of types to ignore | No (default: `@()`) | `@('System.Collections.ArrayList','string')` |
-
-An example configuration might look like:
-
-```PowerShell
-@{
-    Rules = @{
-        PSUseCompatibleTypes = @{
-            Enable = $true
-            TargetProfiles = @(
-                'ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core'
-                'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-                'MyProfile'
-                'another_custom_profile_in_the_profiles_directory.json'
-                'D:\My Profiles\profile1.json'
-            )
-            # You can specify types to not check like this, which will also ignore methods and members on it:
-            IgnoreTypes = @(
-                'System.IO.Compression.ZipFile'
-            )
-        }
-    }
-}
-```
-
-Alternatively, you could provide a settings object as follows:
-
-```PowerShell
-PS> $settings = @{
-      Rules = @{
-        PSUseCompatibleTypes = @{
-          Enable = $true
-          TargetProfiles = @("win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework")
-        }
-      }
-}
-PS> Invoke-ScriptAnalyzer -Settings $settings -ScriptDefinition '[System.Management.Automation.SemanticVersion]"1.18.0-rc1"'
-
-RuleName                            Severity     ScriptName Line  Message
---------                            --------     ---------- ----  -------
-PSUseCompatibleTypes                Warning                 1     The type 'System.Management.Automation.SemanticVersion' is
-                                                                  not available by default in PowerShell version
-                                                                  '5.1.17763.316' on platform 'Microsoft Windows 10 Pro'
-```
-
-## Suppression
-
-Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a scriptblock
-as with other rules.
-
-```powershell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleTypes", "")]
-```
-
-The rule can also be suppressed only for particular types:
-
-```powershell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleTypes", "System.Management.Automation.Security.SystemPolicy")]
-```
-
-And also suppressed only for type members:
-
-```powershell
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseCompatibleCommands", "System.Management.Automation.LanguagePrimitives/ConvertTypeNameToPSTypeName")]
-```
diff --git a/RuleDocumentation/UseConsistentWhitespace.md b/RuleDocumentation/UseConsistentWhitespace.md
deleted file mode 100644
index 0e7509d1e..000000000
--- a/RuleDocumentation/UseConsistentWhitespace.md
+++ /dev/null
@@ -1,66 +0,0 @@
-# UseConsistentWhitespace
-
-**Severity Level: Warning**
-
-## Description
-
-# Parameters
-
-**Note**: This rule is not enabled by default. The user needs to enable it through settings.
-
-## Configuration
-
-```powershell
-    Rules = @{
-        PSUseConsistentWhitespace  = @{
-            Enable                          = $true
-            CheckInnerBrace                 = $true
-            CheckOpenBrace                  = $true
-            CheckOpenParen                  = $true
-            CheckOperator                   = $true
-            CheckPipe                       = $true
-            CheckPipeForRedundantWhitespace = $false
-            CheckSeparator                  = $true
-            CheckParameter                  = $false
-        }
-    }
-```
-
-### Parameters
-
-#### Enable: bool (Default value is `$false`)
-
-Enable or disable the rule during ScriptAnalyzer invocation.
-
-#### CheckInnerBrace: bool (Default value is `$true`)
-
-Checks if there is a space after the opening brace and a space before the closing brace. E.g. `if ($true) { foo }` instead of `if ($true) {bar}`.
-
-#### CheckOpenBrace: bool (Default value is `$true`)
-
-Checks if there is a space between a keyword and its corresponding open brace. E.g. `foo { }` instead of `foo{ }`.
-
-#### CheckOpenParen: bool (Default value is `$true`)
-
-Checks if there is space between a keyword and its corresponding open parenthesis. E.g. `if (true)` instead of `if(true)`.
-
-#### CheckOperator: bool (Default value is `$true`)
-
-Checks if a binary or unary operator is surrounded on both sides by a space. E.g. `$x = 1` instead of `$x=1`.
-
-#### CheckSeparator: bool (Default value is `$true`)
-
-Checks if a comma or a semicolon is followed by a space. E.g. `@(1, 2, 3)` or `@{a = 1; b = 2}` instead of `@(1,2,3)` or `@{a = 1;b = 2}`.
-
-#### CheckPipe: bool (Default value is `$true`)
-
-Checks if a pipe is surrounded on both sides by a space but ignores redundant whitespace. E.g. `foo | bar` instead of `foo|bar`.
-
-#### CheckPipeForRedundantWhitespace : bool (Default value is `$false`)
-
-Checks if a pipe is surrounded by redundant whitespace (i.e. more than 1 whitespace). E.g. `foo | bar` instead of `foo    |    bar`.
-
-#### CheckParameter: bool (Default value is `$false` at the moment due to the setting being new)
-
-Checks if there is more than one space between parameters and values. E.g. `foo -bar $baz -bat` instead of `foo   -bar   $baz   -bat`. This eliminates redundant whitespace that was probably added unintentionally.
-The rule does not check for whitespace between parameter and value when the colon syntax `-ParameterName:$ParameterValue` is used as some users prefer either 0 or 1 whitespace in this case.
diff --git a/RuleDocumentation/UseCorrectCasing.md b/RuleDocumentation/UseCorrectCasing.md
deleted file mode 100644
index 60a93f262..000000000
--- a/RuleDocumentation/UseCorrectCasing.md
+++ /dev/null
@@ -1,25 +0,0 @@
-# UseCorrectCasing
-
-**Severity Level: Information**
-
-## Description
-
-This is a style/formatting rule. PowerShell is case insensitive where applicable. The casing of cmdlet names or parameters does not matter but this rule ensures that the casing matches for consistency and also because most cmdlets/parameters start with an upper case and using that improves readability to the human eye.
-
-## How
-
-Use exact casing of the cmdlet and its parameters, e.g. `Invoke-Command { 'foo' } -RunAsAdministrator`.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-invoke-command { 'foo' } -runasadministrator
-```
-
-### Correct
-
-``` PowerShell
-Invoke-Command { 'foo' } -RunAsAdministrator
-```
diff --git a/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md b/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md
deleted file mode 100644
index 28e7ee9ea..000000000
--- a/RuleDocumentation/UseDeclaredVarsMoreThanAssignments.md
+++ /dev/null
@@ -1,34 +0,0 @@
-# UseDeclaredVarsMoreThanAssignments
-
-**Severity Level: Warning**
-
-## Description
-
-Generally variables that are not used more than their assignments are considered wasteful and not needed.
-
-## How
-
-Remove the variables that are declared but not used.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Test
-{
-    $declaredVar = "Declared just for fun"
-    $declaredVar2 = "Not used"
-    Write-Output $declaredVar
-}
-```
-
-### Correct
-
-``` PowerShell
-function Test
-{
-    $declaredVar = "Declared just for fun"
-    Write-Output $declaredVar
-}
-```
diff --git a/RuleDocumentation/UseLiteralInitializerForHashtable.md b/RuleDocumentation/UseLiteralInitializerForHashtable.md
deleted file mode 100644
index 57f766b91..000000000
--- a/RuleDocumentation/UseLiteralInitializerForHashtable.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# UseLiteralInitializerForHashtable
-
-**Severity Level: Warning**
-
-## Description
-
-Creating a hashtable by either `[hashtable]::new()` or `New-Object -TypeName hashtable` will create a hashtable wherein the keys are looked-up in a case-sensitive manner, unless an `IEqualityComparer` object is passed as an argument. However, PowerShell is case-insensitive in nature and it is best to create hashtables with case-insensitive key look-up. This rule is intended to warn the author of the case-sensitive nature of the hashtable if he/she creates a hashtable using the `new` member or the `New-Object` cmdlet.
-
-## How to Fix
-
-Use the full cmdlet name and not an alias.
-
-## Example
-
-### Wrong???
-
-``` PowerShell
-$hashtable = [hashtable]::new()
-```
-
-### Wrong???
-
-``` PowerShell
-$hashtable = New-Object -TypeName hashtable
-```
-
-### Correct:
-
-``` PowerShell
-$hashtable = @{}
-```
diff --git a/RuleDocumentation/UsePSCredentialType.md b/RuleDocumentation/UsePSCredentialType.md
deleted file mode 100644
index f44e8d9aa..000000000
--- a/RuleDocumentation/UsePSCredentialType.md
+++ /dev/null
@@ -1,31 +0,0 @@
-# UsePSCredentialType
-
-**Severity Level: Warning**
-
-## Description
-
-If the cmdlet or function has a `Credential` parameter, the parameter must accept the `PSCredential` type.
-
-## How
-
-Change the `Credential` parameter's type to be `PSCredential`.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Credential([String]$Credential)
-{
-	...
-}
-```
-
-### Correct
-
-``` PowerShell
-function Credential([PSCredential]$Credential)
-{
-	...
-}
-```
diff --git a/RuleDocumentation/UseProcessBlockForPipelineCommand.md b/RuleDocumentation/UseProcessBlockForPipelineCommand.md
deleted file mode 100644
index d66dc6f72..000000000
--- a/RuleDocumentation/UseProcessBlockForPipelineCommand.md
+++ /dev/null
@@ -1,62 +0,0 @@
-# UseProcessBlockForPipelineCommand
-
-**Severity Level: Warning**
-
-## Description
-
-Functions that support pipeline input should always handle parameter input in a process block. Unexpected behavior can result if input is handled directly in the body of a function where parameters declare pipeline support.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-Function Get-Number
-{
-	[CmdletBinding()]
-	Param(
-		[Parameter(ValueFromPipeline)]
-		[int]
-		$Number
-	)
-	
-	$Number
-}
-```
-
-#### Result
-
-```
-PS C:\> 1..5 | Get-Number
-5
-```
-
-### Correct
-
-``` PowerShell
-Function Get-Number
-{
-	[CmdletBinding()]
-	Param(
-		[Parameter(ValueFromPipeline)]
-		[int]
-		$Number
-	)
-	
-	process
-	{
-		$Number
-	}
-}
-```
-
-#### Result
-
-```
-PS C:\> 1..5 | Get-Number
-1
-2
-3
-4
-5
-```
diff --git a/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md b/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md
deleted file mode 100644
index 9b253e8fb..000000000
--- a/RuleDocumentation/UseShouldProcessForStateChangingFunctions.md
+++ /dev/null
@@ -1,53 +0,0 @@
-# UseShouldProcessForStateChangingFunctions
-
-**Severity Level: Warning**
-
-## Description
-
-Functions whose verbs change system state should support `ShouldProcess`.
-
-Verbs that should support `ShouldProcess`:
-* `New`
-* `Set`
-* `Remove`
-* `Start`
-* `Stop`
-* `Restart`
-* `Reset`
-* `Update`
-
-## How
-
-Include the `SupportsShouldProcess` argument in the `CmdletBinding` attribute.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-	function Set-ServiceObject
-	{
-	    [CmdletBinding()]
-		param
-		(
-			[string]
-			$Parameter1
-		)
-		...
-	}
-```
-
-### Correct
-
-``` PowerShell
-	function Set-ServiceObject
-	{
-	    [CmdletBinding(SupportsShouldProcess = $true)]
-	    param
-		(
-			[string]
-			$Parameter1
-		)
-		...
-	}
-```
diff --git a/RuleDocumentation/UseSingularNouns.md b/RuleDocumentation/UseSingularNouns.md
deleted file mode 100644
index 1966cd2a3..000000000
--- a/RuleDocumentation/UseSingularNouns.md
+++ /dev/null
@@ -1,33 +0,0 @@
-# UseSingularNouns
-
-**Severity Level: Warning**
-
-## Description
-
-PowerShell team best practices state cmdlets should use singular nouns and not plurals.
-
-**NOTE** This rule is not available in PowerShell Core due to the PluralizationService API that the rule uses internally.
-
-## How
-
-Change plurals to singular.
-
-## Example
-
-### Wrong
-
-``` PowerShell
-function Get-Files
-{
-    ...
-}
-```
-
-### Correct
-
-``` PowerShell
-function Get-File
-{
-    ...
-}
-```
diff --git a/RuleDocumentation/UseSupportsShouldProcess.md b/RuleDocumentation/UseSupportsShouldProcess.md
deleted file mode 100644
index 5ae7b486f..000000000
--- a/RuleDocumentation/UseSupportsShouldProcess.md
+++ /dev/null
@@ -1,27 +0,0 @@
-﻿# UseSupportsShouldProcess
-**Severity Level: Warning**
-
-## Description
-This rule discourages manual declaration of `whatif` and `confirm` parameters in a function/cmdlet. These parameters are, however, provided automatically when a function declares a `CmdletBinding` attribute with `SupportsShouldProcess` as its named argument. Using `SupportsShouldProcess` no only provides these parameters but also some generic functionality that allows the function/cmdlet authors to provide the desired interactive experience while using the cmdlet.
-
-## Example
-### Wrong:
-```PowerShell
-function foo {
-    param(
-        $param1,
-        $confirm,
-        $whatif
-    )
-}
-```
-
-### Correct:
-```PowerShell
-function foo {
-    [CmdletBinding(SupportsShouldProcess)]
-    param(
-        $param1
-    )
-}
-```
diff --git a/RuleDocumentation/UseToExportFieldsInManifest.md b/RuleDocumentation/UseToExportFieldsInManifest.md
deleted file mode 100644
index f90f6a383..000000000
--- a/RuleDocumentation/UseToExportFieldsInManifest.md
+++ /dev/null
@@ -1,49 +0,0 @@
-# UseToExportFieldsInManifest
-
-**Severity Level: Warning**
-
-## Description
-
-To improve the performance of module auto-discovery, module manifests should not use wildcards (`'*'`) or null (`$null`) in the following entries:
-* `AliasesToExport`
-* `CmdletsToExport`
-* `FunctionsToExport`
-* `VariablesToExport`
-
-The use of wildcards or null has the potential to cause PowerShell to perform expensive work to analyse a module during module auto-discovery.
-
-## How
-
-Use an explicit list in the entries.
-
-## Example
-
-Suppose there are no functions in your module to export. Then,
-
-### Wrong
-
-``` PowerShell
-FunctionsToExport = $null
-```
-
-### Correct
-
-``` PowerShell
-FunctionToExport = @()
-```
-
-## Example
-
-Suppose there are only two functions in your module, ```Get-Foo``` and ```Set-Foo``` that you want to export. Then,
-
-### Wrong
-
-``` PowerShell
-FunctionsToExport = '*'
-```
-
-### Correct
-
-``` PowerShell
-FunctionToExport = @(Get-Foo, Set-Foo)
-```
diff --git a/RuleDocumentation/UseUTF8EncodingForHelpFile.md b/RuleDocumentation/UseUTF8EncodingForHelpFile.md
deleted file mode 100644
index 30e9691d4..000000000
--- a/RuleDocumentation/UseUTF8EncodingForHelpFile.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# UseUTF8EncodingForHelpFile
-
-**Severity Level: Warning**
-
-## Description
-
-Check if help file uses utf8 encoding
\ No newline at end of file
diff --git a/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md b/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md
deleted file mode 100644
index d1ba06cf8..000000000
--- a/RuleDocumentation/UseUsingScopeModifierInNewRunspaces.md
+++ /dev/null
@@ -1,65 +0,0 @@
-# UseUsingScopeModifierInNewRunspaces
-
-**Severity Level: Warning**
-
-## Description
-
-If a ScriptBlock is intended to be run in a new RunSpace, variables inside it should use $using: scope modifier, or be initialized within the ScriptBlock.
-This applies to:
-
-- Invoke-Command *
-- Workflow { InlineScript {}}
-- Foreach-Object **
-- Start-Job
-- Start-ThreadJob
-- The `Script` resource in DSC configurations, specifically for the `GetScript`, `TestScript` and `SetScript` properties
-
-\* Only with the -ComputerName or -Session parameter.  
-\*\* Only with the -Parallel parameter
-
-## How to Fix
-
-Within the ScriptBlock, instead of just using a variable from the parent scope, you have to add the `using:` scope modifier to it.
-
-## Example
-
-### Wrong
-
-```PowerShell
-$var = "foo"
-1..2 | ForEach-Object -Parallel { $var }
-```
-
-### Correct
-
-```PowerShell
-$var = "foo"
-1..2 | ForEach-Object -Parallel { $using:var }
-```
-
-## More correct examples
-
-```powershell
-$bar = "bar"
-Invoke-Command -ComputerName "foo" -ScriptBlock { $using:bar }
-```
-
-```powershell
-$bar = "bar"
-$s = New-PSSession -ComputerName "foo"
-Invoke-Command -Session $s -ScriptBlock { $using:bar }
-```
-
-```powershell
-# Remark: Workflow is supported on Windows PowerShell only
-Workflow { 
-    $foo = "foo"
-    InlineScript { $using:foo }
-}
-```
-
-```powershell
-$foo = "foo"
-Start-ThreadJob -ScriptBlock { $using:foo }
-Start-Job -ScriptBlock {$using:foo }
-```
\ No newline at end of file
diff --git a/Rules/AlignAssignmentStatement.cs b/Rules/AlignAssignmentStatement.cs
index d8b1623d6..1d79870f2 100644
--- a/Rules/AlignAssignmentStatement.cs
+++ b/Rules/AlignAssignmentStatement.cs
@@ -314,6 +314,11 @@ private static List<Tuple<IScriptExtent, IScriptExtent>> GetExtents(
 
         private bool HasPropertiesOnSeparateLines(IEnumerable<Tuple<IScriptExtent, IScriptExtent>> tuples)
         {
+            if (tuples.Count() == 1)
+            {
+                // If the hashtable has just a single key-value pair, it does not have properties on separate lines
+                return false;
+            }
             var lines = new HashSet<int>();
             foreach (var kvp in tuples)
             {
diff --git a/Rules/AvoidAlias.cs b/Rules/AvoidAlias.cs
index c30de8db2..9efe0e916 100644
--- a/Rules/AvoidAlias.cs
+++ b/Rules/AvoidAlias.cs
@@ -22,13 +22,11 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
 #endif
     public class AvoidAlias : IScriptRule
     {
-        private readonly string whiteListArgName = "whitelist";
+        private readonly string allowListArgName = "allowlist";
+        // keep legacy argument name for next version to allow customers to transition but remove later
+        private readonly string allowListLegacyArgName = "whitelist";
         private bool isPropertiesSet;
-        private List<string> whiteList;
-        public List<string> WhiteList
-        {
-            get { return whiteList; }
-        }
+        public List<string> AllowList { get; private set; }
 
         public AvoidAlias()
         {
@@ -38,22 +36,27 @@ public AvoidAlias()
         /// <summary>
         /// Configure the rule.
         ///
-        /// Sets the whitelist of this rule
+        /// Sets the allowlist of this rule
         /// </summary>
         private void SetProperties()
         {
-            whiteList = new List<string>();
+            AllowList = new List<string>();
             isPropertiesSet = true;
             Dictionary<string, object> ruleArgs = Helper.Instance.GetRuleArguments(GetName());
             if (ruleArgs == null)
             {
                 return;
             }
-            object obj;
-            if (!ruleArgs.TryGetValue(whiteListArgName, out obj))
+            object objLegacy = null;
+            if (!ruleArgs.TryGetValue(allowListArgName, out object obj) &&
+                !ruleArgs.TryGetValue(allowListLegacyArgName, out objLegacy))
             {
                 return;
             }
+            // Fallback for object from legacy allowlist argument name 
+            if (obj == null) {
+                obj = objLegacy;
+            }
             IEnumerable<string> aliases = obj as IEnumerable<string>;
             if (aliases == null)
             {
@@ -72,13 +75,13 @@ private void SetProperties()
                     }
                     else
                     {
-                        whiteList.Add(y);
+                        AllowList.Add(y);
                     }
                 }
             }
             else
             {
-                whiteList.AddRange(aliases);
+                AllowList.AddRange(aliases);
             }
         }
 
@@ -110,7 +113,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 // You can also review the remark section in following document,
                 // MSDN: CommandAst.GetCommandName Method
                 if (commandName == null
-                    || whiteList.Contains<string>(commandName, StringComparer.OrdinalIgnoreCase))
+                    || AllowList.Contains<string>(commandName, StringComparer.OrdinalIgnoreCase))
                 {
                     continue;
                 }
@@ -140,14 +143,27 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                     commandType: CommandTypes.Cmdlet | CommandTypes.Function | CommandTypes.Script);
                 if (cmdletNameIfCommandWasMissingGetPrefix != null)
                 {
-                    yield return new DiagnosticRecord(
-                        string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingCmdletAliasesMissingGetPrefixError, commandName, commdNameWithGetPrefix),
-                        GetCommandExtent(cmdAst),
-                        GetName(),
-                        DiagnosticSeverity.Warning,
-                        fileName,
-                        commandName,
-                        suggestedCorrections: GetCorrectionExtent(cmdAst, commdNameWithGetPrefix));
+                    if (commandName.Equals("process", StringComparison.OrdinalIgnoreCase))
+                    {
+                        yield return new DiagnosticRecord(
+                            Strings.InvalidSyntaxAroundProcessBlockError,
+                            GetCommandExtent(cmdAst),
+                            "InvalidSyntaxAroundProcessBlock",
+                            DiagnosticSeverity.ParseError,
+                            fileName,
+                            commandName);
+                    }
+                    else
+                    {
+                        yield return new DiagnosticRecord(
+                            string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingCmdletAliasesMissingGetPrefixError, commandName, commdNameWithGetPrefix),
+                            GetCommandExtent(cmdAst),
+                            GetName(),
+                            DiagnosticSeverity.Warning,
+                            fileName,
+                            commandName,
+                            suggestedCorrections: GetCorrectionExtent(cmdAst, commdNameWithGetPrefix));
+                    }
                 }
 
             }
diff --git a/Rules/AvoidAssignmentToAutomaticVariable.cs b/Rules/AvoidAssignmentToAutomaticVariable.cs
index 1f2a784dd..c1ce88462 100644
--- a/Rules/AvoidAssignmentToAutomaticVariable.cs
+++ b/Rules/AvoidAssignmentToAutomaticVariable.cs
@@ -62,20 +62,45 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 if (_readOnlyAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase))
                 {
                     yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableError, variableName),
-                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName);
+                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName, variableName);
                 }
 
                 if (_readOnlyAutomaticVariablesIntroducedInVersion6_0.Contains(variableName, StringComparer.OrdinalIgnoreCase))
                 {
                     var severity = IsPowerShellVersion6OrGreater() ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
                     yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error, variableName),
-                                                      variableExpressionAst.Extent, GetName(), severity, fileName);
+                                                      variableExpressionAst.Extent, GetName(), severity, fileName, variableName);
                 }
 
                 if (_writableAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase))
                 {
                     yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToWritableAutomaticVariableError, variableName),
-                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
+                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, variableName);
+                }
+            }
+
+            IEnumerable<Ast> forEachStatementAsts = ast.FindAll(testAst => testAst is ForEachStatementAst, searchNestedScriptBlocks: true);
+            foreach (ForEachStatementAst forEachStatementAst in forEachStatementAsts)
+            {
+                var variableExpressionAst = forEachStatementAst.Variable;
+                var variableName = variableExpressionAst.VariablePath.UserPath;
+                if (_readOnlyAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase))
+                {
+                    yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableError, variableName),
+                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName, variableName);
+                }
+
+                if (_readOnlyAutomaticVariablesIntroducedInVersion6_0.Contains(variableName, StringComparer.OrdinalIgnoreCase))
+                {
+                    var severity = IsPowerShellVersion6OrGreater() ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
+                    yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error, variableName),
+                                                      variableExpressionAst.Extent, GetName(), severity, fileName, variableName);
+                }
+
+                if (_writableAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase))
+                {
+                    yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToWritableAutomaticVariableError, variableName),
+                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, variableName);
                 }
             }
 
@@ -89,24 +114,29 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 {
                     continue;
                 }
-
+                // also check the parent to exclude variableExpressions that appear within attributes,
+                // such as '[ValidateSet($True,$False)]' where the read-only variables $true,$false appear.
+                if (variableExpressionAst.Parent is AttributeAst)
+                {
+                    continue;
+                }
                 if (_readOnlyAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase))
                 {
                     yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableError, variableName),
-                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName);
+                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Error, fileName, variableName);
                 }
 
                 if (_readOnlyAutomaticVariablesIntroducedInVersion6_0.Contains(variableName, StringComparer.OrdinalIgnoreCase))
                 {
                     var severity = IsPowerShellVersion6OrGreater() ? DiagnosticSeverity.Error : DiagnosticSeverity.Warning;
                     yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error, variableName),
-                                                      variableExpressionAst.Extent, GetName(), severity, fileName);
+                                                      variableExpressionAst.Extent, GetName(), severity, fileName, variableName);
                 }
 
                 if (_writableAutomaticVariables.Contains(variableName, StringComparer.OrdinalIgnoreCase))
                 {
                     yield return new DiagnosticRecord(DiagnosticRecordHelper.FormatError(Strings.AvoidAssignmentToWritableAutomaticVariableError, variableName),
-                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
+                                                      variableExpressionAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName, variableName);
                 }
             }
         }
diff --git a/Rules/AvoidExclaimOperator.cs b/Rules/AvoidExclaimOperator.cs
new file mode 100644
index 000000000..5521463ea
--- /dev/null
+++ b/Rules/AvoidExclaimOperator.cs
@@ -0,0 +1,147 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+#if !CORECLR
+using System.ComponentModel.Composition;
+#endif
+using System.Globalization;
+using System.Linq;
+using System.Management.Automation;
+using System.Management.Automation.Language;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
+{
+    /// <summary>
+    /// AvoidExclaimOperator: Checks for use of the exclaim operator
+    /// </summary>
+#if !CORECLR
+    [Export(typeof(IScriptRule))]
+#endif
+    public class AvoidExclaimOperator : ConfigurableRule
+    {
+
+        /// <summary>
+        /// Construct an object of AvoidExclaimOperator type.
+        /// </summary>
+        public AvoidExclaimOperator() {
+            Enable = false;
+        }
+
+        /// <summary>
+        /// Analyzes the given ast to find the [violation]
+        /// </summary>
+        /// <param name="ast">AST to be analyzed. This should be non-null</param>
+        /// <param name="fileName">Name of file that corresponds to the input AST.</param>
+        /// <returns>A an enumerable type containing the violations</returns>
+        public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
+        {
+            if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
+
+            var diagnosticRecords = new List<DiagnosticRecord>();
+
+            IEnumerable<Ast> foundAsts = ast.FindAll(testAst => testAst is UnaryExpressionAst, true);
+            if (foundAsts != null) {
+                var correctionDescription = Strings.AvoidExclaimOperatorCorrectionDescription;
+                foreach (UnaryExpressionAst unaryExpressionAst in foundAsts) {
+                    if (unaryExpressionAst.TokenKind == TokenKind.Exclaim) {
+                        var replaceWith = "-not";
+                        // The UnaryExpressionAST should have a single child, the argument that the unary operator is acting upon.
+                        // If the child's extent starts 1 after the parent's extent then there's no whitespace between the exclaim
+                        // token and any variable/expression; in that case the replacement -not should include a space
+                        if (unaryExpressionAst.Child != null && unaryExpressionAst.Child.Extent.StartColumnNumber == unaryExpressionAst.Extent.StartColumnNumber + 1) {
+                            replaceWith = "-not ";
+                        }
+                        var corrections = new List<CorrectionExtent> {
+                            new CorrectionExtent(
+                                unaryExpressionAst.Extent.StartLineNumber,
+                                unaryExpressionAst.Extent.EndLineNumber,
+                                unaryExpressionAst.Extent.StartColumnNumber,
+                                unaryExpressionAst.Extent.StartColumnNumber + 1,
+                                replaceWith,
+                                fileName,
+                                correctionDescription
+                            )
+                        };
+                        diagnosticRecords.Add(new DiagnosticRecord(
+                                string.Format(
+                                    CultureInfo.CurrentCulture, 
+                                    Strings.AvoidExclaimOperatorError
+                                ), 
+                                unaryExpressionAst.Extent, 
+                                GetName(),
+                                GetDiagnosticSeverity(), 
+                                fileName,
+                                suggestedCorrections: corrections
+                        ));
+                    }
+                }
+            }
+            return diagnosticRecords;
+        }
+
+        /// <summary>
+        /// Retrieves the common name of this rule.
+        /// </summary>
+        public override string GetCommonName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidExclaimOperatorCommonName);
+        }
+
+        /// <summary>
+        /// Retrieves the description of this rule.
+        /// </summary>
+        public override string GetDescription()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidExclaimOperatorDescription);
+        }
+
+        /// <summary>
+        /// Retrieves the name of this rule.
+        /// </summary>
+        public override string GetName()
+        {
+            return string.Format(
+                CultureInfo.CurrentCulture,
+                Strings.NameSpaceFormat,
+                GetSourceName(),
+                Strings.AvoidExclaimOperatorName);
+        }
+
+        /// <summary>
+        /// Retrieves the severity of the rule: error, warning or information.
+        /// </summary>
+        public override RuleSeverity GetSeverity()
+        {
+            return RuleSeverity.Warning;
+        }
+
+        /// <summary>
+        /// Gets the severity of the returned diagnostic record: error, warning, or information.
+        /// </summary>
+        /// <returns></returns>
+        public DiagnosticSeverity GetDiagnosticSeverity()
+        {
+            return DiagnosticSeverity.Warning;
+        }
+
+        /// <summary>
+        /// Retrieves the name of the module/assembly the rule is from.
+        /// </summary>
+        public override string GetSourceName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
+        }
+
+        /// <summary>
+        /// Retrieves the type of the rule, Builtin, Managed or Module.
+        /// </summary>
+        public override SourceType GetSourceType()
+        {
+            return SourceType.Builtin;
+        }
+    }
+}
+
diff --git a/Rules/AvoidLongLines.cs b/Rules/AvoidLongLines.cs
index e0860a75e..ad527bb37 100644
--- a/Rules/AvoidLongLines.cs
+++ b/Rules/AvoidLongLines.cs
@@ -132,7 +132,7 @@ public override RuleSeverity GetSeverity()
         /// Gets the severity of the returned diagnostic record: error, warning, or information.
         /// </summary>
         /// <returns></returns>
-        public DiagnosticSeverity GetDiagnosticSeverity()
+        private DiagnosticSeverity GetDiagnosticSeverity()
         {
             return DiagnosticSeverity.Warning;
         }
diff --git a/Rules/AvoidMultipleTypeAttributes.cs b/Rules/AvoidMultipleTypeAttributes.cs
new file mode 100644
index 000000000..77f63de21
--- /dev/null
+++ b/Rules/AvoidMultipleTypeAttributes.cs
@@ -0,0 +1,104 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation.Language;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+#if !CORECLR
+using System.ComponentModel.Composition;
+#endif
+using System.Globalization;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
+{
+    /// <summary>
+    /// AvoidMultipleTypeAttributes: Check that parameter does not be assigned to multiple types.
+    /// </summary>
+#if !CORECLR
+    [Export(typeof(IScriptRule))]
+#endif
+    public sealed class AvoidMultipleTypeAttributes : IScriptRule
+    {
+        /// <summary>
+        /// AvoidMultipleTypeAttributes: Check that parameter does not be assigned to multiple types.
+        /// </summary>
+        public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
+        {
+            if (ast is null) 
+            {
+                throw new ArgumentNullException(Strings.NullAstErrorMessage);
+            }
+
+            // Finds all ParamAsts.
+            IEnumerable<Ast> paramAsts = ast.FindAll(testAst => testAst is ParameterAst, searchNestedScriptBlocks: true);
+
+            // Iterates all ParamAsts and check the number of its types.
+            foreach (ParameterAst paramAst in paramAsts)
+            {
+                if (paramAst.Attributes.Where(typeAst => typeAst is TypeConstraintAst).Count() > 1)
+                {
+                    yield return new DiagnosticRecord(
+                        String.Format(CultureInfo.CurrentCulture, Strings.AvoidMultipleTypeAttributesError, paramAst.Name),
+                        paramAst.Name.Extent,
+                        GetName(), 
+                        DiagnosticSeverity.Warning, 
+                        fileName);
+                }
+            }
+        }
+    
+        /// <summary>
+        /// GetName: Retrieves the name of this rule.
+        /// </summary>
+        /// <returns>The name of this rule</returns>
+        public string GetName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidMultipleTypeAttributesName);
+        }
+
+        /// <summary>
+        /// GetCommonName: Retrieves the common name of this rule.
+        /// </summary>
+        /// <returns>The common name of this rule</returns>
+        public string GetCommonName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidMultipleTypeAttributesCommonName);
+        }
+
+        /// <summary>
+        /// GetDescription: Retrieves the description of this rule.
+        /// </summary>
+        /// <returns>The description of this rule</returns>
+        public string GetDescription()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidMultipleTypeAttributesDescription);
+        }
+
+        /// <summary>
+        /// GetSourceType: Retrieves the type of the rule, Builtin, Managed or Module.
+        /// </summary>
+        public SourceType GetSourceType()
+        {
+            return SourceType.Builtin;
+        }
+
+        /// <summary>
+        /// GetSeverity: Retrieves the severity of the rule: error, warning or information.
+        /// </summary>
+        /// <returns></returns>
+        public RuleSeverity GetSeverity()
+        {
+            return RuleSeverity.Warning;
+        }
+
+        /// <summary>
+        /// GetSourceName: Retrieves the name of the module/assembly the rule is from.
+        /// </summary>
+        public string GetSourceName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
+        }
+    }
+}
diff --git a/Rules/AvoidPositionalParameters.cs b/Rules/AvoidPositionalParameters.cs
index d1c552957..2071baebd 100644
--- a/Rules/AvoidPositionalParameters.cs
+++ b/Rules/AvoidPositionalParameters.cs
@@ -5,6 +5,8 @@
 using System.Collections.Generic;
 using System.Management.Automation.Language;
 using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+using System.Linq;
+using System.Management.Automation;
 #if !CORECLR
 using System.ComponentModel.Composition;
 #endif
@@ -18,12 +20,20 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
 #if !CORECLR
 [Export(typeof(IScriptRule))]
 #endif
-    public class AvoidPositionalParameters : IScriptRule
+    public class AvoidPositionalParameters : ConfigurableRule
     {
+        [ConfigurableRuleProperty(defaultValue: new string[] { })]
+        public string[] CommandAllowList { get; set; }
+
+        public AvoidPositionalParameters()
+        {
+            Enable = true; // keep it enabled by default, user can still override this with settings
+        }
+
         /// <summary>
         /// AnalyzeScript: Analyze the ast to check that positional parameters are not used.
         /// </summary>
-        public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
+        public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
         {
             if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
 
@@ -52,25 +62,31 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 // MSDN: CommandAst.GetCommandName Method
                 if (cmdAst.GetCommandName() == null) continue;
                 
-                if ((Helper.Instance.IsKnownCmdletFunctionOrExternalScript(cmdAst) || declaredFunctionNames.Contains(cmdAst.GetCommandName())) &&
+                if ((Helper.Instance.IsKnownCmdletFunctionOrExternalScript(cmdAst, out CommandInfo commandInfo) || declaredFunctionNames.Contains(cmdAst.GetCommandName())) &&
                     (Helper.Instance.PositionalParameterUsed(cmdAst, true)))
                 {
+                    if (commandInfo?.CommandType == CommandTypes.Application) continue;
+
                     PipelineAst parent = cmdAst.Parent as PipelineAst;
 
+                    string commandName = cmdAst.GetCommandName();
                     if (parent != null && parent.PipelineElements.Count > 1)
                     {
                         // raise if it's the first element in pipeline. otherwise no.
-                        if (parent.PipelineElements[0] == cmdAst)
+                        if (parent.PipelineElements[0] == cmdAst && !CommandAllowList.Contains(commandName, StringComparer.OrdinalIgnoreCase))
                         {
-                            yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPositionalParametersError, cmdAst.GetCommandName()),
-                                cmdAst.Extent, GetName(), DiagnosticSeverity.Information, fileName, cmdAst.GetCommandName());
+                            yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPositionalParametersError, commandName),
+                                cmdAst.Extent, GetName(), DiagnosticSeverity.Information, fileName, commandName);
                         }
                     }
                     // not in pipeline so just raise it normally
                     else
                     {
-                        yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPositionalParametersError, cmdAst.GetCommandName()),
-                            cmdAst.Extent, GetName(), DiagnosticSeverity.Information, fileName, cmdAst.GetCommandName());
+                        if (!CommandAllowList.Contains(commandName, StringComparer.OrdinalIgnoreCase))
+                        {
+                            yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPositionalParametersError, commandName),
+                                cmdAst.Extent, GetName(), DiagnosticSeverity.Information, fileName, commandName);
+                        }
                     }
                 }
             }
@@ -80,7 +96,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
         /// GetName: Retrieves the name of this rule.
         /// </summary>
         /// <returns>The name of this rule</returns>
-        public string GetName()
+        public override string GetName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingPositionalParametersName);
         }
@@ -89,7 +105,7 @@ public string GetName()
         /// GetCommonName: Retrieves the common name of this rule.
         /// </summary>
         /// <returns>The common name of this rule</returns>
-        public string GetCommonName()
+        public override string GetCommonName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPositionalParametersCommonName);
         }
@@ -98,7 +114,7 @@ public string GetCommonName()
         /// GetDescription: Retrieves the description of this rule.
         /// </summary>
         /// <returns>The description of this rule</returns>
-        public string GetDescription()
+        public override string GetDescription()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingPositionalParametersDescription);
         }
@@ -106,7 +122,7 @@ public string GetDescription()
         /// <summary>
         /// Method: Retrieves the type of the rule: builtin, managed or module.
         /// </summary>
-        public SourceType GetSourceType()
+        public override SourceType GetSourceType()
         {
             return SourceType.Builtin;
         }
@@ -115,7 +131,7 @@ public SourceType GetSourceType()
         /// GetSeverity: Retrieves the severity of the rule: error, warning of information.
         /// </summary>
         /// <returns></returns>
-        public RuleSeverity GetSeverity()
+        public override RuleSeverity GetSeverity()
         {
             return RuleSeverity.Information;
         }
@@ -123,7 +139,7 @@ public RuleSeverity GetSeverity()
         /// <summary>
         /// Method: Retrieves the module/assembly name the rule is from.
         /// </summary>
-        public string GetSourceName()
+        public override string GetSourceName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
         }
diff --git a/Rules/AvoidReservedParams.cs b/Rules/AvoidReservedParams.cs
index 7582d4571..4035a9c89 100644
--- a/Rules/AvoidReservedParams.cs
+++ b/Rules/AvoidReservedParams.cs
@@ -60,7 +60,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) {
                         if (commonParamNames.Contains(paramName, StringComparer.OrdinalIgnoreCase))
                         {
                             yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.ReservedParamsError, funcAst.Name, paramName),
-                                paramAst.Extent, GetName(), DiagnosticSeverity.Warning, fileName);
+                                paramAst.Extent, GetName(), GetDiagnosticSeverity(), fileName);
                         }
                     }
                 }
@@ -107,7 +107,16 @@ public SourceType GetSourceType()
         /// <returns></returns>
         public RuleSeverity GetSeverity()
         {
-            return RuleSeverity.Warning;
+            return RuleSeverity.Error;
+        }
+
+        /// <summary>
+        /// Gets the severity of the returned diagnostic record: error, warning, or information.
+        /// </summary>
+        /// <returns></returns>
+        public DiagnosticSeverity GetDiagnosticSeverity()
+        {
+            return DiagnosticSeverity.Error;
         }
 
         /// <summary>
diff --git a/Rules/AvoidSemicolonsAsLineTerminators.cs b/Rules/AvoidSemicolonsAsLineTerminators.cs
new file mode 100644
index 000000000..68a121d77
--- /dev/null
+++ b/Rules/AvoidSemicolonsAsLineTerminators.cs
@@ -0,0 +1,175 @@
+// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+#if !CORECLR
+using System.ComponentModel.Composition;
+#endif
+using System.Globalization;
+using System.Linq;
+using System.Management.Automation.Language;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
+{
+    /// <summary>
+    /// AvoidSemicolonsAsLineTerminators: Checks for lines that end with a semicolon.
+    /// </summary>
+#if !CORECLR
+    [Export(typeof(IScriptRule))]
+#endif
+    public class AvoidSemicolonsAsLineTerminators : ConfigurableRule
+    {
+        /// <summary>
+        /// Construct an object of AvoidSemicolonsAsLineTerminators type.
+        /// </summary>
+        public AvoidSemicolonsAsLineTerminators()
+        {
+            Enable = false;
+        }
+
+        /// <summary>
+        /// Checks for lines that end with a semicolon.
+        /// </summary>
+        /// <param name="ast">AST to be analyzed. This should be non-null</param>
+        /// <param name="fileName">Name of file that corresponds to the input AST.</param>
+        /// <returns>The diagnostic results of this rule</returns>
+        public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
+        {
+            if (ast == null)
+            {
+                throw new ArgumentNullException(nameof(ast));
+            }
+
+
+            var diagnosticRecords = new List<DiagnosticRecord>();
+
+            IEnumerable<Ast> assignmentStatements = ast.FindAll(item => item is AssignmentStatementAst, true);
+
+            var tokens = Helper.Instance.Tokens;
+            for (int tokenIndex = 0; tokenIndex < tokens.Length; tokenIndex++)
+            {
+
+                var token = tokens[tokenIndex];
+                var semicolonTokenExtent = token.Extent;
+
+                var isSemicolonToken = token.Kind is TokenKind.Semi;
+                if (!isSemicolonToken)
+                {
+                    continue;
+                }
+
+                var isPartOfAnyAssignmentStatement = assignmentStatements.Any(assignmentStatement => (assignmentStatement.Extent.EndOffset == semicolonTokenExtent.StartOffset + 1));
+                if (isPartOfAnyAssignmentStatement)
+                {
+                    continue;
+                }
+
+                var nextTokenIndex = tokenIndex + 1;
+                var isNextTokenIsNewLine = tokens[nextTokenIndex].Kind is TokenKind.NewLine;
+                var isNextTokenIsEndOfInput = tokens[nextTokenIndex].Kind is TokenKind.EndOfInput;
+
+                if (!isNextTokenIsNewLine && !isNextTokenIsEndOfInput)
+                {
+                    continue;
+                }
+
+                var violationExtent = new ScriptExtent(
+                new ScriptPosition(
+                    ast.Extent.File,
+                    semicolonTokenExtent.StartLineNumber,
+                    semicolonTokenExtent.StartColumnNumber,
+                    semicolonTokenExtent.StartScriptPosition.Line
+                ),
+                new ScriptPosition(
+                    ast.Extent.File,
+                    semicolonTokenExtent.EndLineNumber,
+                    semicolonTokenExtent.EndColumnNumber,
+                    semicolonTokenExtent.EndScriptPosition.Line
+                ));
+
+                var suggestedCorrections = new List<CorrectionExtent>();
+                suggestedCorrections.Add(new CorrectionExtent(
+                            violationExtent,
+                            string.Empty,
+                            ast.Extent.File
+                        ));
+
+                var record = new DiagnosticRecord(
+                        String.Format(CultureInfo.CurrentCulture, Strings.AvoidSemicolonsAsLineTerminatorsError),
+                        violationExtent,
+                        GetName(),
+                        GetDiagnosticSeverity(),
+                        ast.Extent.File,
+                        null,
+                        suggestedCorrections
+                    );
+                diagnosticRecords.Add(record);
+            }
+
+            return diagnosticRecords;
+        }
+
+        /// <summary>
+        /// Retrieves the common name of this rule.
+        /// </summary>
+        public override string GetCommonName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidSemicolonsAsLineTerminatorsCommonName);
+        }
+
+        /// <summary>
+        /// Retrieves the description of this rule.
+        /// </summary>
+        public override string GetDescription()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidSemicolonsAsLineTerminatorsDescription);
+        }
+
+        /// <summary>
+        /// Retrieves the name of this rule.
+        /// </summary>
+        public override string GetName()
+        {
+            return string.Format(
+                CultureInfo.CurrentCulture,
+                Strings.NameSpaceFormat,
+                GetSourceName(),
+                Strings.AvoidSemicolonsAsLineTerminatorsName);
+        }
+
+        /// <summary>
+        /// Retrieves the severity of the rule: error, warning or information.
+        /// </summary>
+        public override RuleSeverity GetSeverity()
+        {
+            return RuleSeverity.Warning;
+        }
+
+        /// <summary>
+        /// Gets the severity of the returned diagnostic record: error, warning, or information.
+        /// </summary>
+        /// <returns></returns>
+        public DiagnosticSeverity GetDiagnosticSeverity()
+        {
+            return DiagnosticSeverity.Warning;
+        }
+
+        /// <summary>
+        /// Retrieves the name of the module/assembly the rule is from.
+        /// </summary>
+        public override string GetSourceName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
+        }
+
+        /// <summary>
+        /// Retrieves the type of the rule: builtin, managed, or module.
+        /// </summary>
+        public override SourceType GetSourceType()
+        {
+            return SourceType.Builtin;
+        }
+    }
+}
diff --git a/Rules/AvoidTrailingWhitespace.cs b/Rules/AvoidTrailingWhitespace.cs
index 47f576d5b..a7567d6e6 100644
--- a/Rules/AvoidTrailingWhitespace.cs
+++ b/Rules/AvoidTrailingWhitespace.cs
@@ -54,7 +54,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 }
 
                 int startColumnOfTrailingWhitespace = 1;
-                for (int i = line.Length - 2; i > 0; i--)
+                for (int i = line.Length - 2; i >= 0; i--)
                 {
                     if (line[i] != ' ' && line[i] != '\t')
                     {
diff --git a/Rules/AvoidUserNameAndPasswordParams.cs b/Rules/AvoidUserNameAndPasswordParams.cs
index 9429e2aa4..ced0c8ee1 100644
--- a/Rules/AvoidUserNameAndPasswordParams.cs
+++ b/Rules/AvoidUserNameAndPasswordParams.cs
@@ -36,7 +36,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
 
             List<String> passwords = new List<String>() {"Password", "Passphrase"};
             List<String> usernames = new List<String>() { "Username", "User"};
-            Type[] typeWhiteList = {typeof(CredentialAttribute),
+            Type[] typeAllowList = {typeof(CredentialAttribute),
                                             typeof(PSCredential),
                                             typeof(System.Security.SecureString),
                                             typeof(SwitchParameter),
@@ -54,7 +54,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 // Iterates all ParamAsts and check if their names are on the list.
                 foreach (ParameterAst paramAst in paramAsts)
                 {
-                    var attributes = typeWhiteList.Select(x => GetAttributeOfType(paramAst.Attributes, x));
+                    var attributes = typeAllowList.Select(x => GetAttributeOfType(paramAst.Attributes, x));
                     String paramName = paramAst.Name.VariablePath.ToString();                    
                     foreach (String password in passwords)
                     {
@@ -86,7 +86,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
                 {
                     yield return new DiagnosticRecord(
                         String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsernameAndPasswordParamsError, funcAst.Name),
-                        GetExtent(usernameAst, passwordAst, ast), GetName(), DiagnosticSeverity.Error, fileName);
+                        GetExtent(usernameAst, passwordAst), GetName(), DiagnosticSeverity.Error, fileName);
                 }
             }
         }
@@ -111,7 +111,7 @@ private bool IsAttributeOfType(AttributeBaseAst attributeAst, Type type)
         /// <param name="usernameAst"></param>
         /// <param name="passwordAst"></param>
         /// <returns>IScriptExtent</returns>
-        private IScriptExtent GetExtent(ParameterAst usernameAst, ParameterAst passwordAst, Ast scriptAst)
+        private IScriptExtent GetExtent(ParameterAst usernameAst, ParameterAst passwordAst)
         {
             var usrExt = usernameAst.Extent;
             var pwdExt = passwordAst.Extent;
diff --git a/Rules/AvoidUsingAllowUnencryptedAuthentication.cs b/Rules/AvoidUsingAllowUnencryptedAuthentication.cs
new file mode 100644
index 000000000..955de8113
--- /dev/null
+++ b/Rules/AvoidUsingAllowUnencryptedAuthentication.cs
@@ -0,0 +1,117 @@
+﻿// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Management.Automation.Language;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+#if !CORECLR
+using System.ComponentModel.Composition;
+#endif
+using System.Globalization;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
+{
+    /// <summary>
+    /// AvoidUsingAllowUnencryptedAuthentication: Avoid sending credentials and secrets over unencrypted connections.
+    /// </summary>
+#if !CORECLR
+[Export(typeof(IScriptRule))]
+#endif
+    public class AvoidUsingAllowUnencryptedAuthentication : AvoidParameterGeneric
+    {
+        /// <summary>
+        /// Condition on the cmdlet that must be satisfied for the error to be raised
+        /// </summary>
+        /// <param name="CmdAst"></param>
+        /// <returns></returns>
+        public override bool CommandCondition(CommandAst CmdAst)
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Condition on the parameter that must be satisfied for the error to be raised.
+        /// </summary>
+        /// <param name="CmdAst"></param>
+        /// <param name="CeAst"></param>
+        /// <returns></returns>
+        public override bool ParameterCondition(CommandAst CmdAst, CommandElementAst CeAst)
+        {
+            return CeAst is CommandParameterAst && String.Equals((CeAst as CommandParameterAst).ParameterName, "AllowUnencryptedAuthentication", StringComparison.OrdinalIgnoreCase);
+        }
+
+        /// <summary>
+        /// Retrieves the error message
+        /// </summary>
+        /// <param name="FileName"></param>
+        /// <param name="CmdAst"></param>
+        /// <returns></returns>
+        public override string GetError(string fileName, CommandAst cmdAst)
+        {
+            return String.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingAllowUnencryptedAuthenticationError);
+        }
+
+        /// <summary>
+        /// GetName: Retrieves the name of this rule.
+        /// </summary>
+        /// <returns>The name of this rule</returns>
+        public override string GetName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingAllowUnencryptedAuthenticationName);
+        }
+
+        /// <summary>
+        /// GetCommonName: Retrieves the common name of this rule.
+        /// </summary>
+        /// <returns>The common name of this rule</returns>
+        public override string GetCommonName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingAllowUnencryptedAuthenticationCommonName);
+        }
+
+        /// <summary>
+        /// GetDescription: Retrieves the description of this rule.
+        /// </summary>
+        /// <returns>The description of this rule</returns>
+        public override string GetDescription()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingAllowUnencryptedAuthenticationDescription);
+        }
+
+        /// <summary>
+        /// GetSourceType: Retrieves the type of the rule: builtin, managed or module.
+        /// </summary>
+        public override SourceType GetSourceType()
+        {
+            return SourceType.Builtin;
+        }
+
+        /// <summary>
+        /// GetSeverity: Retrieves the severity of the rule: error, warning or information.
+        /// </summary>
+        /// <returns></returns>
+        public override RuleSeverity GetSeverity()
+        {
+            return RuleSeverity.Warning;
+        }
+
+        /// <summary>
+        /// DiagnosticSeverity: Retrieves the severity of the rule of type DiagnosticSeverity: error, warning or information.
+        /// </summary>
+        /// <returns></returns>
+        public override DiagnosticSeverity GetDiagnosticSeverity()
+        {
+            return DiagnosticSeverity.Warning;
+        }
+
+        /// <summary>
+        /// GetSourceName: Retrieves the module/assembly name the rule is from.
+        /// </summary>
+        public override string GetSourceName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
+        }
+    }
+}
diff --git a/Rules/AvoidUsingBrokenHashAlgorithms.cs b/Rules/AvoidUsingBrokenHashAlgorithms.cs
new file mode 100644
index 000000000..b43116020
--- /dev/null
+++ b/Rules/AvoidUsingBrokenHashAlgorithms.cs
@@ -0,0 +1,186 @@
+﻿// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Management.Automation.Language;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+#if !CORECLR
+using System.ComponentModel.Composition;
+#endif
+using System.Globalization;
+using System.Linq;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
+{
+    /// <summary>
+    /// AvoidUsingBrokenHashAlgorithms: Avoid using the broken algorithms MD5 or SHA-1.
+    /// </summary>
+#if !CORECLR
+[Export(typeof(IScriptRule))]
+#endif
+    public class AvoidUsingBrokenHashAlgorithms : AvoidParameterGeneric
+    {
+        private readonly string[] brokenAlgorithms = new string[]
+        {
+            "MD5",
+            "SHA1",
+        };
+
+        private string algorithm;
+
+        /// <summary>
+        /// Condition on the cmdlet that must be satisfied for the error to be raised
+        /// </summary>
+        /// <param name="CmdAst"></param>
+        /// <returns></returns>
+        public override bool CommandCondition(CommandAst CmdAst)
+        {
+            return true;
+        }
+
+        /// <summary>
+        /// Condition on the parameter that must be satisfied for the error to be raised.
+        /// </summary>
+        /// <param name="CmdAst"></param>
+        /// <param name="CeAst"></param>
+        /// <returns></returns>
+        public override bool ParameterCondition(CommandAst CmdAst, CommandElementAst CeAst)
+        {
+            if (CeAst is CommandParameterAst)
+            {
+                CommandParameterAst cmdParamAst = CeAst as CommandParameterAst;
+
+                if (String.Equals(cmdParamAst.ParameterName, "algorithm", StringComparison.OrdinalIgnoreCase))
+                {
+                    Ast hashAlgorithmArgument = cmdParamAst.Argument;
+                    if (hashAlgorithmArgument is null)
+                    {
+                        hashAlgorithmArgument = GetHashAlgorithmArg(CmdAst, cmdParamAst.Extent.StartOffset);
+                        if (hashAlgorithmArgument is null)
+                        {
+                            return false;
+                        }
+                    }
+
+                    var constExprAst = hashAlgorithmArgument as ConstantExpressionAst;
+                    if (constExprAst != null)
+                    {
+                        algorithm = constExprAst.Value as string;
+                        return IsBrokenAlgorithm(algorithm);
+                    }
+                }
+            }
+
+            return false;
+        }
+
+        private bool IsBrokenAlgorithm(string algorithm)
+        {
+            if (algorithm != null)
+            {
+                return brokenAlgorithms.Contains<string>(
+                    algorithm,
+                    StringComparer.OrdinalIgnoreCase);
+            }
+
+            return false;
+        }
+
+        private Ast GetHashAlgorithmArg(CommandAst CmdAst, int StartIndex)
+        {
+            int small = int.MaxValue;
+            Ast hashAlgorithmArg = null;
+            foreach (Ast ast in CmdAst.CommandElements)
+            {
+                if (ast.Extent.StartOffset > StartIndex && ast.Extent.StartOffset < small)
+                {
+                    hashAlgorithmArg = ast;
+                    small = ast.Extent.StartOffset;
+                }
+            }
+
+            return hashAlgorithmArg;
+        }
+
+        /// <summary>
+        /// Retrieves the error message
+        /// </summary>
+        /// <param name="FileName"></param>
+        /// <param name="CmdAst"></param>
+        /// <returns></returns>
+        public override string GetError(string FileName, CommandAst CmdAst)
+        {
+            if (CmdAst is null)
+            {
+                return string.Empty;
+            }
+
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingBrokenHashAlgorithmsError, CmdAst.GetCommandName(), algorithm);
+        }
+
+        /// <summary>
+        /// GetName: Retrieves the name of this rule.
+        /// </summary>
+        /// <returns>The name of this rule</returns>
+        public override string GetName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.AvoidUsingBrokenHashAlgorithmsName);
+        }
+
+        /// <summary>
+        /// GetCommonName: Retrieves the common name of this rule.
+        /// </summary>
+        /// <returns>The common name of this rule</returns>
+        public override string GetCommonName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingBrokenHashAlgorithmsCommonName);
+        }
+
+        /// <summary>
+        /// GetDescription: Retrieves the description of this rule.
+        /// </summary>
+        /// <returns>The description of this rule</returns>
+        public override string GetDescription()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingBrokenHashAlgorithmsDescription);
+        }
+
+        /// <summary>
+        /// GetSourceType: Retrieves the type of the rule: builtin, managed or module.
+        /// </summary>
+        public override SourceType GetSourceType()
+        {
+            return SourceType.Builtin;
+        }
+
+        /// <summary>
+        /// GetSeverity: Retrieves the severity of the rule: error, warning or information.
+        /// </summary>
+        /// <returns></returns>
+        public override RuleSeverity GetSeverity()
+        {
+            return RuleSeverity.Warning;
+        }
+
+        /// <summary>
+        /// DiagnosticSeverity: Retrieves the severity of the rule of type DiagnosticSeverity: error, warning or information.
+        /// </summary>
+        /// <returns></returns>
+        public override DiagnosticSeverity GetDiagnosticSeverity()
+        {
+            return DiagnosticSeverity.Warning;
+        }
+
+        /// <summary>
+        /// GetSourceName: Retrieves the module/assembly name the rule is from.
+        /// </summary>
+        public override string GetSourceName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
+        }
+    }
+}
+
+
+
+
diff --git a/Rules/AvoidUsingDeprecatedManifestFields.cs b/Rules/AvoidUsingDeprecatedManifestFields.cs
index 8856745d2..fd3431251 100644
--- a/Rules/AvoidUsingDeprecatedManifestFields.cs
+++ b/Rules/AvoidUsingDeprecatedManifestFields.cs
@@ -70,10 +70,9 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
 
                                 if (value != null)
                                 {
-                                    Version psVersion = null;
 
                                     // get the version
-                                    if (Version.TryParse((value as StringConstantExpressionAst).Value, out psVersion))
+                                    if (Version.TryParse((value as StringConstantExpressionAst).Value, out Version psVersion))
                                     {
                                         // if version exists and version less than 3, don't raise rule
                                         if (psVersion.Major < 3)
diff --git a/Rules/AvoidUsingDoubleQuotesForConstantString.cs b/Rules/AvoidUsingDoubleQuotesForConstantString.cs
new file mode 100644
index 000000000..5b2c232b7
--- /dev/null
+++ b/Rules/AvoidUsingDoubleQuotesForConstantString.cs
@@ -0,0 +1,161 @@
+﻿// Copyright (c) Microsoft Corporation. All rights reserved.
+// Licensed under the MIT License.
+
+using System;
+using System.Collections.Generic;
+#if !CORECLR
+using System.ComponentModel.Composition;
+#endif
+using System.Globalization;
+using System.Management.Automation.Language;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+
+namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
+{
+    /// <summary>
+    /// AvoidUsingDoubleQuotesForConstantStrings: Checks if a string that uses double quotes contains a constant string, which could be simplified to a single quote.
+    /// </summary>
+#if !CORECLR
+    [Export(typeof(IScriptRule))]
+#endif
+    public class AvoidUsingDoubleQuotesForConstantString : ConfigurableRule
+    {
+        /// <summary>
+        /// Construct an object of type <seealso cref="AvoidUsingDoubleQuotesForConstantStrings"/>.
+        /// </summary>
+        public AvoidUsingDoubleQuotesForConstantString()
+        {
+            Enable = false;
+        }
+
+        /// <summary>
+        /// Analyzes the given ast to find occurences of StringConstantExpressionAst where double quotes are used
+        /// and could be replaced with single quotes.
+        /// </summary>
+        /// <param name="ast">AST to be analyzed. This should be non-null</param>
+        /// <param name="fileName">Name of file that corresponds to the input AST.</param>
+        /// <returns>A an enumerable type containing the violations</returns>
+        public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
+        {
+            if (ast == null)
+            {
+                throw new ArgumentNullException(nameof(ast));
+            }
+
+            var stringConstantExpressionAsts = ast.FindAll(testAst => testAst is StringConstantExpressionAst, searchNestedScriptBlocks: true);
+            foreach (StringConstantExpressionAst stringConstantExpressionAst in stringConstantExpressionAsts)
+            {
+                switch (stringConstantExpressionAst.StringConstantType)
+                {
+                    /*
+                        If an interpolated string (i.e. using double quotes) uses single quotes (or @' in case of a here-string), then do not warn.
+                        This because one would then have to escape this single quote, which would make the string less readable.
+                        If an interpolated string contains a backtick character, then do not warn as well.
+                        This is because we'd have to replace the backtick in some cases like `$ and in others like `a it would not be possible at all.
+                        Therefore to keep it simple, all interpolated strings with a backtick are being excluded. 
+                    */
+                    case StringConstantType.DoubleQuoted:
+                        if (stringConstantExpressionAst.Value.Contains("'") || stringConstantExpressionAst.Extent.Text.Contains("`"))
+                        {
+                            break;
+                        }
+                        yield return GetDiagnosticRecord(stringConstantExpressionAst,
+                            $"'{stringConstantExpressionAst.Value}'");
+                        break;
+
+                    case StringConstantType.DoubleQuotedHereString:
+                        if (stringConstantExpressionAst.Value.Contains("@'") || stringConstantExpressionAst.Extent.Text.Contains("`"))
+                        {
+                            break;
+                        }
+                        yield return GetDiagnosticRecord(stringConstantExpressionAst,
+                            $"@'{Environment.NewLine}{stringConstantExpressionAst.Value}{Environment.NewLine}'@");
+                        break;
+
+                    default:
+                        break;
+                }
+            }
+        }
+
+        private DiagnosticRecord GetDiagnosticRecord(StringConstantExpressionAst stringConstantExpressionAst,
+            string suggestedCorrection)
+        {
+            return new DiagnosticRecord(
+                Strings.AvoidUsingDoubleQuotesForConstantStringError,
+                stringConstantExpressionAst.Extent,
+                GetName(),
+                GetDiagnosticSeverity(),
+                stringConstantExpressionAst.Extent.File,
+                suggestedCorrections: new[] {
+                    new CorrectionExtent(
+                        stringConstantExpressionAst.Extent,
+                        suggestedCorrection,
+                        stringConstantExpressionAst.Extent.File
+                    )
+                }
+            );
+        }
+
+        /// <summary>
+        /// Retrieves the common name of this rule.
+        /// </summary>
+        public override string GetCommonName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingDoubleQuotesForConstantStringCommonName);
+        }
+
+        /// <summary>
+        /// Retrieves the description of this rule.
+        /// </summary>
+        public override string GetDescription()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.AvoidUsingDoubleQuotesForConstantStringDescription);
+        }
+
+        /// <summary>
+        /// Retrieves the name of this rule.
+        /// </summary>
+        public override string GetName()
+        {
+            return string.Format(
+                CultureInfo.CurrentCulture,
+                Strings.NameSpaceFormat,
+                GetSourceName(),
+                Strings.AvoidUsingDoubleQuotesForConstantStringName);
+        }
+
+        /// <summary>
+        /// Retrieves the severity of the rule: error, warning or information.
+        /// </summary>
+        public override RuleSeverity GetSeverity()
+        {
+            return RuleSeverity.Information;
+        }
+
+        /// <summary>
+        /// Gets the severity of the returned diagnostic record: error, warning, or information.
+        /// </summary>
+        /// <returns></returns>
+        public DiagnosticSeverity GetDiagnosticSeverity()
+        {
+            return DiagnosticSeverity.Information;
+        }
+
+        /// <summary>
+        /// Retrieves the name of the module/assembly the rule is from.
+        /// </summary>
+        public override string GetSourceName()
+        {
+            return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
+        }
+
+        /// <summary>
+        /// Retrieves the type of the rule, Builtin, Managed or Module.
+        /// </summary>
+        public override SourceType GetSourceType()
+        {
+            return SourceType.Builtin;
+        }
+    }
+}
diff --git a/Rules/AvoidUsingPlainTextForPassword.cs b/Rules/AvoidUsingPlainTextForPassword.cs
index f44585afc..6d877e400 100644
--- a/Rules/AvoidUsingPlainTextForPassword.cs
+++ b/Rules/AvoidUsingPlainTextForPassword.cs
@@ -64,37 +64,43 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
             }
         }
 
-        private List<CorrectionExtent> GetCorrectionExtent(ParameterAst paramAst)
+        private IEnumerable<CorrectionExtent> GetCorrectionExtent(ParameterAst paramAst)
         {
             //Find the parameter type extent and replace that with secure string
             IScriptExtent extent;
             var typeAttributeAst = GetTypeAttributeAst(paramAst);
             var corrections = new List<CorrectionExtent>();
             string correctionText;
-            if (typeAttributeAst == null)
-            {
-                // cannot find any type attribute
-                extent = paramAst.Name.Extent;
-                correctionText = string.Format("[SecureString] {0}", paramAst.Name.Extent.Text);
-            }
-            else
+
+            foreach (string correctionType in new[] { "SecureString", "PSCredential" })
             {
-                // replace only the existing type with [SecureString]
-                extent = typeAttributeAst.Extent;
-                correctionText = typeAttributeAst.TypeName.IsArray ? "[SecureString[]]" : "[SecureString]";
+                if (typeAttributeAst == null)
+                {
+                    // cannot find any type attribute
+                    extent = paramAst.Name.Extent;
+                    correctionText = $"[{correctionType}] {paramAst.Name.Extent.Text}";
+                }
+                else
+                {
+                    // replace only the existing type with [SecureString]
+                    extent = typeAttributeAst.Extent;
+                    correctionText = typeAttributeAst.TypeName.IsArray ? $"[{correctionType}[]]" : $"[{correctionType}]";
+                }
+                string description = string.Format(
+                    CultureInfo.CurrentCulture,
+                    Strings.AvoidUsingPlainTextForPasswordCorrectionDescription,
+                    paramAst.Name.Extent.Text,
+                    correctionType);
+                corrections.Add(new CorrectionExtent(
+                    extent.StartLineNumber,
+                    extent.EndLineNumber,
+                    extent.StartColumnNumber,
+                    extent.EndColumnNumber,
+                    correctionText.ToString(),
+                    paramAst.Extent.File,
+                    description));
             }
-            string description = string.Format(
-                CultureInfo.CurrentCulture,
-                Strings.AvoidUsingPlainTextForPasswordCorrectionDescription,
-                paramAst.Name.Extent.Text);
-            corrections.Add(new CorrectionExtent(
-                extent.StartLineNumber,
-                extent.EndLineNumber,
-                extent.StartColumnNumber,
-                extent.EndColumnNumber,
-                correctionText.ToString(),
-                paramAst.Extent.File,
-                description));
+
             return corrections;
         }
 
diff --git a/Rules/CompatibilityRules/UseCompatibleCommands.cs b/Rules/CompatibilityRules/UseCompatibleCommands.cs
index 0f7cfadbf..bad708e2c 100644
--- a/Rules/CompatibilityRules/UseCompatibleCommands.cs
+++ b/Rules/CompatibilityRules/UseCompatibleCommands.cs
@@ -263,8 +263,7 @@ public static CommandCompatibilityDiagnostic CreateForParameter(
             PlatformData platform,
             IScriptExtent extent,
             string analyzedFileName,
-            IRule rule,
-            IEnumerable<CorrectionExtent> suggestedCorrections = null)
+            IRule rule)
         {
             string message = string.Format(
                 CultureInfo.CurrentCulture,
diff --git a/Rules/ProvideCommentHelp.cs b/Rules/ProvideCommentHelp.cs
index 63e8d6438..3a46f0ada 100644
--- a/Rules/ProvideCommentHelp.cs
+++ b/Rules/ProvideCommentHelp.cs
@@ -264,13 +264,13 @@ private void GetCorrectionPosition(
 
         private class ViolationFinder : AstVisitor
         {
-            private HashSet<string> functionWhitelist;
+            private HashSet<string> functionAllowList;
             private List<FunctionDefinitionAst> functionDefinitionAsts;
-            private bool useFunctionWhitelist;
+            private bool useFunctionAllowList;
 
             public ViolationFinder()
             {
-                functionWhitelist = new HashSet<string>();
+                functionAllowList = new HashSet<string>();
                 functionDefinitionAsts = new List<FunctionDefinitionAst>();
             }
 
@@ -281,12 +281,12 @@ public ViolationFinder(HashSet<string> exportedFunctions) : this()
                     throw new ArgumentNullException(nameof(exportedFunctions));
                 }
 
-                this.functionWhitelist = exportedFunctions;
+                this.functionAllowList = exportedFunctions;
             }
 
             public ViolationFinder(HashSet<string> exportedFunctions, bool exportedOnly) : this(exportedFunctions)
             {
-                this.useFunctionWhitelist = exportedOnly;
+                this.useFunctionAllowList = exportedOnly;
             }
 
             public IEnumerable<FunctionDefinitionAst> FunctionDefinitionAsts
@@ -299,7 +299,7 @@ public IEnumerable<FunctionDefinitionAst> FunctionDefinitionAsts
 
             public override AstVisitAction VisitFunctionDefinition(FunctionDefinitionAst funcAst)
             {
-                if ((!useFunctionWhitelist || functionWhitelist.Contains(funcAst.Name))
+                if ((!useFunctionAllowList || functionAllowList.Contains(funcAst.Name))
                     && funcAst.GetHelpContent() == null)
                 {
                     functionDefinitionAsts.Add(funcAst);
diff --git a/Rules/ReviewUnusedParameter.cs b/Rules/ReviewUnusedParameter.cs
index 5a06500d8..9b727e7fc 100644
--- a/Rules/ReviewUnusedParameter.cs
+++ b/Rules/ReviewUnusedParameter.cs
@@ -6,6 +6,7 @@
 using System.Linq;
 using System.Management.Automation.Language;
 using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+using Microsoft.Windows.PowerShell.ScriptAnalyzer.Extensions;
 #if !CORECLR
 using System.ComponentModel.Composition;
 #endif
@@ -21,8 +22,60 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
 #endif
     public class ReviewUnusedParameter : IScriptRule
     {
+        private readonly string TraverseArgName = "CommandsToTraverse";
+        public List<string> TraverseCommands { get; private set; }
+
+        /// <summary>
+        /// Configure the rule.
+        ///
+        /// Sets the list of commands to traverse of this rule
+        /// </summary>
+        private void SetProperties()
+        {
+            TraverseCommands = new List<string>() { "Where-Object", "ForEach-Object" };
+
+            Dictionary<string, object> ruleArgs = Helper.Instance.GetRuleArguments(GetName());
+            if (ruleArgs == null)
+            {
+                return;
+            }
+
+            if (!ruleArgs.TryGetValue(TraverseArgName, out object obj))
+            {
+                return;
+            }
+            IEnumerable<string> commands = obj as IEnumerable<string>;
+            if (commands == null)
+            {
+                // try with enumerable objects
+                var enumerableObjs = obj as IEnumerable<object>;
+                if (enumerableObjs == null)
+                {
+                    return;
+                }
+                foreach (var x in enumerableObjs)
+                {
+                    var y = x as string;
+                    if (y == null)
+                    {
+                        return;
+                    }
+                    else
+                    {
+                        TraverseCommands.Add(y);
+                    }
+                }
+            }
+            else
+            {
+                TraverseCommands.AddRange(commands);
+            }
+        }
+
         public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
         {
+            SetProperties();
+
             if (ast == null)
             {
                 throw new ArgumentNullException(Strings.NullAstErrorMessage);
@@ -36,23 +89,49 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
 
             foreach (ScriptBlockAst scriptBlockAst in scriptBlockAsts)
             {
+                // bail out if PS bound parameter used.
+                if (scriptBlockAst.Find(IsBoundParametersReference, searchNestedScriptBlocks: false) != null)
+                {
+                    continue;
+                }
+
                 // find all declared parameters
                 IEnumerable<Ast> parameterAsts = scriptBlockAst.FindAll(oneAst => oneAst is ParameterAst, false);
 
-                // list all variables
-                IDictionary<string, int> variableCount = scriptBlockAst.FindAll(oneAst => oneAst is VariableExpressionAst, false)
-                    .Select(variableExpressionAst => ((VariableExpressionAst)variableExpressionAst).VariablePath.UserPath)
-                    .GroupBy(variableName => variableName, StringComparer.OrdinalIgnoreCase)
-                    .ToDictionary(variableName => variableName.Key, variableName => variableName.Count(), StringComparer.OrdinalIgnoreCase);
-
-                // all bets are off if the script uses PSBoundParameters
-                if (variableCount.ContainsKey("PSBoundParameters"))
+                // does the scriptblock have a process block where either $PSItem or $_ is referenced
+                bool hasProcessBlockWithPSItemOrUnderscore = false;
+                if (scriptBlockAst.ProcessBlock != null)
                 {
-                    continue;
+                    IDictionary<string, int> processBlockVariableCount = GetVariableCount(scriptBlockAst.ProcessBlock);
+                    processBlockVariableCount.TryGetValue("_", out int underscoreVariableCount);
+                    processBlockVariableCount.TryGetValue("psitem", out int psitemVariableCount);
+                    if (underscoreVariableCount > 0 || psitemVariableCount > 0)
+                    {
+                        hasProcessBlockWithPSItemOrUnderscore = true;
+                    }
                 }
 
+                // list all variables
+                IDictionary<string, int> variableCount = GetVariableCount(scriptBlockAst);
+
                 foreach (ParameterAst parameterAst in parameterAsts)
                 {
+                    // Check if the parameter has the ValueFromPipeline attribute
+                    NamedAttributeArgumentAst valueFromPipeline = (NamedAttributeArgumentAst)parameterAst.Find(
+                        valFromPipelineAst => valFromPipelineAst is NamedAttributeArgumentAst namedAttrib && string.Equals(
+                            namedAttrib.ArgumentName, "ValueFromPipeline",
+                            StringComparison.OrdinalIgnoreCase
+                        ),
+                        false
+                    );
+                    // If the parameter has the ValueFromPipeline attribute and the scriptblock has a process block with
+                    // $_ or $PSItem usage, then the parameter is considered used
+                    if (valueFromPipeline != null && valueFromPipeline.GetValue() && hasProcessBlockWithPSItemOrUnderscore)
+
+                    {
+                        continue;
+                    }
+
                     // there should be at least two usages of the variable since the parameter declaration counts as one
                     variableCount.TryGetValue(parameterAst.Name.VariablePath.UserPath, out int variableUsageCount);
                     if (variableUsageCount >= 2)
@@ -72,6 +151,47 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
             }
         }
 
+        /// <summary>
+        /// Checks for PS bound parameter reference.
+        /// </summary>
+        /// <param name="ast">AST to be analyzed. This should be non-null</param>
+        /// <returns>Boolean true indicating that given AST has PS bound parameter reference, otherwise false</returns>
+        private static bool IsBoundParametersReference(Ast ast)
+        {
+            // $PSBoundParameters
+            if (ast is VariableExpressionAst variableAst
+                && variableAst.VariablePath.UserPath.Equals("PSBoundParameters", StringComparison.OrdinalIgnoreCase))
+            {
+                return true;
+            }
+
+            if (ast is MemberExpressionAst memberAst
+                && memberAst.Member is StringConstantExpressionAst memberStringAst
+                && memberStringAst.Value.Equals("BoundParameters", StringComparison.OrdinalIgnoreCase))
+            {
+                // $MyInvocation.BoundParameters
+                if (memberAst.Expression is VariableExpressionAst veAst
+                    && veAst.VariablePath.UserPath.Equals("MyInvocation", StringComparison.OrdinalIgnoreCase))
+                {
+                    return true;
+                }
+
+                // $PSCmdlet.MyInvocation.BoundParameters
+                if (memberAst.Expression is MemberExpressionAst meAstNested)
+                {
+                    if (meAstNested.Expression is VariableExpressionAst veAstNested
+                        && veAstNested.VariablePath.UserPath.Equals("PSCmdlet", StringComparison.OrdinalIgnoreCase)
+                        && meAstNested.Member is StringConstantExpressionAst sceAstNested
+                        && sceAstNested.Value.Equals("MyInvocation", StringComparison.OrdinalIgnoreCase))
+                    {
+                        return true;
+                    }
+                }
+            }
+
+            return false;
+        }
+
         /// <summary>
         /// GetName: Retrieves the name of this rule.
         /// </summary>
@@ -123,5 +243,39 @@ public string GetSourceName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
         }
+
+        /// <summary>
+        /// Returns a dictionary including all variables in the scriptblock and their count
+        /// </summary>
+        /// <param name="ast">The scriptblock ast to scan</param>
+        /// <param name="data">Previously generated data. New findings are added to any existing dictionary if present</param>
+        /// <returns>a dictionary including all variables in the scriptblock and their count</returns>
+        IDictionary<string, int> GetVariableCount(Ast ast, Dictionary<string, int> data = null)
+        {
+            Dictionary<string, int> content = data;
+            if (null == data)
+                content = new Dictionary<string, int>(StringComparer.OrdinalIgnoreCase);
+            IDictionary<string, int> result = ast.FindAll(oneAst => oneAst is VariableExpressionAst, false)
+                    .Select(variableExpressionAst => ((VariableExpressionAst)variableExpressionAst).VariablePath.UserPath)
+                    .GroupBy(variableName => variableName, StringComparer.OrdinalIgnoreCase)
+                    .ToDictionary(variableName => variableName.Key, variableName => variableName.Count(), StringComparer.OrdinalIgnoreCase);
+            
+            foreach (string key in result.Keys)
+            {
+                if (content.ContainsKey(key))
+                    content[key] = content[key] + result[key];
+                else
+                    content[key] = result[key];
+            }
+
+            IEnumerable<Ast> foundScriptBlocks = ast.FindAll(oneAst => oneAst is ScriptBlockExpressionAst, false)
+                .Where(oneAst => oneAst?.Parent is CommandAst && ((CommandAst)oneAst.Parent).CommandElements[0] is StringConstantExpressionAst && TraverseCommands.Contains(((StringConstantExpressionAst)((CommandAst)oneAst.Parent).CommandElements[0]).Value, StringComparer.OrdinalIgnoreCase))
+                .Select(oneAst => ((ScriptBlockExpressionAst)oneAst).ScriptBlock);
+            foreach (Ast astItem in foundScriptBlocks)
+                if (astItem != ast)
+                    GetVariableCount((ScriptBlockAst)astItem, content);
+
+            return content;
+        }
     }
 }
diff --git a/Rules/Rules.csproj b/Rules/Rules.csproj
index 105e57723..6e485c4e9 100644
--- a/Rules/Rules.csproj
+++ b/Rules/Rules.csproj
@@ -1,57 +1,58 @@
-﻿<Project Sdk="Microsoft.NET.Sdk">
+<Project Sdk="Microsoft.NET.Sdk">
 
   <PropertyGroup>
-    <VersionPrefix>1.19.0</VersionPrefix>
-    <TargetFrameworks>netcoreapp3.1;netstandard2.0;net452</TargetFrameworks>
+    <VersionPrefix>$(ModuleVersion)</VersionPrefix>
+    <TargetFrameworks>net8;net462</TargetFrameworks>
     <AssemblyName>Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules</AssemblyName>
+    <AssemblyVersion>$(ModuleVersion)</AssemblyVersion>
     <PackageId>Rules</PackageId>
     <RootNamespace>Microsoft.Windows.PowerShell.ScriptAnalyzer</RootNamespace> <!-- Namespace needs to match Assembly name for ressource binding -->
+    <CopyLocalLockFileAssemblies>true</CopyLocalLockFileAssemblies> <!-- Needed in order for Pluralize.NET DLL to appear in bin folder - https://github.com/NuGet/Home/issues/4488 -->
   </PropertyGroup>
 
   <ItemGroup>
     <ProjectReference Include="..\Engine\Engine.csproj" />
     <ProjectReference Include="..\PSCompatibilityCollector\Microsoft.PowerShell.CrossCompatibility\Microsoft.PowerShell.CrossCompatibility.csproj" />
-    <PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
+
   </ItemGroup>
 
-  <ItemGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'netcoreapp3.1' ">
-    <PackageReference Include="Microsoft.Management.Infrastructure" Version="2.0.0" />
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net8' ">
+    <PackageReference Include="Newtonsoft.Json" />
+    <PackageReference Include="System.Reflection.TypeExtensions" />
+    <PackageReference Include="Microsoft.Management.Infrastructure" />
+    <PackageReference Include="Pluralize.NET" />
   </ItemGroup>
 
-  <ItemGroup Condition=" '$(TargetFramework)' == 'net452' ">
-    <PackageReference Include="Microsoft.Management.Infrastructure" Version="1.0.0" />
+  <ItemGroup Condition=" '$(TargetFramework)' == 'net462' ">
+    <PackageReference Include="Newtonsoft.Json" />
     <Reference Include="System.ComponentModel.Composition" />
     <Reference Include="System.Data.Entity.Design" />
   </ItemGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'net452' ">
+  <PropertyGroup Condition=" '$(TargetFramework)' == 'net462' ">
     <DebugType>portable</DebugType>
   </PropertyGroup>
 
-  <PropertyGroup Condition=" '$(TargetFramework)' == 'netstandard2.0' ">
-    <DefineConstants>$(DefineConstants);CORECLR</DefineConstants>
-  </PropertyGroup>
-
-  <ItemGroup>
-    <Compile Update="Strings.Designer.cs">
-      <DesignTime>True</DesignTime>
-      <AutoGen>True</AutoGen>
-      <DependentUpon>Strings.resx</DependentUpon>
-    </Compile>
-  </ItemGroup>
-
+  <!--
+       This ItemGroup and PropertyGroup block is required for resource generation to work for
+       .NET CLI, Visual Studio and VS-Code: https://github.com/dotnet/msbuild/issues/4751
+  -->
   <ItemGroup>
     <EmbeddedResource Update="Strings.resx">
-      <Generator>ResXFileCodeGenerator</Generator>
+      <!-- Tell Visual Studio that MSBuild will do the generation and run a build if resx file changes. -->
+      <Generator>MSBuild:Compile</Generator>
       <LastGenOutput>Strings.Designer.cs</LastGenOutput>
+      <StronglyTypedFileName>$(IntermediateOutputPath)\Strings.Designer.cs</StronglyTypedFileName>
+      <StronglyTypedLanguage>CSharp</StronglyTypedLanguage>
+      <StronglyTypedNamespace>Microsoft.Windows.PowerShell.ScriptAnalyzer</StronglyTypedNamespace>
+      <StronglyTypedClassName>Strings</StronglyTypedClassName>
     </EmbeddedResource>
   </ItemGroup>
+  <!-- For VS Code/OmniSharp support, ensure that CoreResGen runs before CoreCompile -->
+  <PropertyGroup>
+    <CoreCompileDependsOn>PrepareResources;$(CompileDependsOn)</CoreCompileDependsOn>
+  </PropertyGroup>
 
-  <ItemGroup Condition="'$(TargetFramework)' == 'netstandard2.0' OR '$(TargetFramework)' == 'netcoreapp3.1'">
-    <PackageReference Include="System.Reflection.TypeExtensions" Version="4.5.1" />
-    <Compile Remove="UseSingularNouns.cs" />
-  </ItemGroup>
-  
   <PropertyGroup Condition=" '$(Configuration)' == 'PSV3Release' OR '$(Configuration)' == 'PSV3Debug'">
     <DefineConstants>$(DefineConstants);PSV3</DefineConstants>
   </PropertyGroup>
@@ -60,12 +61,8 @@
     <DefineConstants>$(DefineConstants);PSV3;PSV4</DefineConstants>
   </PropertyGroup>
 
-  <PropertyGroup Condition="'$(TargetFramework)' == 'netcoreapp3.1'">
+  <PropertyGroup Condition="'$(TargetFramework)' == 'net8'">
     <DefineConstants>$(DefineConstants);PSV7;CORECLR</DefineConstants>
   </PropertyGroup>
 
-  <PropertyGroup Condition="'$(TargetFramework)' == 'netstandard2.0'">
-    <DefineConstants>$(DefineConstants);PSV6;CORECLR</DefineConstants>
-  </PropertyGroup>
-
 </Project>
diff --git a/Rules/Strings.Designer.cs b/Rules/Strings.Designer.cs
deleted file mode 100644
index 4b253c71a..000000000
--- a/Rules/Strings.Designer.cs
+++ /dev/null
@@ -1,3123 +0,0 @@
-﻿//------------------------------------------------------------------------------
-// <auto-generated>
-//     This code was generated by a tool.
-//     Runtime Version:4.0.30319.42000
-//
-//     Changes to this file may cause incorrect behavior and will be lost if
-//     the code is regenerated.
-// </auto-generated>
-//------------------------------------------------------------------------------
-
-namespace Microsoft.Windows.PowerShell.ScriptAnalyzer {
-    using System;
-    
-    
-    /// <summary>
-    ///   A strongly-typed resource class, for looking up localized strings, etc.
-    /// </summary>
-    // This class was auto-generated by the StronglyTypedResourceBuilder
-    // class via a tool like ResGen or Visual Studio.
-    // To add or remove a member, edit your .ResX file then rerun ResGen
-    // with the /str option, or rebuild your VS project.
-    [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "16.0.0.0")]
-    [global::System.Diagnostics.DebuggerNonUserCodeAttribute()]
-    [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()]
-    internal class Strings {
-        
-        private static global::System.Resources.ResourceManager resourceMan;
-        
-        private static global::System.Globalization.CultureInfo resourceCulture;
-        
-        [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")]
-        internal Strings() {
-        }
-        
-        /// <summary>
-        ///   Returns the cached ResourceManager instance used by this class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Resources.ResourceManager ResourceManager {
-            get {
-                if (object.ReferenceEquals(resourceMan, null)) {
-                    global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("Microsoft.Windows.PowerShell.ScriptAnalyzer.Strings", typeof(Strings).Assembly);
-                    resourceMan = temp;
-                }
-                return resourceMan;
-            }
-        }
-        
-        /// <summary>
-        ///   Overrides the current thread's CurrentUICulture property for all
-        ///   resource lookups using this strongly typed resource class.
-        /// </summary>
-        [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)]
-        internal static global::System.Globalization.CultureInfo Culture {
-            get {
-                return resourceCulture;
-            }
-            set {
-                resourceCulture = value;
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Align assignment statement.
-        /// </summary>
-        internal static string AlignAssignmentStatementCommonName {
-            get {
-                return ResourceManager.GetString("AlignAssignmentStatementCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line up assignment statements such that the assignment operator are aligned..
-        /// </summary>
-        internal static string AlignAssignmentStatementDescription {
-            get {
-                return ResourceManager.GetString("AlignAssignmentStatementDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Assignment statements are not aligned.
-        /// </summary>
-        internal static string AlignAssignmentStatementError {
-            get {
-                return ResourceManager.GetString("AlignAssignmentStatementError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AlignAssignmentStatement.
-        /// </summary>
-        internal static string AlignAssignmentStatementName {
-            get {
-                return ResourceManager.GetString("AlignAssignmentStatementName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidAssignmentToAutomaticVariable.
-        /// </summary>
-        internal static string AvoidAssignmentToAutomaticVariableName {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToAutomaticVariableName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use a different variable name.
-        /// </summary>
-        internal static string AvoidAssignmentToReadOnlyAutomaticVariable {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToReadOnlyAutomaticVariable", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Changing automtic variables might have undesired side effects.
-        /// </summary>
-        internal static string AvoidAssignmentToReadOnlyAutomaticVariableCommonName {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToReadOnlyAutomaticVariableCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to This automatic variables is built into PowerShell and readonly..
-        /// </summary>
-        internal static string AvoidAssignmentToReadOnlyAutomaticVariableDescription {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToReadOnlyAutomaticVariableDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Variable &apos;{0}&apos; cannot be assigned since it is a readonly automatic variable that is built into PowerShell, please use a different name..
-        /// </summary>
-        internal static string AvoidAssignmentToReadOnlyAutomaticVariableError {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToReadOnlyAutomaticVariableError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Starting from PowerShell 6.0, the Variable &apos;{0}&apos; cannot be assigned any more since it is a readonly automatic variable that is built into PowerShell, please use a different name..
-        /// </summary>
-        internal static string AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Variable &apos;{0}&apos; is an automatic variable that is built into PowerShell, assigning to it might have undesired side effects. If assignment is not by design, please use a different name..
-        /// </summary>
-        internal static string AvoidAssignmentToWritableAutomaticVariableError {
-            get {
-                return ResourceManager.GetString("AvoidAssignmentToWritableAutomaticVariableError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using ComputerName Hardcoded.
-        /// </summary>
-        internal static string AvoidComputerNameHardcodedCommonName {
-            get {
-                return ResourceManager.GetString("AvoidComputerNameHardcodedCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The ComputerName parameter of a cmdlet should not be hardcoded as this will expose sensitive information about the system..
-        /// </summary>
-        internal static string AvoidComputerNameHardcodedDescription {
-            get {
-                return ResourceManager.GetString("AvoidComputerNameHardcodedDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The ComputerName parameter of cmdlet &apos;{0}&apos; is hardcoded. This will expose sensitive information about the system if the script is shared..
-        /// </summary>
-        internal static string AvoidComputerNameHardcodedError {
-            get {
-                return ResourceManager.GetString("AvoidComputerNameHardcodedError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingComputerNameHardcoded.
-        /// </summary>
-        internal static string AvoidComputerNameHardcodedName {
-            get {
-                return ResourceManager.GetString("AvoidComputerNameHardcodedName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Default Value For Mandatory Parameter.
-        /// </summary>
-        internal static string AvoidDefaultValueForMandatoryParameterCommonName {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueForMandatoryParameterCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Mandatory parameter should not be initialized with a default value in the param block because this value will be ignored.. To fix a violation of this rule, please avoid initializing a value for the mandatory parameter in the param block..
-        /// </summary>
-        internal static string AvoidDefaultValueForMandatoryParameterDescription {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueForMandatoryParameterDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Mandatory Parameter &apos;{0}&apos; is initialized in the Param block. To fix a violation of this rule, please leave it uninitialized..
-        /// </summary>
-        internal static string AvoidDefaultValueForMandatoryParameterError {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueForMandatoryParameterError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidDefaultValueForMandatoryParameter.
-        /// </summary>
-        internal static string AvoidDefaultValueForMandatoryParameterName {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueForMandatoryParameterName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Switch Parameters Should Not Default To True.
-        /// </summary>
-        internal static string AvoidDefaultValueSwitchParameterCommonName {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueSwitchParameterCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Switch parameter should not default to true..
-        /// </summary>
-        internal static string AvoidDefaultValueSwitchParameterDescription {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueSwitchParameterDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File &apos;{0}&apos; has a switch parameter default to true..
-        /// </summary>
-        internal static string AvoidDefaultValueSwitchParameterError {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueSwitchParameterError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Script definition has a switch parameter default to true..
-        /// </summary>
-        internal static string AvoidDefaultValueSwitchParameterErrorScriptDefinition {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueSwitchParameterErrorScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidDefaultValueSwitchParameter.
-        /// </summary>
-        internal static string AvoidDefaultValueSwitchParameterName {
-            get {
-                return ResourceManager.GetString("AvoidDefaultValueSwitchParameterName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Empty catch block is used. Please use Write-Error or throw statements in catch blocks..
-        /// </summary>
-        internal static string AvoidEmptyCatchBlockError {
-            get {
-                return ResourceManager.GetString("AvoidEmptyCatchBlockError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid global aliases..
-        /// </summary>
-        internal static string AvoidGlobalAliasesCommonName {
-            get {
-                return ResourceManager.GetString("AvoidGlobalAliasesCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that global aliases are not used. Global aliases are strongly discouraged as they overwrite desired aliases with name conflicts..
-        /// </summary>
-        internal static string AvoidGlobalAliasesDescription {
-            get {
-                return ResourceManager.GetString("AvoidGlobalAliasesDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid creating aliases with a Global scope..
-        /// </summary>
-        internal static string AvoidGlobalAliasesError {
-            get {
-                return ResourceManager.GetString("AvoidGlobalAliasesError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidGlobalAliases.
-        /// </summary>
-        internal static string AvoidGlobalAliasesName {
-            get {
-                return ResourceManager.GetString("AvoidGlobalAliasesName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid global functiosn and aliases.
-        /// </summary>
-        internal static string AvoidGlobalFunctionsCommonName {
-            get {
-                return ResourceManager.GetString("AvoidGlobalFunctionsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that global functions and aliases are not used. Global functions are strongly discouraged as they can cause errors across different systems..
-        /// </summary>
-        internal static string AvoidGlobalFunctionsDescription {
-            get {
-                return ResourceManager.GetString("AvoidGlobalFunctionsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid creating functions with a Global scope..
-        /// </summary>
-        internal static string AvoidGlobalFunctionsError {
-            get {
-                return ResourceManager.GetString("AvoidGlobalFunctionsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidGlobalFunctions.
-        /// </summary>
-        internal static string AvoidGlobalFunctionsName {
-            get {
-                return ResourceManager.GetString("AvoidGlobalFunctionsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to No Global Variables.
-        /// </summary>
-        internal static string AvoidGlobalVarsCommonName {
-            get {
-                return ResourceManager.GetString("AvoidGlobalVarsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that global variables are not used. Global variables are strongly discouraged as they can cause errors across different systems..
-        /// </summary>
-        internal static string AvoidGlobalVarsDescription {
-            get {
-                return ResourceManager.GetString("AvoidGlobalVarsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Found global variable &apos;{0}&apos;..
-        /// </summary>
-        internal static string AvoidGlobalVarsError {
-            get {
-                return ResourceManager.GetString("AvoidGlobalVarsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidGlobalVars.
-        /// </summary>
-        internal static string AvoidGlobalVarsName {
-            get {
-                return ResourceManager.GetString("AvoidGlobalVarsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Invoking Empty Members.
-        /// </summary>
-        internal static string AvoidInvokingEmptyMembersCommonName {
-            get {
-                return ResourceManager.GetString("AvoidInvokingEmptyMembersCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Invoking non-constant members would cause potential bugs. Please double check the syntax to make sure members invoked are non-constant..
-        /// </summary>
-        internal static string AvoidInvokingEmptyMembersDescription {
-            get {
-                return ResourceManager.GetString("AvoidInvokingEmptyMembersDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; has non-constant members. Invoking non-constant members may cause bugs in the script..
-        /// </summary>
-        internal static string AvoidInvokingEmptyMembersError {
-            get {
-                return ResourceManager.GetString("AvoidInvokingEmptyMembersError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidInvokingEmptyMembers.
-        /// </summary>
-        internal static string AvoidInvokingEmptyMembersName {
-            get {
-                return ResourceManager.GetString("AvoidInvokingEmptyMembersName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid long lines.
-        /// </summary>
-        internal static string AvoidLongLinesCommonName {
-            get {
-                return ResourceManager.GetString("AvoidLongLinesCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line lengths should be less than the configured maximum.
-        /// </summary>
-        internal static string AvoidLongLinesDescription {
-            get {
-                return ResourceManager.GetString("AvoidLongLinesDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line exceeds the configured maximum length of {0} characters.
-        /// </summary>
-        internal static string AvoidLongLinesError {
-            get {
-                return ResourceManager.GetString("AvoidLongLinesError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidLongLines.
-        /// </summary>
-        internal static string AvoidLongLinesName {
-            get {
-                return ResourceManager.GetString("AvoidLongLinesName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid using null or empty HelpMessage parameter attribute..
-        /// </summary>
-        internal static string AvoidNullOrEmptyHelpMessageAttributeCommonName {
-            get {
-                return ResourceManager.GetString("AvoidNullOrEmptyHelpMessageAttributeCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Setting the HelpMessage attribute to an empty string or null value causes PowerShell interpreter to throw an error while executing the corresponding function..
-        /// </summary>
-        internal static string AvoidNullOrEmptyHelpMessageAttributeDescription {
-            get {
-                return ResourceManager.GetString("AvoidNullOrEmptyHelpMessageAttributeDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to HelpMessage parameter attribute should not be null or empty. To fix a violation of this rule, please set its value to a non-empty string..
-        /// </summary>
-        internal static string AvoidNullOrEmptyHelpMessageAttributeError {
-            get {
-                return ResourceManager.GetString("AvoidNullOrEmptyHelpMessageAttributeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidNullOrEmptyHelpMessageAttribute.
-        /// </summary>
-        internal static string AvoidNullOrEmptyHelpMessageAttributeName {
-            get {
-                return ResourceManager.GetString("AvoidNullOrEmptyHelpMessageAttributeName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid overwriting built in cmdlets.
-        /// </summary>
-        internal static string AvoidOverwritingBuiltInCmdletsCommonName {
-            get {
-                return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Do not overwrite the definition of a cmdlet that is included with PowerShell.
-        /// </summary>
-        internal static string AvoidOverwritingBuiltInCmdletsDescription {
-            get {
-                return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; is a cmdlet that is included with PowerShell (version {1}) whose definition should not be overridden.
-        /// </summary>
-        internal static string AvoidOverwritingBuiltInCmdletsError {
-            get {
-                return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidOverwritingBuiltInCmdlets.
-        /// </summary>
-        internal static string AvoidOverwritingBuiltInCmdletsName {
-            get {
-                return ResourceManager.GetString("AvoidOverwritingBuiltInCmdletsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using ShouldContinue Without Boolean Force Parameter.
-        /// </summary>
-        internal static string AvoidShouldContinueWithoutForceCommonName {
-            get {
-                return ResourceManager.GetString("AvoidShouldContinueWithoutForceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Functions that use ShouldContinue should have a boolean force parameter to allow user to bypass it..
-        /// </summary>
-        internal static string AvoidShouldContinueWithoutForceDescription {
-            get {
-                return ResourceManager.GetString("AvoidShouldContinueWithoutForceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Function &apos;{0}&apos; in file &apos;{1}&apos; uses ShouldContinue but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt.
-        /// </summary>
-        internal static string AvoidShouldContinueWithoutForceError {
-            get {
-                return ResourceManager.GetString("AvoidShouldContinueWithoutForceError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Function &apos;{0}&apos; in script definition uses ShouldContinue but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt.
-        /// </summary>
-        internal static string AvoidShouldContinueWithoutForceErrorScriptDefinition {
-            get {
-                return ResourceManager.GetString("AvoidShouldContinueWithoutForceErrorScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidShouldContinueWithoutForce.
-        /// </summary>
-        internal static string AvoidShouldContinueWithoutForceName {
-            get {
-                return ResourceManager.GetString("AvoidShouldContinueWithoutForceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid trailing whitespace.
-        /// </summary>
-        internal static string AvoidTrailingWhitespaceCommonName {
-            get {
-                return ResourceManager.GetString("AvoidTrailingWhitespaceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Each line should have no trailing whitespace..
-        /// </summary>
-        internal static string AvoidTrailingWhitespaceDescription {
-            get {
-                return ResourceManager.GetString("AvoidTrailingWhitespaceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Line has trailing whitespace.
-        /// </summary>
-        internal static string AvoidTrailingWhitespaceError {
-            get {
-                return ResourceManager.GetString("AvoidTrailingWhitespaceError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidTrailingWhitespace.
-        /// </summary>
-        internal static string AvoidTrailingWhitespaceName {
-            get {
-                return ResourceManager.GetString("AvoidTrailingWhitespaceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Module Must Be Loadable.
-        /// </summary>
-        internal static string AvoidUnloadableModuleCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUnloadableModuleCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to If a script file is in a PowerShell module folder, then that folder must be loadable..
-        /// </summary>
-        internal static string AvoidUnloadableModuleDescription {
-            get {
-                return ResourceManager.GetString("AvoidUnloadableModuleDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot load the module &apos;{0}&apos; that file &apos;{1}&apos; is in..
-        /// </summary>
-        internal static string AvoidUnloadableModuleError {
-            get {
-                return ResourceManager.GetString("AvoidUnloadableModuleError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUnloadableModule.
-        /// </summary>
-        internal static string AvoidUnloadableModuleName {
-            get {
-                return ResourceManager.GetString("AvoidUnloadableModuleName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Username and Password Parameters.
-        /// </summary>
-        internal static string AvoidUsernameAndPasswordParamsCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsernameAndPasswordParamsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Functions should take in a Credential parameter of type PSCredential (with a Credential transformation attribute defined after it in PowerShell 4.0 or earlier) or set the Password parameter to type SecureString..
-        /// </summary>
-        internal static string AvoidUsernameAndPasswordParamsDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsernameAndPasswordParamsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Function &apos;{0}&apos; has both Username and Password parameters. Either set the type of the Password parameter to SecureString or replace the Username and Password parameters with a Credential parameter of type PSCredential. If using a Credential parameter in PowerShell 4.0 or earlier, please define a credential transformation attribute after the PSCredential type attribute..
-        /// </summary>
-        internal static string AvoidUsernameAndPasswordParamsError {
-            get {
-                return ResourceManager.GetString("AvoidUsernameAndPasswordParamsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingUsernameAndPasswordParams.
-        /// </summary>
-        internal static string AvoidUsernameAndPasswordParamsName {
-            get {
-                return ResourceManager.GetString("AvoidUsernameAndPasswordParamsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Clear-Host.
-        /// </summary>
-        internal static string AvoidUsingClearHostCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingClearHostCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Using Clear-Host is not recommended because the cmdlet may not work in some hosts or there may even be no hosts at all..
-        /// </summary>
-        internal static string AvoidUsingClearHostDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingClearHostDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File &apos;{0}&apos; uses Clear-Host. This is not recommended because it may not work in some hosts or there may even be no hosts at all..
-        /// </summary>
-        internal static string AvoidUsingClearHostError {
-            get {
-                return ResourceManager.GetString("AvoidUsingClearHostError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingClearHost.
-        /// </summary>
-        internal static string AvoidUsingClearHostName {
-            get {
-                return ResourceManager.GetString("AvoidUsingClearHostName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Cmdlet Aliases or omitting the &apos;Get-&apos; prefix..
-        /// </summary>
-        internal static string AvoidUsingCmdletAliasesCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingCmdletAliasesCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Replace {0} with {1}.
-        /// </summary>
-        internal static string AvoidUsingCmdletAliasesCorrectionDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingCmdletAliasesCorrectionDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to An alias is an alternate name or nickname for a cmdlet or for a command element, such as a function, script, file, or executable file. An implicit alias is also the omission of the &apos;Get-&apos; prefix for commands with this prefix. But when writing scripts that will potentially need to be maintained over time, either by the original author or another Windows PowerShell scripter, please consider using full cmdlet name instead of alias. Aliases can introduce these problems, readability, understandability and availa [rest of string was truncated]&quot;;.
-        /// </summary>
-        internal static string AvoidUsingCmdletAliasesDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingCmdletAliasesDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; is an alias of &apos;{1}&apos;. Alias can introduce possible problems and make scripts hard to maintain. Please consider changing alias to its full content..
-        /// </summary>
-        internal static string AvoidUsingCmdletAliasesError {
-            get {
-                return ResourceManager.GetString("AvoidUsingCmdletAliasesError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; is implicitly aliasing &apos;{1}&apos; because it is missing the &apos;Get-&apos; prefix. This can introduce possible problems and make scripts hard to maintain. Please consider changing command to its full name..
-        /// </summary>
-        internal static string AvoidUsingCmdletAliasesMissingGetPrefixError {
-            get {
-                return ResourceManager.GetString("AvoidUsingCmdletAliasesMissingGetPrefixError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingCmdletAliases.
-        /// </summary>
-        internal static string AvoidUsingCmdletAliasesName {
-            get {
-                return ResourceManager.GetString("AvoidUsingCmdletAliasesName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File &apos;{0}&apos; uses Console.&apos;{1}&apos;. Using Console to write is not recommended because it may not work in all hosts or there may even be no hosts at all. Use Write-Output instead..
-        /// </summary>
-        internal static string AvoidUsingConsoleWriteError {
-            get {
-                return ResourceManager.GetString("AvoidUsingConsoleWriteError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using SecureString With Plain Text.
-        /// </summary>
-        internal static string AvoidUsingConvertToSecureStringWithPlainTextCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingConvertToSecureStringWithPlainTextCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Using ConvertTo-SecureString with plain text will expose secure information..
-        /// </summary>
-        internal static string AvoidUsingConvertToSecureStringWithPlainTextDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingConvertToSecureStringWithPlainTextDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File &apos;{0}&apos; uses ConvertTo-SecureString with plaintext. This will expose secure information. Encrypted standard strings should be used instead..
-        /// </summary>
-        internal static string AvoidUsingConvertToSecureStringWithPlainTextError {
-            get {
-                return ResourceManager.GetString("AvoidUsingConvertToSecureStringWithPlainTextError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Script definition uses ConvertTo-SecureString with plaintext. This will expose secure information. Encrypted standard strings should be used instead..
-        /// </summary>
-        internal static string AvoidUsingConvertToSecureStringWithPlainTextErrorScriptDefinition {
-            get {
-                return ResourceManager.GetString("AvoidUsingConvertToSecureStringWithPlainTextErrorScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingConvertToSecureStringWithPlainText.
-        /// </summary>
-        internal static string AvoidUsingConvertToSecureStringWithPlainTextName {
-            get {
-                return ResourceManager.GetString("AvoidUsingConvertToSecureStringWithPlainTextName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Deprecated Manifest Fields.
-        /// </summary>
-        internal static string AvoidUsingDeprecatedManifestFieldsCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingDeprecatedManifestFieldsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &quot;ModuleToProcess&quot; is obsolete in the latest PowerShell version. Please update with the latest field &quot;RootModule&quot; in manifest files to avoid PowerShell version inconsistency..
-        /// </summary>
-        internal static string AvoidUsingDeprecatedManifestFieldsDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingDeprecatedManifestFieldsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingDeprecatedManifestFields.
-        /// </summary>
-        internal static string AvoidUsingDeprecatedManifestFieldsName {
-            get {
-                return ResourceManager.GetString("AvoidUsingDeprecatedManifestFieldsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Empty Catch Block.
-        /// </summary>
-        internal static string AvoidUsingEmptyCatchBlockCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingEmptyCatchBlockCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Empty catch blocks are considered poor design decisions because if an error occurs in the try block, this error is simply swallowed and not acted upon. While this does not inherently lead to bad things. It can and this should be avoided if possible. To fix a violation of this rule, using Write-Error or throw statements in catch blocks..
-        /// </summary>
-        internal static string AvoidUsingEmptyCatchBlockDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingEmptyCatchBlockDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingEmptyCatchBlock.
-        /// </summary>
-        internal static string AvoidUsingEmptyCatchBlockName {
-            get {
-                return ResourceManager.GetString("AvoidUsingEmptyCatchBlockName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Internal URLs.
-        /// </summary>
-        internal static string AvoidUsingInternalURLsCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingInternalURLsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Using Internal URLs in the scripts may cause security problems..
-        /// </summary>
-        internal static string AvoidUsingInternalURLsDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingInternalURLsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; could be an internal URL. Using internal URL directly in the script may cause potential information disclosure..
-        /// </summary>
-        internal static string AvoidUsingInternalURLsError {
-            get {
-                return ResourceManager.GetString("AvoidUsingInternalURLsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingInternalURLs.
-        /// </summary>
-        internal static string AvoidUsingInternalURLsName {
-            get {
-                return ResourceManager.GetString("AvoidUsingInternalURLsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Invoke-Expression is used. Please remove Invoke-Expression from script and find other options instead..
-        /// </summary>
-        internal static string AvoidUsingInvokeExpressionError {
-            get {
-                return ResourceManager.GetString("AvoidUsingInvokeExpressionError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Invoke-Expression.
-        /// </summary>
-        internal static string AvoidUsingInvokeExpressionRuleCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingInvokeExpressionRuleCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Invoke-Expression cmdlet evaluates or runs a specified string as a command and returns the results of the expression or command. It can be extraordinarily powerful so it is not that you want to never use it but you need to be very careful about using it.  In particular, you are probably on safe ground if the data only comes from the program itself.  If you include any data provided from the user - you need to protect yourself from Code Injection. To fix a violation of this rule, please remove Invoke-Exp [rest of string was truncated]&quot;;.
-        /// </summary>
-        internal static string AvoidUsingInvokeExpressionRuleDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingInvokeExpressionRuleDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingInvokeExpression.
-        /// </summary>
-        internal static string AvoidUsingInvokeExpressionRuleName {
-            get {
-                return ResourceManager.GetString("AvoidUsingInvokeExpressionRuleName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Plain Text For Password Parameter.
-        /// </summary>
-        internal static string AvoidUsingPlainTextForPasswordCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingPlainTextForPasswordCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Set {0} type to SecureString.
-        /// </summary>
-        internal static string AvoidUsingPlainTextForPasswordCorrectionDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingPlainTextForPasswordCorrectionDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Password parameters that take in plaintext will expose passwords and compromise the security of your system..
-        /// </summary>
-        internal static string AvoidUsingPlainTextForPasswordDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingPlainTextForPasswordDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Parameter &apos;{0}&apos; should use SecureString, otherwise this will expose sensitive information. See ConvertTo-SecureString for more information..
-        /// </summary>
-        internal static string AvoidUsingPlainTextForPasswordError {
-            get {
-                return ResourceManager.GetString("AvoidUsingPlainTextForPasswordError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingPlainTextForPassword.
-        /// </summary>
-        internal static string AvoidUsingPlainTextForPasswordName {
-            get {
-                return ResourceManager.GetString("AvoidUsingPlainTextForPasswordName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Positional Parameters.
-        /// </summary>
-        internal static string AvoidUsingPositionalParametersCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingPositionalParametersCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Readability and clarity should be the goal of any script we expect to maintain over time. When calling a command that takes parameters, where possible consider using name parameters as opposed to positional parameters. To fix a violation of this rule, please use named parameters instead of positional parameters when calling a command..
-        /// </summary>
-        internal static string AvoidUsingPositionalParametersDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingPositionalParametersDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet &apos;{0}&apos; has positional parameter. Please use named parameters instead of positional parameters when calling a command..
-        /// </summary>
-        internal static string AvoidUsingPositionalParametersError {
-            get {
-                return ResourceManager.GetString("AvoidUsingPositionalParametersError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingPositionalParameters.
-        /// </summary>
-        internal static string AvoidUsingPositionalParametersName {
-            get {
-                return ResourceManager.GetString("AvoidUsingPositionalParametersName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance.
-        /// </summary>
-        internal static string AvoidUsingWMICmdletCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingWMICmdletCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Deprecated. Starting in Windows PowerShell 3.0, these cmdlets have been superseded by CIM cmdlets..
-        /// </summary>
-        internal static string AvoidUsingWMICmdletDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingWMICmdletDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File &apos;{0}&apos; uses WMI cmdlet. For PowerShell 3.0 and above, use CIM cmdlet which perform the same tasks as the WMI cmdlets. The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, which enables the cmdlets to use the same techniques to manage Windows computers and those running other operating systems..
-        /// </summary>
-        internal static string AvoidUsingWMICmdletError {
-            get {
-                return ResourceManager.GetString("AvoidUsingWMICmdletError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Script definition uses WMI cmdlet. For PowerShell 3.0 and above, use CIM cmdlet which perform the same tasks as the WMI cmdlets. The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, which enables the cmdlets to use the same techniques to manage Windows computers and those running other operating systems..
-        /// </summary>
-        internal static string AvoidUsingWMICmdletErrorScriptDefinition {
-            get {
-                return ResourceManager.GetString("AvoidUsingWMICmdletErrorScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingWMICmdlet.
-        /// </summary>
-        internal static string AvoidUsingWMICmdletName {
-            get {
-                return ResourceManager.GetString("AvoidUsingWMICmdletName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid Using Write-Host.
-        /// </summary>
-        internal static string AvoidUsingWriteHostCommonName {
-            get {
-                return ResourceManager.GetString("AvoidUsingWriteHostCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Avoid using the Write-Host cmdlet. Instead, use Write-Output, Write-Verbose, or Write-Information. Because Write-Host is host-specific, its implementation might vary unpredictably. Also, prior to PowerShell 5.0, Write-Host did not write to a stream, so users cannot suppress it, capture its value, or redirect it..
-        /// </summary>
-        internal static string AvoidUsingWriteHostDescription {
-            get {
-                return ResourceManager.GetString("AvoidUsingWriteHostDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File &apos;{0}&apos; uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information..
-        /// </summary>
-        internal static string AvoidUsingWriteHostError {
-            get {
-                return ResourceManager.GetString("AvoidUsingWriteHostError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Script definition uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information..
-        /// </summary>
-        internal static string AvoidUsingWriteHostErrorScriptDefinition {
-            get {
-                return ResourceManager.GetString("AvoidUsingWriteHostErrorScriptDefinition", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to AvoidUsingWriteHost.
-        /// </summary>
-        internal static string AvoidUsingWriteHostName {
-            get {
-                return ResourceManager.GetString("AvoidUsingWriteHostName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Command Not Found.
-        /// </summary>
-        internal static string CommandNotFoundCommonName {
-            get {
-                return ResourceManager.GetString("CommandNotFoundCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Commands that are undefined or do not exist should not be used..
-        /// </summary>
-        internal static string CommandNotFoundDescription {
-            get {
-                return ResourceManager.GetString("CommandNotFoundDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Command &apos;{0}&apos; Is Not Found.
-        /// </summary>
-        internal static string CommandNotFoundError {
-            get {
-                return ResourceManager.GetString("CommandNotFoundError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to CommandNotFound.
-        /// </summary>
-        internal static string CommandNotFoundName {
-            get {
-                return ResourceManager.GetString("CommandNotFoundName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to DscExamplesPresent.
-        /// </summary>
-        internal static string DscExamplesPresent {
-            get {
-                return ResourceManager.GetString("DscExamplesPresent", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to DSC examples are present.
-        /// </summary>
-        internal static string DscExamplesPresentCommonName {
-            get {
-                return ResourceManager.GetString("DscExamplesPresentCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Every DSC resource module should contain folder &quot;Examples&quot; with sample configurations for every resource. Sample configurations should have resource name they are demonstrating in the title..
-        /// </summary>
-        internal static string DscExamplesPresentDescription {
-            get {
-                return ResourceManager.GetString("DscExamplesPresentDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to No examples found for resource &apos;{0}&apos;.
-        /// </summary>
-        internal static string DscExamplesPresentNoExamplesError {
-            get {
-                return ResourceManager.GetString("DscExamplesPresentNoExamplesError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PSDSC.
-        /// </summary>
-        internal static string DSCSourceName {
-            get {
-                return ResourceManager.GetString("DSCSourceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to DscTestsPresent.
-        /// </summary>
-        internal static string DscTestsPresent {
-            get {
-                return ResourceManager.GetString("DscTestsPresent", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Dsc tests are present.
-        /// </summary>
-        internal static string DscTestsPresentCommonName {
-            get {
-                return ResourceManager.GetString("DscTestsPresentCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Every DSC resource module should contain folder &quot;Tests&quot; with tests for every resource. Test scripts should have resource name they are testing in the file name..
-        /// </summary>
-        internal static string DscTestsPresentDescription {
-            get {
-                return ResourceManager.GetString("DscTestsPresentDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to No tests found for resource &apos;{0}&apos;.
-        /// </summary>
-        internal static string DscTestsPresentNoTestsError {
-            get {
-                return ResourceManager.GetString("DscTestsPresentNoTestsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Misleading Backtick.
-        /// </summary>
-        internal static string MisleadingBacktickCommonName {
-            get {
-                return ResourceManager.GetString("MisleadingBacktickCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Ending a line with an escaped whitepsace character is misleading. A trailing backtick is usually used for line continuation. Users typically don&apos;t intend to end a line with escaped whitespace..
-        /// </summary>
-        internal static string MisleadingBacktickDescription {
-            get {
-                return ResourceManager.GetString("MisleadingBacktickDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to This line has a backtick at the end trailed by a whitespace character. Did you mean for this to be a line continuation?.
-        /// </summary>
-        internal static string MisleadingBacktickError {
-            get {
-                return ResourceManager.GetString("MisleadingBacktickError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to MisleadingBacktick.
-        /// </summary>
-        internal static string MisleadingBacktickName {
-            get {
-                return ResourceManager.GetString("MisleadingBacktickName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Module Manifest Fields.
-        /// </summary>
-        internal static string MissingModuleManifestFieldCommonName {
-            get {
-                return ResourceManager.GetString("MissingModuleManifestFieldCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Add {0} = {1} to the module manifest.
-        /// </summary>
-        internal static string MissingModuleManifestFieldCorrectionDescription {
-            get {
-                return ResourceManager.GetString("MissingModuleManifestFieldCorrectionDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Some fields of the module manifest (such as ModuleVersion) are required..
-        /// </summary>
-        internal static string MissingModuleManifestFieldDescription {
-            get {
-                return ResourceManager.GetString("MissingModuleManifestFieldDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to MissingModuleManifestField.
-        /// </summary>
-        internal static string MissingModuleManifestFieldName {
-            get {
-                return ResourceManager.GetString("MissingModuleManifestFieldName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0}{1}.
-        /// </summary>
-        internal static string NameSpaceFormat {
-            get {
-                return ResourceManager.GetString("NameSpaceFormat", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Not all code path in {0} function in DSC Class {1} returns a value.
-        /// </summary>
-        internal static string NotAllCodePathReturnsDSCFunctionsError {
-            get {
-                return ResourceManager.GetString("NotAllCodePathReturnsDSCFunctionsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot process null Ast.
-        /// </summary>
-        internal static string NullAstErrorMessage {
-            get {
-                return ResourceManager.GetString("NullAstErrorMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cannot process null CommandInfo.
-        /// </summary>
-        internal static string NullCommandInfoError {
-            get {
-                return ResourceManager.GetString("NullCommandInfoError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Error Message is Null..
-        /// </summary>
-        internal static string NullErrorMessage {
-            get {
-                return ResourceManager.GetString("NullErrorMessage", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to One Char.
-        /// </summary>
-        internal static string OneCharCommonName {
-            get {
-                return ResourceManager.GetString("OneCharCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that cmdlets and parameters have more than one character..
-        /// </summary>
-        internal static string OneCharDescription {
-            get {
-                return ResourceManager.GetString("OneCharDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet name &apos;{0}&apos; only has one character..
-        /// </summary>
-        internal static string OneCharErrorCmdlet {
-            get {
-                return ResourceManager.GetString("OneCharErrorCmdlet", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos; has a parameter &apos;{1}&apos; that only has one character..
-        /// </summary>
-        internal static string OneCharErrorParameter {
-            get {
-                return ResourceManager.GetString("OneCharErrorParameter", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to A script block has a parameter &apos;{0}&apos; that only has one character..
-        /// </summary>
-        internal static string OneCharErrorParameterSB {
-            get {
-                return ResourceManager.GetString("OneCharErrorParameterSB", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to OneChar.
-        /// </summary>
-        internal static string OneCharName {
-            get {
-                return ResourceManager.GetString("OneCharName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Place close braces.
-        /// </summary>
-        internal static string PlaceCloseBraceCommonName {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Close brace should be on a new line by itself..
-        /// </summary>
-        internal static string PlaceCloseBraceDescription {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Close brace is not on a new line..
-        /// </summary>
-        internal static string PlaceCloseBraceErrorShouldBeOnNewLine {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceErrorShouldBeOnNewLine", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Close brace before a branch statement is followed by a new line..
-        /// </summary>
-        internal static string PlaceCloseBraceErrorShouldCuddleBranchStatement {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceErrorShouldCuddleBranchStatement", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Close brace does not follow a new line..
-        /// </summary>
-        internal static string PlaceCloseBraceErrorShouldFollowNewLine {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceErrorShouldFollowNewLine", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Close brace does not follow a non-empty line..
-        /// </summary>
-        internal static string PlaceCloseBraceErrorShouldNotFollowEmptyLine {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceErrorShouldNotFollowEmptyLine", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PlaceCloseBrace.
-        /// </summary>
-        internal static string PlaceCloseBraceName {
-            get {
-                return ResourceManager.GetString("PlaceCloseBraceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Place open braces consistently.
-        /// </summary>
-        internal static string PlaceOpenBraceCommonName {
-            get {
-                return ResourceManager.GetString("PlaceOpenBraceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Place open braces either on the same line as the preceding expression or on a new line..
-        /// </summary>
-        internal static string PlaceOpenBraceDescription {
-            get {
-                return ResourceManager.GetString("PlaceOpenBraceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to There is no new line after open brace..
-        /// </summary>
-        internal static string PlaceOpenBraceErrorNoNewLineAfterBrace {
-            get {
-                return ResourceManager.GetString("PlaceOpenBraceErrorNoNewLineAfterBrace", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Open brace not on same line as preceding keyword. It should be on the same line..
-        /// </summary>
-        internal static string PlaceOpenBraceErrorShouldBeOnSameLine {
-            get {
-                return ResourceManager.GetString("PlaceOpenBraceErrorShouldBeOnSameLine", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Open brace is not on a new line..
-        /// </summary>
-        internal static string PlaceOpenBraceErrorShouldNotBeOnSameLine {
-            get {
-                return ResourceManager.GetString("PlaceOpenBraceErrorShouldNotBeOnSameLine", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PlaceOpenBrace.
-        /// </summary>
-        internal static string PlaceOpenBraceName {
-            get {
-                return ResourceManager.GetString("PlaceOpenBraceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Null Comparison.
-        /// </summary>
-        internal static string PossibleIncorrectComparisonWithNullCommonName {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectComparisonWithNullCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that $null is on the left side of any equaltiy comparisons (eq, ne, ceq, cne, ieq, ine). When there is an array on the left side of a null equality comparison, PowerShell will check for a $null IN the array rather than if the array is null. If the two sides of the comaprision are switched this is fixed. Therefore, $null should always be on the left side of equality comparisons just in case..
-        /// </summary>
-        internal static string PossibleIncorrectComparisonWithNullDescription {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectComparisonWithNullDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to $null should be on the left side of equality comparisons..
-        /// </summary>
-        internal static string PossibleIncorrectComparisonWithNullError {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectComparisonWithNullError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PossibleIncorrectComparisonWithNull.
-        /// </summary>
-        internal static string PossibleIncorrectComparisonWithNullName {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectComparisonWithNullName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use $null on the left hand side for safe comparison with $null..
-        /// </summary>
-        internal static string PossibleIncorrectComparisonWithNullSuggesteCorrectionDescription {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectComparisonWithNullSuggesteCorrectionDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;=&apos; is not an assignment operator. Did you mean the equality operator &apos;-eq&apos;?.
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfAssignmentOperatorCommonName {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfAssignmentOperatorCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;=&apos; or &apos;==&apos; are not comparison operators in the PowerShell language and rarely needed inside conditional statements..
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfAssignmentOperatorDescription {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfAssignmentOperatorDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Did you mean to use the assignment operator &apos;=&apos;? The equality operator in PowerShell is &apos;eq&apos;..
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfAssignmentOperatorError {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfAssignmentOperatorError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PossibleIncorrectUsageOfAssignmentOperator.
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfAssignmentOperatorName {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfAssignmentOperatorName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;&gt;&apos; is not a comparison operator. Use  &apos;-gt&apos; (greater than) or &apos;-ge&apos; (greater or equal)..
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfRedirectionOperatorCommonName {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfRedirectionOperatorCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to When switching between different languages it is easy to forget that &apos;&gt;&apos; does not mean &apos;great than&apos; in PowerShell..
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfRedirectionOperatorDescription {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfRedirectionOperatorDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Did you mean to use the redirection operator &apos;&gt;&apos;? The comparison operators in PowerShell are &apos;-gt&apos; (greater than) or &apos;-ge&apos; (greater or equal)..
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfRedirectionOperatorError {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfRedirectionOperatorError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PossibleIncorrectUsageOfRedirectionOperator.
-        /// </summary>
-        internal static string PossibleIncorrectUsageOfRedirectionOperatorName {
-            get {
-                return ResourceManager.GetString("PossibleIncorrectUsageOfRedirectionOperatorName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Basic Comment Help.
-        /// </summary>
-        internal static string ProvideCommentHelpCommonName {
-            get {
-                return ResourceManager.GetString("ProvideCommentHelpCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that all cmdlets have a help comment. This rule only checks existence. It does not check the content of the comment..
-        /// </summary>
-        internal static string ProvideCommentHelpDescription {
-            get {
-                return ResourceManager.GetString("ProvideCommentHelpDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos; does not have a help comment..
-        /// </summary>
-        internal static string ProvideCommentHelpError {
-            get {
-                return ResourceManager.GetString("ProvideCommentHelpError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ProvideCommentHelp.
-        /// </summary>
-        internal static string ProvideCommentHelpName {
-            get {
-                return ResourceManager.GetString("ProvideCommentHelpName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Reserved Cmdlet Chars.
-        /// </summary>
-        internal static string ReservedCmdletCharCommonName {
-            get {
-                return ResourceManager.GetString("ReservedCmdletCharCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks for reserved characters in cmdlet names. These characters usually cause a parsing error. Otherwise they will generally cause runtime errors..
-        /// </summary>
-        internal static string ReservedCmdletCharDescription {
-            get {
-                return ResourceManager.GetString("ReservedCmdletCharDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos; uses a reserved char in its name..
-        /// </summary>
-        internal static string ReservedCmdletCharError {
-            get {
-                return ResourceManager.GetString("ReservedCmdletCharError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ReservedCmdletChar.
-        /// </summary>
-        internal static string ReservedCmdletCharName {
-            get {
-                return ResourceManager.GetString("ReservedCmdletCharName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos;.
-        /// </summary>
-        internal static string ReservedParamsCmdletPrefix {
-            get {
-                return ResourceManager.GetString("ReservedParamsCmdletPrefix", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Reserved Parameters.
-        /// </summary>
-        internal static string ReservedParamsCommonName {
-            get {
-                return ResourceManager.GetString("ReservedParamsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks for reserved parameters in function definitions. If these parameters are defined by the user, an error generally occurs..
-        /// </summary>
-        internal static string ReservedParamsDescription {
-            get {
-                return ResourceManager.GetString("ReservedParamsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; defines the reserved common parameter &apos;{1}&apos;..
-        /// </summary>
-        internal static string ReservedParamsError {
-            get {
-                return ResourceManager.GetString("ReservedParamsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ReservedParams.
-        /// </summary>
-        internal static string ReservedParamsName {
-            get {
-                return ResourceManager.GetString("ReservedParamsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The script.
-        /// </summary>
-        internal static string ReservedParamsScriptPrefix {
-            get {
-                return ResourceManager.GetString("ReservedParamsScriptPrefix", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to #,(){}[]&amp;/\\$^;:\&quot;&apos;&lt;&gt;|?@`*%+=~.
-        /// </summary>
-        internal static string ReserverCmdletChars {
-            get {
-                return ResourceManager.GetString("ReserverCmdletChars", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ReturnCorrectTypesForDSCFunctions.
-        /// </summary>
-        internal static string ReturnCorrectTypeDSCFunctionsName {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypeDSCFunctionsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Return Correct Types For DSC Functions.
-        /// </summary>
-        internal static string ReturnCorrectTypesForDSCFunctionsCommonName {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForDSCFunctionsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Set function in DSC class and Set-TargetResource in DSC resource must not return anything. Get function in DSC class must return an instance of the DSC class and Get-TargetResource function in DSC resource must return a hashtable. Test function in DSC class and Get-TargetResource function in DSC resource must return a boolean..
-        /// </summary>
-        internal static string ReturnCorrectTypesForDSCFunctionsDescription {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForDSCFunctionsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} function in DSC Class {1} should return object of type {2}.
-        /// </summary>
-        internal static string ReturnCorrectTypesForDSCFunctionsNoTypeError {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForDSCFunctionsNoTypeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} function in DSC Class {1} should return object of type {2} instead of type {3}.
-        /// </summary>
-        internal static string ReturnCorrectTypesForDSCFunctionsWrongTypeError {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForDSCFunctionsWrongTypeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to {0} function in DSC Resource should return object of type {1} instead of {2}.
-        /// </summary>
-        internal static string ReturnCorrectTypesForGetTestTargetResourceFunctionsDSCResourceError {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForGetTestTargetResourceFunctionsDSCResourceError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Set function in DSC Class {0} should not return anything.
-        /// </summary>
-        internal static string ReturnCorrectTypesForSetFunctionsDSCError {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForSetFunctionsDSCError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Set-TargetResource function in DSC Resource should not output anything to the pipeline..
-        /// </summary>
-        internal static string ReturnCorrectTypesForSetTargetResourceFunctionsDSCError {
-            get {
-                return ResourceManager.GetString("ReturnCorrectTypesForSetTargetResourceFunctionsDSCError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ReviewUnusedParameter.
-        /// </summary>
-        internal static string ReviewUnusedParameterCommonName {
-            get {
-                return ResourceManager.GetString("ReviewUnusedParameterCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Ensure all parameters are used within the same script, scriptblock, or function where they are declared..
-        /// </summary>
-        internal static string ReviewUnusedParameterDescription {
-            get {
-                return ResourceManager.GetString("ReviewUnusedParameterDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The parameter &apos;{0}&apos; has been declared but not used. .
-        /// </summary>
-        internal static string ReviewUnusedParameterError {
-            get {
-                return ResourceManager.GetString("ReviewUnusedParameterError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ReviewUnusedParameter.
-        /// </summary>
-        internal static string ReviewUnusedParameterName {
-            get {
-                return ResourceManager.GetString("ReviewUnusedParameterName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ScriptDefinition.
-        /// </summary>
-        internal static string ScriptDefinitionName {
-            get {
-                return ResourceManager.GetString("ScriptDefinitionName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to www.sharepoint.com.
-        /// </summary>
-        internal static string SharepointURL {
-            get {
-                return ResourceManager.GetString("SharepointURL", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Should Process.
-        /// </summary>
-        internal static string ShouldProcessCommonName {
-            get {
-                return ResourceManager.GetString("ShouldProcessCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that if the SupportsShouldProcess is present, the function calls ShouldProcess/ShouldContinue and vice versa. Scripts with one or the other but not both will generally run into an error or unexpected behavior..
-        /// </summary>
-        internal static string ShouldProcessDescription {
-            get {
-                return ResourceManager.GetString("ShouldProcessDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; has the ShouldProcess attribute but does not call ShouldProcess/ShouldContinue..
-        /// </summary>
-        internal static string ShouldProcessErrorHasAttribute {
-            get {
-                return ResourceManager.GetString("ShouldProcessErrorHasAttribute", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to A script block has the ShouldProcess attribute but does not call ShouldProcess/ShouldContinue..
-        /// </summary>
-        internal static string ShouldProcessErrorHasAttributeSB {
-            get {
-                return ResourceManager.GetString("ShouldProcessErrorHasAttributeSB", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; calls ShouldProcess/ShouldContinue but does not have the ShouldProcess attribute..
-        /// </summary>
-        internal static string ShouldProcessErrorHasCmdlet {
-            get {
-                return ResourceManager.GetString("ShouldProcessErrorHasCmdlet", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to A script block calls ShouldProcess/ShouldContinue but does not have the ShouldProcess attribute..
-        /// </summary>
-        internal static string ShouldProcessErrorHasCmdletSB {
-            get {
-                return ResourceManager.GetString("ShouldProcessErrorHasCmdletSB", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to ShouldProcess.
-        /// </summary>
-        internal static string ShouldProcessName {
-            get {
-                return ResourceManager.GetString("ShouldProcessName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PS.
-        /// </summary>
-        internal static string SourceName {
-            get {
-                return ResourceManager.GetString("SourceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Type Not Found.
-        /// </summary>
-        internal static string TypeNotFoundCommonName {
-            get {
-                return ResourceManager.GetString("TypeNotFoundCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Undefined type should not be used.
-        /// </summary>
-        internal static string TypeNotFoundDescription {
-            get {
-                return ResourceManager.GetString("TypeNotFoundDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Type &apos;{0}&apos; is not found. Please check that it is defined..
-        /// </summary>
-        internal static string TypeNotFoundError {
-            get {
-                return ResourceManager.GetString("TypeNotFoundError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to TypeNotFound.
-        /// </summary>
-        internal static string TypeNotFoundName {
-            get {
-                return ResourceManager.GetString("TypeNotFoundName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet Verbs.
-        /// </summary>
-        internal static string UseApprovedVerbsCommonName {
-            get {
-                return ResourceManager.GetString("UseApprovedVerbsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Checks that all defined cmdlets use approved verbs. This is in line with PowerShell&apos;s best practices..
-        /// </summary>
-        internal static string UseApprovedVerbsDescription {
-            get {
-                return ResourceManager.GetString("UseApprovedVerbsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos; uses an unapproved verb..
-        /// </summary>
-        internal static string UseApprovedVerbsError {
-            get {
-                return ResourceManager.GetString("UseApprovedVerbsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseApprovedVerbs.
-        /// </summary>
-        internal static string UseApprovedVerbsName {
-            get {
-                return ResourceManager.GetString("UseApprovedVerbsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use BOM encoding for non-ASCII files.
-        /// </summary>
-        internal static string UseBOMForUnicodeEncodedFileCommonName {
-            get {
-                return ResourceManager.GetString("UseBOMForUnicodeEncodedFileCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to For a file encoded with a format other than ASCII, ensure BOM is present to ensure that any application consuming this file can interpret it correctly..
-        /// </summary>
-        internal static string UseBOMForUnicodeEncodedFileDescription {
-            get {
-                return ResourceManager.GetString("UseBOMForUnicodeEncodedFileDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Missing BOM encoding for non-ASCII encoded file &apos;{0}&apos;.
-        /// </summary>
-        internal static string UseBOMForUnicodeEncodedFileError {
-            get {
-                return ResourceManager.GetString("UseBOMForUnicodeEncodedFileError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseBOMForUnicodeEncodedFile.
-        /// </summary>
-        internal static string UseBOMForUnicodeEncodedFileName {
-            get {
-                return ResourceManager.GetString("UseBOMForUnicodeEncodedFileName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use Cmdlet Correctly.
-        /// </summary>
-        internal static string UseCmdletCorrectlyCommonName {
-            get {
-                return ResourceManager.GetString("UseCmdletCorrectlyCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet should be called with the mandatory parameters..
-        /// </summary>
-        internal static string UseCmdletCorrectlyDescription {
-            get {
-                return ResourceManager.GetString("UseCmdletCorrectlyDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet &apos;{0}&apos; may be used incorrectly. Please check that all mandatory parameters are supplied..
-        /// </summary>
-        internal static string UseCmdletCorrectlyError {
-            get {
-                return ResourceManager.GetString("UseCmdletCorrectlyError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseCmdletCorrectly.
-        /// </summary>
-        internal static string UseCmdletCorrectlyName {
-            get {
-                return ResourceManager.GetString("UseCmdletCorrectlyName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use compatible cmdlets.
-        /// </summary>
-        internal static string UseCompatibleCmdletsCommonName {
-            get {
-                return ResourceManager.GetString("UseCompatibleCmdletsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use cmdlets compatible with the given PowerShell version and edition and operating system.
-        /// </summary>
-        internal static string UseCompatibleCmdletsDescription {
-            get {
-                return ResourceManager.GetString("UseCompatibleCmdletsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to &apos;{0}&apos; is not compatible with PowerShell edition &apos;{1}&apos;, version &apos;{2}&apos; and OS &apos;{3}&apos;.
-        /// </summary>
-        internal static string UseCompatibleCmdletsError {
-            get {
-                return ResourceManager.GetString("UseCompatibleCmdletsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseCompatibleCmdlets.
-        /// </summary>
-        internal static string UseCompatibleCmdletsName {
-            get {
-                return ResourceManager.GetString("UseCompatibleCmdletsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The command &apos;{0}&apos; is not available by default in PowerShell version &apos;{1}&apos; on platform &apos;{2}&apos;.
-        /// </summary>
-        internal static string UseCompatibleCommandsCommandError {
-            get {
-                return ResourceManager.GetString("UseCompatibleCommandsCommandError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use compatible commands.
-        /// </summary>
-        internal static string UseCompatibleCommandsCommonName {
-            get {
-                return ResourceManager.GetString("UseCompatibleCommandsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use commands compatible with the given PowerShell version and operating system.
-        /// </summary>
-        internal static string UseCompatibleCommandsDescription {
-            get {
-                return ResourceManager.GetString("UseCompatibleCommandsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseCompatibleCommands.
-        /// </summary>
-        internal static string UseCompatibleCommandsName {
-            get {
-                return ResourceManager.GetString("UseCompatibleCommandsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The parameter &apos;{0}&apos; is not available for command &apos;{1}&apos; by default in PowerShell version &apos;{2}&apos; on platform &apos;{3}&apos;.
-        /// </summary>
-        internal static string UseCompatibleCommandsParameterError {
-            get {
-                return ResourceManager.GetString("UseCompatibleCommandsParameterError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use compatible syntax.
-        /// </summary>
-        internal static string UseCompatibleSyntaxCommonName {
-            get {
-                return ResourceManager.GetString("UseCompatibleSyntaxCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use the &apos;{0}&apos; syntax instead for compatibility with PowerShell versions {1}.
-        /// </summary>
-        internal static string UseCompatibleSyntaxCorrection {
-            get {
-                return ResourceManager.GetString("UseCompatibleSyntaxCorrection", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use script syntax compatible with the given PowerShell versions.
-        /// </summary>
-        internal static string UseCompatibleSyntaxDescription {
-            get {
-                return ResourceManager.GetString("UseCompatibleSyntaxDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The {0} syntax &apos;{1}&apos; is not available by default in PowerShell versions {2}.
-        /// </summary>
-        internal static string UseCompatibleSyntaxError {
-            get {
-                return ResourceManager.GetString("UseCompatibleSyntaxError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseCompatibleSyntax.
-        /// </summary>
-        internal static string UseCompatibleSyntaxName {
-            get {
-                return ResourceManager.GetString("UseCompatibleSyntaxName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use compatible types.
-        /// </summary>
-        internal static string UseCompatibleTypesCommonName {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use types compatible with the given PowerShell version and operating system.
-        /// </summary>
-        internal static string UseCompatibleTypesDescription {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The member &apos;{0}&apos; is not available on type &apos;{1}&apos; by default in PowerShell version &apos;{2}&apos; on platform &apos;{3}&apos;.
-        /// </summary>
-        internal static string UseCompatibleTypesMemberError {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesMemberError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The method &apos;{0}&apos; is not available on type &apos;{1}&apos; by default in PowerShell version &apos;{2}&apos; on platform &apos;{3}&apos;.
-        /// </summary>
-        internal static string UseCompatibleTypesMethodError {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesMethodError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseCompatibleTypes.
-        /// </summary>
-        internal static string UseCompatibleTypesName {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The type accelerator &apos;{0}&apos; is not available by default in PowerShell version &apos;{1}&apos; on platform &apos;{2}&apos;.
-        /// </summary>
-        internal static string UseCompatibleTypesTypeAcceleratorError {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesTypeAcceleratorError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The type &apos;{0}&apos; is not available by default in PowerShell version &apos;{1}&apos; on platform &apos;{2}&apos;.
-        /// </summary>
-        internal static string UseCompatibleTypesTypeError {
-            get {
-                return ResourceManager.GetString("UseCompatibleTypesTypeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use consistent indentation.
-        /// </summary>
-        internal static string UseConsistentIndentationCommonName {
-            get {
-                return ResourceManager.GetString("UseConsistentIndentationCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Each statement block should have a consistent indenation..
-        /// </summary>
-        internal static string UseConsistentIndentationDescription {
-            get {
-                return ResourceManager.GetString("UseConsistentIndentationDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Indentation not consistent.
-        /// </summary>
-        internal static string UseConsistentIndentationError {
-            get {
-                return ResourceManager.GetString("UseConsistentIndentationError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseConsistentIndentation.
-        /// </summary>
-        internal static string UseConsistentIndentationName {
-            get {
-                return ResourceManager.GetString("UseConsistentIndentationName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use whitespaces.
-        /// </summary>
-        internal static string UseConsistentWhitespaceCommonName {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Check for whitespace between keyword and open paren/curly, around assigment operator (&apos;=&apos;), around arithmetic operators and after separators (&apos;,&apos; and &apos;;&apos;).
-        /// </summary>
-        internal static string UseConsistentWhitespaceDescription {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space after open brace..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorAfterOpeningBrace {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorAfterOpeningBrace", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space before closing brace..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorBeforeClosingInnerBrace {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorBeforeClosingInnerBrace", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space before open brace..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorBeforeOpeningBrace {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorBeforeOpeningBrace", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space before open parenthesis..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorBeforeParen {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorBeforeParen", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space before and after binary and assignment operators..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorOperator {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorOperator", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space after a comma..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorSeparatorComma {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorSeparatorComma", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space after a semicolon..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorSeparatorSemi {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorSeparatorSemi", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space after pipe..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorSpaceAfterPipe {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorSpaceAfterPipe", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use space before pipe..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorSpaceBeforePipe {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorSpaceBeforePipe", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use only 1 whitespace between parameter names or values..
-        /// </summary>
-        internal static string UseConsistentWhitespaceErrorSpaceBetweenParameter {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceErrorSpaceBetweenParameter", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseConsistentWhitespace.
-        /// </summary>
-        internal static string UseConsistentWhitespaceName {
-            get {
-                return ResourceManager.GetString("UseConsistentWhitespaceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use exact casing of cmdlet/function/parameter name..
-        /// </summary>
-        internal static string UseCorrectCasingCommonName {
-            get {
-                return ResourceManager.GetString("UseCorrectCasingCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to For better readability and consistency, use the exact casing of the cmdlet/function/parameter..
-        /// </summary>
-        internal static string UseCorrectCasingDescription {
-            get {
-                return ResourceManager.GetString("UseCorrectCasingDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet/Function/Parameter does not match its exact casing &apos;{0}&apos;..
-        /// </summary>
-        internal static string UseCorrectCasingError {
-            get {
-                return ResourceManager.GetString("UseCorrectCasingError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseCorrectCasing.
-        /// </summary>
-        internal static string UseCorrectCasingName {
-            get {
-                return ResourceManager.GetString("UseCorrectCasingName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Extra Variables.
-        /// </summary>
-        internal static string UseDeclaredVarsMoreThanAssignmentsCommonName {
-            get {
-                return ResourceManager.GetString("UseDeclaredVarsMoreThanAssignmentsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Ensure declared variables are used elsewhere in the script and not just during assignment..
-        /// </summary>
-        internal static string UseDeclaredVarsMoreThanAssignmentsDescription {
-            get {
-                return ResourceManager.GetString("UseDeclaredVarsMoreThanAssignmentsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The variable &apos;{0}&apos; is assigned but never used..
-        /// </summary>
-        internal static string UseDeclaredVarsMoreThanAssignmentsError {
-            get {
-                return ResourceManager.GetString("UseDeclaredVarsMoreThanAssignmentsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseDeclaredVarsMoreThanAssignments.
-        /// </summary>
-        internal static string UseDeclaredVarsMoreThanAssignmentsName {
-            get {
-                return ResourceManager.GetString("UseDeclaredVarsMoreThanAssignmentsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use identical mandatory parameters for DSC Get/Test/Set TargetResource functions.
-        /// </summary>
-        internal static string UseIdenticalMandatoryParametersDSCCommonName {
-            get {
-                return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Get/Test/Set TargetResource functions of DSC resource must have the same mandatory parameters..
-        /// </summary>
-        internal static string UseIdenticalMandatoryParametersDSCDescription {
-            get {
-                return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The &apos;{0}&apos; parameter &apos;{1}&apos; is not present in &apos;{2}&apos; DSC resource function(s)..
-        /// </summary>
-        internal static string UseIdenticalMandatoryParametersDSCError {
-            get {
-                return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseIdenticalMandatoryParametersForDSC.
-        /// </summary>
-        internal static string UseIdenticalMandatoryParametersDSCName {
-            get {
-                return ResourceManager.GetString("UseIdenticalMandatoryParametersDSCName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use Identical Parameters For DSC Test and Set Functions.
-        /// </summary>
-        internal static string UseIdenticalParametersDSCCommonName {
-            get {
-                return ResourceManager.GetString("UseIdenticalParametersDSCCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Test and Set-TargetResource functions of DSC Resource must have the same parameters..
-        /// </summary>
-        internal static string UseIdenticalParametersDSCDescription {
-            get {
-                return ResourceManager.GetString("UseIdenticalParametersDSCDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Test and Set-TargetResource functions of DSC Resource must have the same parameters..
-        /// </summary>
-        internal static string UseIdenticalParametersDSCError {
-            get {
-                return ResourceManager.GetString("UseIdenticalParametersDSCError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseIdenticalParametersForDSC.
-        /// </summary>
-        internal static string UseIdenticalParametersDSCName {
-            get {
-                return ResourceManager.GetString("UseIdenticalParametersDSCName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Create hashtables with literal initializers.
-        /// </summary>
-        internal static string UseLiteralInitilializerForHashtableCommonName {
-            get {
-                return ResourceManager.GetString("UseLiteralInitilializerForHashtableCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use literal initializer, @{{}}, for creating a hashtable as they are case-insensitive by default.
-        /// </summary>
-        internal static string UseLiteralInitilializerForHashtableDescription {
-            get {
-                return ResourceManager.GetString("UseLiteralInitilializerForHashtableDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Create hashtables with literal initliazers.
-        /// </summary>
-        internal static string UseLiteralInitilializerForHashtableError {
-            get {
-                return ResourceManager.GetString("UseLiteralInitilializerForHashtableError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseLiteralInitializerForHashtable.
-        /// </summary>
-        internal static string UseLiteralInitilializerForHashtableName {
-            get {
-                return ResourceManager.GetString("UseLiteralInitilializerForHashtableName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use OutputType Correctly.
-        /// </summary>
-        internal static string UseOutputTypeCorrectlyCommonName {
-            get {
-                return ResourceManager.GetString("UseOutputTypeCorrectlyCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The return types of a cmdlet should be declared using the OutputType attribute..
-        /// </summary>
-        internal static string UseOutputTypeCorrectlyDescription {
-            get {
-                return ResourceManager.GetString("UseOutputTypeCorrectlyDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos; returns an object of type &apos;{1}&apos; but this type is not declared in the OutputType attribute..
-        /// </summary>
-        internal static string UseOutputTypeCorrectlyError {
-            get {
-                return ResourceManager.GetString("UseOutputTypeCorrectlyError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseOutputTypeCorrectly.
-        /// </summary>
-        internal static string UseOutputTypeCorrectlyName {
-            get {
-                return ResourceManager.GetString("UseOutputTypeCorrectlyName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use process block for command that accepts input from pipeline..
-        /// </summary>
-        internal static string UseProcessBlockForPipelineCommandCommonName {
-            get {
-                return ResourceManager.GetString("UseProcessBlockForPipelineCommandCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to If a command parameter takes its value from the pipeline, the command must use a process block to bind the input objects from the pipeline to that parameter..
-        /// </summary>
-        internal static string UseProcessBlockForPipelineCommandDescription {
-            get {
-                return ResourceManager.GetString("UseProcessBlockForPipelineCommandDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Command accepts pipeline input but has not defined a process block..
-        /// </summary>
-        internal static string UseProcessBlockForPipelineCommandError {
-            get {
-                return ResourceManager.GetString("UseProcessBlockForPipelineCommandError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseProcessBlockForPipelineCommand.
-        /// </summary>
-        internal static string UseProcessBlockForPipelineCommandName {
-            get {
-                return ResourceManager.GetString("UseProcessBlockForPipelineCommandName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use PSCredential type..
-        /// </summary>
-        internal static string UsePSCredentialTypeCommonName {
-            get {
-                return ResourceManager.GetString("UsePSCredentialTypeCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to For PowerShell 4.0 and earlier, a parameter named Credential with type PSCredential must have a credential transformation attribute defined after the PSCredential type attribute. .
-        /// </summary>
-        internal static string UsePSCredentialTypeDescription {
-            get {
-                return ResourceManager.GetString("UsePSCredentialTypeDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Credential parameter in &apos;{0}&apos; must be of type PSCredential. For PowerShell 4.0 and earlier, please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute..
-        /// </summary>
-        internal static string UsePSCredentialTypeError {
-            get {
-                return ResourceManager.GetString("UsePSCredentialTypeError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The Credential parameter found in the script block must be of type PSCredential. For PowerShell 4.0 and earlier please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute. .
-        /// </summary>
-        internal static string UsePSCredentialTypeErrorSB {
-            get {
-                return ResourceManager.GetString("UsePSCredentialTypeErrorSB", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UsePSCredentialType.
-        /// </summary>
-        internal static string UsePSCredentialTypeName {
-            get {
-                return ResourceManager.GetString("UsePSCredentialTypeName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use ShouldProcess For State Changing Functions.
-        /// </summary>
-        internal static string UseShouldProcessForStateChangingFunctionsCommonName {
-            get {
-                return ResourceManager.GetString("UseShouldProcessForStateChangingFunctionsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Functions that have verbs like New, Start, Stop, Set, Reset, Restart that change system state should support &apos;ShouldProcess&apos;..
-        /// </summary>
-        internal static string UseShouldProcessForStateChangingFunctionsDescrption {
-            get {
-                return ResourceManager.GetString("UseShouldProcessForStateChangingFunctionsDescrption", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Function &apos;{0}&apos; has verb that could change system state. Therefore, the function has to support &apos;ShouldProcess&apos;..
-        /// </summary>
-        internal static string UseShouldProcessForStateChangingFunctionsError {
-            get {
-                return ResourceManager.GetString("UseShouldProcessForStateChangingFunctionsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseShouldProcessForStateChangingFunctions.
-        /// </summary>
-        internal static string UseShouldProcessForStateChangingFunctionsName {
-            get {
-                return ResourceManager.GetString("UseShouldProcessForStateChangingFunctionsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet Singular Noun.
-        /// </summary>
-        internal static string UseSingularNounsCommonName {
-            get {
-                return ResourceManager.GetString("UseSingularNounsCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Cmdlet should use singular instead of plural nouns..
-        /// </summary>
-        internal static string UseSingularNounsDescription {
-            get {
-                return ResourceManager.GetString("UseSingularNounsDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The cmdlet &apos;{0}&apos; uses a plural noun. A singular noun should be used instead..
-        /// </summary>
-        internal static string UseSingularNounsError {
-            get {
-                return ResourceManager.GetString("UseSingularNounsError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseSingularNouns.
-        /// </summary>
-        internal static string UseSingularNounsName {
-            get {
-                return ResourceManager.GetString("UseSingularNounsName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Missing &apos;{0}&apos; function. DSC Class must implement Get, Set and Test functions..
-        /// </summary>
-        internal static string UseStandardDSCFunctionsInClassError {
-            get {
-                return ResourceManager.GetString("UseStandardDSCFunctionsInClassError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use Standard Get/Set/Test TargetResource functions in DSC Resource .
-        /// </summary>
-        internal static string UseStandardDSCFunctionsInResourceCommonName {
-            get {
-                return ResourceManager.GetString("UseStandardDSCFunctionsInResourceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to DSC Resource must implement Get, Set and Test-TargetResource functions. DSC Class must implement Get, Set and Test functions..
-        /// </summary>
-        internal static string UseStandardDSCFunctionsInResourceDescription {
-            get {
-                return ResourceManager.GetString("UseStandardDSCFunctionsInResourceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Missing &apos;{0}&apos; function. DSC Resource must implement Get, Set and Test-TargetResource functions..
-        /// </summary>
-        internal static string UseStandardDSCFunctionsInResourceError {
-            get {
-                return ResourceManager.GetString("UseStandardDSCFunctionsInResourceError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to StandardDSCFunctionsInResource.
-        /// </summary>
-        internal static string UseStandardDSCFunctionsInResourceName {
-            get {
-                return ResourceManager.GetString("UseStandardDSCFunctionsInResourceName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use SupportsShouldProcess.
-        /// </summary>
-        internal static string UseSupportsShouldProcessCommonName {
-            get {
-                return ResourceManager.GetString("UseSupportsShouldProcessCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Commands typically provide Confirm and Whatif parameters to give more control on its execution in an interactive environment. In PowerShell, a command can use a SupportsShouldProcess attribute to provide this capability. Hence, manual addition of these parameters to a command is discouraged. If a commands need Confirm and Whatif parameters, then it should support ShouldProcess..
-        /// </summary>
-        internal static string UseSupportsShouldProcessDescription {
-            get {
-                return ResourceManager.GetString("UseSupportsShouldProcessDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Whatif and/or Confirm manually defined in function {0}. Instead, please use SupportsShouldProcess attribute..
-        /// </summary>
-        internal static string UseSupportsShouldProcessError {
-            get {
-                return ResourceManager.GetString("UseSupportsShouldProcessError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseSupportsShouldProcess.
-        /// </summary>
-        internal static string UseSupportsShouldProcessName {
-            get {
-                return ResourceManager.GetString("UseSupportsShouldProcessName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use the *ToExport module manifest fields..
-        /// </summary>
-        internal static string UseToExportFieldsInManifestCommonName {
-            get {
-                return ResourceManager.GetString("UseToExportFieldsInManifestCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Replace {0} with {1}.
-        /// </summary>
-        internal static string UseToExportFieldsInManifestCorrectionDescription {
-            get {
-                return ResourceManager.GetString("UseToExportFieldsInManifestCorrectionDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to In a module manifest, AliasesToExport, CmdletsToExport, FunctionsToExport and VariablesToExport fields should not use wildcards or $null in their entries. During module auto-discovery, if any of these entries are missing or $null or wildcard, PowerShell does some potentially expensive work to analyze the rest of the module..
-        /// </summary>
-        internal static string UseToExportFieldsInManifestDescription {
-            get {
-                return ResourceManager.GetString("UseToExportFieldsInManifestDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Do not use wildcard or $null in this field. Explicitly specify a list for {0}.  .
-        /// </summary>
-        internal static string UseToExportFieldsInManifestError {
-            get {
-                return ResourceManager.GetString("UseToExportFieldsInManifestError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseToExportFieldsInManifest.
-        /// </summary>
-        internal static string UseToExportFieldsInManifestName {
-            get {
-                return ResourceManager.GetString("UseToExportFieldsInManifestName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use Type At Variable Assignment.
-        /// </summary>
-        internal static string UseTypeAtVariableAssignmentCommonName {
-            get {
-                return ResourceManager.GetString("UseTypeAtVariableAssignmentCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Types should be specified at variable assignments to maintain readability and maintainability of script..
-        /// </summary>
-        internal static string UseTypeAtVariableAssignmentDescription {
-            get {
-                return ResourceManager.GetString("UseTypeAtVariableAssignmentDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Specify type at the assignment of variable &apos;{0}&apos;.
-        /// </summary>
-        internal static string UseTypeAtVariableAssignmentError {
-            get {
-                return ResourceManager.GetString("UseTypeAtVariableAssignmentError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseTypeAtVariableAssignment.
-        /// </summary>
-        internal static string UseTypeAtVariableAssignmentName {
-            get {
-                return ResourceManager.GetString("UseTypeAtVariableAssignmentName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use &apos;Using:&apos; scope modifier in RunSpace ScriptBlocks.
-        /// </summary>
-        internal static string UseUsingScopeModifierInNewRunspacesCommonName {
-            get {
-                return ResourceManager.GetString("UseUsingScopeModifierInNewRunspacesCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Replace {0} with {1}.
-        /// </summary>
-        internal static string UseUsingScopeModifierInNewRunspacesCorrectionDescription {
-            get {
-                return ResourceManager.GetString("UseUsingScopeModifierInNewRunspacesCorrectionDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to If a ScriptBlock is intended to be run as a new RunSpace, variables inside it should use &apos;Using:&apos; scope modifier, or be initialized within the ScriptBlock..
-        /// </summary>
-        internal static string UseUsingScopeModifierInNewRunspacesDescription {
-            get {
-                return ResourceManager.GetString("UseUsingScopeModifierInNewRunspacesDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to The variable &apos;{0}&apos; is not declared within this ScriptBlock, and is missing the &apos;Using:&apos; scope modifier..
-        /// </summary>
-        internal static string UseUsingScopeModifierInNewRunspacesError {
-            get {
-                return ResourceManager.GetString("UseUsingScopeModifierInNewRunspacesError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseUsingScopeModifierInNewRunspaces.
-        /// </summary>
-        internal static string UseUsingScopeModifierInNewRunspacesName {
-            get {
-                return ResourceManager.GetString("UseUsingScopeModifierInNewRunspacesName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use UTF8 Encoding For Help File.
-        /// </summary>
-        internal static string UseUTF8EncodingForHelpFileCommonName {
-            get {
-                return ResourceManager.GetString("UseUTF8EncodingForHelpFileCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to PowerShell help file needs to use UTF8 Encoding..
-        /// </summary>
-        internal static string UseUTF8EncodingForHelpFileDescription {
-            get {
-                return ResourceManager.GetString("UseUTF8EncodingForHelpFileDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to File {0} has to use UTF8 instead of {1} encoding because it is a powershell help file..
-        /// </summary>
-        internal static string UseUTF8EncodingForHelpFileError {
-            get {
-                return ResourceManager.GetString("UseUTF8EncodingForHelpFileError", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseUTF8EncodingForHelpFile.
-        /// </summary>
-        internal static string UseUTF8EncodingForHelpFileName {
-            get {
-                return ResourceManager.GetString("UseUTF8EncodingForHelpFileName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to Use verbose message in DSC resource.
-        /// </summary>
-        internal static string UseVerboseMessageInDSCResourceCommonName {
-            get {
-                return ResourceManager.GetString("UseVerboseMessageInDSCResourceCommonName", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to It is a best practice to emit informative, verbose messages in DSC resource functions. This helps in debugging issues when a DSC configuration is executed..
-        /// </summary>
-        internal static string UseVerboseMessageInDSCResourceDescription {
-            get {
-                return ResourceManager.GetString("UseVerboseMessageInDSCResourceDescription", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to There is no call to Write-Verbose in DSC function &apos;{0}&apos;. If you are using Write-Verbose in a helper function, suppress this rule application..
-        /// </summary>
-        internal static string UseVerboseMessageInDSCResourceErrorFunction {
-            get {
-                return ResourceManager.GetString("UseVerboseMessageInDSCResourceErrorFunction", resourceCulture);
-            }
-        }
-        
-        /// <summary>
-        ///   Looks up a localized string similar to UseVerboseMessageInDSCResource.
-        /// </summary>
-        internal static string UseVerboseMessageInDSCResourceName {
-            get {
-                return ResourceManager.GetString("UseVerboseMessageInDSCResourceName", resourceCulture);
-            }
-        }
-    }
-}
diff --git a/Rules/Strings.resx b/Rules/Strings.resx
index e64cecd6b..260214967 100644
--- a/Rules/Strings.resx
+++ b/Rules/Strings.resx
@@ -1,17 +1,17 @@
 ﻿<?xml version="1.0" encoding="utf-8"?>
 <root>
-  <!-- 
-    Microsoft ResX Schema 
-    
+  <!--
+    Microsoft ResX Schema
+
     Version 2.0
-    
-    The primary goals of this format is to allow a simple XML format 
-    that is mostly human readable. The generation and parsing of the 
-    various data types are done through the TypeConverter classes 
+
+    The primary goals of this format is to allow a simple XML format
+    that is mostly human readable. The generation and parsing of the
+    various data types are done through the TypeConverter classes
     associated with the data types.
-    
+
     Example:
-    
+
     ... ado.net/XML headers & schema ...
     <resheader name="resmimetype">text/microsoft-resx</resheader>
     <resheader name="version">2.0</resheader>
@@ -26,36 +26,36 @@
         <value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
         <comment>This is a comment</comment>
     </data>
-                
-    There are any number of "resheader" rows that contain simple 
+
+    There are any number of "resheader" rows that contain simple
     name/value pairs.
-    
-    Each data row contains a name, and value. The row also contains a 
-    type or mimetype. Type corresponds to a .NET class that support 
-    text/value conversion through the TypeConverter architecture. 
-    Classes that don't support this are serialized and stored with the 
+
+    Each data row contains a name, and value. The row also contains a
+    type or mimetype. Type corresponds to a .NET class that support
+    text/value conversion through the TypeConverter architecture.
+    Classes that don't support this are serialized and stored with the
     mimetype set.
-    
-    The mimetype is used for serialized objects, and tells the 
-    ResXResourceReader how to depersist the object. This is currently not 
+
+    The mimetype is used for serialized objects, and tells the
+    ResXResourceReader how to depersist the object. This is currently not
     extensible. For a given mimetype the value must be set accordingly:
-    
-    Note - application/x-microsoft.net.object.binary.base64 is the format 
-    that the ResXResourceWriter will generate, however the reader can 
+
+    Note - application/x-microsoft.net.object.binary.base64 is the format
+    that the ResXResourceWriter will generate, however the reader can
     read any of the formats listed below.
-    
+
     mimetype: application/x-microsoft.net.object.binary.base64
-    value   : The object must be serialized with 
+    value   : The object must be serialized with
             : System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
             : and then encoded with base64 encoding.
-    
+
     mimetype: application/x-microsoft.net.object.soap.base64
-    value   : The object must be serialized with 
+    value   : The object must be serialized with
             : System.Runtime.Serialization.Formatters.Soap.SoapFormatter
             : and then encoded with base64 encoding.
 
     mimetype: application/x-microsoft.net.object.bytearray.base64
-    value   : The object must be serialized into a byte array 
+    value   : The object must be serialized into a byte array
             : using a System.ComponentModel.TypeConverter
             : and then encoded with base64 encoding.
     -->
@@ -202,13 +202,13 @@
     <value>One Char</value>
   </data>
   <data name="UsePSCredentialTypeDescription" xml:space="preserve">
-    <value>For PowerShell 4.0 and earlier, a parameter named Credential with type PSCredential must have a credential transformation attribute defined after the PSCredential type attribute. </value>
+    <value>For PowerShell 4.0 and earlier, a parameter named Credential with type PSCredential must have a credential transformation attribute defined after the PSCredential type attribute.</value>
   </data>
   <data name="UsePSCredentialTypeError" xml:space="preserve">
     <value>The Credential parameter in '{0}' must be of type PSCredential. For PowerShell 4.0 and earlier, please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute.</value>
   </data>
   <data name="UsePSCredentialTypeErrorSB" xml:space="preserve">
-    <value>The Credential parameter found in the script block must be of type PSCredential. For PowerShell 4.0 and earlier please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute. </value>
+    <value>The Credential parameter found in the script block must be of type PSCredential. For PowerShell 4.0 and earlier please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute.</value>
   </data>
   <data name="UsePSCredentialTypeCommonName" xml:space="preserve">
     <value>Use PSCredential type.</value>
@@ -292,7 +292,7 @@
     <value>Password parameters that take in plaintext will expose passwords and compromise the security of your system.</value>
   </data>
   <data name="AvoidUsingPlainTextForPasswordError" xml:space="preserve">
-    <value>Parameter '{0}' should use SecureString, otherwise this will expose sensitive information. See ConvertTo-SecureString for more information.</value>
+    <value>Parameter '{0}' should not use String type but either SecureString or PSCredential, otherwise it increases the chance to expose this sensitive information.</value>
   </data>
   <data name="AvoidUsingPlainTextForPasswordCommonName" xml:space="preserve">
     <value>Avoid Using Plain Text For Password Parameter</value>
@@ -535,7 +535,7 @@
     <value>PSDSC</value>
   </data>
   <data name="UseStandardDSCFunctionsInResourceCommonName" xml:space="preserve">
-    <value>Use Standard Get/Set/Test TargetResource functions in DSC Resource </value>
+    <value>Use Standard Get/Set/Test TargetResource functions in DSC Resource</value>
   </data>
   <data name="UseStandardDSCFunctionsInResourceDescription" xml:space="preserve">
     <value>DSC Resource must implement Get, Set and Test-TargetResource functions. DSC Class must implement Get, Set and Test functions.</value>
@@ -769,7 +769,7 @@
     <value>In a module manifest, AliasesToExport, CmdletsToExport, FunctionsToExport and VariablesToExport fields should not use wildcards or $null in their entries. During module auto-discovery, if any of these entries are missing or $null or wildcard, PowerShell does some potentially expensive work to analyze the rest of the module.</value>
   </data>
   <data name="UseToExportFieldsInManifestError" xml:space="preserve">
-    <value>Do not use wildcard or $null in this field. Explicitly specify a list for {0}.  </value>
+    <value>Do not use wildcard or $null in this field. Explicitly specify a list for {0}.</value>
   </data>
   <data name="UseToExportFieldsInManifestName" xml:space="preserve">
     <value>UseToExportFieldsInManifest</value>
@@ -778,7 +778,7 @@
     <value>Replace {0} with {1}</value>
   </data>
   <data name="AvoidUsingPlainTextForPasswordCorrectionDescription" xml:space="preserve">
-    <value>Set {0} type to SecureString</value>
+    <value>Set {0} type to {1}</value>
   </data>
   <data name="MissingModuleManifestFieldCorrectionDescription" xml:space="preserve">
     <value>Add {0} = {1} to the module manifest</value>
@@ -921,6 +921,18 @@
   <data name="AvoidLongLinesError" xml:space="preserve">
     <value>Line exceeds the configured maximum length of {0} characters</value>
   </data>
+  <data name="AvoidSemicolonsAsLineTerminatorsName" xml:space="preserve">
+    <value>AvoidSemicolonsAsLineTerminators</value>
+  </data>
+  <data name="AvoidSemicolonsAsLineTerminatorsCommonName" xml:space="preserve">
+    <value>Avoid semicolons as line terminators</value>
+  </data>
+  <data name="AvoidSemicolonsAsLineTerminatorsDescription" xml:space="preserve">
+    <value>Line should not end with a semicolon</value>
+  </data>
+  <data name="AvoidSemicolonsAsLineTerminatorsError" xml:space="preserve">
+    <value>Line ends with a semicolon</value>
+  </data>
   <data name="PlaceOpenBraceName" xml:space="preserve">
     <value>PlaceOpenBrace</value>
   </data>
@@ -1057,7 +1069,7 @@
     <value>'&gt;' is not a comparison operator. Use  '-gt' (greater than) or '-ge' (greater or equal).</value>
   </data>
   <data name="PossibleIncorrectUsageOfRedirectionOperatorDescription" xml:space="preserve">
-    <value>When switching between different languages it is easy to forget that '&gt;' does not mean 'great than' in PowerShell.</value>
+    <value>When switching between different languages it is easy to forget that '&gt;' does not mean 'greater than' in PowerShell.</value>
   </data>
   <data name="PossibleIncorrectUsageOfRedirectionOperatorError" xml:space="preserve">
     <value>Did you mean to use the redirection operator '&gt;'? The comparison operators in PowerShell are '-gt' (greater than) or '-ge' (greater or equal).</value>
@@ -1084,14 +1096,23 @@
     <value>Use exact casing of cmdlet/function/parameter name.</value>
   </data>
   <data name="UseCorrectCasingDescription" xml:space="preserve">
-    <value>For better readability and consistency, use the exact casing of the cmdlet/function/parameter.</value>
+    <value>For better readability and consistency, use consistent casing.</value>
   </data>
   <data name="UseCorrectCasingError" xml:space="preserve">
-    <value>Cmdlet/Function/Parameter does not match its exact casing '{0}'.</value>
+    <value>Function/Cmdlet '{0}' does not match its exact casing '{1}'.</value>
   </data>
   <data name="UseCorrectCasingName" xml:space="preserve">
     <value>UseCorrectCasing</value>
   </data>
+  <data name="UseCorrectCasingKeywordError" xml:space="preserve">
+    <value>Keyword '{0}' does not match the expected case '{1}'.</value>
+  </data>
+  <data name="UseCorrectCasingOperatorError" xml:space="preserve">
+    <value>Operator '{0}' does not match the expected case '{1}'.</value>
+  </data>
+  <data name="UseCorrectCasingParameterError" xml:space="preserve">
+    <value>Parameter '{0}' of function/cmdlet '{1}' does not match its exact casing '{2}'.</value>
+  </data>
   <data name="UseProcessBlockForPipelineCommandCommonName" xml:space="preserve">
     <value>Use process block for command that accepts input from pipeline.</value>
   </data>
@@ -1117,7 +1138,7 @@
     <value>Ensure all parameters are used within the same script, scriptblock, or function where they are declared.</value>
   </data>
   <data name="ReviewUnusedParameterError" xml:space="preserve">
-    <value>The parameter '{0}' has been declared but not used. </value>
+    <value>The parameter '{0}' has been declared but not used.</value>
   </data>
   <data name="ReviewUnusedParameterName" xml:space="preserve">
     <value>ReviewUnusedParameter</value>
@@ -1137,4 +1158,70 @@
   <data name="UseUsingScopeModifierInNewRunspacesCorrectionDescription" xml:space="preserve">
     <value>Replace {0} with {1}</value>
   </data>
-</root>
+  <data name="AvoidUsingDoubleQuotesForConstantStringCommonName" xml:space="preserve">
+    <value>Avoid using double quotes if the string is constant.</value>
+  </data>
+  <data name="AvoidUsingDoubleQuotesForConstantStringDescription" xml:space="preserve">
+    <value>Use single quotes if the string is constant.</value>
+  </data>
+  <data name="AvoidUsingDoubleQuotesForConstantStringName" xml:space="preserve">
+    <value>AvoidUsingDoubleQuotesForConstantString</value>
+  </data>
+  <data name="AvoidUsingDoubleQuotesForConstantStringError" xml:space="preserve">
+    <value>Use single quotes when a string is constant.</value>
+  </data>
+  <data name="InvalidSyntaxAroundProcessBlockError" xml:space="preserve">
+    <value>When using an explicit process block, no preceding code is allowed, only begin, end and dynamicparams blocks.</value>
+  </data>
+  <data name="AvoidMultipleTypeAttributesCommonName" xml:space="preserve">
+    <value>Avoid multiple type specifiers on parameters</value>
+  </data>
+  <data name="AvoidMultipleTypeAttributesDescription" xml:space="preserve">
+    <value>Prameter should not have more than one type specifier.</value>
+  </data>
+  <data name="AvoidMultipleTypeAttributesError" xml:space="preserve">
+    <value>Parameter '{0}' has more than one type specifier.</value>
+  </data>
+  <data name="AvoidMultipleTypeAttributesName" xml:space="preserve">
+    <value>AvoidMultipleTypeAttributes</value>
+  </data>
+  <data name="AvoidUsingBrokenHashAlgorithmsCommonName" xml:space="preserve">
+    <value>Avoid Using Broken Hash Algorithms</value>
+  </data>
+  <data name="AvoidUsingBrokenHashAlgorithmsDescription" xml:space="preserve">
+    <value>Avoid using the broken algorithms MD5 or SHA-1.</value>
+  </data>
+  <data name="AvoidUsingBrokenHashAlgorithmsError" xml:space="preserve">
+    <value>The Algorithm parameter of cmdlet '{0}' was used with the broken algorithm '{1}'.</value>
+  </data>
+  <data name="AvoidUsingBrokenHashAlgorithmsName" xml:space="preserve">
+    <value>AvoidUsingBrokenHashAlgorithms</value>
+  </data>
+  <data name="AvoidExclaimOperatorName" xml:space="preserve">
+    <value>AvoidExclaimOperator</value>
+  </data>
+  <data name="AvoidExclaimOperatorCommonName" xml:space="preserve">
+    <value>Avoid exclaim operator</value>
+  </data>
+  <data name="AvoidExclaimOperatorDescription" xml:space="preserve">
+    <value>The negation operator ! should not be used for readability purposes. Use -not instead.</value>
+  </data>
+  <data name="AvoidExclaimOperatorError" xml:space="preserve">
+    <value>Avoid using the ! negation operator</value>
+  </data>
+  <data name="AvoidExclaimOperatorCorrectionDescription" xml:space="preserve">
+    <value>Replace ! with -not</value>
+  </data>
+  <data name="AvoidUsingAllowUnencryptedAuthenticationCommonName" xml:space="preserve">
+    <value>Avoid AllowUnencryptedAuthentication Switch</value>
+  </data>
+  <data name="AvoidUsingAllowUnencryptedAuthenticationDescription" xml:space="preserve">
+    <value>Avoid sending credentials and secrets over unencrypted connections.</value>
+  </data>
+  <data name="AvoidUsingAllowUnencryptedAuthenticationError" xml:space="preserve">
+    <value>The insecure AllowUsingUnencryptedAuthentication switch was used. This should be avoided except for compatability with legacy systems.</value>
+  </data>
+  <data name="AvoidUsingAllowUnencryptedAuthenticationName" xml:space="preserve">
+    <value>AvoidUsingAllowUnencryptedAuthentication</value>
+  </data>
+</root>
\ No newline at end of file
diff --git a/Rules/UseCmdletCorrectly.cs b/Rules/UseCmdletCorrectly.cs
index a0d08e2c1..ccec27e0b 100644
--- a/Rules/UseCmdletCorrectly.cs
+++ b/Rules/UseCmdletCorrectly.cs
@@ -29,11 +29,11 @@ public class UseCmdletCorrectly : IScriptRule
         private static readonly ConcurrentDictionary<string, IReadOnlyList<string>> s_pkgMgmtMandatoryParameters =
             new ConcurrentDictionary<string, IReadOnlyList<string>>(new Dictionary<string, IReadOnlyList<string>>
             {
-                { "Find-Package", new string[0] },
-                { "Find-PackageProvider", new string[0] },
-                { "Get-Package", new string[0] },
-                { "Get-PackageProvider", new string[0] },
-                { "Get-PackageSource", new string[0] },
+                { "Find-Package", Array.Empty<string>() },
+                { "Find-PackageProvider", Array.Empty<string>() },
+                { "Get-Package", Array.Empty<string>() },
+                { "Get-PackageProvider", Array.Empty<string>() },
+                { "Get-PackageSource", Array.Empty<string>() },
                 { "Import-PackageProvider", new string[] { "Name" } },
                 { "Install-Package", new string[] { "Name" } },
                 { "Install-PackageProvider", new string[] { "Name" } },
@@ -100,7 +100,7 @@ private bool MandatoryParameterExists(CommandAst cmdAst)
             }
 
             // Positional parameters could be mandatory, so we assume all is well
-            if (Helper.Instance.PositionalParameterUsed(cmdAst) && Helper.Instance.IsKnownCmdletFunctionOrExternalScript(cmdAst))
+            if (Helper.Instance.PositionalParameterUsed(cmdAst) && Helper.Instance.IsKnownCmdletFunctionOrExternalScript(cmdAst, out _))
             {
                 return true;
             }
diff --git a/Rules/UseCompatibleCmdlets.cs b/Rules/UseCompatibleCmdlets.cs
index ffa2e40ee..c74665e95 100644
--- a/Rules/UseCompatibleCmdlets.cs
+++ b/Rules/UseCompatibleCmdlets.cs
@@ -498,7 +498,7 @@ private bool RuleParamsValid(Dictionary<string, object> ruleArgs)
         }
 
         /// <summary>
-        /// Check if current command is present in the whitelists
+        /// Check if current command is present in the allowlists
         /// If not, flag the corresponding value in curCmdletCompatibilityMap
         /// </summary>
         private void CheckCompatibility()
diff --git a/Rules/UseConsistentIndentation.cs b/Rules/UseConsistentIndentation.cs
index 8f17e2462..41aa4ef4d 100644
--- a/Rules/UseConsistentIndentation.cs
+++ b/Rules/UseConsistentIndentation.cs
@@ -1,4 +1,4 @@
-﻿// Copyright (c) Microsoft Corporation. All rights reserved.
+// Copyright (c) Microsoft Corporation. All rights reserved.
 // Licensed under the MIT License.
 
 using System;
@@ -133,7 +133,13 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
             var currentIndenationLevelIncreaseDueToPipelines = 0;
             var onNewLine = true;
             var pipelineAsts = ast.FindAll(testAst => testAst is PipelineAst && (testAst as PipelineAst).PipelineElements.Count > 1, true).ToList();
-            int minimumPipelineAstIndex = 0;
+            /*
+                When an LParen and LBrace are on the same line, it can lead to too much de-indentation.
+                In order to prevent the RParen code from de-indenting too much, we keep a stack of when we skipped the indentation
+                caused by tokens that require a closing RParen (which are LParen, AtParen and DollarParen).
+            */
+            var lParenSkippedIndentation = new Stack<bool>();
+            
             for (int tokenIndex = 0; tokenIndex < tokens.Length; tokenIndex++)
             {
                 var token = tokens[tokenIndex];
@@ -146,13 +152,31 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
                 switch (token.Kind)
                 {
                     case TokenKind.AtCurly:
-                    case TokenKind.AtParen:
-                    case TokenKind.LParen:
                     case TokenKind.LCurly:
+                        AddViolation(token, indentationLevel++, diagnosticRecords, ref onNewLine);
+                        break;
+
                     case TokenKind.DollarParen:
+                    case TokenKind.AtParen:
+                        lParenSkippedIndentation.Push(false);
                         AddViolation(token, indentationLevel++, diagnosticRecords, ref onNewLine);
                         break;
 
+                    case TokenKind.LParen:
+                        AddViolation(token, indentationLevel, diagnosticRecords, ref onNewLine);
+                        // When a line starts with a parenthesis and it is not the last non-comment token of that line,
+                        // then indentation does not need to be increased.
+                        if ((tokenIndex == 0 || tokens[tokenIndex - 1].Kind == TokenKind.NewLine) &&
+                            NextTokenIgnoringComments(tokens, tokenIndex)?.Kind != TokenKind.NewLine)
+                        {
+                            onNewLine = false;
+                            lParenSkippedIndentation.Push(true);
+                            break;
+                        }
+                        lParenSkippedIndentation.Push(false);
+                        indentationLevel++;
+                        break;
+
                     case TokenKind.Pipe:
                         if (pipelineIndentationStyle == PipelineIndentationStyle.None) { break; }
                         bool pipelineIsFollowedByNewlineOrLineContinuation =
@@ -181,6 +205,20 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
                         break;
 
                     case TokenKind.RParen:
+                        bool matchingLParenIncreasedIndentation = false;
+                        if (lParenSkippedIndentation.Count > 0)
+                        {
+                            matchingLParenIncreasedIndentation = lParenSkippedIndentation.Pop();
+                        }
+                        if (matchingLParenIncreasedIndentation)
+                        {
+                            onNewLine = false;
+                            break;
+                        }
+                        indentationLevel = ClipNegative(indentationLevel - 1);
+                        AddViolation(token, indentationLevel, diagnosticRecords, ref onNewLine);
+                        break;
+
                     case TokenKind.RCurly:
                         indentationLevel = ClipNegative(indentationLevel - 1);
                         AddViolation(token, indentationLevel, diagnosticRecords, ref onNewLine);
@@ -220,16 +258,22 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
                                 }
                             }
 
-                            bool lineHasPipelineBeforeToken = LineHasPipelineBeforeToken(tokens, tokenIndex, token);
+                            if (pipelineIndentationStyle == PipelineIndentationStyle.None && PreviousLineEndedWithPipe(tokens, tokenIndex, token))
+                            {
+                                onNewLine = false;
+                                continue;
+                            }
 
+                            bool lineHasPipelineBeforeToken = LineHasPipelineBeforeToken(tokens, tokenIndex, token);
                             AddViolation(token, tempIndentationLevel, diagnosticRecords, ref onNewLine, lineHasPipelineBeforeToken);
                         }
                         break;
                 }
 
-                if (pipelineIndentationStyle == PipelineIndentationStyle.None) { break; }
+                if (pipelineIndentationStyle == PipelineIndentationStyle.None) { continue; }
+
                 // Check if the current token matches the end of a PipelineAst
-                PipelineAst matchingPipeLineAstEnd = MatchingPipelineAstEnd(pipelineAsts, ref minimumPipelineAstIndex, token);
+                PipelineAst matchingPipeLineAstEnd = MatchingPipelineAstEnd(pipelineAsts, token);
                 if (matchingPipeLineAstEnd == null)
                 {
                     continue;
@@ -254,6 +298,29 @@ public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string file
             return diagnosticRecords;
         }
 
+        private static Token NextTokenIgnoringComments(Token[] tokens, int startIndex)
+        {
+            if (startIndex >= tokens.Length - 1)
+            {
+                return null;
+            }
+            
+            for (int i = startIndex + 1; i < tokens.Length; i++)
+            {
+                switch (tokens[i].Kind)
+                {
+                    case TokenKind.Comment:
+                        continue;
+
+                    default:
+                        return tokens[i];
+                }
+            }
+            
+            // We've run out of tokens
+            return null;
+        }
+        
         private static bool PipelineIsFollowedByNewlineOrLineContinuation(Token[] tokens, int startIndex)
         {
             if (startIndex >= tokens.Length - 1)
@@ -284,6 +351,35 @@ private static bool PipelineIsFollowedByNewlineOrLineContinuation(Token[] tokens
             return false;
         }
 
+        private static bool PreviousLineEndedWithPipe(Token[] tokens, int tokenIndex, Token token)
+        {
+            if (tokenIndex < 2 || token.Extent.StartLineNumber == 1)
+            {
+                return false;
+            }
+
+            int searchIndex = tokenIndex - 2;
+            int searchLine;
+            do
+            {
+                searchLine = tokens[searchIndex].Extent.StartLineNumber;
+                if (tokens[searchIndex].Kind == TokenKind.Comment)
+                {
+                    searchIndex--;
+                }
+                else if (tokens[searchIndex].Kind == TokenKind.Pipe)
+                {
+                    return true;
+                }
+                else
+                {
+                    break;
+                }
+            } while (searchLine == token.Extent.StartLineNumber - 1 && searchIndex >= 0);
+
+            return false;
+        }
+
         private static bool LineHasPipelineBeforeToken(Token[] tokens, int tokenIndex, Token token)
         {
             int searchIndex = tokenIndex;
@@ -316,10 +412,10 @@ private static CommandBaseAst LastPipeOnFirstLineWithPipeUsage(PipelineAst pipel
             return lastPipeOnFirstLineWithPipeUsage;
         }
 
-        private static PipelineAst MatchingPipelineAstEnd(List<Ast> pipelineAsts, ref int minimumPipelineAstIndex, Token token)
+        private static PipelineAst MatchingPipelineAstEnd(List<Ast> pipelineAsts, Token token)
         {
             PipelineAst matchingPipeLineAstEnd = null;
-            for (int i = minimumPipelineAstIndex; i < pipelineAsts.Count; i++)
+            for (int i = 0; i < pipelineAsts.Count; i++)
             {
                 if (pipelineAsts[i].Extent.EndScriptPosition.LineNumber > token.Extent.EndScriptPosition.LineNumber)
                 {
@@ -329,7 +425,6 @@ private static PipelineAst MatchingPipelineAstEnd(List<Ast> pipelineAsts, ref in
                 if (PositionIsEqual(pipelineAsts[i].Extent.EndScriptPosition, token.Extent.EndScriptPosition))
                 {
                     matchingPipeLineAstEnd = pipelineAsts[i] as PipelineAst;
-                    minimumPipelineAstIndex = i;
                     break;
                 }
             }
@@ -469,11 +564,6 @@ private static int ClipNegative(int x)
             return x > 0 ? x : 0;
         }
 
-        private int GetIndentationColumnNumber(int indentationLevel)
-        {
-            return GetIndentation(indentationLevel) + 1;
-        }
-
         private int GetIndentation(int indentationLevel)
         {
             // todo if condition can be evaluated during rule configuration
diff --git a/Rules/UseConsistentWhitespace.cs b/Rules/UseConsistentWhitespace.cs
index f589d9e45..e6d4cff99 100644
--- a/Rules/UseConsistentWhitespace.cs
+++ b/Rules/UseConsistentWhitespace.cs
@@ -26,7 +26,7 @@ private enum ErrorKind { BeforeOpeningBrace, Paren, Operator, SeparatorComma, Se
             AfterOpeningBrace, BeforeClosingBrace, BeforePipe, AfterPipe, BetweenParameter };
         private const int whiteSpaceSize = 1;
         private const string whiteSpace = " ";
-        private readonly SortedSet<TokenKind> openParenKeywordWhitelist = new SortedSet<TokenKind>()
+        private readonly SortedSet<TokenKind> openParenKeywordAllowList = new SortedSet<TokenKind>()
         {
             TokenKind.If,
             TokenKind.ElseIf,
@@ -63,6 +63,9 @@ private List<Func<TokenOperations, IEnumerable<DiagnosticRecord>>> violationFind
         [ConfigurableRuleProperty(defaultValue: false)]
         public bool CheckParameter { get; protected set; }
 
+        [ConfigurableRuleProperty(defaultValue: false)]
+        public bool IgnoreAssignmentOperatorInsideHashTable { get; protected set; }
+
         public override void ConfigureRule(IDictionary<string, object> paramValueMap)
         {
             base.ConfigureRule(paramValueMap);
@@ -230,22 +233,25 @@ private IEnumerable<DiagnosticRecord> FindOpenBraceViolations(TokenOperations to
                 if (lcurly.Previous == null
                     || !IsPreviousTokenOnSameLine(lcurly)
                     || lcurly.Previous.Value.Kind == TokenKind.LCurly
+                    || lcurly.Previous.Value.Kind == TokenKind.Dot
                     || ((lcurly.Previous.Value.TokenFlags & TokenFlags.MemberName) == TokenFlags.MemberName))
                 {
                     continue;
                 }
 
-                if (!IsPreviousTokenApartByWhitespace(lcurly))
+                if (IsPreviousTokenApartByWhitespace(lcurly) || IsPreviousTokenLParen(lcurly))
                 {
-                    yield return new DiagnosticRecord(
-                        GetError(ErrorKind.BeforeOpeningBrace),
-                        lcurly.Value.Extent,
-                        GetName(),
-                        GetDiagnosticSeverity(),
-                        tokenOperations.Ast.Extent.File,
-                        null,
-                        GetCorrections(lcurly.Previous.Value, lcurly.Value, lcurly.Next.Value, false, true).ToList());
+                    continue;
                 }
+                
+                yield return new DiagnosticRecord(
+                    GetError(ErrorKind.BeforeOpeningBrace),
+                    lcurly.Value.Extent,
+                    GetName(),
+                    GetDiagnosticSeverity(),
+                    tokenOperations.Ast.Extent.File,
+                    null,
+                    GetCorrections(lcurly.Previous.Value, lcurly.Value, lcurly.Next.Value, false, true).ToList());
             }
         }
 
@@ -254,7 +260,7 @@ private IEnumerable<DiagnosticRecord> FindInnerBraceViolations(TokenOperations t
             foreach (var lCurly in tokenOperations.GetTokenNodes(TokenKind.LCurly))
             {
                 if (lCurly.Next == null
-                    || !IsPreviousTokenOnSameLine(lCurly)
+                    || !(lCurly.Previous == null || IsPreviousTokenOnSameLine(lCurly))
                     || lCurly.Next.Value.Kind == TokenKind.NewLine
                     || lCurly.Next.Value.Kind == TokenKind.LineContinuation
                     || lCurly.Next.Value.Kind == TokenKind.RCurly
@@ -390,7 +396,17 @@ private IEnumerable<DiagnosticRecord> FindParameterViolations(Ast ast)
                     testAst => testAst is CommandAst, true);
             foreach (CommandAst commandAst in commandAsts)
             {
-                List<Ast> commandParameterAstElements = commandAst.FindAll(testAst => true, searchNestedScriptBlocks: false).ToList();
+                /// When finding all the command parameter elements, there is no guarantee that
+                /// we will read them from the AST in the order they appear in the script (in token
+                /// order). So we first sort the tokens by their starting line number, followed by
+                /// their starting column number.
+                List<Ast> commandParameterAstElements = commandAst.FindAll(
+                        testAst => testAst.Parent == commandAst, searchNestedScriptBlocks: false
+                    ).OrderBy(
+                        e => e.Extent.StartLineNumber
+                    ).ThenBy(
+                        e => e.Extent.StartColumnNumber
+                    ).ToList();
                 for (int i = 0; i < commandParameterAstElements.Count - 1; i++)
                 {
                     IScriptExtent leftExtent = commandParameterAstElements[i].Extent;
@@ -405,8 +421,8 @@ private IEnumerable<DiagnosticRecord> FindParameterViolations(Ast ast)
                     {
                         int numberOfRedundantWhiteSpaces = rightExtent.StartColumnNumber - expectedStartColumnNumberOfRightExtent;
                         var correction = new CorrectionExtent(
-                            startLineNumber: leftExtent.StartLineNumber,
-                            endLineNumber: leftExtent.EndLineNumber,
+                            startLineNumber: leftExtent.EndLineNumber,
+                            endLineNumber: rightExtent.StartLineNumber,
                             startColumnNumber: leftExtent.EndColumnNumber + 1,
                             endColumnNumber: leftExtent.EndColumnNumber + 1 + numberOfRedundantWhiteSpaces,
                             text: string.Empty,
@@ -435,6 +451,7 @@ private IEnumerable<DiagnosticRecord> FindSeparatorViolations(TokenOperations to
             {
                 return node.Next != null
                     && node.Next.Value.Kind != TokenKind.NewLine
+                    && node.Next.Value.Kind != TokenKind.Comment
                     && node.Next.Value.Kind != TokenKind.EndOfInput // semicolon can be followed by end of input
                     && !IsPreviousTokenApartByWhitespace(node.Next);
             };
@@ -473,7 +490,7 @@ private DiagnosticRecord getDiagnosticRecord(
 
         private bool IsKeyword(Token token)
         {
-            return openParenKeywordWhitelist.Contains(token.Kind);
+            return openParenKeywordAllowList.Contains(token.Kind);
         }
 
         private static bool IsPreviousTokenApartByWhitespace(LinkedListNode<Token> tokenNode)
@@ -483,10 +500,20 @@ private static bool IsPreviousTokenApartByWhitespace(LinkedListNode<Token> token
 
         private static bool IsPreviousTokenApartByWhitespace(LinkedListNode<Token> tokenNode, out bool hasRedundantWhitespace)
         {
+            if (tokenNode.Value.Extent.StartLineNumber != tokenNode.Previous.Value.Extent.StartLineNumber)
+            {
+                hasRedundantWhitespace = false;
+                return true;
+            }
             var actualWhitespaceSize = tokenNode.Value.Extent.StartColumnNumber - tokenNode.Previous.Value.Extent.EndColumnNumber;
             hasRedundantWhitespace = actualWhitespaceSize - whiteSpaceSize > 0;
             return whiteSpaceSize == actualWhitespaceSize;
         }
+        
+        private static bool IsPreviousTokenLParen(LinkedListNode<Token> tokenNode)
+        {
+            return tokenNode.Previous.Value.Kind == TokenKind.LParen;
+        }
 
         private static bool IsNextTokenApartByWhitespace(LinkedListNode<Token> tokenNode)
         {
@@ -524,6 +551,16 @@ private IEnumerable<DiagnosticRecord> FindOperatorViolations(TokenOperations tok
                     continue;
                 }
 
+                // exclude assignment operator inside of multi-line hash tables if requested
+                if (IgnoreAssignmentOperatorInsideHashTable && tokenNode.Value.Kind == TokenKind.Equals)
+                {
+                    Ast containingAst = tokenOperations.GetAstPosition(tokenNode.Value);
+                    if (containingAst is HashtableAst && containingAst.Extent.EndLineNumber != containingAst.Extent.StartLineNumber)
+                    {
+                        continue;
+                    }
+                }
+
                 var hasWhitespaceBefore = IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode);
                 var hasWhitespaceAfter = tokenNode.Next.Value.Kind == TokenKind.NewLine
                             || IsPreviousTokenOnSameLineAndApartByWhitespace(tokenNode.Next);
@@ -589,7 +626,7 @@ private List<CorrectionExtent> GetCorrections(
         }
 
 
-        private bool IsPreviousTokenOnSameLine(LinkedListNode<Token> lparen)
+        private static bool IsPreviousTokenOnSameLine(LinkedListNode<Token> lparen)
         {
             return lparen.Previous.Value.Extent.EndLineNumber == lparen.Value.Extent.StartLineNumber;
         }
diff --git a/Rules/UseCorrectCasing.cs b/Rules/UseCorrectCasing.cs
index d1f579731..5d1393d45 100644
--- a/Rules/UseCorrectCasing.cs
+++ b/Rules/UseCorrectCasing.cs
@@ -22,76 +22,122 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
 #endif
     public class UseCorrectCasing : ConfigurableRule
     {
+
+        /// <summary>If true, require the case of all operators to be lowercase.</summary>
+        [ConfigurableRuleProperty(defaultValue: true)]
+        public bool CheckOperator { get; set; }
+
+        /// <summary>If true, require the case of all keywords to be lowercase.</summary>
+        [ConfigurableRuleProperty(defaultValue: true)]
+        public bool CheckKeyword { get; set; }
+
+        /// <summary>If true, require the case of all commands to match their actual casing.</summary>
+        [ConfigurableRuleProperty(defaultValue: true)]
+        public bool CheckCommands { get; set; }
+
+        private TokenFlags operators = TokenFlags.BinaryOperator | TokenFlags.UnaryOperator;
+
         /// <summary>
         /// AnalyzeScript: Analyze the script to check if cmdlet alias is used.
         /// </summary>
         public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
         {
-            if (ast == null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
-
-            IEnumerable<Ast> commandAsts = ast.FindAll(testAst => testAst is CommandAst, true);
+            if (ast is null) throw new ArgumentNullException(Strings.NullAstErrorMessage);
 
-            // Iterates all CommandAsts and check the command name.
-            foreach (CommandAst commandAst in commandAsts)
+            if (CheckOperator || CheckKeyword)
             {
-                string commandName = commandAst.GetCommandName();
-
-                // Handles the exception caused by commands like, {& $PLINK $args 2> $TempErrorFile}.
-                // You can also review the remark section in following document,
-                // MSDN: CommandAst.GetCommandName Method
-                if (commandName == null)
+                // Iterate tokens to look for the keywords and operators
+                for (int i = 0; i < Helper.Instance.Tokens.Length; i++)
                 {
-                    continue;
-                }
+                    Token token = Helper.Instance.Tokens[i];
 
-                var commandInfo = Helper.Instance.GetCommandInfo(commandName);
-                if (commandInfo == null || commandInfo.CommandType == CommandTypes.ExternalScript || commandInfo.CommandType == CommandTypes.Application)
-                {
-                    continue;
+                    if (CheckKeyword && ((token.TokenFlags & TokenFlags.Keyword) != 0))
+                    {
+                        string correctCase = token.Text.ToLowerInvariant();
+                        if (!token.Text.Equals(correctCase, StringComparison.Ordinal))
+                        {
+                            yield return GetDiagnosticRecord(token, fileName, correctCase, Strings.UseCorrectCasingKeywordError);
+                        }
+                        continue;
+                    }
+
+                    if (CheckOperator && ((token.TokenFlags & operators) != 0))
+                    {
+                        string correctCase = token.Text.ToLowerInvariant();
+                        if (!token.Text.Equals(correctCase, StringComparison.Ordinal))
+                        {
+                            yield return GetDiagnosticRecord(token, fileName, correctCase, Strings.UseCorrectCasingOperatorError);
+                        }
+                    }
                 }
+            }
 
-                var shortName = commandInfo.Name;
-                var fullyqualifiedName = $"{commandInfo.ModuleName}\\{shortName}";
-                var isFullyQualified = commandName.Equals(fullyqualifiedName, StringComparison.OrdinalIgnoreCase);
-                var correctlyCasedCommandName = isFullyQualified ? fullyqualifiedName : shortName;
+            if (CheckCommands)
+            {
+                // Iterate command ASTs for command and parameter names
+                IEnumerable<Ast> commandAsts = ast.FindAll(testAst => testAst is CommandAst, true);
 
-                if (!commandName.Equals(correctlyCasedCommandName, StringComparison.Ordinal))
+                // Iterates all CommandAsts and check the command name.
+                foreach (CommandAst commandAst in commandAsts)
                 {
-                    yield return new DiagnosticRecord(
-                        string.Format(CultureInfo.CurrentCulture, Strings.UseCorrectCasingError, commandName, shortName),
-                        GetCommandExtent(commandAst),
-                        GetName(),
-                        DiagnosticSeverity.Warning,
-                        fileName,
-                        commandName,
-                        suggestedCorrections: GetCorrectionExtent(commandAst, correctlyCasedCommandName));
-                }
+                    string commandName = commandAst.GetCommandName();
 
-                var commandParameterAsts = commandAst.FindAll(
-                    testAst => testAst is CommandParameterAst, true).Cast<CommandParameterAst>();
-                var availableParameters = commandInfo.Parameters;
-                foreach (var commandParameterAst in commandParameterAsts)
-                {
-                    var parameterName = commandParameterAst.ParameterName;
-                    if (availableParameters.TryGetValue(parameterName, out ParameterMetadata parameterMetaData))
+                    // Handles the exception caused by commands like, {& $PLINK $args 2> $TempErrorFile}.
+                    // You can also review the remark section in following document,
+                    // MSDN: CommandAst.GetCommandName Method
+                    if (commandName == null)
+                    {
+                        continue;
+                    }
+
+                    var commandInfo = Helper.Instance.GetCommandInfo(commandName);
+                    if (commandInfo == null || commandInfo.CommandType == CommandTypes.ExternalScript || commandInfo.CommandType == CommandTypes.Application)
                     {
-                        var correctlyCasedParameterName = parameterMetaData.Name;
-                        if (!parameterName.Equals(correctlyCasedParameterName, StringComparison.Ordinal))
+                        continue;
+                    }
+
+                    var shortName = commandInfo.Name;
+                    var fullyqualifiedName = $"{commandInfo.ModuleName}\\{shortName}";
+                    var isFullyQualified = commandName.Equals(fullyqualifiedName, StringComparison.OrdinalIgnoreCase);
+                    var correctlyCasedCommandName = isFullyQualified ? fullyqualifiedName : shortName;
+
+                    if (!commandName.Equals(correctlyCasedCommandName, StringComparison.Ordinal))
+                    {
+                        yield return GetDiagnosticRecord(commandAst, fileName, correctlyCasedCommandName, Strings.UseCorrectCasingError);
+                    }
+
+                    var commandParameterAsts = commandAst.FindAll(
+                        testAst => testAst is CommandParameterAst, true).Cast<CommandParameterAst>();
+                    Dictionary<string, ParameterMetadata> availableParameters;
+                    try
+                    {
+                        availableParameters = commandInfo.Parameters;
+                    }
+                    // It's a known issue that objects from PowerShell can have a runspace affinity,
+                    // therefore if that happens, we query a fresh object instead of using the cache.
+                    // https://github.com/PowerShell/PowerShell/issues/4003
+                    catch (InvalidOperationException)
+                    {
+                        commandInfo = Helper.Instance.GetCommandInfo(commandName, bypassCache: true);
+                        availableParameters = commandInfo.Parameters;
+                    }
+                    foreach (var commandParameterAst in commandParameterAsts)
+                    {
+                        var parameterName = commandParameterAst.ParameterName;
+                        if (availableParameters.TryGetValue(parameterName, out ParameterMetadata parameterMetaData))
                         {
-                            yield return new DiagnosticRecord(
-                                string.Format(CultureInfo.CurrentCulture, Strings.UseCorrectCasingError, commandName, parameterName),
-                                GetCommandExtent(commandAst),
-                                GetName(),
-                                DiagnosticSeverity.Warning,
-                                fileName,
-                                commandName,
-                                suggestedCorrections: GetCorrectionExtent(commandParameterAst, correctlyCasedParameterName));
+                            var correctlyCasedParameterName = parameterMetaData.Name;
+                            if (!parameterName.Equals(correctlyCasedParameterName, StringComparison.Ordinal))
+                            {
+                                yield return GetDiagnosticRecord(commandParameterAst, fileName, correctlyCasedParameterName, Strings.UseCorrectCasingError);
+                            }
                         }
                     }
                 }
             }
         }
 
+
         /// <summary>
         /// For a command like "gci -path c:", returns the extent of "gci" in the command
         /// </summary>
@@ -112,44 +158,69 @@ private IScriptExtent GetCommandExtent(CommandAst commandAst)
             return commandAst.Extent;
         }
 
-        private IEnumerable<CorrectionExtent> GetCorrectionExtent(CommandAst commandAst, string correctlyCaseName)
+        private IEnumerable<CorrectionExtent> GetCorrectionExtent(Ast ast, IScriptExtent extent, string correctlyCaseName)
         {
-            var description = string.Format(
-                CultureInfo.CurrentCulture,
-                Strings.UseCorrectCasingDescription,
-                correctlyCaseName,
-                correctlyCaseName);
-            var cmdExtent = GetCommandExtent(commandAst);
             var correction = new CorrectionExtent(
-                cmdExtent.StartLineNumber,
-                cmdExtent.EndLineNumber,
-                cmdExtent.StartColumnNumber,
-                cmdExtent.EndColumnNumber,
+                extent.StartLineNumber,
+                extent.EndLineNumber,
+                // For parameters, add +1 because of the dash before the parameter name
+                (ast is CommandParameterAst ? extent.StartColumnNumber + 1 : extent.StartColumnNumber),
+                // and do not use EndColumnNumber property, because sometimes it's all of: -ParameterName:$ParameterValue
+                (ast is CommandParameterAst ? extent.StartColumnNumber + 1 + ((CommandParameterAst)ast).ParameterName.Length : extent.EndColumnNumber),
                 correctlyCaseName,
-                commandAst.Extent.File,
-                description);
+                extent.File,
+                GetDescription());
             yield return correction;
         }
 
-        private IEnumerable<CorrectionExtent> GetCorrectionExtent(CommandParameterAst commandParameterAst, string correctlyCaseName)
+        private DiagnosticRecord GetDiagnosticRecord(Token token, string fileName, string correction, string message)
         {
-            var description = string.Format(
-                CultureInfo.CurrentCulture,
-                Strings.UseCorrectCasingDescription,
-                correctlyCaseName,
-                correctlyCaseName);
-            var cmdExtent = commandParameterAst.Extent;
-            var correction = new CorrectionExtent(
-                cmdExtent.StartLineNumber,
-                cmdExtent.EndLineNumber,
-                // +1 because of the dash before the parameter name
-                cmdExtent.StartColumnNumber + 1,
-                // do not use EndColumnNumber property as it would not cover the case where the colon syntax: -ParameterName:$ParameterValue
-                cmdExtent.StartColumnNumber + 1 + commandParameterAst.ParameterName.Length,
-                correctlyCaseName,
-                commandParameterAst.Extent.File,
-                description);
-            yield return correction;
+            var extents = new[]
+            {
+                new CorrectionExtent(
+                    token.Extent.StartLineNumber,
+                    token.Extent.EndLineNumber,
+                    token.Extent.StartColumnNumber,
+                    token.Extent.EndColumnNumber,
+                    correction,
+                    token.Extent.File,
+                    GetDescription())
+            };
+
+            return new DiagnosticRecord(
+                string.Format(CultureInfo.CurrentCulture, message, token.Text, correction),
+                token.Extent,
+                GetName(),
+                DiagnosticSeverity.Information,
+                fileName,
+                correction, // return the keyword case as the id, so you can turn this off for specific keywords...
+                suggestedCorrections: extents);
+        }
+
+        private DiagnosticRecord GetDiagnosticRecord(Ast ast, string fileName, string correction, string message)
+        {
+            var extent = ast is CommandAst ? GetCommandExtent((CommandAst)ast) : ast.Extent;
+            return new DiagnosticRecord(
+                string.Format(CultureInfo.CurrentCulture, message, extent.Text, correction),
+                extent,
+                GetName(),
+                DiagnosticSeverity.Information,
+                fileName,
+                correction,
+                suggestedCorrections: GetCorrectionExtent(ast, extent, correction));
+        }
+
+        private DiagnosticRecord GetDiagnosticRecord(CommandParameterAst ast, string fileName, string correction, string message)
+        {
+            var extent = ast.Extent;
+            return new DiagnosticRecord(
+                string.Format(CultureInfo.CurrentCulture, message, extent.Text, correction),
+                extent,
+                GetName(),
+                DiagnosticSeverity.Information,
+                fileName,
+                correction,
+                suggestedCorrections: GetCorrectionExtent(ast, extent, correction));
         }
 
         /// <summary>
diff --git a/Rules/UseDeclaredVarsMoreThanAssignments.cs b/Rules/UseDeclaredVarsMoreThanAssignments.cs
index 5a8440ada..b35caafbc 100644
--- a/Rules/UseDeclaredVarsMoreThanAssignments.cs
+++ b/Rules/UseDeclaredVarsMoreThanAssignments.cs
@@ -143,7 +143,7 @@ private IEnumerable<DiagnosticRecord> AnalyzeScriptBlockAst(ScriptBlockAst scrip
                 if (assignmentVarAst != null)
                 {
                     // Ignore if variable is global or environment variable or scope is drive qualified variable
-                    if (!Helper.Instance.IsVariableGlobalOrEnvironment(assignmentVarAst, scriptBlockAst)
+                    if (!Helper.Instance.IsVariableGlobalOrEnvironment(assignmentVarAst)
                         && !assignmentVarAst.VariablePath.IsScript
                         && assignmentVarAst.VariablePath.DriveName == null)
                     {
diff --git a/Rules/UseIdenticalMandatoryParametersDSC.cs b/Rules/UseIdenticalMandatoryParametersDSC.cs
index 713b86814..56acb5b48 100644
--- a/Rules/UseIdenticalMandatoryParametersDSC.cs
+++ b/Rules/UseIdenticalMandatoryParametersDSC.cs
@@ -32,7 +32,6 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
     public class UseIdenticalMandatoryParametersDSC : IDSCResourceRule
     {
         private bool isDSCClassCacheInitialized = false;
-        private Ast ast;
         private string fileName;
         private IDictionary<string, string> propAttrDict;
         private IEnumerable<FunctionDefinitionAst> resourceFunctions;
@@ -94,7 +93,6 @@ public IEnumerable<DiagnosticRecord> AnalyzeDSCResource(Ast ast, string fileName
             }
 
             // Get the keys in the corresponding mof file
-            this.ast = ast;
             this.fileName = fileName;
             this.propAttrDict = GetKeys(fileName);
             this.resourceFunctions = Helper.Instance.DscResourceFunctions(ast)
diff --git a/Rules/UseShouldProcessCorrectly.cs b/Rules/UseShouldProcessCorrectly.cs
index 74b330a60..47bf5eb5c 100644
--- a/Rules/UseShouldProcessCorrectly.cs
+++ b/Rules/UseShouldProcessCorrectly.cs
@@ -350,7 +350,7 @@ private bool SupportsShouldProcess(string cmdName)
         private bool TryGetShouldProcessValueFromAst(FunctionInfo functionInfo, out bool hasShouldProcessSet)
         {
             // Get the body of the function
-            ScriptBlockAst functionBodyAst = (ScriptBlockAst)functionInfo.ScriptBlock.Ast.Find(ast => ast is ScriptBlockAst, searchNestedScriptBlocks: false);
+            ScriptBlockAst functionBodyAst = (ScriptBlockAst)functionInfo.ScriptBlock.Ast.Find(ast => ast is ScriptBlockAst, searchNestedScriptBlocks: true);
 
             // Go through attributes on the parameter block, since this is where [CmdletBinding()] will be
             foreach (AttributeAst attributeAst in functionBodyAst.ParamBlock.Attributes)
diff --git a/Rules/UseSingularNouns.cs b/Rules/UseSingularNouns.cs
index 9f64cc46c..21a6afa90 100644
--- a/Rules/UseSingularNouns.cs
+++ b/Rules/UseSingularNouns.cs
@@ -15,9 +15,13 @@
 using System.Linq;
 using System.Management.Automation.Language;
 using Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic;
+#if CORECLR
+using Pluralize.NET;
+#else
 using System.ComponentModel.Composition;
+using System.Data.Entity.Design.PluralizationServices;
+#endif
 using System.Globalization;
-using System.Text.RegularExpressions;
 
 namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
 {
@@ -25,13 +29,18 @@ namespace Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules
     /// CmdletSingularNoun: Analyzes scripts to check that all defined cmdlets use singular nouns.
     /// 
     /// </summary>
-    [Export(typeof(IScriptRule))]
-    public class CmdletSingularNoun : IScriptRule {
-
-        private readonly string[] nounWhiteList =
+#if !CORECLR
+[Export(typeof(IScriptRule))]
+#endif
+    public class CmdletSingularNoun : ConfigurableRule 
+    {
+        [ConfigurableRuleProperty(defaultValue: new string[] { "Data", "Windows" })]
+        public string[] NounAllowList { get; set; }
+
+        public CmdletSingularNoun()
         {
-            "Data"
-        };
+            Enable = true;
+        }
 
         /// <summary>
         /// Checks that all defined cmdlet use singular noun
@@ -39,46 +48,50 @@ public class CmdletSingularNoun : IScriptRule {
         /// <param name="ast"></param>
         /// <param name="fileName"></param>
         /// <returns></returns>
-        public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) {
+        public override IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
+        {
             if (ast == null) throw new ArgumentNullException(Strings.NullCommandInfoError);
 
             IEnumerable<Ast> funcAsts = ast.FindAll(item => item is FunctionDefinitionAst, true);
 
-            char[] funcSeperator = { '-' };
-            string[] funcNamePieces = new string[2];
+            var pluralizer = new PluralizerProxy();
 
             foreach (FunctionDefinitionAst funcAst in funcAsts)
             {
-                if (funcAst.Name != null && funcAst.Name.Contains('-'))
+                if (funcAst.Name == null || !funcAst.Name.Contains('-'))
+                {
+                    continue;
+                }
+
+                string noun = GetLastWordInCmdlet(funcAst.Name);
+
+                if (noun is null)
+                {
+                    continue;
+                }
+
+                if (pluralizer.CanOnlyBePlural(noun))
                 {
-                    funcNamePieces = funcAst.Name.Split(funcSeperator);
-                    String nounPart = funcNamePieces[1];
-
-                    // Convert the noun part of the function into a series of space delimited words
-                    // This helps the PluralizationService to provide an accurate determination about the plurality of the string
-                    nounPart = SplitCamelCaseString(nounPart);
-                    var words = nounPart.Split(new char [] { ' ' });
-                    var noun = words.LastOrDefault();
-                    if (noun == null)
+                    if (NounAllowList.Contains(noun, StringComparer.OrdinalIgnoreCase))
                     {
                         continue;
                     }
-                    var ps = System.Data.Entity.Design.PluralizationServices.PluralizationService.CreateService(CultureInfo.GetCultureInfo("en-us"));
 
-                    if (!ps.IsSingular(noun) && ps.IsPlural(noun))
+                    IScriptExtent extent = Helper.Instance.GetScriptExtentForFunctionName(funcAst);
+
+                    if (extent is null)
                     {
-                        IScriptExtent extent = Helper.Instance.GetScriptExtentForFunctionName(funcAst);
-                        if (nounWhiteList.Contains(noun, StringComparer.OrdinalIgnoreCase))
-                        {
-                            continue;
-                        }
-                        if (null == extent)
-                        {
-                            extent = funcAst.Extent;
-                        }
-                        yield return new DiagnosticRecord(string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsError, funcAst.Name),
-                            extent, GetName(), DiagnosticSeverity.Warning, fileName);
+                        extent = funcAst.Extent;
                     }
+
+                    yield return new DiagnosticRecord(
+                        string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsError, funcAst.Name),
+                        extent,
+                        GetName(),
+                        DiagnosticSeverity.Warning,
+                        fileName,
+                        funcAst.Name,
+                        suggestedCorrections: new CorrectionExtent[] { GetCorrection(pluralizer, extent, funcAst.Name, noun) });
                 }
             }
 
@@ -88,7 +101,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName) {
         /// GetName: Retrieves the name of this rule.
         /// </summary>
         /// <returns>The name of this rule</returns>
-        public string GetName()
+        public override string GetName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.NameSpaceFormat, GetSourceName(), Strings.UseSingularNounsName);
         }
@@ -97,7 +110,7 @@ public string GetName()
         /// GetName: Retrieves the common name of this rule.
         /// </summary>
         /// <returns>The common name of this rule</returns>
-        public string GetCommonName()
+        public override string GetCommonName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsCommonName);
         }
@@ -106,14 +119,15 @@ public string GetCommonName()
         /// GetDescription: Retrieves the description of this rule.
         /// </summary>
         /// <returns>The description of this rule</returns>
-        public string GetDescription() {
+        public override string GetDescription()
+        {
             return string.Format(CultureInfo.CurrentCulture, Strings.UseSingularNounsDescription);
         }
 
         /// <summary>
         /// GetSourceType: Retrieves the type of the rule: builtin, managed or module.
         /// </summary>
-        public SourceType GetSourceType()
+        public override SourceType GetSourceType()
         {
             return SourceType.Builtin;
         }
@@ -122,7 +136,7 @@ public SourceType GetSourceType()
         /// GetSeverity: Retrieves the severity of the rule: error, warning of information.
         /// </summary>
         /// <returns></returns>
-        public RuleSeverity GetSeverity()
+        public override RuleSeverity GetSeverity()
         {
             return RuleSeverity.Warning;
         }
@@ -130,23 +144,82 @@ public RuleSeverity GetSeverity()
         /// <summary>
         /// GetSourceName: Retrieves the module/assembly name the rule is from.
         /// </summary>
-        public string GetSourceName()
+        public override string GetSourceName()
         {
             return string.Format(CultureInfo.CurrentCulture, Strings.SourceName);
         }
 
+        private CorrectionExtent GetCorrection(PluralizerProxy pluralizer, IScriptExtent extent, string commandName, string noun)
+        {
+            string singularNoun = pluralizer.Singularize(noun);
+            string newCommandName = commandName.Substring(0, commandName.Length - noun.Length) + singularNoun;
+            return new CorrectionExtent(extent, newCommandName, extent.File, $"Singularized correction of '{extent.Text}'");
+        }
+
         /// <summary>
-        /// SplitCamelCaseString: Splits a Camel Case'd string into individual words with space delimited
+        /// Gets the last word in a standard syntax, CamelCase cmdlet.
+        /// If the cmdlet name is non-standard, returns null.
         /// </summary>
-        private string SplitCamelCaseString(string input)
+        private string GetLastWordInCmdlet(string cmdletName)
         {
-            if (String.IsNullOrEmpty(input))
+            if (string.IsNullOrEmpty(cmdletName))
             {
-                return String.Empty;
+                return null;
             }
 
-            return Regex.Replace(input, "([A-Z])", " $1", RegexOptions.Compiled).Trim();
+            // Cmdlet doesn't use CamelCase, so assume it's something like an initialism that shouldn't be singularized
+            if (!char.IsLower(cmdletName[cmdletName.Length - 1]))
+            {
+                return null;
+            }
+
+            for (int i = cmdletName.Length - 1; i >= 0; i--)
+            {
+                if (cmdletName[i] == '-')
+                {
+                    // We got to the dash without seeing a CamelCase word, so nothing to singularize
+                    return null;
+                }
+
+                // We just changed from lower case to upper, so we have the end word
+                if (char.IsUpper(cmdletName[i]))
+                {
+                    return cmdletName.Substring(i);
+                }
+            }
+
+            // We shouldn't ever get here since we should always eventually hit a '-'
+            // But if we do, assume this isn't supported cmdlet name
+            return null;
+        }
+
+#if CORECLR
+        private class PluralizerProxy
+        {
+            private readonly Pluralizer _pluralizer;
+
+            public PluralizerProxy()
+            {
+                _pluralizer = new Pluralizer();
+            }
+
+            public bool CanOnlyBePlural(string noun) =>
+                !_pluralizer.IsSingular(noun) && _pluralizer.IsPlural(noun);
+
+            public string Singularize(string noun) => _pluralizer.Singularize(noun);
+        }
+#else
+        private class PluralizerProxy
+        {
+            private static readonly PluralizationService s_pluralizationService = PluralizationService.CreateService(
+                CultureInfo.GetCultureInfo("en-us"));
+
+            public bool CanOnlyBePlural(string noun) =>
+                !s_pluralizationService.IsSingular(noun) && s_pluralizationService.IsPlural(noun);
+
+            public string Singularize(string noun) => s_pluralizationService.Singularize(noun);
         }
+#endif
     }
 
 }
diff --git a/Rules/UseToExportFieldsInManifest.cs b/Rules/UseToExportFieldsInManifest.cs
index bfd99db9e..9bf612f83 100644
--- a/Rules/UseToExportFieldsInManifest.cs
+++ b/Rules/UseToExportFieldsInManifest.cs
@@ -69,7 +69,7 @@ public IEnumerable<DiagnosticRecord> AnalyzeScript(Ast ast, string fileName)
             foreach(string field in manifestFields)
             {
                 IScriptExtent extent;
-                if (!HasAcceptableExportField(field, hashtableAst, ast.Extent.Text, out extent) && extent != null)
+                if (!HasAcceptableExportField(field, hashtableAst, out extent) && extent != null)
                 {
                     yield return new DiagnosticRecord(
                         GetError(field), 
@@ -200,10 +200,9 @@ private bool HasNullInExpression(Ast ast)
         /// </summary>
         /// <param name="key"></param>
         /// <param name="hast"></param>
-        /// <param name="scriptText"></param>
         /// <param name="extent"></param>
         /// <returns>A boolean value indicating if the the ToExport fields are explicitly set to arrays or not.</returns>
-        private bool HasAcceptableExportField(string key, HashtableAst hast, string scriptText, out IScriptExtent extent)
+        private bool HasAcceptableExportField(string key, HashtableAst hast, out IScriptExtent extent)
         {
             extent = null;
             foreach (var pair in hast.KeyValuePairs)
diff --git a/Rules/UseUsingScopeModifierInNewRunspaces.cs b/Rules/UseUsingScopeModifierInNewRunspaces.cs
index 1db914276..a435c1d31 100644
--- a/Rules/UseUsingScopeModifierInNewRunspaces.cs
+++ b/Rules/UseUsingScopeModifierInNewRunspaces.cs
@@ -116,7 +116,7 @@ private class SyntaxCompatibilityVisitor : AstVisitor
             private static readonly IEnumerable<string> s_invokeCommandCmdletNamesAndAliases =
                 Helper.Instance.CmdletNameAndAliases("Invoke-Command");
 
-            private readonly Dictionary<string, Dictionary<string, VariableExpressionAst>> _varsDeclaredPerSession;
+            private readonly Dictionary<string, HashSet<string>> _varsDeclaredPerSession;
 
             private readonly List<DiagnosticRecord> _diagnosticAccumulator;
         
@@ -127,7 +127,7 @@ private class SyntaxCompatibilityVisitor : AstVisitor
             public SyntaxCompatibilityVisitor(UseUsingScopeModifierInNewRunspaces rule, string analyzedScriptPath)
             {
                 _diagnosticAccumulator = new List<DiagnosticRecord>();
-                _varsDeclaredPerSession = new Dictionary<string, Dictionary<string, VariableExpressionAst>>();
+                _varsDeclaredPerSession = new Dictionary<string, HashSet<string>>();
                 _rule = rule;
                 _analyzedFilePath = analyzedScriptPath;
             }
@@ -183,7 +183,7 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA
                         return AstVisitAction.Continue;
                     }
 
-                    IReadOnlyDictionary<string, VariableExpressionAst> varsInLocalAssignments = FindVarsInAssignmentAsts(scriptBlockExpressionAst);
+                    IReadOnlyCollection<string> varsInLocalAssignments = FindVarsInAssignmentAsts(scriptBlockExpressionAst);
                     if (varsInLocalAssignments != null)
                     {
                         AddAssignedVarsToSession(sessionName, varsInLocalAssignments);
@@ -191,7 +191,7 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA
 
                     GenerateDiagnosticRecords(
                         FindNonAssignedNonUsingVarAsts(
-                            scriptBlockExpressionAst, 
+                            scriptBlockExpressionAst,
                             GetAssignedVarsInSession(sessionName)));
 
                     return AstVisitAction.SkipChildren;
@@ -205,10 +205,10 @@ public override AstVisitAction VisitScriptBlockExpression(ScriptBlockExpressionA
             /// Example: `$foo = "foo"` ==> the VariableExpressionAst for $foo is returned
             /// </summary>
             /// <param name="ast"></param>
-            private static IReadOnlyDictionary<string, VariableExpressionAst> FindVarsInAssignmentAsts(Ast ast)
+            private static IReadOnlyCollection<string> FindVarsInAssignmentAsts(Ast ast)
             {
-                Dictionary<string, VariableExpressionAst> variableDictionary =
-                    new Dictionary<string, VariableExpressionAst>();
+                HashSet<string> variableDictionary =
+                    new HashSet<string>();
 
                 // Find all variables that are assigned within this ast
                 foreach (AssignmentStatementAst statementAst in ast.FindAll(IsAssignmentStatementAst, true))
@@ -217,11 +217,11 @@ private static IReadOnlyDictionary<string, VariableExpressionAst> FindVarsInAssi
                     {
                         string variableName = string.Format(variable.VariablePath.UserPath,
                             StringComparer.OrdinalIgnoreCase);
-                        variableDictionary.Add(variableName, variable);
+                        variableDictionary.Add(variableName);
                     }
                 };
 
-                return new ReadOnlyDictionary<string, VariableExpressionAst>(variableDictionary);
+                return variableDictionary;
             }
 
             /// <summary>
@@ -264,14 +264,14 @@ private static bool IsAssignmentStatementAst(Ast ast)
             /// <param name="ast"></param>
             /// <param name="varsInAssignments"></param>
             private static IEnumerable<VariableExpressionAst> FindNonAssignedNonUsingVarAsts(
-                Ast ast, IReadOnlyDictionary<string, VariableExpressionAst> varsInAssignments)
+                Ast ast, IReadOnlyCollection<string> varsInAssignments)
             {
                 // Find all variables that are not locally assigned, and don't have $using: scope modifier
                 foreach (VariableExpressionAst variable in ast.FindAll(IsNonUsingNonSpecialVariableExpressionAst, true))
                 {
                     var varName = string.Format(variable.VariablePath.UserPath, StringComparer.OrdinalIgnoreCase);
                     
-                    if (varsInAssignments.ContainsKey(varName))
+                    if (varsInAssignments.Contains(varName))
                     {
                         yield break;    
                     }
@@ -368,7 +368,7 @@ private static bool TryGetSessionNameFromInvokeCommand(CommandAst invokeCommandA
             /// GetAssignedVarsInSession: Retrieves all previously declared vars for a given session (as in Invoke-Command -Session $session).
             /// </summary>
             /// <param name="sessionName"></param>
-            private IReadOnlyDictionary<string,VariableExpressionAst> GetAssignedVarsInSession(string sessionName)
+            private IReadOnlyCollection<string> GetAssignedVarsInSession(string sessionName)
             {
                 return _varsDeclaredPerSession[sessionName];
             }
@@ -378,16 +378,19 @@ private IReadOnlyDictionary<string,VariableExpressionAst> GetAssignedVarsInSessi
             /// </summary>
             /// <param name="sessionName"></param>
             /// <param name="variablesToAdd"></param>
-            private void AddAssignedVarsToSession(string sessionName, IReadOnlyDictionary<string, VariableExpressionAst> variablesToAdd)
+            private void AddAssignedVarsToSession(string sessionName, IReadOnlyCollection<string> variablesToAdd)
             {
                 if (!_varsDeclaredPerSession.ContainsKey(sessionName))
                 {
-                    _varsDeclaredPerSession.Add(sessionName, new Dictionary<string, VariableExpressionAst>());
+                    _varsDeclaredPerSession.Add(sessionName, new HashSet<string>());
                 }
 
                 foreach (var item in variablesToAdd)
                 {
-                    _varsDeclaredPerSession[sessionName].Add(item.Key, item.Value);
+                    if (!_varsDeclaredPerSession[sessionName].Contains(item))
+                    {
+                        _varsDeclaredPerSession[sessionName].Add(item);
+                    }
                 }
             }
 
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..f941d308b
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,41 @@
+<!-- BEGIN MICROSOFT SECURITY.MD V0.0.9 BLOCK -->
+
+## Security
+
+Microsoft takes the security of our software products and services seriously, which includes all source code repositories managed through our GitHub organizations, which include [Microsoft](https://github.com/Microsoft), [Azure](https://github.com/Azure), [DotNet](https://github.com/dotnet), [AspNet](https://github.com/aspnet), [Xamarin](https://github.com/xamarin) and [PowerShell](https://github.com/PowerShell).
+
+If you believe you have found a security vulnerability in any Microsoft-owned repository that meets [Microsoft's definition of a security vulnerability](https://aka.ms/security.md/definition), please report it to us as described below.
+
+## Reporting Security Issues
+
+**Please do not report security vulnerabilities through public GitHub issues.**
+
+Instead, please report them to the Microsoft Security Response Center (MSRC) at [https://msrc.microsoft.com/create-report](https://aka.ms/security.md/msrc/create-report).
+
+If you prefer to submit without logging in, send email to [secure@microsoft.com](mailto:secure@microsoft.com).  If possible, encrypt your message with our PGP key; please download it from the [Microsoft Security Response Center PGP Key page](https://aka.ms/security.md/msrc/pgp).
+
+You should receive a response within 24 hours. If for some reason you do not, please follow up via email to ensure we received your original message. Additional information can be found at [microsoft.com/msrc](https://www.microsoft.com/msrc). 
+
+Please include the requested information listed below (as much as you can provide) to help us better understand the nature and scope of the possible issue:
+
+  * Type of issue (e.g. buffer overflow, SQL injection, cross-site scripting, etc.)
+  * Full paths of source file(s) related to the manifestation of the issue
+  * The location of the affected source code (tag/branch/commit or direct URL)
+  * Any special configuration required to reproduce the issue
+  * Step-by-step instructions to reproduce the issue
+  * Proof-of-concept or exploit code (if possible)
+  * Impact of the issue, including how an attacker might exploit the issue
+
+This information will help us triage your report more quickly.
+
+If you are reporting for a bug bounty, more complete reports can contribute to a higher bounty award. Please visit our [Microsoft Bug Bounty Program](https://aka.ms/security.md/msrc/bounty) page for more details about our active programs.
+
+## Preferred Languages
+
+We prefer all communications to be in English.
+
+## Policy
+
+Microsoft follows the principle of [Coordinated Vulnerability Disclosure](https://aka.ms/security.md/cvd).
+
+<!-- END MICROSOFT SECURITY.MD BLOCK -->
diff --git a/ScriptRuleDocumentation.md b/ScriptRuleDocumentation.md
deleted file mode 100644
index 9c5adcf4e..000000000
--- a/ScriptRuleDocumentation.md
+++ /dev/null
@@ -1,208 +0,0 @@
-## Documentation for Customized Rules in PowerShell Scripts
-
-PSScriptAnalyzer uses MEF(Managed Extensibility Framework) to import all rules defined in the assembly. It can also consume rules written in PowerShell scripts.
-
-When calling Invoke-ScriptAnalyzer, users can specify custom rules using the parameter `CustomizedRulePath`.
-
-The purpose of this documentation is to serve as a basic guide on creating your own customized rules.
-
-### Basics
-
-- Functions should have comment-based help. Make sure .DESCRIPTION field is there, as it will be consumed as rule description for the customized rule.
-
-``` PowerShell
-<#
-.SYNOPSIS
-    Name of your rule.
-.DESCRIPTION
-    This would be the description of your rule. Please refer to Rule Documentation for consistent rule messages.
-.EXAMPLE
-.INPUTS
-.OUTPUTS
-.NOTES
-#>
-```
-
-- Output type should be DiagnosticRecord:
-
-``` PowerShell
-[OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
-```
-
-- Make sure each function takes either a Token array or an Ast as a parameter. The _Ast_ parameter name must end with 'Ast' and the _Token_ parameter name must end with 'Token'
-
-``` PowerShell
-Param
-(
-    [Parameter(Mandatory = $true)]
-    [ValidateNotNullOrEmpty()]
-    [System.Management.Automation.Language.ScriptBlockAst]
-    $testAst
-)
-```
-
-``` PowerShell
-Param
-(
-    [Parameter(Mandatory = $true)]
-    [ValidateNotNullOrEmpty()]
-    [System.Management.Automation.Language.Token[]]
-    $testToken
-)
-```
-
-- DiagnosticRecord should have at least four properties: Message, Extent, RuleName and Severity
-
-``` PowerShell
-$result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]@{
-    "Message"  = "This is a sample rule"
-    "Extent"   = $ast.Extent
-    "RuleName" = $PSCmdlet.MyInvocation.InvocationName
-    "Severity" = "Warning"
-}
-```
-Optionally, since version 1.17.0, a `SuggestedCorrections` property of type `IEnumerable<CorrectionExtent>` can also be added in script rules but care must be taken that the type is correct, an example is:
-```powershell
-[int]$startLineNumber =  $ast.Extent.StartLineNumber
-[int]$endLineNumber = $ast.Extent.EndLineNumber
-[int]$startColumnNumber = $ast.Extent.StartColumnNumber
-[int]$endColumnNumber = $ast.Extent.EndColumnNumber
-[string]$correction = 'Correct text that replaces Extent text'
-[string]$file = $MyInvocation.MyCommand.Definition
-[string]$optionalDescription = 'Useful but optional description text'
-$correctionExtent = New-Object 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent' $startLineNumber,$endLineNumber,$startColumnNumber,$endColumnNumber,$correction,$description
-$suggestedCorrections = New-Object System.Collections.ObjectModel.Collection['Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent']
-$suggestedCorrections.add($correctionExtent) | out-null
-
-[Microsoft.Windows.Powershell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
-    "Message"              = "This is a rule with a suggested correction"
-    "Extent"               = $ast.Extent
-    "RuleName"             = $PSCmdlet.MyInvocation.InvocationName
-    "Severity"             = "Warning"
-    "Severity"             = "Warning"
-    "RuleSuppressionID"    = "MyRuleSuppressionID"
-    "SuggestedCorrections" = $suggestedCorrections
-}
-```
-
-- Make sure you export the function(s) at the end of the script using Export-ModuleMember
-
-``` PowerShell
-Export-ModuleMember -Function (FunctionName)
-```
-
-### Example
-
-``` PowerShell
-<#
-        .SYNOPSIS
-        Uses #Requires -RunAsAdministrator instead of your own methods.
-        .DESCRIPTION
-        The #Requires statement prevents a script from running unless the Windows PowerShell version, modules, snap-ins, and module and snap-in version prerequisites are met.
-        From Windows PowerShell 4.0, the #Requires statement let script developers require that sessions be run with elevated user rights (run as Administrator).
-        Script developers does not need to write their own methods any more.
-        To fix a violation of this rule, please consider to use #Requires -RunAsAdministrator instead of your own methods.
-        .EXAMPLE
-        Measure-RequiresRunAsAdministrator -ScriptBlockAst $ScriptBlockAst
-        .INPUTS
-        [System.Management.Automation.Language.ScriptBlockAst]
-        .OUTPUTS
-        [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]]
-        .NOTES
-        None
-#>
-function Measure-RequiresRunAsAdministrator
-{
-    [CmdletBinding()]
-    [OutputType([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord[]])]
-    Param
-    (
-        [Parameter(Mandatory = $true)]
-        [ValidateNotNullOrEmpty()]
-        [System.Management.Automation.Language.ScriptBlockAst]
-        $ScriptBlockAst
-    )
-
-    Process
-    {
-        $results = @()
-        try
-        {
-            #region Define predicates to find ASTs.
-            # Finds specific method, IsInRole.
-            [ScriptBlock]$predicate1 = {
-                param ([System.Management.Automation.Language.Ast]$Ast)
-                [bool]$returnValue = $false
-                if ($Ast -is [System.Management.Automation.Language.MemberExpressionAst])
-                {
-                    [System.Management.Automation.Language.MemberExpressionAst]$meAst = $Ast
-                    if ($meAst.Member -is [System.Management.Automation.Language.StringConstantExpressionAst])
-                    {
-                        [System.Management.Automation.Language.StringConstantExpressionAst]$sceAst = $meAst.Member
-                        if ($sceAst.Value -eq 'isinrole')
-                        {
-                            $returnValue = $true
-                        }
-                    }
-                }
-                return $returnValue
-            }
-
-            # Finds specific value, [system.security.principal.windowsbuiltinrole]::administrator.
-            [ScriptBlock]$predicate2 = {
-                param ([System.Management.Automation.Language.Ast]$Ast)
-                [bool]$returnValue = $false
-                if ($Ast -is [System.Management.Automation.Language.AssignmentStatementAst])
-                {
-                    [System.Management.Automation.Language.AssignmentStatementAst]$asAst = $Ast
-                    if ($asAst.Right.ToString() -eq '[system.security.principal.windowsbuiltinrole]::administrator')
-                    {
-                        $returnValue = $true
-                    }
-                }
-                return $returnValue
-            }
-            #endregion
-            #region Finds ASTs that match the predicates.
-
-            [System.Management.Automation.Language.Ast[]]$methodAst     = $ScriptBlockAst.FindAll($predicate1, $true)
-            [System.Management.Automation.Language.Ast[]]$assignmentAst = $ScriptBlockAst.FindAll($predicate2, $true)
-            if ($null -ne $ScriptBlockAst.ScriptRequirements)
-            {
-                if ((!$ScriptBlockAst.ScriptRequirements.IsElevationRequired) -and
-                ($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0))
-                {
-                    $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
-                        'Message' = $Messages.MeasureRequiresRunAsAdministrator
-                        'Extent' = $assignmentAst.Extent
-                        'RuleName' = $PSCmdlet.MyInvocation.InvocationName
-                        'Severity' = 'Information'
-                    }
-                    $results += $result
-                }
-            }
-            else
-            {
-                if (($methodAst.Count -ne 0) -and ($assignmentAst.Count -ne 0))
-                {
-                    $result = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord]@{
-                        'Message' = $Messages.MeasureRequiresRunAsAdministrator
-                        'Extent' = $assignmentAst.Extent
-                        'RuleName' = $PSCmdlet.MyInvocation.InvocationName
-                        'Severity' = 'Information'
-                    }
-                    $results += $result
-                }
-            }
-            return $results
-            #endregion
-        }
-        catch
-        {
-            $PSCmdlet.ThrowTerminatingError($PSItem)
-        }
-    }
-}
-```
-
-More examples can be found in *Tests\Engine\CommunityAnalyzerRules*
diff --git a/BuildModule.tests.ps1 b/Tests/Build/BuildModule.tests.ps1
similarity index 66%
rename from BuildModule.tests.ps1
rename to Tests/Build/BuildModule.tests.ps1
index 417ba5ae9..ebc4e2a6a 100644
--- a/BuildModule.tests.ps1
+++ b/Tests/Build/BuildModule.tests.ps1
@@ -3,11 +3,11 @@
 
 # these are tests for the build module
 
-import-module -force "./build.psm1"
+import-module -force "$PSScriptRoot\..\..\build.psm1"
 Describe "Build Module Tests" {
     Context "Global.json" {
         BeforeAll {
-            $globalJson = Get-Content (Join-Path $PSScriptRoot global.json) | ConvertFrom-Json
+            $globalJson = Get-Content (Join-Path "$PSScriptRoot\..\..\" global.json) | ConvertFrom-Json
             $expectedVersion = $globalJson.sdk.version
             $result = Get-GlobalJsonSdkVersion
         }
@@ -48,64 +48,10 @@ Describe "Build Module Tests" {
         }
     }
 
-    Context "Test-DotnetInstallation" {
-        BeforeAll {
-            $availableVersions = ConvertTo-PortableVersion -strVersion "2.2.400","2.2.401","2.2.405"
-            $foundVersion = ConvertTo-PortableVersion -strVersion 2.2.402
-            $missingVersion = ConvertTo-PortableVersion -strVersion 2.2.410
-        }
-
-        It "Test-DotnetInstallation finds a good version" {
-            Mock Get-InstalledCLIVersion { return $availableVersions }
-            Mock Get-GlobalJSonSdkVersion { return $foundVersion }
-            $result = Test-DotnetInstallation -requestedVersion (Get-GlobalJsonSdkVersion) -installedVersions (Get-InstalledCLIVersion)
-            Assert-MockCalled "Get-InstalledCLIVersion" -Times 1
-            Assert-MockCalled "Get-GlobalJsonSdkVersion" -Times 1
-            $result | Should -Be $true
-        }
-
-        It "Test-DotnetInstallation cannot find a good version should return false" {
-            Mock Get-InstalledCLIVersion { return $availableVersions }
-            Mock Get-GlobalJSonSdkVersion { return $missingVersion }
-            $result = Test-DotnetInstallation -requestedVersion (Get-GlobalJsonSdkVersion) -installedVersions (Get-InstalledCLIVersion)
-            Assert-MockCalled "Get-InstalledCLIVersion" -Times 1
-            Assert-MockCalled "Get-GlobalJsonSdkVersion" -Times 1
-            $result | Should -Be $false
-        }
-    }
-
-    Context "Receive-DotnetInstallScript" {
-
-        Mock -ModuleName Build Receive-File { new-item -type file TestDrive:/dotnet-install.sh }
-        It "Downloads the proper non-Windows file" {
-            try {
-                push-location TestDrive:
-                Receive-DotnetInstallScript -platform NonWindows
-                "TestDrive:/dotnet-install.sh" | Should -Exist
-            }
-            finally {
-                Pop-Location
-            }
-        }
-
-        Mock -ModuleName Build Receive-File { new-item -type file TestDrive:/dotnet-install.ps1 }
-        It "Downloads the proper file Windows file" {
-            try {
-                push-location TestDrive:
-                Receive-DotnetInstallScript -platform "Windows"
-                "TestDrive:/dotnet-install.ps1" | Should -Exist
-            }
-            finally {
-                Pop-Location
-            }
-        }
-
-    }
-
     Context "Test result functions" {
         BeforeAll {
             $xmlFile = @'
-﻿<?xml version="1.0" encoding="utf-8" standalone="no"?>
+<?xml version="1.0" encoding="utf-8" standalone="no"?>
 <test-results xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="nunit_schema_2.5.xsd" name="Pester" total="2" errors="0" failures="1" not-run="0" inconclusive="0" ignored="0" skipped="0" invalid="0" date="2019-02-19" time="11:36:56">
   <environment platform="Darwin" clr-version="Unknown" os-version="18.2.0" cwd="/Users/jimtru/src/github/forks/JamesWTruher/PSScriptAnalyzer" user="jimtru" user-domain="" machine-name="Jims-Mac-mini.guest.corp.microsoft.com" nunit-version="2.5.8.0" />
   <culture-info current-culture="en-US" current-uiculture="en-US" />
@@ -133,8 +79,8 @@ Describe "Build Module Tests" {
 '@
 
             $xmlFile | out-file TESTDRIVE:/results.xml
-            $results = Get-TestResults -logfile TESTDRIVE:/results.xml
-            $failures = Get-TestFailures -logfile TESTDRIVE:/results.xml
+            $results = @(Get-TestResults -logfile TESTDRIVE:/results.xml)
+            $failures = @(Get-TestFailures -logfile TESTDRIVE:/results.xml)
         }
 
         It "Get-TestResults finds 2 results" {
diff --git a/Tests/DisabledRules/AvoidOneChar.tests.ps1 b/Tests/DisabledRules/AvoidOneChar.tests.ps1
index 29ff0b7db..dae259602 100644
--- a/Tests/DisabledRules/AvoidOneChar.tests.ps1
+++ b/Tests/DisabledRules/AvoidOneChar.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-$oneCharMessage = "The cmdlet name O only has one character."
+﻿$oneCharMessage = "The cmdlet name O only has one character."
 $oneCharName = "PSOneChar"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $invoke = Invoke-ScriptAnalyzer $directory\AvoidUsingReservedCharOneCharNames.ps1 | Where-Object {$_.RuleName -eq $oneCharName}
diff --git a/Tests/DisabledRules/AvoidTrapStatements.tests.ps1 b/Tests/DisabledRules/AvoidTrapStatements.tests.ps1
index 348d13f7c..985ced734 100644
--- a/Tests/DisabledRules/AvoidTrapStatements.tests.ps1
+++ b/Tests/DisabledRules/AvoidTrapStatements.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-$violationMessage = "Trap found."
+﻿$violationMessage = "Trap found."
 $violationName = "PSAvoidTrapStatement"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\AvoidTrapStatements.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/DisabledRules/AvoidUnloadableModule.tests.ps1 b/Tests/DisabledRules/AvoidUnloadableModule.tests.ps1
index 283bdc748..7149c3631 100644
--- a/Tests/DisabledRules/AvoidUnloadableModule.tests.ps1
+++ b/Tests/DisabledRules/AvoidUnloadableModule.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer 
-$unloadableMessage = [regex]::Escape("Cannot load the module TestBadModule that the file TestBadModule.psd1 is in.")
+﻿$unloadableMessage = [regex]::Escape("Cannot load the module TestBadModule that the file TestBadModule.psd1 is in.")
 $unloadableName = "PSAvoidUnloadableModule"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\TestBadModule\TestBadModule.psd1 | Where-Object {$_.RuleName -eq $unloadableName}
diff --git a/Tests/DisabledRules/AvoidUsingClearHost.tests.ps1 b/Tests/DisabledRules/AvoidUsingClearHost.tests.ps1
index 143ffb3b2..4f883cfa4 100644
--- a/Tests/DisabledRules/AvoidUsingClearHost.tests.ps1
+++ b/Tests/DisabledRules/AvoidUsingClearHost.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-Set-Alias ctss ConvertTo-SecureString
+﻿Set-Alias ctss ConvertTo-SecureString
 $clearHostMessage = "File 'AvoidUsingClearHostWriteHost.ps1' uses Clear-Host. This is not recommended because it may not work in some hosts or there may even be no hosts at all."
 $clearHostName = "PSAvoidUsingClearHost"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
diff --git a/Tests/DisabledRules/AvoidUsingFilePath.tests.ps1 b/Tests/DisabledRules/AvoidUsingFilePath.tests.ps1
index bd7f37b5e..a93ae3141 100644
--- a/Tests/DisabledRules/AvoidUsingFilePath.tests.ps1
+++ b/Tests/DisabledRules/AvoidUsingFilePath.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-$violationMessage = @'
+﻿$violationMessage = @'
 The file path "D:\\Code" of AvoidUsingFilePath.ps1 is rooted. This should be avoided if AvoidUsingFilePath.ps1 is published online
 '@
 $violationUNCMessage = @'
diff --git a/Tests/DisabledRules/AvoidUsingInternalURLs.tests.ps1 b/Tests/DisabledRules/AvoidUsingInternalURLs.tests.ps1
index 376f840d0..3584dae84 100644
--- a/Tests/DisabledRules/AvoidUsingInternalURLs.tests.ps1
+++ b/Tests/DisabledRules/AvoidUsingInternalURLs.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-$violationMessage = "could be an internal URL. Using internal URL directly in the script may cause potential information disclosure."
+﻿$violationMessage = "could be an internal URL. Using internal URL directly in the script may cause potential information disclosure."
 $violationName = "PSAvoidUsingInternalURLs"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\AvoidUsingInternalURLs.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/DisabledRules/AvoidUsingUninitializedVariable.Tests.ps1 b/Tests/DisabledRules/AvoidUsingUninitializedVariable.Tests.ps1
index f2922535f..45843cc10 100644
--- a/Tests/DisabledRules/AvoidUsingUninitializedVariable.Tests.ps1
+++ b/Tests/DisabledRules/AvoidUsingUninitializedVariable.Tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-$AvoidUninitializedVariable = "PSAvoidUninitializedVariable"
+﻿$AvoidUninitializedVariable = "PSAvoidUninitializedVariable"
 $violationMessage = "Variable 'MyVerbosePreference' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables."
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\AvoidUsingUninitializedVariable.ps1 -IncludeRule $AvoidUninitializedVariable
@@ -12,7 +11,7 @@ Describe "AvoidUsingUninitializedVariable" {
         }
 
         It "has the correct description message for UninitializedVariable rule violation" {
-            $violations[0].Message | Should -Be $violationMessage            
+            $violations[0].Message | Should -Be $violationMessage
         }
     }
 
diff --git a/Tests/DisabledRules/CommandNotFound.tests.ps1 b/Tests/DisabledRules/CommandNotFound.tests.ps1
index e311fdca5..c6b198b09 100644
--- a/Tests/DisabledRules/CommandNotFound.tests.ps1
+++ b/Tests/DisabledRules/CommandNotFound.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module -Verbose ScriptAnalyzer
-$violationMessage = "Command Get-WrongCommand Is Not Found"
+﻿$violationMessage = "Command Get-WrongCommand Is Not Found"
 $violationName = "PSCommandNotFound"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\CommandNotFound.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1 b/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1
index 290e1ec91..7f5867177 100644
--- a/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1
+++ b/Tests/DisabledRules/ProvideVerboseMessage.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module PSScriptAnalyzer
-$violationMessage = [regex]::Escape("There is no call to Write-Verbose in the function 'Verb-Files'.")
+﻿$violationMessage = [regex]::Escape("There is no call to Write-Verbose in the function 'Verb-Files'.")
 $violationName = "PSProvideVerboseMessage"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/DisabledRules/TypeNotFound.tests.ps1 b/Tests/DisabledRules/TypeNotFound.tests.ps1
index 48e4261fb..51b36b2b3 100644
--- a/Tests/DisabledRules/TypeNotFound.tests.ps1
+++ b/Tests/DisabledRules/TypeNotFound.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module -Verbose PSScriptAnalyzer
-$violationMessage = "Type Stre is not found"
+﻿$violationMessage = "Type Stre is not found"
 $violationName = "PSTypeNotFound"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\TypeNotFound.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/DisabledRules/UseTypeAtVariableAssignment.tests.ps1 b/Tests/DisabledRules/UseTypeAtVariableAssignment.tests.ps1
index 8f6eec23c..d7476890e 100644
--- a/Tests/DisabledRules/UseTypeAtVariableAssignment.tests.ps1
+++ b/Tests/DisabledRules/UseTypeAtVariableAssignment.tests.ps1
@@ -1,5 +1,4 @@
-﻿Import-Module -Verbose PSScriptAnalyzer
-$violationMessage = [regex]::Escape('Specify type at the assignment of variable $test')
+﻿$violationMessage = [regex]::Escape('Specify type at the assignment of variable $test')
 $violationName = "PSUseTypeAtVariableAssignment"
 $directory = Split-Path -Parent $MyInvocation.MyCommand.Path
 $violations = Invoke-ScriptAnalyzer $directory\UseTypeAtVariableAssignment.ps1 | Where-Object {$_.RuleName -eq $violationName}
diff --git a/Tests/Documentation/RuleDocumentation.tests.ps1 b/Tests/Documentation/RuleDocumentation.tests.ps1
index 6b0d93a51..a62c8506e 100644
--- a/Tests/Documentation/RuleDocumentation.tests.ps1
+++ b/Tests/Documentation/RuleDocumentation.tests.ps1
@@ -1,6 +1,6 @@
 Describe "Validate rule documentation files" {
     BeforeAll {
-        $ruleDocDirectory = Join-Path $PSScriptRoot '../../RuleDocumentation'
+        $ruleDocDirectory = Join-Path $PSScriptRoot '../../docs/Rules'
         $docs = Get-ChildItem $ruleDocDirectory/*.md -Exclude README.md |
             ForEach-Object { "PS" + $_.BaseName} | Sort-Object
 
@@ -15,14 +15,8 @@ Describe "Validate rule documentation files" {
             }} |
             Sort-Object
 
-        # Remove rules from the diff list that aren't supported on PSCore
-        if (($PSVersionTable.PSVersion.Major -ge 6) -and ($PSVersionTable.PSEdition -eq "Core"))
-        {
-            $RulesNotSupportedInNetstandard2 = @("PSUseSingularNouns")
-            $docs = $docs | Where-Object {$RulesNotSupportedInNetstandard2 -notcontains $_}
-            $readmeRules = $readmeRules | Where-Object { $RulesNotSupportedInNetstandard2 -notcontains $_ }
-        }
-        elseif ($PSVersionTable.PSVersion.Major -eq 4) {
+        # Remove rules from the diff list that aren't supported on old PS version
+        if ($PSVersionTable.PSVersion.Major -eq 4) {
             $docs = $docs | Where-Object {$_ -notmatch '^PSAvoidGlobalAliases$'}
             $readmeRules = $readmeRules | Where-Object { $_ -notmatch '^PSAvoidGlobalAliases$' }
         }
diff --git a/Tests/Engine/CorrectionExtent.tests.ps1 b/Tests/Engine/CorrectionExtent.tests.ps1
index 3959088d5..9269df613 100644
--- a/Tests/Engine/CorrectionExtent.tests.ps1
+++ b/Tests/Engine/CorrectionExtent.tests.ps1
@@ -1,8 +1,10 @@
-Describe "Correction Extent" {
-    $type = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent]
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
+Describe "Correction Extent" {
     Context "Object construction" {
         It "creates the object with correct properties" {
+            $type = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.CorrectionExtent]
             $correctionExtent = $obj = New-Object -TypeName $type -ArgumentList 1, 1, 1, 3, "get-childitem", "newfile", "cool description"
 
             $correctionExtent.StartLineNumber | Should -Be 1
diff --git a/Tests/Engine/CustomRuleNREAssets/CLMTest.ps1 b/Tests/Engine/CustomRuleNREAssets/CLMTest.ps1
new file mode 100644
index 000000000..ed3c800c1
--- /dev/null
+++ b/Tests/Engine/CustomRuleNREAssets/CLMTest.ps1
@@ -0,0 +1,7 @@
+write-host "test"
+$a = "asdf"
+$a = $a.replace('s','ssssssss')
+[math]::abs(-1)
+Function ASDF1234{
+    "asdf"
+}
diff --git a/Tests/Engine/CustomRuleNREAssets/MyCustom.psm1 b/Tests/Engine/CustomRuleNREAssets/MyCustom.psm1
new file mode 100644
index 000000000..34368748d
--- /dev/null
+++ b/Tests/Engine/CustomRuleNREAssets/MyCustom.psm1
@@ -0,0 +1,48 @@
+<#
+.SYNOPSIS
+    Static methods are not allowed in constrained language mode.
+.DESCRIPTION
+    Static methods are not allowed in constrained language mode.
+    To fix a violation of this rule, use a cmdlet or function instead of a static method.
+.EXAMPLE
+    Test-StaticMethod -CommandAst $CommandAst
+.INPUTS
+    [System.Management.Automation.Language.ScriptBlockAst]
+.OUTPUTS
+    [PSCustomObject[]]
+.NOTES
+    Reference: Output, CLM info.
+#>
+function Test-StaticMethod
+{
+    [CmdletBinding()]
+    [OutputType([PSCustomObject[]])]
+    Param
+    (
+        [Parameter(Mandatory = $true)]
+        [ValidateNotNullOrEmpty()]
+        [System.Management.Automation.Language.ScriptBlockAst]
+        $ScriptBlockAst
+    )
+
+    Process
+    {
+        try
+        {
+            # Gets methods
+
+            $invokedMethods = $ScriptBlockAst.FindAll({$args[0] -is [System.Management.Automation.Language.CommandExpressionAst] -and $args[0].Expression -match "^\[.*\]::" },$true)
+            foreach ($invokedMethod in $invokedMethods)
+            {
+                [PSCustomObject]@{Message  = "Avoid Using Static Methods";
+                                  Extent   = $invokedMethod.Extent;
+                                  RuleName = $PSCmdlet.MyInvocation.InvocationName;
+                                  Severity = "Warning"}
+            }
+        }
+        catch
+        {
+            $PSCmdlet.ThrowTerminatingError($PSItem)
+        }
+    }
+}
diff --git a/Tests/Engine/CustomizedRule.tests.ps1 b/Tests/Engine/CustomizedRule.tests.ps1
index b08d2dec2..ba0686d75 100644
--- a/Tests/Engine/CustomizedRule.tests.ps1
+++ b/Tests/Engine/CustomizedRule.tests.ps1
@@ -1,23 +1,27 @@
-﻿if (-not $IsCoreCLR)
-{
-	# Force Get-Help not to prompt for interactive input to download help using Update-Help
-	# By adding this registry key we turn off Get-Help interactivity logic during ScriptRule parsing
-	$null,"Wow6432Node" | ForEach-Object {
-		try
-		{
-			Set-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -Value 1 -Force -ErrorAction SilentlyContinue
-		}
-		catch
-		{
-			# Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+	if (-not $IsCoreCLR)
+	{
+		# Force Get-Help not to prompt for interactive input to download help using Update-Help
+		# By adding this registry key we turn off Get-Help interactivity logic during ScriptRule parsing
+		$null,"Wow6432Node" | ForEach-Object {
+			try
+			{
+				Set-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -Value 1 -Force -ErrorAction SilentlyContinue
+			}
+			catch
+			{
+				# Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
+			}
 		}
 	}
+	$message = "this is help"
+	$measure = "Measure-RequiresRunAsAdministrator"
 }
 
 
-$message = "this is help"
-$measure = "Measure-RequiresRunAsAdministrator"
-
 Describe "Test importing customized rules with null return results" {
     Context "Test Get-ScriptAnalyzer with customized rules" {
         It "will not terminate the engine" {
@@ -38,40 +42,38 @@ Describe "Test importing customized rules with null return results" {
 
 Describe "Test importing correct customized rules" {
 
-	if(-not $IsCoreCLR)
-	{
-		Context "Test Get-Help functionality in ScriptRule parsing logic" {
-			It "ScriptRule help section must be correctly processed when Get-Help is called for the first time" {
-
-				# Force Get-Help to prompt for interactive input to download help using Update-Help
-				# By removing this registry key we force to turn on Get-Help interactivity logic during ScriptRule parsing
-				$null,"Wow6432Node" | ForEach-Object {
-					try
-					{
-						Remove-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -ErrorAction Stop
-					} catch {
-						#Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
-					}
+	Context "Test Get-Help functionality in ScriptRule parsing logic" -Skip:$IsCoreCLR {
+		It "ScriptRule help section must be correctly processed when Get-Help is called for the first time" {
+
+			# Force Get-Help to prompt for interactive input to download help using Update-Help
+			# By removing this registry key we force to turn on Get-Help interactivity logic during ScriptRule parsing
+			$null,"Wow6432Node" | ForEach-Object {
+				try
+				{
+					Remove-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -ErrorAction Stop
+				} catch {
+					#Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
 				}
+			}
 
-				$customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\samplerule\samplerule.psm1 | Where-Object {$_.Message -eq $message}
-				$customizedRulePath.Count | Should -Be 1
+			$customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\samplerule\samplerule.psm1 | Where-Object {$_.Message -eq $message}
+			$customizedRulePath.Count | Should -Be 1
 
-				# Force Get-Help not to prompt for interactive input to download help using Update-Help
-				# By adding this registry key we turn off Get-Help interactivity logic during ScriptRule parsing
-				$null,"Wow6432Node" | ForEach-Object {
-					try
-					{
-						Set-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -Value 1 -Force -EA SilentlyContinue
-					}
-					catch
-					{
-						# Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
-					}
+			# Force Get-Help not to prompt for interactive input to download help using Update-Help
+			# By adding this registry key we turn off Get-Help interactivity logic during ScriptRule parsing
+			$null,"Wow6432Node" | ForEach-Object {
+				try
+				{
+					Set-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -Value 1 -Force -EA SilentlyContinue
+				}
+				catch
+				{
+					# Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
 				}
 			}
 		}
 	}
+	# }
 
     Context "Test Get-ScriptAnalyzer with customized rules" {
         It "will show the custom rule" {
@@ -197,8 +199,20 @@ Describe "Test importing correct customized rules" {
             $violations[0].RuleSuppressionID   | Should -Be "MyRuleSuppressionID"
         }
 
-        if (!$testingLibraryUsage)
-		{
+		It "Does not throw an exception when optional diagnostic properties are not present" {
+			$violations = Invoke-ScriptAnalyzer -Path "$PSScriptRoot\CustomRuleNREAssets\CLMTest.ps1" -CustomizedRulePath "$PSScriptRoot\CustomRuleNREAssets\MyCustom.psm1"
+
+			$violations.Count | Should -Be 1
+			$violations[0].RuleName | Should -BeExactly 'MyCustom\Test-StaticMethod'
+			$violations[0].Severity | Should -Be 'Warning'
+			$violations[0].ScriptName | Should -BeExactly 'CLMTest.ps1'
+			$violations[0].Extent.StartLineNumber | Should -Be 4
+			$violations[0].Message | Should -BeExactly 'Avoid Using Static Methods'
+			$violations[0].RuleSuppressionID | Should -BeNullOrEmpty
+			$violations[0].SuggestedCorrections | Should -BeNullOrEmpty
+		}
+
+		Context "Test Invoke-ScriptAnalyzer with customized rules - Advanced test cases" -Skip:$testingLibraryUsage {
             It "will show the custom rule in the results when given a rule folder path with trailing backslash" {
 				# needs fixing for Linux
 				if (!$IsLinux -and !$IsMacOS)
@@ -243,7 +257,7 @@ Describe "Test importing correct customized rules" {
                 $customizedRulePath.Count | Should -Be 1
             }
 
-			It "loads custom rules that contain version in their path" -Skip:($PSVersionTable.PSVersion -lt [Version]'5.0.0') {
+			It "loads custom rules that contain version in their path" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
 				$customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomRulePath $PSScriptRoot\VersionedSampleRule\SampleRuleWithVersion
 				$customizedRulePath.Count | Should -Be 1
 
@@ -251,7 +265,7 @@ Describe "Test importing correct customized rules" {
 				$customizedRulePath.Count | Should -Be 1
 			}
 
-			It "loads custom rules that contain version in their path with the RecurseCustomRule switch" -Skip:($PSVersionTable.PSVersion -lt [Version]'5.0.0') {
+			It "loads custom rules that contain version in their path with the RecurseCustomRule switch" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
 				$customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomRulePath $PSScriptRoot\VersionedSampleRule -RecurseCustomRulePath
 				$customizedRulePath.Count | Should -Be 1
 
diff --git a/Tests/Engine/EditableText.tests.ps1 b/Tests/Engine/EditableText.tests.ps1
index eb0222e94..b973b5cb5 100644
--- a/Tests/Engine/EditableText.tests.ps1
+++ b/Tests/Engine/EditableText.tests.ps1
@@ -1,7 +1,12 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
-$editableTextType = "Microsoft.Windows.PowerShell.ScriptAnalyzer.EditableText"
-$textEditType = "Microsoft.Windows.PowerShell.ScriptAnalyzer.TextEdit"
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+    $editableTextType = "Microsoft.Windows.PowerShell.ScriptAnalyzer.EditableText"
+    $textEditType = "Microsoft.Windows.PowerShell.ScriptAnalyzer.TextEdit"
+}
 
 Describe "EditableText class" {
     Context "When a single edit is given for application" {
diff --git a/Tests/Engine/Extensions.tests.ps1 b/Tests/Engine/Extensions.tests.ps1
index 875c8ce96..11ab79147 100644
--- a/Tests/Engine/Extensions.tests.ps1
+++ b/Tests/Engine/Extensions.tests.ps1
@@ -1,30 +1,36 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
-
-function Get-Extent {
-    param($line, $startLineNum, $startColumnNum, $endLineNum, $endColumnNum)
-    $scriptPositionType = 'System.Management.Automation.Language.ScriptPosition'
-    $scriptExtentType = 'System.Management.Automation.Language.ScriptExtent'
-    $extentStartPos = New-Object -TypeName $scriptPositionType -ArgumentList $null, $startLineNum, $startColumnNum, $line
-    $extentEndPos = New-Object -TypeName $scriptPositionType -ArgumentList $null, $endLineNum, $endColumnNum, $line
-    New-Object -TypeName $scriptExtentType -ArgumentList $extentStartPos, $extentEndPos
-}
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+
+    function Get-Extent {
+        param($line, $startLineNum, $startColumnNum, $endLineNum, $endColumnNum)
+        $scriptPositionType = 'System.Management.Automation.Language.ScriptPosition'
+        $scriptExtentType = 'System.Management.Automation.Language.ScriptExtent'
+        $extentStartPos = New-Object -TypeName $scriptPositionType -ArgumentList $null, $startLineNum, $startColumnNum, $line
+        $extentEndPos = New-Object -TypeName $scriptPositionType -ArgumentList $null, $endLineNum, $endColumnNum, $line
+        New-Object -TypeName $scriptExtentType -ArgumentList $extentStartPos, $extentEndPos
+    }
+
+    function Test-Extent {
+        param(
+            $translatedExtent,
+            $expectedStartLineNumber,
+            $expectedStartColumnNumber,
+            $expectedEndLineNumber,
+            $expectedEndColumnNumber)
+
+        $translatedExtent.StartLineNumber | Should -Be $expectedStartLineNumber
+        $translatedExtent.StartColumnNumber | Should -Be $expectedStartColumnNumber
+        $translatedExtent.EndLineNumber | Should -Be $expectedEndLineNumber
+        $translatedExtent.EndColumnNumber | Should -Be $expectedEndColumnNumber
+    }
 
-function Test-Extent {
-    param(
-        $translatedExtent,
-        $expectedStartLineNumber,
-        $expectedStartColumnNumber,
-        $expectedEndLineNumber,
-        $expectedEndColumnNumber)
-
-    $translatedExtent.StartLineNumber | Should -Be $expectedStartLineNumber
-    $translatedExtent.StartColumnNumber | Should -Be $expectedStartColumnNumber
-    $translatedExtent.EndLineNumber | Should -Be $expectedEndLineNumber
-    $translatedExtent.EndColumnNumber | Should -Be $expectedEndColumnNumber
+    $extNamespace = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Extensions.Extensions]
 }
 
-$extNamespace = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Extensions.Extensions]
 
 Describe "String extension methods" {
     Context "When a text is given to GetLines" {
diff --git a/Tests/Engine/GetScriptAnalyzerRule.tests.ps1 b/Tests/Engine/GetScriptAnalyzerRule.tests.ps1
index 53ffe5e63..8d61c1c7f 100644
--- a/Tests/Engine/GetScriptAnalyzerRule.tests.ps1
+++ b/Tests/Engine/GetScriptAnalyzerRule.tests.ps1
@@ -1,14 +1,20 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
-$sa = Get-Command Get-ScriptAnalyzerRule
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$singularNouns = "PSUseSingularNouns" # this rule does not exist for coreclr version
-$approvedVerbs = "PSUseApprovedVerbs"
-$cmdletAliases = "PSAvoidUsingCmdletAliases"
-$dscIdentical = "PSDSCUseIdenticalParametersForDSC"
+BeforeAll {
+    $sa = Get-Command Get-ScriptAnalyzerRule
+
+    $singularNouns = "PSUseSingularNouns" # this rule does not exist for coreclr version
+    $approvedVerbs = "PSUseApprovedVerbs"
+    $cmdletAliases = "PSAvoidUsingCmdletAliases"
+    $dscIdentical = "PSDSCUseIdenticalParametersForDSC"
+}
 
 Describe "Test available parameters" {
-    $params = $sa.Parameters
+    BeforeAll {
+        $params = $sa.Parameters
+    }
+
     Context "Name parameter" {
         It "has a RuleName parameter" {
             $params.ContainsKey("Name") | Should -BeTrue
@@ -32,7 +38,6 @@ Describe "Test available parameters" {
 			$params.CustomRulePath.Aliases.Contains("CustomizedRulePath") | Should -BeTrue
 		}
     }
-
 }
 
 Describe "Test Name parameters" {
@@ -58,15 +63,12 @@ Describe "Test Name parameters" {
 
         It "get Rules with no parameters supplied" {
             $defaultRules = Get-ScriptAnalyzerRule
-            $expectedNumRules = 64
-            if ((Test-PSEditionCoreClr) -or (Test-PSVersionV3) -or (Test-PSVersionV4))
+            $expectedNumRules = 70
+            if ($PSVersionTable.PSVersion.Major -le 4)
             {
                 # for PSv3 PSAvoidGlobalAliases is not shipped because
                 # it uses StaticParameterBinder.BindCommand which is
                 # available only on PSv4 and above
-                # for PowerShell Core, PSUseSingularNouns is not
-                # shipped because it uses APIs that are not present
-                # in dotnet core.
 
                 $expectedNumRules--
             }
@@ -94,15 +96,16 @@ Describe "Test Name parameters" {
 }
 
 Describe "Test RuleExtension" {
-    $community = "CommunityAnalyzerRules"
-    $measureRequired = "Measure-RequiresModules"
     Context "When used correctly" {
-
-		$expectedNumCommunityRules = 10
-		if ($PSVersionTable.PSVersion -ge [Version]'4.0.0')
-		{
-			$expectedNumCommunityRules = 12
-		}
+        BeforeAll {
+            $community = "CommunityAnalyzerRules"
+            $measureRequired = "Measure-RequiresModules"
+            $expectedNumCommunityRules = 10
+            if ($PSVersionTable.PSVersion -ge [Version]'4.0.0')
+            {
+                $expectedNumCommunityRules = 12
+            }
+        }
         It "with the module folder path" {
             $ruleExtension = Get-ScriptAnalyzerRule -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules | Where-Object {$_.SourceName -eq $community}
             $ruleExtension.Count | Should -Be $expectedNumCommunityRules
@@ -151,17 +154,17 @@ Describe "Test RuleExtension" {
 Describe "TestSeverity" {
     It "filters rules based on the specified rule severity" {
         $rules = Get-ScriptAnalyzerRule -Severity Error
-        $rules.Count | Should -Be 7
+        $rules.Count | Should -Be 8
     }
 
     It "filters rules based on multiple severity inputs"{
         $rules = Get-ScriptAnalyzerRule -Severity Error,Information
-        $rules.Count | Should -Be 17
+        $rules.Count | Should -Be 19
     }
 
         It "takes lower case inputs" {
         $rules = Get-ScriptAnalyzerRule -Severity error
-        $rules.Count | Should -Be 7
+        $rules.Count | Should -Be 8
     }
 }
 
diff --git a/Tests/Engine/GlobalSuppression.test.ps1 b/Tests/Engine/GlobalSuppression.test.ps1
index 76da8fc36..b489f39a5 100644
--- a/Tests/Engine/GlobalSuppression.test.ps1
+++ b/Tests/Engine/GlobalSuppression.test.ps1
@@ -1,15 +1,12 @@
-﻿# Check if PSScriptAnalyzer is already loaded so we don't
-# overwrite a test version of Invoke-ScriptAnalyzer by
-# accident
-if (!(Get-Module PSScriptAnalyzer) -and !$testingLibraryUsage)
-{
-	Import-Module -Verbose PSScriptAnalyzer
-}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$violations = Invoke-ScriptAnalyzer "$PSScriptRoot\GlobalSuppression.ps1"
-$violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\GlobalSuppression.ps1")
-$suppression = Invoke-ScriptAnalyzer "$PSScriptRoot\GlobalSuppression.ps1" -Profile "$PSScriptRoot\Profile.ps1"
-$suppressionUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\GlobalSuppression.ps1") -Profile "$PSScriptRoot\Profile.ps1"
+BeforeAll {
+    $violations = Invoke-ScriptAnalyzer "$PSScriptRoot\GlobalSuppression.ps1"
+    $violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\GlobalSuppression.ps1")
+    $suppression = Invoke-ScriptAnalyzer "$PSScriptRoot\GlobalSuppression.ps1" -Profile "$PSScriptRoot\Profile.ps1"
+    $suppressionUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\GlobalSuppression.ps1") -Profile "$PSScriptRoot\Profile.ps1"
+}
 
 Describe "GlobalSuppression" {
     Context "Exclude Rule" {
diff --git a/Tests/Engine/Helper.tests.ps1 b/Tests/Engine/Helper.tests.ps1
index 90706c8ca..b0932be32 100644
--- a/Tests/Engine/Helper.tests.ps1
+++ b/Tests/Engine/Helper.tests.ps1
@@ -1,15 +1,20 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
 Describe "Test Directed Graph" {
     Context "When a graph is created" {
-        $digraph = New-Object -TypeName 'Microsoft.Windows.PowerShell.ScriptAnalyzer.DiGraph[string]'
-        $digraph.AddVertex('v1');
-        $digraph.AddVertex('v2');
-        $digraph.AddVertex('v3');
-        $digraph.AddVertex('v4');
-        $digraph.AddVertex('v5');
+        BeforeAll {
+            $digraph = New-Object -TypeName 'Microsoft.Windows.PowerShell.ScriptAnalyzer.DiGraph[string]'
+            $digraph.AddVertex('v1');
+            $digraph.AddVertex('v2');
+            $digraph.AddVertex('v3');
+            $digraph.AddVertex('v4');
+            $digraph.AddVertex('v5');
 
-        $digraph.AddEdge('v1', 'v2');
-        $digraph.AddEdge('v1', 'v5');
-        $digraph.AddEdge('v2', 'v4');
+            $digraph.AddEdge('v1', 'v2');
+            $digraph.AddEdge('v1', 'v5');
+            $digraph.AddEdge('v2', 'v4');
+        }
 
         It "correctly adds the vertices" {
             $digraph.NumVertices | Should -Be 5
diff --git a/Tests/Engine/InvokeFormatter.tests.ps1 b/Tests/Engine/InvokeFormatter.tests.ps1
index 39f248865..dcc0a6174 100644
--- a/Tests/Engine/InvokeFormatter.tests.ps1
+++ b/Tests/Engine/InvokeFormatter.tests.ps1
@@ -1,5 +1,10 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+}
 
 Describe "Invoke-Formatter Cmdlet" {
     Context "Cmdlet cleans up and has no knock on effect" {
@@ -9,6 +14,19 @@ Describe "Invoke-Formatter Cmdlet" {
         }
     }
 
+    Context 'Accept Value from Pipeline' {
+        It 'Value from Pipeline' {
+            'foo' | Invoke-Formatter | Should -Be 'foo'
+        }
+        It 'Value from Pipeline by Property Name with just the mandatory ScriptDefinition parameter' {
+            [pscustomobject]@{ 'ScriptDefinition' = 'foo' } | Invoke-Formatter | Should -Be 'foo'
+        }
+        It 'Value from Pipeline by Property Name with all parameters' {
+            [pscustomobject]@{ ScriptDefinition = 'foo'; Settings = @(); Range = 1, 1, 1, 4 } |
+                Invoke-Formatter | Should -Be 'foo'
+        }
+    }
+
     Context "When positional parameters are given" {
         It "Should use the positional parameters" {
             $def = @"
diff --git a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1 b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1
index 39e98666c..b930c9980 100644
--- a/Tests/Engine/InvokeScriptAnalyzer.tests.ps1
+++ b/Tests/Engine/InvokeScriptAnalyzer.tests.ps1
@@ -1,12 +1,22 @@
-﻿$sa = Get-Command Invoke-ScriptAnalyzer
-$singularNouns = "PSUseSingularNouns"
-$approvedVerb = "PSUseApprovedVerbs"
-$rules = Get-ScriptAnalyzerRule -Name ($singularNouns, "PSUseApprovedVerbs")
-$avoidRules = Get-ScriptAnalyzerRule -Name "PSAvoid*"
-$useRules = "PSUse*"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    # NOTE: We also run these tests with a custom Invoke-ScriptAnalyzer function defined in LibraryUsage.Tests.ps1
+    #       This can cause issues if the cmdlet is updated and the function isn't
+    $sa = Get-Command Invoke-ScriptAnalyzer
+    $singularNouns = "PSUseSingularNouns"
+    $approvedVerb = "PSUseApprovedVerbs"
+    $rules = Get-ScriptAnalyzerRule -Name ($singularNouns, "PSUseApprovedVerbs")
+    $avoidRules = Get-ScriptAnalyzerRule -Name "PSAvoid*"
+    $useRules = "PSUse*"
+}
 
 Describe "Test available parameters" {
-    $params = $sa.Parameters
+    BeforeAll {
+        $params = $sa.Parameters
+    }
+
     Context "Path parameter" {
         It "has a Path parameter" {
             $params.ContainsKey("Path") | Should -BeTrue
@@ -33,12 +43,12 @@ Describe "Test available parameters" {
         }
 
         It "accepts a string array" {
-				$params["CustomRulePath"].ParameterType.FullName | Should -Be "System.String[]"
+            $params["CustomRulePath"].ParameterType.FullName | Should -Be "System.String[]"
         }
 
-		It "has a CustomizedRulePath alias"{
-			$params.CustomRulePath.Aliases.Contains("CustomizedRulePath") | Should -BeTrue
-		}
+        It "has a CustomizedRulePath alias" {
+            $params.CustomRulePath.Aliases.Contains("CustomizedRulePath") | Should -BeTrue
+        }
     }
 
     Context "IncludeRule parameters" {
@@ -61,52 +71,29 @@ Describe "Test available parameters" {
         }
     }
 
-    if (!$testingLibraryUsage -and ($PSVersionTable.PSVersion -ge [Version]'5.0.0'))
-    {
-        Context "SaveDscDependency parameter" {
-            It "has the parameter" {
-                $params.ContainsKey("SaveDscDependency") | Should -BeTrue
-            }
-
-            It "is a switch parameter" {
-                $params["SaveDscDependency"].ParameterType.FullName | Should -Be "System.Management.Automation.SwitchParameter"
-            }
-
-            It 'does not throw when being applied against a dummy script with no DSC code' {
-                Invoke-ScriptAnalyzer -ScriptDefinition 'foo' -SaveDscDependency
-            }
+    Context "SaveDscDependency parameter" -Skip:($testingLibraryUsage -or ($PSVersionTable.PSVersion -lt '5.0')) {
+        It "has the parameter" {
+            $params.ContainsKey("SaveDscDependency") | Should -BeTrue
         }
-    }
 
-    Context "It has 2 parameter sets: File and ScriptDefinition" {
-        It "Has 2 parameter sets" {
-            $sa.ParameterSets.Count | Should -Be 2
+        It "is a switch parameter" {
+            $params["SaveDscDependency"].ParameterType.FullName | Should -Be "System.Management.Automation.SwitchParameter"
         }
 
-        It "Has File parameter set" {
-            $hasFile = $false
-            foreach ($paramSet in $sa.ParameterSets) {
-                if ($paramSet.Name -eq "File") {
-                    $hasFile = $true
-                    break
-                }
-            }
-
-            $hasFile | Should -BeTrue
+        It 'does not throw when being applied against a dummy script with no DSC code' {
+            Invoke-ScriptAnalyzer -ScriptDefinition 'foo' -SaveDscDependency
         }
+    }
 
-        It "Has ScriptDefinition parameter set" {
-            $hasFile = $false
-            foreach ($paramSet in $sa.ParameterSets) {
-                if ($paramSet.Name -eq "ScriptDefinition") {
-                    $hasFile = $true
-                    break
-                }
-            }
-
-            $hasFile | Should -BeTrue
-        }
+    It "Has 4 parameter sets" {
+        $parameterSets = @(
+            'Path_IncludeSuppressed'
+            'Path_SuppressedOnly'
+            'ScriptDefinition_IncludeSuppressed'
+            'ScriptDefinition_SuppressedOnly'
+        )
 
+        $sa.ParameterSets | Select-Object -ExpandProperty Name | Sort-Object | Should -Be $parameterSets
     }
 }
 
@@ -134,92 +121,93 @@ Describe "Test Path" {
     Context "When there are more than 10 errors in a file" {
         It "All errors are found in a file" {
             # this is a script with 12 parse errors
-            1..12 | Foreach-Object { ');' } | Out-File -Encoding ASCII "${TestDrive}\badfile.ps1"
+            1..12 | ForEach-Object { ');' } | Out-File -Encoding ASCII "${TestDrive}\badfile.ps1"
             $moreThanTenErrors = Invoke-ScriptAnalyzer -Path "${TestDrive}\badfile.ps1"
             @($moreThanTenErrors).Count | Should -Be 12
         }
     }
 
     Context "DiagnosticRecord  " {
-	It "has valid ScriptPath and ScriptName properties when an input file is given" {
-	   $scriptName = "TestScript.ps1"
-	   $scriptPath = Join-Path $PSScriptRoot $scriptName
-	   $expectedScriptPath = Resolve-Path $PSScriptRoot\TestScript.ps1
-	   $diagnosticRecords = Invoke-ScriptAnalyzer $scriptPath -IncludeRule "PSAvoidUsingEmptyCatchBlock"
-	   $diagnosticRecords[0].ScriptPath | Should -Be $expectedScriptPath.Path
-	   $diagnosticRecords[0].ScriptName | Should -Be $scriptName
-	}
-
-	It "has empty ScriptPath and ScriptName properties when a script definition is given" {
-	   $diagnosticRecords = Invoke-ScriptAnalyzer -ScriptDefinition gci -IncludeRule "PSAvoidUsingCmdletAliases"
-	   $diagnosticRecords[0].ScriptPath | Should -Be ([System.String]::Empty)
-	   $diagnosticRecords[0].ScriptName | Should -Be ([System.String]::Empty)
-	}
-    }
-
-	if (!$testingLibraryUsage)
-	{
-		#There is probably a more concise way to do this but for now we will settle for this!
-		Function GetFreeDrive ($freeDriveLen) {
-			$ordA = 65
-			$ordZ = 90
-			$freeDrive = ""
-			$freeDriveName = ""
-			do{
-				$freeDriveName = (1..$freeDriveLen | %{[char](Get-Random -Maximum $ordZ -Minimum $ordA)}) -join ''
-				$freeDrive = $freeDriveName + ":"
-			}while(Test-Path $freeDrive)
-			$freeDrive, $freeDriveName
-		}
-
-		Context "When given a glob" {
-    		It "Invokes on all the matching files" {
-			$numFilesResult = (Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestTestPath*.ps1 | Select-Object -Property ScriptName -Unique).Count
-			$numFilesExpected = (Get-ChildItem -Path $PSScriptRoot\TestTestPath*.ps1).Count
-			$numFilesResult | Should -Be $numFilesExpected
-			}
-		}
-
-		Context "When given a FileSystem PSDrive" {
-    		It "Recognizes the path" {
-			$freeDriveNameLen = 2
-			$freeDrive, $freeDriveName = GetFreeDrive $freeDriveNameLen
-			New-PSDrive -Name $freeDriveName -PSProvider FileSystem -Root $PSScriptRoot
-			$numFilesExpected = (Get-ChildItem -Path $freeDrive\TestTestPath*.ps1).Count
-			$numFilesResult = (Invoke-ScriptAnalyzer -Path $freeDrive\TestTestPath*.ps1 | Select-Object -Property ScriptName -Unique).Count
-			Remove-PSDrive $freeDriveName
-			$numFilesResult | Should -Be $numFilesExpected
-			}
-        }
-
-        Context "When piping in files" {
-            It "Can be piped in from a string" {
-                $piped = ("$PSScriptRoot\TestScript.ps1" | Invoke-ScriptAnalyzer)
-                $explicit = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1
-
-                $piped.Count | Should Be $explicit.Count
-            }
+        It "has valid ScriptPath and ScriptName properties when an input file is given" {
+            $scriptName = "TestScript.ps1"
+            $scriptPath = Join-Path $PSScriptRoot $scriptName
+            $expectedScriptPath = Resolve-Path $PSScriptRoot\TestScript.ps1
+            $diagnosticRecords = Invoke-ScriptAnalyzer $scriptPath -IncludeRule "PSAvoidUsingEmptyCatchBlock"
+            $diagnosticRecords[0].ScriptPath | Should -Be $expectedScriptPath.Path
+            $diagnosticRecords[0].ScriptName | Should -Be $scriptName
+        }
+
+        It "has empty ScriptPath and ScriptName properties when a script definition is given" {
+            $diagnosticRecords = Invoke-ScriptAnalyzer -ScriptDefinition gci -IncludeRule "PSAvoidUsingCmdletAliases"
+            $diagnosticRecords[0].ScriptPath | Should -Be ([System.String]::Empty)
+            $diagnosticRecords[0].ScriptName | Should -Be ([System.String]::Empty)
+        }
+    }
+
+    Context "When given a glob" -Skip:$testingLibraryUsage {
+        It "Invokes on all the matching files" {
+            $numFilesResult = (Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestTestPath*.ps1 | Select-Object -Property ScriptName -Unique).Count
+            $numFilesExpected = (Get-ChildItem -Path $PSScriptRoot\TestTestPath*.ps1).Count
+            $numFilesResult | Should -Be $numFilesExpected
+        }
+    }
 
-            It "Can be piped from Get-ChildItem" {
-                $piped = ( Get-ChildItem -Path $PSScriptRoot -Filter TestTestPath*.ps1 | Invoke-ScriptAnalyzer)
-                $explicit = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestTestPath*.ps1
-                $piped.Count | Should Be $explicit.Count
+    Context "When given a FileSystem PSDrive" -Skip:$testingLibraryUsage {
+        BeforeAll {
+            #There is probably a more concise way to do this but for now we will settle for this!
+            Function GetFreeDrive ($freeDriveLen) {
+                $ordA = 65
+                $ordZ = 90
+                $freeDrive = ""
+                $freeDriveName = ""
+                do{
+                    $freeDriveName = (1..$freeDriveLen | %{[char](Get-Random -Maximum $ordZ -Minimum $ordA)}) -join ''
+                    $freeDrive = $freeDriveName + ":"
+                }while (Test-Path $freeDrive)
+                $freeDrive, $freeDriveName
             }
         }
-	}
+
+        It "Recognizes the path" {
+            $freeDriveNameLen = 2
+            $freeDrive, $freeDriveName = GetFreeDrive $freeDriveNameLen
+            New-PSDrive -Name $freeDriveName -PSProvider FileSystem -Root $PSScriptRoot
+            $numFilesExpected = (Get-ChildItem -Path $freeDrive\TestTestPath*.ps1).Count
+            $numFilesResult = (Invoke-ScriptAnalyzer -Path $freeDrive\TestTestPath*.ps1 | Select-Object -Property ScriptName -Unique).Count
+            Remove-PSDrive $freeDriveName
+            $numFilesResult | Should -Be $numFilesExpected
+        }
+    }
+
+    Context "When piping in files" -Skip:$testingLibraryUsage {
+        It "Can be piped in from a string" {
+            $piped = ("$PSScriptRoot\TestScript.ps1" | Invoke-ScriptAnalyzer)
+            $explicit = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1
+
+            $piped.Count | Should -Be $explicit.Count
+        }
+
+        It "Can be piped from Get-ChildItem" {
+            $piped = ( Get-ChildItem -Path $PSScriptRoot -Filter TestTestPath*.ps1 | Invoke-ScriptAnalyzer)
+            $explicit = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestTestPath*.ps1
+            $piped.Count | Should -Be $explicit.Count
+        }
+    }
 
     Context "When given a directory" {
-        $withoutPathWithDirectory = Invoke-ScriptAnalyzer -Recurse $PSScriptRoot\RecursionDirectoryTest
-        $withPathWithDirectory = Invoke-ScriptAnalyzer -Recurse -Path $PSScriptRoot\RecursionDirectoryTest
+        BeforeAll {
+            $withoutPathWithDirectory = Invoke-ScriptAnalyzer -Recurse $PSScriptRoot\RecursionDirectoryTest
+            $withPathWithDirectory = Invoke-ScriptAnalyzer -Recurse -Path $PSScriptRoot\RecursionDirectoryTest
+        }
 
-        It "Has the same count as without Path parameter"{
-            $withoutPathWithDirectory.Count -eq $withPathWithDirectory.Count | Should -BeTrue
+        It "Has the same count as without Path parameter" {
+            $withoutPathWithDirectory.Count | Should -Be $withPathWithDirectory.Count
         }
 
         It "Analyzes all the files" {
-            $globalVarsViolation = $withPathWithDirectory | Where-Object {$_.RuleName -eq "PSAvoidGlobalVars"}
-            $clearHostViolation = $withPathWithDirectory | Where-Object {$_.RuleName -eq "PSAvoidUsingClearHost"}
-            $writeHostViolation = $withPathWithDirectory | Where-Object {$_.RuleName -eq "PSAvoidUsingWriteHost"}
+            $globalVarsViolation = $withPathWithDirectory | Where-Object { $_.RuleName -eq "PSAvoidGlobalVars" }
+            $clearHostViolation = $withPathWithDirectory | Where-Object { $_.RuleName -eq "PSAvoidUsingClearHost" }
+            $writeHostViolation = $withPathWithDirectory | Where-Object { $_.RuleName -eq "PSAvoidUsingWriteHost" }
             Write-Output $globalVarsViolation.Count
             Write-Output $clearHostViolation.Count
             Write-Output $writeHostViolation.Count
@@ -231,12 +219,12 @@ Describe "Test Path" {
 Describe "Test ExcludeRule" {
     Context "When used correctly" {
         It "excludes 1 rule" {
-            $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -ExcludeRule $singularNouns | Where-Object {$_.RuleName -eq $singularNouns}
+            $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -ExcludeRule $singularNouns | Where-Object { $_.RuleName -eq $singularNouns }
             $noViolations.Count | Should -Be 0
         }
 
         It "excludes 3 rules" {
-            $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -ExcludeRule $rules | Where-Object {$rules -contains $_.RuleName}
+            $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -ExcludeRule $rules | Where-Object { $rules -contains $_.RuleName }
             $noViolations.Count | Should -Be 0
         }
     }
@@ -250,27 +238,21 @@ Describe "Test ExcludeRule" {
     }
 
     Context "Support wild card" {
-        It "supports wild card exclusions of input rules"{
-            $excludeWildCard = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -ExcludeRule $avoidRules | Where-Object {$_.RuleName -match $avoidRules}
+        It "supports wild card exclusions of input rules" {
+            $excludeWildCard = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -ExcludeRule $avoidRules | Where-Object { $_.RuleName -match $avoidRules }
         }
     }
-
 }
 
 Describe "Test IncludeRule" {
     Context "When used correctly" {
         It "includes 1 rule" {
-            $violations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -IncludeRule $approvedVerb | Where-Object {$_.RuleName -eq $approvedVerb}
+            $violations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -IncludeRule $approvedVerb | Where-Object { $_.RuleName -eq $approvedVerb }
             $violations.Count | Should -Be 1
         }
 
         It "includes the given rules" {
-            # CoreCLR version of PSScriptAnalyzer does not contain PSUseSingularNouns rule
             $expectedNumViolations = 2
-            if ($IsCoreCLR)
-            {
-                $expectedNumViolations = 1
-            }
             $violations = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -IncludeRule $rules
             $violations.Count | Should -Be $expectedNumViolations
         }
@@ -284,18 +266,13 @@ Describe "Test IncludeRule" {
     }
 
     Context "IncludeRule supports wild card" {
-        It "includes 1 wildcard rule"{
+        It "includes 1 wildcard rule" {
             $includeWildcard = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -IncludeRule $avoidRules
             $includeWildcard.Count | Should -Be 0
         }
 
-        it "includes 2 wildcardrules" {
-            # CoreCLR version of PSScriptAnalyzer does not contain PSUseSingularNouns rule
+        It "includes 2 wildcardrules" {
             $expectedNumViolations = 4
-            if ($IsCoreCLR)
-            {
-                $expectedNumViolations = 3
-            }
             $includeWildcard = Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -IncludeRule $avoidRules
             $includeWildcard += Invoke-ScriptAnalyzer $PSScriptRoot\..\Rules\BadCmdlet.ps1 -IncludeRule $useRules
             $includeWildcard.Count | Should -Be $expectedNumViolations
@@ -303,7 +280,7 @@ Describe "Test IncludeRule" {
     }
 }
 
-Describe "Test Exclude And Include" {1
+Describe "Test Exclude And Include" {
     It "Exclude and Include different rules" {
         $violations = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -IncludeRule "PSAvoidUsingEmptyCatchBlock" -ExcludeRule "PSAvoidUsingPositionalParameters"
         $violations.Count | Should -Be 1
@@ -318,28 +295,32 @@ Describe "Test Exclude And Include" {1
 Describe "Test Severity" {
     Context "Each severity can be chosen in any combination" {
         BeforeAll {
-            $Severities = "ParseError","Error","Warning","Information"
+            $Severities = "ParseError", "Error", "Warning", "Information"
             # end space is important
             $script = '$a=;ConvertTo-SecureString -Force -AsPlainText "bad practice" '
-            $testcases = @{ Severity = "ParseError" }, @{ Severity = "Error" },
-                @{ Severity = "Warning" }, @{ Severity = "Information" },
-                @{ Severity = "ParseError", "Error" }, @{ Severity = "ParseError","Information" },
-                @{ Severity = "Information", "Warning", "Error" }
-        }
-
-        It "Can retrieve specific severity <severity>" -testcase $testcases {
-            param ( $severity )
-            $result = Invoke-ScriptAnalyzer -ScriptDefinition $script -Severity $severity
-            if ( $severity -is [array] ) {
-                @($result).Count | Should -Be @($severity).Count
-                foreach ( $sev in $severity ) {
+        }
+
+        It "Can retrieve specific severity <Severity>" {
+            param ( $Severity )
+            $result = Invoke-ScriptAnalyzer -ScriptDefinition $script -Severity $Severity
+            if ( $Severity -is [array] ) {
+                @($result).Count | Should -Be @($Severity).Count
+                foreach ( $sev in $Severity ) {
                     $result.Severity | Should -Contain $sev
                 }
             }
             else {
                 $result.Severity | Should -Be $severity
             }
-        }
+        } -TestCases @(
+            @{ Severity = 'ParseError' }
+            @{ Severity = 'Error' }
+            @{ Severity = 'Warning' }
+            @{ Severity = 'Information' }
+            @{ Severity = 'ParseError', 'Error' }
+            @{ Severity = 'ParseError', 'Information' }
+            @{ Severity = 'Information', 'Warning', 'Error' }
+        )
     }
 
     Context "When used correctly" {
@@ -353,30 +334,30 @@ Describe "Test Severity" {
             $errors.Count | Should -Be 1
         }
 
-        It "works with lowercase argument"{
-             $errors = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -Severity information, warning
+        It "works with lowercase argument" {
+            $errors = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -Severity information, warning
             $errors.Count | Should -Be 1
         }
 
         It "works for dsc rules" {
             $testDataPath = [System.IO.Path]::Combine($(Split-Path $PSScriptRoot -Parent), `
-                                                                'Rules', `
-                                                                'DSCResourceModule', `
-                                                                'DSCResources', `
-                                                                'MSFT_WaitForAll', `
-                                                                'MSFT_WaitForAll.psm1')
+                    'Rules', `
+                    'DSCResourceModule', `
+                    'DSCResources', `
+                    'MSFT_WaitForAll', `
+                    'MSFT_WaitForAll.psm1')
 
-            Function Get-Count {begin{$count=0} process{$count++} end{$count}}
+            Function Get-Count { begin { $count = 0 } process { $count++ } end { $count } }
 
             Invoke-ScriptAnalyzer -Path $testDataPath -Severity Error | `
-                Where-Object {$_.RuleName -eq "PSDSCUseVerboseMessageInDSCResource"} | `
-                Get-Count | `
-                Should -Be 0
+                    Where-Object { $_.RuleName -eq "PSDSCUseVerboseMessageInDSCResource" } | `
+                    Get-Count | `
+                    Should -Be 0
 
             Invoke-ScriptAnalyzer -Path $testDataPath -Severity Information | `
-                Where-Object {$_.RuleName -eq "PSDSCUseVerboseMessageInDSCResource"} | `
-                Get-Count | `
-                Should -Be 2
+                    Where-Object { $_.RuleName -eq "PSDSCUseVerboseMessageInDSCResource" } | `
+                    Get-Count | `
+                    Should -Be 2
         }
     }
 
@@ -388,21 +369,24 @@ Describe "Test Severity" {
 }
 
 Describe "Test CustomizedRulePath" {
-    $measureRequired = "CommunityAnalyzerRules\Measure-RequiresModules"
+    BeforeAll {
+        $measureRequired = "CommunityAnalyzerRules\Measure-RequiresModules"
+    }
+
     Context "When used correctly" {
         It "with the module folder path" {
-            $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules | Where-Object {$_.RuleName -eq $measureRequired}
+            $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules | Where-Object { $_.RuleName -eq $measureRequired }
             $customizedRulePath.Count | Should -Be 1
         }
 
         It "with the psd1 path" {
-            $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules\CommunityAnalyzerRules.psd1 | Where-Object {$_.RuleName -eq $measureRequired}
+            $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules\CommunityAnalyzerRules.psd1 | Where-Object { $_.RuleName -eq $measureRequired }
             $customizedRulePath.Count | Should -Be 1
 
         }
 
         It "with the psm1 path" {
-            $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules\CommunityAnalyzerRules.psm1 | Where-Object {$_.RuleName -eq $measureRequired}
+            $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules\CommunityAnalyzerRules.psm1 | Where-Object { $_.RuleName -eq $measureRequired }
             $customizedRulePath.Count | Should -Be 1
         }
 
@@ -412,109 +396,106 @@ Describe "Test CustomizedRulePath" {
         }
 
         It "with ExcludeRule" {
-            $customizedRulePathExclude = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules\CommunityAnalyzerRules.psm1 -ExcludeRule "Measure-RequiresModules" | Where-Object {$_.RuleName -eq $measureRequired}
+            $customizedRulePathExclude = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomizedRulePath $PSScriptRoot\CommunityAnalyzerRules\CommunityAnalyzerRules.psm1 -ExcludeRule "Measure-RequiresModules" | Where-Object { $_.RuleName -eq $measureRequired }
             $customizedRulePathExclude.Count | Should -Be 0
         }
 
-		It "When supplied with a collection of paths" {
+        It "When supplied with a collection of paths" {
             $customizedRulePath = Invoke-ScriptAnalyzer $PSScriptRoot\TestScript.ps1 -CustomRulePath ("$PSScriptRoot\CommunityAnalyzerRules", "$PSScriptRoot\samplerule", "$PSScriptRoot\samplerule\samplerule2")
             $customizedRulePath.Count | Should -Be 3
         }
     }
 
-    if (!$testingLibraryUsage)
-    {
-        Context "When used from settings file" {
-            It "Should process relative settings path" {
-                try {
-                    Push-Location $PSScriptRoot
-                    $warnings = Invoke-ScriptAnalyzer -ScriptDefinition 'gci' -Settings .\SettingsTest\..\SettingsTest\Project1\PSScriptAnalyzerSettings.psd1
-                    $warnings.Count | Should -Be 1
-                }
-                finally {
-                    Pop-Location
-                }
+    Context "When used from settings file" -Skip:$testingLibraryUsage {
+        It "Should process relative settings path" {
+            try {
+                Push-Location $PSScriptRoot
+                $warnings = Invoke-ScriptAnalyzer -ScriptDefinition 'gci' -Settings .\SettingsTest\..\SettingsTest\Project1\PSScriptAnalyzerSettings.psd1
+                $warnings.Count | Should -Be 1
             }
-
-            It "Should process relative settings path even when settings path object is not resolved to a string yet" {
-                try {
-                    Push-Location $PSScriptRoot
-                    $warnings = Invoke-ScriptAnalyzer -ScriptDefinition 'gci' -Settings (Join-Path (Get-Location).Path '.\SettingsTest\..\SettingsTest\Project1\PSScriptAnalyzerSettings.psd1')
-                    $warnings.Count | Should -Be 1
-                }
-                finally {
-                    Pop-Location
-                }
+            finally {
+                Pop-Location
             }
+        }
 
-            It "resolves rule preset when passed in via pipeline" {
-                $warnings = 'CodeFormattingStroustrup' | ForEach-Object {
-                    Invoke-ScriptAnalyzer -ScriptDefinition 'if ($true){ }' -Settings $_}
+        It "Should process relative settings path even when settings path object is not resolved to a string yet" {
+            try {
+                Push-Location $PSScriptRoot
+                $warnings = Invoke-ScriptAnalyzer -ScriptDefinition 'gci' -Settings (Join-Path (Get-Location).Path '.\SettingsTest\..\SettingsTest\Project1\PSScriptAnalyzerSettings.psd1')
                 $warnings.Count | Should -Be 1
-                $warnings.RuleName | Should -Be 'PSUseConsistentWhitespace'
             }
+            finally {
+                Pop-Location
+            }
+        }
 
-            It "Should use the CustomRulePath parameter" {
-                $settings = @{
-                    CustomRulePath        = "$PSScriptRoot\CommunityAnalyzerRules"
-                    IncludeDefaultRules   = $false
-                    RecurseCustomRulePath = $false
-                }
+        It "resolves rule preset when passed in via pipeline" {
+            $warnings = 'CodeFormattingStroustrup' | ForEach-Object {
+                Invoke-ScriptAnalyzer -ScriptDefinition 'if ($true){ }' -Settings $_ }
+            $warnings.Count | Should -Be 1
+            $warnings.RuleName | Should -Be 'PSUseConsistentWhitespace'
+        }
 
-                $v = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1 -Settings $settings
-                $v.Count | Should -Be 1
+        It "Should use the CustomRulePath parameter" {
+            $settings = @{
+                CustomRulePath        = "$PSScriptRoot\CommunityAnalyzerRules"
+                IncludeDefaultRules   = $false
+                RecurseCustomRulePath = $false
             }
 
-            It "Should use the IncludeDefaultRulePath parameter" {
-                $settings = @{
-                    CustomRulePath        = "$PSScriptRoot\CommunityAnalyzerRules"
-                    IncludeDefaultRules   = $true
-                    RecurseCustomRulePath = $false
-                }
+            $v = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1 -Settings $settings
+            $v.Count | Should -Be 1
+        }
 
-                $v = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1 -Settings $settings
-                $v.Count | Should -Be 2
+        It "Should use the IncludeDefaultRulePath parameter" {
+            $settings = @{
+                CustomRulePath        = "$PSScriptRoot\CommunityAnalyzerRules"
+                IncludeDefaultRules   = $true
+                RecurseCustomRulePath = $false
             }
 
-            It "Should use the RecurseCustomRulePath parameter" {
-                $settings = @{
-                    CustomRulePath        = "$PSScriptRoot\samplerule"
-                    IncludeDefaultRules   = $false
-                    RecurseCustomRulePath = $true
-                }
+            $v = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1 -Settings $settings
+            $v.Count | Should -Be 2
+        }
 
-                $v = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1 -Settings $settings
-                $v.Count | Should -Be 3
+        It "Should use the RecurseCustomRulePath parameter" {
+            $settings = @{
+                CustomRulePath        = "$PSScriptRoot\samplerule"
+                IncludeDefaultRules   = $false
+                RecurseCustomRulePath = $true
             }
+
+            $v = Invoke-ScriptAnalyzer -Path $PSScriptRoot\TestScript.ps1 -Settings $settings
+            $v.Count | Should -Be 3
         }
+    }
 
-        Context "When used from settings file and command line simulataneusly" {
-            BeforeAll {
-                $settings = @{
-                    CustomRulePath        = "$PSScriptRoot\samplerule"
-                    IncludeDefaultRules   = $false
-                    RecurseCustomRulePath = $false
-                }
-                $isaParams = @{
-                    Path     = "$PSScriptRoot\TestScript.ps1"
-                    Settings = $settings
-                }
+    Context "When used from settings file and command line simulataneusly" -Skip:$testingLibraryUsage {
+        BeforeAll {
+            $settings = @{
+                CustomRulePath        = "$PSScriptRoot\samplerule"
+                IncludeDefaultRules   = $false
+                RecurseCustomRulePath = $false
             }
-
-            It "Should combine CustomRulePaths" {
-                $v = Invoke-ScriptAnalyzer @isaParams -CustomRulePath "$PSScriptRoot\CommunityAnalyzerRules"
-                $v.Count | Should -Be 2
+            $isaParams = @{
+                Path     = "$PSScriptRoot\TestScript.ps1"
+                Settings = $settings
             }
+        }
 
-            It "Should override the settings IncludeDefaultRules parameter" {
-                $v = Invoke-ScriptAnalyzer @isaParams -IncludeDefaultRules
-                $v.Count | Should -Be 2
-            }
+        It "Should combine CustomRulePaths" {
+            $v = Invoke-ScriptAnalyzer @isaParams -CustomRulePath "$PSScriptRoot\CommunityAnalyzerRules"
+            $v.Count | Should -Be 2
+        }
 
-            It "Should override the settings RecurseCustomRulePath parameter" {
-                $v = Invoke-ScriptAnalyzer @isaParams -RecurseCustomRulePath
-                $v.Count | Should -Be 3
-            }
+        It "Should override the settings IncludeDefaultRules parameter" {
+            $v = Invoke-ScriptAnalyzer @isaParams -IncludeDefaultRules
+            $v.Count | Should -Be 2
+        }
+
+        It "Should override the settings RecurseCustomRulePath parameter" {
+            $v = Invoke-ScriptAnalyzer @isaParams -RecurseCustomRulePath
+            $v.Count | Should -Be 3
         }
     }
 
@@ -527,7 +508,7 @@ Describe "Test CustomizedRulePath" {
             catch
             {
                 if (-not $testingLibraryUsage)
-			    {
+                {
                     $_.FullyQualifiedErrorId | Should -Match "PathNotFound,Microsoft.Windows.PowerShell.ScriptAnalyzer.Commands.InvokeScriptAnalyzerCommand"
                 }
             }
@@ -536,13 +517,12 @@ Describe "Test CustomizedRulePath" {
 }
 
 Describe "Test -Fix Switch" {
-
     BeforeAll {
         $scriptName = "TestScriptWithFixableWarnings.ps1"
-        $testSource = join-path $PSScriptRoot $scriptName
-        $fixedScript = join-path $PSScriptRoot TestScriptWithFixableWarnings_AfterFix.ps1
-        $expectedScriptContent = Get-Content $fixedScript -raw
-        $testScript  = Join-Path $TESTDRIVE $scriptName
+        $testSource = Join-Path $PSScriptRoot $scriptName
+        $fixedScript = Join-Path $PSScriptRoot TestScriptWithFixableWarnings_AfterFix.ps1
+        $expectedScriptContent = Get-Content $fixedScript -Raw
+        $testScript = Join-Path $TESTDRIVE $scriptName
     }
 
     BeforeEach {
@@ -579,66 +559,106 @@ Describe "Test -EnableExit Switch" {
             $pwshExe = 'powershell'
         }
 
-        & $pwshExe -Command 'Import-Module PSScriptAnalyzer; Invoke-ScriptAnalyzer -ScriptDefinition gci -EnableExit'
+        $pssaPath = (Get-Module PSScriptAnalyzer).Path
 
-        $LASTEXITCODE  | Should -Be 1
-    }
+        & $pwshExe -NoProfile -Command "Import-Module '$pssaPath'; Invoke-ScriptAnalyzer -ScriptDefinition gci -EnableExit"
 
-    Describe "-ReportSummary switch" {
-        BeforeAll {
-            if ($IsCoreCLR)
-            {
-                $pwshExe = (Get-Process -Id $PID).Path
-            }
-            else
-            {
-                $pwshExe = 'powershell'
-            }
+        $LASTEXITCODE | Should -Be 1
+    }
 
-            $reportSummaryFor1Warning = '*1 rule violation found.    Severity distribution:  Error = 0, Warning = 1, Information = 0*'
+    It "Returns exit code equivalent to number of warnings for multiple piped files" {
+        if ($IsCoreCLR)
+        {
+            $pwshExe = (Get-Process -Id $PID).Path
+        }
+        else
+        {
+            $pwshExe = 'powershell'
         }
 
-        It "prints the correct report summary using the -NoReportSummary switch" {
-            $result = & $pwshExe -Command 'Import-Module PSScriptAnalyzer; Invoke-ScriptAnalyzer -ScriptDefinition gci -ReportSummary'
+        $pssaPath = (Get-Module PSScriptAnalyzer).Path
 
-            "$result" | Should -BeLike $reportSummaryFor1Warning
-        }
-        It "does not print the report summary when not using -NoReportSummary switch" {
-            $result = & $pwshExe -Command 'Import-Module PSScriptAnalyzer; Invoke-ScriptAnalyzer -ScriptDefinition gci'
+        & $pwshExe -NoProfile {
+            Import-Module $Args[0]
+            Get-ChildItem $Args[1] | Invoke-ScriptAnalyzer -EnableExit
+        } -Args $pssaPath, "$PSScriptRoot\RecursionDirectoryTest"
+
+        $LASTEXITCODE | Should -Be 2
+    }
+}
+
+Describe "-ReportSummary switch" {
+    BeforeAll {
+        $pssaPath = (Get-Module PSScriptAnalyzer).Path
 
-            "$result" | Should -Not -BeLike $reportSummaryFor1Warning
+        if ($IsCoreCLR)
+        {
+            $pwshExe = (Get-Process -Id $PID).Path
+        }
+        else
+        {
+            $pwshExe = 'powershell'
         }
+
+        $reportSummaryFor1Warning = '*1 rule violation found. Severity distribution: Error = 0, Warning = 1, Information = 0*'
     }
 
-    # using statements are only supported in v5+
-    if (!$testingLibraryUsage -and ($PSVersionTable.PSVersion -ge [Version]'5.0.0')) {
-        Describe "Handles parse errors due to unknown types" {
-            $script = @'
-                using namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels
-                using namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions
-                Import-Module "AzureRm"
-                class MyClass { [IStorageContext]$StorageContext } # This will result in a parser error due to [IStorageContext] type that comes from the using statement but is not known at parse time
+    It "prints the correct report summary using the -NoReportSummary switch" {
+        $result = & $pwshExe -NoProfile -Command "Import-Module '$pssaPath'; Invoke-ScriptAnalyzer -ScriptDefinition gci -ReportSummary"
+
+        "$result" | Should -BeLike $reportSummaryFor1Warning
+    }
+    It "does not print the report summary when not using -NoReportSummary switch" {
+        $result = & $pwshExe -Command "Import-Module '$pssaPath'; Invoke-ScriptAnalyzer -ScriptDefinition gci"
+
+        "$result" | Should -Not -BeLike $reportSummaryFor1Warning
+    }
+}
+
+# using statements are only supported in v5+
+Describe "Handles parse errors due to unknown types" -Skip:($testingLibraryUsage -or ($PSVersionTable.PSVersion -lt '5.0')) {
+    BeforeAll {
+        $script = @'
+            using namespace Microsoft.Azure.Commands.ResourceManager.Cmdlets.SdkModels
+            using namespace Microsoft.Azure.Commands.Common.Authentication.Abstractions
+            Import-Module "AzureRm"
+            class MyClass { [IStorageContext]$StorageContext } # This will result in a parser error due to [IStorageContext] type that comes from the using statement but is not known at parse time
 '@
-            It "does not throw and detect one expected warning after the parse error has occured when using -ScriptDefintion parameter set" {
-                $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $script
-                $warnings.Count | Should -Be 1
-                $warnings.RuleName | Should -Be 'TypeNotFound'
-            }
+    }
+    It "does not throw and detect one expected warning after the parse error has occured when using -ScriptDefintion parameter set" {
+        $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $script
+        $warnings.Count | Should -Be 1
+        $warnings.RuleName | Should -Be 'TypeNotFound'
+    }
 
-            $testFilePath = "TestDrive:\testfile.ps1"
-            Set-Content $testFilePath -value $script
-            It "does not throw and detect one expected warning after the parse error has occured when using -Path parameter set" {
-                $warnings = Invoke-ScriptAnalyzer -Path $testFilePath
-                $warnings.Count | Should -Be 1
-                $warnings.RuleName | Should -Be 'TypeNotFound'
-            }
-        }
+    It "does not throw and detect one expected warning after the parse error has occured when using -Path parameter set" {
+        $testFilePath = "TestDrive:\testfile.ps1"
+        Set-Content $testFilePath -Value $script
+        $warnings = Invoke-ScriptAnalyzer -Path $testFilePath
+        $warnings.Count | Should -Be 1
+        $warnings.RuleName | Should -Be 'TypeNotFound'
+    }
+}
 
-        Describe "Handles static Singleton (issue 1182)" {
-            It "Does not throw or return diagnostic record" {
-                $scriptDefinition = 'class T { static [T]$i }; function foo { [CmdletBinding()] param () $script:T.WriteLog() }'
-                Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -ErrorAction Stop | Should -BeNullOrEmpty
-            }
+Describe 'Handles static Singleton (issue 1182)' -Skip:($testingLibraryUsage -or ($PSVersionTable.PSVersion -lt '5.0')) {
+    It 'Does not throw or return diagnostic record' {
+        $scriptDefinition = 'class T { static [T]$i }; function foo { [CmdletBinding()] param () $script:T.WriteLog() }'
+        Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -ErrorAction Stop | Should -BeNullOrEmpty
+    }
+}
+
+Describe 'Suppression switch parameter sets' {
+    It 'Should not allow both suppression switches to be used' {
+        try
+        {
+            Invoke-ScriptAnalyzer -ScriptDefinition 'gci' -IncludeSuppressed -SuppressedOnly
+        }
+        catch
+        {
+            $errorId = $_.FullyQualifiedErrorId
         }
+
+        $errorId = $errorId.Substring(0, $errorId.IndexOf(','))
+        $errorId | Should -BeExactly 'AmbiguousParameterSet'
     }
 }
diff --git a/Tests/Engine/LibraryUsage.tests.ps1 b/Tests/Engine/LibraryUsage.tests.ps1
index 279f48238..f8f30226b 100644
--- a/Tests/Engine/LibraryUsage.tests.ps1
+++ b/Tests/Engine/LibraryUsage.tests.ps1
@@ -1,212 +1,227 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
-
-# test is meant to verify functionality if csharp apis are used. Hence not if psedition is CoreCLR
-if ($IsCoreCLR)
-{
-	return
-}
-
-
-# Overwrite Invoke-ScriptAnalyzer with a version that
-# wraps the usage of ScriptAnalyzer as a .NET library
-function Invoke-ScriptAnalyzer {
-	param (
-        [CmdletBinding(DefaultParameterSetName="File", SupportsShouldProcess = $true)]
-
-		[parameter(Mandatory = $true, Position = 0, ParameterSetName="File")]
-		[Alias("PSPath")]
-		[string] $Path,
-
-		[parameter(Mandatory = $true, ParameterSetName="ScriptDefinition")]
-		[string] $ScriptDefinition,
-
-        [Parameter(Mandatory = $false)]
-		[Alias("CustomizedRulePath")]
-		[string[]] $CustomRulePath = $null,
-
-		[Parameter(Mandatory = $false)]
-		[switch] $RecurseCustomRulePath,
-
-        [Parameter(Mandatory=$false)]
-        [string[]] $ExcludeRule = $null,
-
-        [Parameter(Mandatory = $false)]
-        [string[]] $IncludeRule = $null,
-
-        [ValidateSet("Warning", "Error", "Information", "ParseError", IgnoreCase = $true)]
-        [Parameter(Mandatory = $false)]
-        [string[]] $Severity = $null,
-
-        [Parameter(Mandatory = $false)]
-		[switch] $Recurse,
-
-        [Parameter(Mandatory = $false)]
-		[switch] $IncludeDefaultRules,
-
-        [Parameter(Mandatory = $false)]
-        [switch] $SuppressedOnly,
-
-        [Parameter(Mandatory = $false)]
-        [switch] $Fix,
-
-        [Parameter(Mandatory = $false)]
-        [switch] $EnableExit,
-
-        [Parameter(Mandatory = $false)]
-        [switch] $ReportSummary
-    )
-
-    if ($null -eq $CustomRulePath)
-    {
-        $IncludeDefaultRules = $true
-    }
-	# There is an inconsistency between this implementation and c# implementation of the cmdlet.
-	# The CustomRulePath parameter here is of "string[]" type whereas in the c# implementation it is of "string" type.
-	# If we set the CustomRulePath parameter here to  "string[]", then the library usage test fails when run as an administrator.
-	# We want to note that the library usage test doesn't fail when run as a non-admin user.
-	# The following is the error statement when the test runs as an administrator.
-	# Assert failed on "Initialize" with "7" argument(s): "Test failed due to terminating error: The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)"
-
-	$scriptAnalyzer = New-Object "Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer";
-	$scriptAnalyzer.Initialize(
-		$runspace,
-		$testOutputWriter,
-		$CustomRulePath,
-		$IncludeRule,
-		$ExcludeRule,
-		$Severity,
-        $IncludeDefaultRules.IsPresent,
-		$SuppressedOnly.IsPresent
-	);
-
-    if ($PSCmdlet.ParameterSetName -eq "File")
-    {
-        $supportsShouldProcessFunc = [Func[string, string, bool]] { return $PSCmdlet.Shouldprocess }
-        if ($Fix.IsPresent)
-        {
-            $results = $scriptAnalyzer.AnalyzeAndFixPath($Path, $supportsShouldProcessFunc, $Recurse.IsPresent);
-        }
-        else
-        {
-            $results = $scriptAnalyzer.AnalyzePath($Path, $supportsShouldProcessFunc, $Recurse.IsPresent);
-        }
-    }
-    else
-    {
-        $results = $scriptAnalyzer.AnalyzeScriptDefinition($ScriptDefinition, [ref] $null, [ref] $null)
-	}
-
-	$results
-
-    if ($ReportSummary.IsPresent)
-    {
-        if ($null -ne $results)
-        {
-			 # This is not the exact message that it would print but close enough
-            Write-Host "$($results.Count) rule violations found.    Severity distribution:  Error = 1, Warning = 3, Information  = 5" -ForegroundColor Red
-        }
-        else
-        {
-            Write-Host '0 rule violations found.' -ForegroundColor Green
-        }
-    }
-
-    if ($EnableExit.IsPresent -and $null -ne $results)
-    {
-        exit $results.Count
-    }
-}
-
-# Define an implementation of the IOutputWriter interface
-Add-Type -Language CSharp @"
-using System.Management.Automation;
-using System.Management.Automation.Host;
-using Microsoft.Windows.PowerShell.ScriptAnalyzer;
-
-public class PesterTestOutputWriter : IOutputWriter
-{
-	private PSHost psHost;
-
-	public string MostRecentWarningMessage { get; private set; }
-
-	public static PesterTestOutputWriter Create(PSHost psHost)
-	{
-		PesterTestOutputWriter testOutputWriter = new PesterTestOutputWriter();
-		testOutputWriter.psHost = psHost;
-		return testOutputWriter;
-	}
-
-	public void WriteError(ErrorRecord error)
-	{
-		// We don't write errors to avoid misleading
-		// error messages in test output
-	}
-
-	public void WriteWarning(string message)
-	{
-		psHost.UI.WriteWarningLine(message);
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+Describe 'Library Usage' -Skip:$IsCoreCLR {
+	BeforeAll {
+		# Overwrite Invoke-ScriptAnalyzer with a version that
+		# wraps the usage of ScriptAnalyzer as a .NET library
+		function Invoke-ScriptAnalyzer {
+			param (
+				[CmdletBinding(DefaultParameterSetName="Path_SuppressedOnly", SupportsShouldProcess = $true)]
+
+				[parameter(Mandatory = $true, Position = 0, ParameterSetName="Path_SuppressedOnly")]
+				[parameter(Mandatory = $true, Position = 0, ParameterSetName="Path_IncludeSuppressed")]
+				[Alias("PSPath")]
+				[string] $Path,
+
+				[parameter(Mandatory = $true, ParameterSetName="ScriptDefinition_SuppressedOnly")]
+				[parameter(Mandatory = $true, ParameterSetName="ScriptDefinition_IncludeSuppressed")]
+				[string] $ScriptDefinition,
+
+				[Parameter(Mandatory = $false)]
+				[Alias("CustomizedRulePath")]
+				[string[]] $CustomRulePath = $null,
+
+				[Parameter(Mandatory = $false)]
+				[switch] $RecurseCustomRulePath,
+
+				[Parameter(Mandatory=$false)]
+				[string[]] $ExcludeRule = $null,
+
+				[Parameter(Mandatory = $false)]
+				[string[]] $IncludeRule = $null,
+
+				[ValidateSet("Warning", "Error", "Information", "ParseError", IgnoreCase = $true)]
+				[Parameter(Mandatory = $false)]
+				[string[]] $Severity = $null,
+
+				[Parameter(Mandatory = $false)]
+				[switch] $Recurse,
+
+				[Parameter(Mandatory = $false)]
+				[switch] $IncludeDefaultRules,
+
+				[Parameter(Mandatory = $false, ParameterSetName = "Path_SuppressedOnly")]
+				[Parameter(Mandatory = $false, ParameterSetName = "ScriptDefinition_SuppressedOnly")]
+				[switch] $SuppressedOnly,
+
+				[Parameter(Mandatory, ParameterSetName = "Path_IncludeSuppressed")]
+				[Parameter(Mandatory, ParameterSetName = "ScriptDefinition_IncludeSuppressed")]
+				[switch] $IncludeSuppressed,
+
+				[Parameter(Mandatory = $false)]
+				[switch] $Fix,
+
+				[Parameter(Mandatory = $false)]
+				[switch] $EnableExit,
+
+				[Parameter(Mandatory = $false)]
+				[switch] $ReportSummary
+			)
+
+			if ($null -eq $CustomRulePath)
+			{
+				$IncludeDefaultRules = $true
+			}
+			# There is an inconsistency between this implementation and c# implementation of the cmdlet.
+			# The CustomRulePath parameter here is of "string[]" type whereas in the c# implementation it is of "string" type.
+			# If we set the CustomRulePath parameter here to  "string[]", then the library usage test fails when run as an administrator.
+			# We want to note that the library usage test doesn't fail when run as a non-admin user.
+			# The following is the error statement when the test runs as an administrator.
+			# Assert failed on "Initialize" with "7" argument(s): "Test failed due to terminating error: The module was expected to contain an assembly manifest. (Exception from HRESULT: 0x80131018)"
+
+			$scriptAnalyzer = New-Object "Microsoft.Windows.PowerShell.ScriptAnalyzer.ScriptAnalyzer";
+			$scriptAnalyzer.Initialize(
+				$runspace,
+				$testOutputWriter,
+				$CustomRulePath,
+				$IncludeRule,
+				$ExcludeRule,
+				$Severity,
+				$IncludeDefaultRules,
+				$SuppressedOnly,
+				$IncludeSuppressed
+			);
+
+			if ($Path)
+			{
+				$supportsShouldProcessFunc = [Func[string, string, bool]] { return $PSCmdlet.Shouldprocess }
+				if ($Fix)
+				{
+					$results = $scriptAnalyzer.AnalyzeAndFixPath($Path, $supportsShouldProcessFunc, $Recurse);
+				}
+				else
+				{
+					$results = $scriptAnalyzer.AnalyzePath($Path, $supportsShouldProcessFunc, $Recurse);
+				}
+			}
+			else
+			{
+				$results = $scriptAnalyzer.AnalyzeScriptDefinition($ScriptDefinition, [ref] $null, [ref] $null)
+			}
+
+			$results
+
+			if ($ReportSummary.IsPresent)
+			{
+				if ($null -ne $results)
+				{
+					# This is not the exact message that it would print but close enough
+					Write-Host "$($results.Count) rule violations found.    Severity distribution:  Error = 1, Warning = 3, Information  = 5" -ForegroundColor Red
+				}
+				else
+				{
+					Write-Host '0 rule violations found.' -ForegroundColor Green
+				}
+			}
+
+			if ($EnableExit.IsPresent -and $null -ne $results)
+			{
+				exit $results.Count
+			}
+		}
+
+		# Define an implementation of the IOutputWriter interface.
+		# For this to compile the ScriptAnalyzer module needs to have been loaded
+		Import-Module PSScriptAnalyzer
+		Add-Type -Language CSharp @"
+		using System.Management.Automation;
+		using System.Management.Automation.Host;
+		using Microsoft.Windows.PowerShell.ScriptAnalyzer;
+
+		public class PesterTestOutputWriter : IOutputWriter
+		{
+			private PSHost psHost;
+
+			public string MostRecentWarningMessage { get; private set; }
+
+			public static PesterTestOutputWriter Create(PSHost psHost)
+			{
+				PesterTestOutputWriter testOutputWriter = new PesterTestOutputWriter();
+				testOutputWriter.psHost = psHost;
+				return testOutputWriter;
+			}
+
+			public void WriteError(ErrorRecord error)
+			{
+				// We don't write errors to avoid misleading
+				// error messages in test output
+			}
+
+			public void WriteWarning(string message)
+			{
+				psHost.UI.WriteWarningLine(message);
+
+				this.MostRecentWarningMessage = message;
+			}
+
+			public void WriteVerbose(string message)
+			{
+				// We don't write verbose output to avoid lots
+				// of unnecessary messages in test output
+			}
+
+			public void WriteDebug(string message)
+			{
+				psHost.UI.WriteDebugLine(message);
+			}
+
+			public void ThrowTerminatingError(ErrorRecord record)
+			{
+				throw new RuntimeException(
+					"Test failed due to terminating error: \r\n" + record.ToString(),
+					null,
+					record);
+			}
+		}
+"@ -ReferencedAssemblies "Microsoft.Windows.PowerShell.ScriptAnalyzer" -ErrorAction SilentlyContinue
 
-		this.MostRecentWarningMessage = message;
+		if ($testOutputWriter -eq $null)
+		{
+			$testOutputWriter = [PesterTestOutputWriter]::Create($Host);
+		}
+
+		# Create a fresh runspace to pass into the ScriptAnalyzer class
+		$initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault2();
+		$runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace([System.Management.Automation.Host.PSHost]$Host, [System.Management.Automation.Runspaces.InitialSessionState]$initialSessionState);
+		$runspace.Open();
+
+		# Let other test scripts know we are testing library usage now
+		$testingLibraryUsage = $true
+
+		# Force Get-Help not to prompt for interactive input to download help using Update-Help
+		# By adding this registry key we force to turn off Get-Help interactivity logic during ScriptRule parsing
+		$null,"Wow6432Node" | ForEach-Object {
+			try
+			{
+				Set-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -Value 1 -Force -ErrorAction SilentlyContinue
+			}
+			catch
+			{
+				# Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
+			}
+		}
 	}
 
-	public void WriteVerbose(string message)
-	{
-		// We don't write verbose output to avoid lots
-		// of unnecessary messages in test output
+	Describe 'InvokeScriptAnalyzer.tests.ps1' {
+		$testingLibraryUsage = $true
+		. (Join-Path $PSScriptRoot 'InvokeScriptAnalyzer.tests.ps1')
 	}
-
-	public void WriteDebug(string message)
-	{
-		psHost.UI.WriteDebugLine(message);
+	Describe 'RuleSuppression.tests.ps1' {
+		$testingLibraryUsage = $true
+		. (Join-Path $PSScriptRoot 'RuleSuppression.tests.ps1')
 	}
-
-	public void ThrowTerminatingError(ErrorRecord record)
-	{
-		throw new RuntimeException(
-			"Test failed due to terminating error: \r\n" + record.ToString(),
-			null,
-			record);
+	Describe 'CustomizedRule.tests.ps1' {
+		$testingLibraryUsage = $true
+		. (Join-Path $PSScriptRoot 'CustomizedRule.tests.ps1')
 	}
-}
-"@ -ReferencedAssemblies "Microsoft.Windows.PowerShell.ScriptAnalyzer" -ErrorAction SilentlyContinue
 
-if ($testOutputWriter -eq $null)
-{
-	$testOutputWriter = [PesterTestOutputWriter]::Create($Host);
-}
 
-# Create a fresh runspace to pass into the ScriptAnalyzer class
-$initialSessionState = [System.Management.Automation.Runspaces.InitialSessionState]::CreateDefault2();
-$runspace = [System.Management.Automation.Runspaces.RunspaceFactory]::CreateRunspace([System.Management.Automation.Host.PSHost]$Host, [System.Management.Automation.Runspaces.InitialSessionState]$initialSessionState);
-$runspace.Open();
+	AfterAll {
+		# Clean up the test runspace
+		$runspace.Dispose();
 
-# Let other test scripts know we are testing library usage now
-$testingLibraryUsage = $true
-
-# Force Get-Help not to prompt for interactive input to download help using Update-Help
-# By adding this registry key we force to turn off Get-Help interactivity logic during ScriptRule parsing
-$null,"Wow6432Node" | ForEach-Object {
-	try
-	{
-		Set-ItemProperty -Name "DisablePromptToUpdateHelp" -Path "HKLM:\SOFTWARE\$($_)\Microsoft\PowerShell" -Value 1 -Force -ErrorAction SilentlyContinue
-	}
-	catch
-	{
-		# Ignore for cases when tests are running in non-elevated more or registry key does not exist or not accessible
+		# Re-import the PSScriptAnalyzer module to overwrite the library test cmdlet
+		Import-Module PSScriptAnalyzer
 	}
 }
-
-# Invoke existing test files that use Invoke-ScriptAnalyzer
-. $PSScriptRoot\InvokeScriptAnalyzer.tests.ps1
-. $PSScriptRoot\RuleSuppression.tests.ps1
-. $PSScriptRoot\CustomizedRule.tests.ps1
-
-# We're done testing library usage
-$testingLibraryUsage = $false
-
-# Clean up the test runspace
-$runspace.Dispose();
-
-# Re-import the PSScriptAnalyzer module to overwrite the library test cmdlet
-Import-Module PSScriptAnalyzer
diff --git a/Tests/Engine/ModuleDependencyHandler.tests.ps1 b/Tests/Engine/ModuleDependencyHandler.tests.ps1
index 22045644e..09bd74912 100644
--- a/Tests/Engine/ModuleDependencyHandler.tests.ps1
+++ b/Tests/Engine/ModuleDependencyHandler.tests.ps1
@@ -1,20 +1,26 @@
-Describe "Resolve DSC Resource Dependency" {
-    BeforeAll {
-        $skipTest = $false # Test that require DSC to be installed
-        if ($testingLibararyUsage -or ($PSversionTable.PSVersion -lt [Version]'5.0.0'))
-        {
-            $skipTest = $true
-            return
-        }
-        if ($IsLinux -or $IsMacOS)
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+function Get-Skip
+{
+    if ($testingLibararyUsage -or ($PSVersionTable.PSVersion -lt '5.0'))
+    {
+        return $true
+    }
+    if ($IsLinux -or $IsMacOS)
+    {
+        $dscIsInstalled = Test-Path /etc/opt/omi/conf/dsc/configuration
+        if (-not $dscIsInstalled)
         {
-            $dscIsInstalled = Test-Path /etc/opt/omi/conf/dsc/configuration
-            if (-not $dscIsInstalled)
-            {
-                $skipTest = $true
-            }
+            return $true
         }
+    }
+    return $false
+}
+$skipTest = Get-Skip
 
+Describe "Resolve DSC Resource Dependency" {
+    BeforeAll {
         $savedPSModulePath = $env:PSModulePath
         $violationFileName = 'MissingDSCResource.ps1'
         $violationFilePath = Join-Path $PSScriptRoot $violationFileName
@@ -44,7 +50,7 @@ Describe "Resolve DSC Resource Dependency" {
 
     Context "Module handler class" {
         BeforeAll {
-            if ($PSversionTable.PSVersion -lt [Version]'5.0.0') { return }
+            if ($PSVersionTable.PSVersion -lt '5.0') { return }
             $moduleHandlerType = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.ModuleDependencyHandler]
             $oldEnvVars = Get-Item Env:\* | Sort-Object -Property Key
             $savedPSModulePath = $env:PSModulePath
@@ -53,7 +59,7 @@ Describe "Resolve DSC Resource Dependency" {
             if ( $skipTest ) { return }
             $env:PSModulePath = $savedPSModulePath
         }
-        It "Sets defaults correctly" -Skip:($PSversionTable.PSVersion -lt [Version]'5.0.0') {
+        It "Sets defaults correctly" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
             $rsp = [runspacefactory]::CreateRunspace()
             $rsp.Open()
             $depHandler = $moduleHandlerType::new($rsp)
@@ -76,15 +82,15 @@ Describe "Resolve DSC Resource Dependency" {
             $rsp.Dispose()
         }
 
-        It "Keeps the environment variables unchanged" -Skip:($PSversionTable.PSVersion -lt [Version]'5.0.0') {
+        It "Keeps the environment variables unchanged" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
             Test-EnvironmentVariables($oldEnvVars)
         }
 
-        It "Throws if runspace is null" -Skip:($PSversionTable.PSVersion -lt [Version]'5.0.0') {
+        It "Throws if runspace is null" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
             {$moduleHandlerType::new($null)} | Should -Throw
         }
 
-        It "Throws if runspace is not opened" -Skip:($PSversionTable.PSVersion -lt [Version]'5.0.0') {
+        It "Throws if runspace is not opened" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
             $rsp = [runspacefactory]::CreateRunspace()
             {$moduleHandlerType::new($rsp)} | Should -Throw
             $rsp.Dispose()
@@ -179,7 +185,7 @@ Describe "Resolve DSC Resource Dependency" {
         }
     }
 
-    Context "Invoke-ScriptAnalyzer without switch but with module in temp path" {
+    Context "Invoke-ScriptAnalyzer without switch but with module in temp path" -Skip:$skipTest {
         BeforeAll {
             if ( $skipTest ) { return }
             $oldEnvVars = Get-Item Env:\* | Sort-Object -Property Key
@@ -238,8 +244,7 @@ Describe "Resolve DSC Resource Dependency" {
             $env:PSModulePath | Should -Be $savedPSModulePath
         }
 
-        if (!$skipTest)
-        {
+        It "Keeps the environment variables unchanged" -skip:$skipTest {
             if ($IsLinux -or $IsMacOS)
             {
                 $env:HOME = $oldLocalAppDataPath
@@ -252,9 +257,7 @@ Describe "Resolve DSC Resource Dependency" {
             }
             Remove-Item -Recurse -Path $tempModulePath -Force
             Remove-Item -Recurse -Path $tempPath -Force
-        }
 
-        It "Keeps the environment variables unchanged" -skip:$skipTest {
             Test-EnvironmentVariables($oldEnvVars)
         }
     }
diff --git a/Tests/Engine/ModuleHelp.Tests.ps1 b/Tests/Engine/ModuleHelp.Tests.ps1
index c84b19cb4..ac40dcf94 100644
--- a/Tests/Engine/ModuleHelp.Tests.ps1
+++ b/Tests/Engine/ModuleHelp.Tests.ps1
@@ -1,153 +1,5 @@
-<#
-.SYNOPSIS
-Tests the PowerShell help for the commands in a module.
-
-.DESCRIPTION
-This Pester test verifies that the commands in a module have basic help content.
-It works on all command types and both comment-based and XML help.
-
-This test verifies that Get-Help is not autogenerating help because it cannot
-find any help for the command. Then, it checks for the following help elements:
-	- Synopsis
-	- Description
-	- Parameter:
-		- A description of each parameter.
-		- An accurate value for the Mandatory property.
-		- An accurate value for the .NET type of the parameter value.
-	- No extra parameters:
-		- Verifies that there are no parameters in help that are not also in the code.
-
-When testing attributes of parameters that appear in multiple parameter sets,
-this test uses the parameter that appears in the default parameter set, if one
-is defined.
-
-You can run this Tests file from any location. For a help test that is located in a module
-directory, use https://github.com/juneb/PesterTDD/InModule.Help.Tests.ps1
-
-.PARAMETER ModuleName
-Enter the name of the module to test. You can enter only one name at a time. This
-parameter is mandatory.
-
-.PARAMETER RequiredVersion
-Enter the version of the module to test. This parameter is optional. If you
-omit it, the test runs on the latest version of the module in $env:PSModulePath.
-
-.EXAMPLE
-.\Module.Help.Tests.ps1 -ModuleName Pester -RequiredVersion 4.3.1
-This command runs the tests on the commands in Pester 4.3.1.
-
-.EXAMPLE
-.\Module.Help.Tests.ps1 -ModuleName Pester
-This command runs the tests on the commands in latest local version of the
-Pester module.
-
-
-.NOTES
-	===========================================================================
-	Created with: 	SAPIEN Technologies, Inc., PowerShell Studio 2016 v5.2.119
-	Created on:   	4/12/2016 1:11 AM
-	Created by:   	June Blender
-	Organization: 	SAPIEN Technologies, Inc
-	Filename:		*.Help.Tests.ps1
-	===========================================================================
-#>
-
-Param
-(
-	[ValidateScript({ Get-Module -ListAvailable -Name $_ })]
-	[string]
-	$ModuleName = 'PSScriptAnalyzer',
-
-	[Parameter(Mandatory = $false)]
-	[System.Version]
-	$RequiredVersion
-)
-
-# #Requires -Module @{ModuleName = 'Pester'; ModuleVersion = '4.3.1'}
-
-<#
-.SYNOPSIS
-Gets command parameters; one per name. Prefers default parameter set.
-
-.DESCRIPTION
-Gets one CommandParameterInfo object for each parameter in the specified
-command. If a command has more than one parameter with the same name, this
-function gets the parameters in the default parameter set, if one is specified.
-
-For example, if a command has two parameter sets:
-	Name, ID  (default)
-	Name, Path
-This function returns:
-    Name (default), ID Path
-
-This function is used to get parameters for help and for help testing.
-
-.PARAMETER Command
-Enter a CommandInfo object, such as the object that Get-Command returns. You
-can also pipe a CommandInfo object to the function.
-
-This parameter takes a CommandInfo object, instead of a command name, so
-you can use the parameters of Get-Command to specify the module and version
-of the command.
-
-.EXAMPLE
-PS C:\> Get-ParametersDefaultFirst -Command (Get-Command New-Guid)
-This command uses the Command parameter to specify the command to
-Get-ParametersDefaultFirst
-
-.EXAMPLE
-PS C:\> Get-Command New-Guid | Get-ParametersDefaultFirst
-You can also pipe a CommandInfo object to Get-ParametersDefaultFirst
-
-.EXAMPLE
-PS C:\> Get-ParametersDefaultFirst -Command (Get-Command BetterCredentials\Get-Credential)
-You can use the Command parameter to specify the CommandInfo object. This
-command runs Get-Command module-qualified name value.
-
-.EXAMPLE
-PS C:\> $ModuleSpec = @{ModuleName='BetterCredentials';RequiredVersion=4.3}
-PS C:\> Get-Command -FullyQualifiedName $ModuleSpec | Get-ParametersDefaultFirst
-This command uses a Microsoft.PowerShell.Commands.ModuleSpecification object to
-specify the module and version. You can also use it to specify the module GUID.
-Then, it pipes the CommandInfo object to Get-ParametersDefaultFirst.
-#>
-function Get-ParametersDefaultFirst {
-	Param
-	(
-		[Parameter(Mandatory = $true,
-				   ValueFromPipeline = $true)]
-		[System.Management.Automation.CommandInfo]
-		$Command
-	)
-
-	BEGIN {
-		$Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable', 'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable', 'WhatIf', 'Confirm'
-		$parameters = @()
-	}
-	PROCESS {
-		if ($defaultPSetName = $Command.DefaultParameterSet) {
-			$defaultParameters = ($Command.ParameterSets | Where-Object Name -eq $defaultPSetName).parameters | Where-Object Name -NotIn $common
-			$otherParameters = ($Command.ParameterSets | Where-Object Name -ne $defaultPSetName).parameters | Where-Object Name -NotIn $common
-
-			$parameters = $defaultParameters
-			if ($parameters -and $otherParameters) {
-				$otherParameters | ForEach-Object {
-					if ($_.Name -notin $parameters.Name) {
-						$parameters += $_
-					}
-				}
-				$parameters = $parameters | Sort-Object Name
-			}
-		}
-		else {
-			$parameters = $Command.ParameterSets.Parameters | Where-Object Name -NotIn $common | Sort-Object Name -Unique
-		}
-
-
-		return $parameters
-	}
-	END { }
-}
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
 <#
 .SYNOPSIS
@@ -202,119 +54,212 @@ function Get-CommandVersion {
 	}
 }
 
+$RequiredVersion = (Get-Command Invoke-ScriptAnalyzer).Module.Version
 
-if (!$RequiredVersion) {
-	$RequiredVersion = (Get-Module $ModuleName -ListAvailable | Sort-Object -Property Version -Descending | Select-Object -First 1).Version
-}
-
-# Remove all versions of the module from the session. Pester can't handle multiple versions.
-Get-Module $ModuleName | Remove-Module
-
-# Import the required version
-Import-Module $ModuleName -RequiredVersion $RequiredVersion -ErrorAction Stop
 $ms = $null
-$commands =$null
-$paramBlackList = @(
+$commands = $null
+$paramBlockList = @(
 	'AttachAndDebug' # Reason: When building with DEGUG configuration, an additional parameter 'AttachAndDebug' will be added to Invoke-ScriptAnalyzer and Invoke-Formatter, but there is no Help for those, as they are not intended for production usage.
 )
-if ($PSVersionTable.PSVersion -lt [Version]'5.0.0') {
+[string] $ModuleName = 'PSScriptAnalyzer'
+if ($PSVersionTable.PSVersion -lt '5.0') {
 	$ms = New-Object -TypeName 'Microsoft.PowerShell.Commands.ModuleSpecification' -ArgumentList $ModuleName
 	$commands = Get-Command -Module $ms.Name
-	$paramBlackList += 'SaveDscDependency'
 }
 else {
 	$ms = [Microsoft.PowerShell.Commands.ModuleSpecification]@{ ModuleName = $ModuleName; RequiredVersion = $RequiredVersion }
 	$commands = Get-Command -FullyQualifiedModule $ms
 }
 
-## When testing help, remember that help is cached at the beginning of each session.
-## To test, restart session.
-
-foreach ($command in $commands) {
-	$commandName = $command.Name
+$testCases = $commands.ForEach{
+	@{
+		Command              = $_
+		CommandName          = $_.Name
+		CommandModuleVersion = Get-CommandVersion -CommandInfo $_
+		Help                 = & {
+			$Help = Get-Help "${ModuleName}\$($_.Name)" -ErrorAction SilentlyContinue
+			if ($Help.Synopsis -like '*`[`<CommonParameters`>`]*')
+			{
+				$Help = Get-Help $commandName -ErrorAction SilentlyContinue
+			}
+			$Help
+		}
+	}
+}
 
-	# Get the module name and version of the command. Used in the Describe name.
-	$commandModuleVersion = Get-CommandVersion -CommandInfo $command
 
-	# The module-qualified command fails on Microsoft.PowerShell.Archive cmdlets
-	$Help = Get-Help $ModuleName\$commandName -ErrorAction SilentlyContinue
-	if ($Help.Synopsis -like '*`[`<CommonParameters`>`]*') {
-		$Help = Get-Help $commandName -ErrorAction SilentlyContinue
+BeforeAll {
+	$paramBlockList = @(
+		'AttachAndDebug' # Reason: When building with DEGUG configuration, an additional parameter 'AttachAndDebug' will be added to Invoke-ScriptAnalyzer and Invoke-Formatter, but there is no Help for those, as they are not intended for production usage.
+	)
+	if ($PSVersionTable.PSVersion -lt '5.0') {
+		$paramBlockList += 'SaveDscDependency'
 	}
+}
 
-	Describe "Test help for $commandName in $($commandModuleVersion.ModuleName) ($($commandModuleVersion.Version))" {
 
-		# If help is not found, synopsis in auto-generated help is the syntax diagram
-		It "should not be auto-generated" {
-			# Replace pester BeLike with powershell -like as pester 3.3.9 does not support BeLike
-			$Help.Synopsis -like '*`[`<CommonParameters`>`]*' | Should Be $false
-		}
+Describe "Cmdlet help" {
 
-		# Should be a description for every function
-		It "gets description for $commandName" {
-			$Help.Description | Should -Not -BeNullOrEmpty
-		}
+	# If help is not found, synopsis in auto-generated help is the syntax diagram
+	It "should not be auto-generated" -TestCases $testCases {
+		# Replace pester BeLike with powershell -like as pester 3.3.9 does not support BeLike
+		$Help.Synopsis -like '*`[`<CommonParameters`>`]*' | Should -BeFalse
+	}
 
-		# Should be at least one example
-		It "gets example code from $commandName" {
-			($Help.Examples.Example | Select-Object -First 1).Code | Should -Not -BeNullOrEmpty
-		}
+	# Should be a description for every function
+	It "gets description for <CommandName>" -TestCases $testCases {
+		$Help.Description | Should -Not -BeNullOrEmpty
+	}
 
-		# Should be at least one example description
-		It "gets example help from $commandName" {
-			($Help.Examples.Example.Remarks | Select-Object -First 1).Text | Should -Not -BeNullOrEmpty
-		}
+	# Should be at least one example
+	It "gets example code from <CommandName>" -TestCases $testCases {
+		($Help.Examples.Example | Select-Object -First 1).Code | Should -Not -BeNullOrEmpty
+	}
+}
 
-		Context "Test parameter help for $commandName" {
+Describe 'Cmdlet parameter help' {
+	BeforeAll {
+				<#
+		.SYNOPSIS
+		Gets command parameters; one per name. Prefers default parameter set.
+
+		.DESCRIPTION
+		Gets one CommandParameterInfo object for each parameter in the specified
+		command. If a command has more than one parameter with the same name, this
+		function gets the parameters in the default parameter set, if one is specified.
+
+		For example, if a command has two parameter sets:
+			Name, ID  (default)
+			Name, Path
+		This function returns:
+			Name (default), ID Path
+
+		This function is used to get parameters for help and for help testing.
+
+		.PARAMETER Command
+		Enter a CommandInfo object, such as the object that Get-Command returns. You
+		can also pipe a CommandInfo object to the function.
+
+		This parameter takes a CommandInfo object, instead of a command name, so
+		you can use the parameters of Get-Command to specify the module and version
+		of the command.
+
+		.EXAMPLE
+		PS C:\> Get-ParametersDefaultFirst -Command (Get-Command New-Guid)
+		This command uses the Command parameter to specify the command to
+		Get-ParametersDefaultFirst
+
+		.EXAMPLE
+		PS C:\> Get-Command New-Guid | Get-ParametersDefaultFirst
+		You can also pipe a CommandInfo object to Get-ParametersDefaultFirst
+
+		.EXAMPLE
+		PS C:\> Get-ParametersDefaultFirst -Command (Get-Command BetterCredentials\Get-Credential)
+		You can use the Command parameter to specify the CommandInfo object. This
+		command runs Get-Command module-qualified name value.
+
+		.EXAMPLE
+		PS C:\> $ModuleSpec = @{ModuleName='BetterCredentials';RequiredVersion=4.3}
+		PS C:\> Get-Command -FullyQualifiedName $ModuleSpec | Get-ParametersDefaultFirst
+		This command uses a Microsoft.PowerShell.Commands.ModuleSpecification object to
+		specify the module and version. You can also use it to specify the module GUID.
+		Then, it pipes the CommandInfo object to Get-ParametersDefaultFirst.
+		#>
+		function Get-ParametersDefaultFirst {
+			Param
+			(
+				[Parameter(Mandatory = $true,
+						ValueFromPipeline = $true)]
+				[System.Management.Automation.CommandInfo]
+				$Command
+			)
+
+			BEGIN {
+				$Common = [System.Management.Automation.PSCmdlet]::CommonParameters
+				$parameters = @()
+			}
+			PROCESS {
+				if ($defaultPSetName = $Command.DefaultParameterSet) {
+					$defaultParameters = ($Command.ParameterSets | Where-Object Name -eq $defaultPSetName).parameters | Where-Object Name -NotIn $common
+					$otherParameters = ($Command.ParameterSets | Where-Object Name -ne $defaultPSetName).parameters | Where-Object Name -NotIn $common
+
+					$parameters = $defaultParameters
+					if ($parameters -and $otherParameters) {
+						$otherParameters | ForEach-Object {
+							if ($_.Name -notin $parameters.Name) {
+								$parameters += $_
+							}
+						}
+						$parameters = $parameters | Sort-Object Name
+					}
+				}
+				else {
+					$parameters = $Command.ParameterSets.Parameters | Where-Object Name -NotIn $common | Sort-Object Name -Unique
+				}
 
-			$Common = 'Debug', 'ErrorAction', 'ErrorVariable', 'InformationAction', 'InformationVariable', 'OutBuffer', 'OutVariable',
-			'PipelineVariable', 'Verbose', 'WarningAction', 'WarningVariable', 'WhatIf', 'Confirm'
 
-			# Get parameters. When >1 parameter with same name,
-			# get parameter from the default parameter set, if any.
-			$parameters = Get-ParametersDefaultFirst -Command $command
+				return $parameters
+			}
+			END { }
+		}
+	}
+	It "Parameter help for <CommandName>" -TestCases $testCases {
+		# Get parameters. When >1 parameter with same name,
+		# get parameter from the default parameter set, if any.
+		$parameters = Get-ParametersDefaultFirst -Command $command
 
-			$parameterNames = $parameters.Name
-			$HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique
+		$parameterNames = $parameters.Name
+		$HelpParameterNames = $Help.Parameters.Parameter.Name | Sort-Object -Unique
 
-			foreach ($parameter in $parameters) {
-				if ($parameter.Name -in $paramBlackList) {
-					continue
+		foreach ($parameter in $parameters) {
+			if ($parameter.Name -in $paramBlockList) {
+				continue
+			}
+			$parameterName = $parameter.Name
+			$parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName
+
+			# Should be a description for every parameter
+			# It "gets help for parameter: $parameterName : in $commandName" {
+				# `$parameterHelp.Description.Text | Should -Not -BeNullOrEmpty` fails for -Settings paramter
+				# without explicit [string] casting on the Text property
+				$parameterHelp.Description.Text | Should -Not -BeNullOrEmpty -Because "Parameter '$parameterName' of command '$CommandName' should have a Description"
+			# }
+
+			# Required value in Help should match IsMandatory property of parameter
+			$codeMandatory = $parameter.IsMandatory.toString()
+			$parameterHelp.Required | Should -Be $codeMandatory -Because "Parameter '$parameterName' of command '$CommandName should have the correct IsMandatory attribute"
+
+			# Parameter type in Help should match code
+			$codeType = $parameter.ParameterType.Name
+			# To avoid calling Trim method on a null object.
+			$helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() }
+			$helpType | Should -Be $codeType -Because "help for $commandName has correct parameter type for $parameterName"
+
+			foreach($parameterAttribute in $parameter.Attributes) {
+				if ($parameterAttribute.ValueFromPipeline -eq $null) { continue }
+
+				$parameterHelpPipelineInput = if ($parameterHelp.pipelineInput -eq 'True (ByPropertyName, ByValue)') {
+					$true
 				}
-				$parameterName = $parameter.Name
-				$parameterHelp = $Help.parameters.parameter | Where-Object Name -EQ $parameterName
-
-				# Should be a description for every parameter
-				It "gets help for parameter: $parameterName : in $commandName" {
-					# `$parameterHelp.Description.Text | Should -Not -BeNullOrEmpty` fails for -Settings paramter
-					# without explicit [string] casting on the Text property
-					$parameterHelp.Description.Text | Should -Not -BeNullOrEmpty
+				else {
+					[System.Boolean]::Parse($parameterHelp.pipelineInput)
 				}
 
-				# Required value in Help should match IsMandatory property of parameter
-				It "help for $parameterName parameter in $commandName has correct Mandatory value" {
-					$codeMandatory = $parameter.IsMandatory.toString()
-					$parameterHelp.Required | Should -Be $codeMandatory
-				}
+				$parameterHelpPipelineInput | Should -Be $parameterAttribute.ValueFromPipelineByPropertyName `
+					-Because "Parameter $parameterName of command $CommandName and parameter set $($parameterAttribute.ParameterSetName) has correct ValueFromPipelineByPropertyName attribute"
 
-				# Parameter type in Help should match code
-				It "help for $commandName has correct parameter type for $parameterName" {
-					$codeType = $parameter.ParameterType.Name
-					# To avoid calling Trim method on a null object.
-					$helpType = if ($parameterHelp.parameterValue) { $parameterHelp.parameterValue.Trim() }
-					$helpType | Should -Be $codeType
+				if ($parameterHelp.pipelineInput -eq 'True (ByPropertyName, ByValue)') {
+					$parameterAttribute.ValueFromPipeline | Should -BeTrue `
+						-Because "Parameter $parameterName of command $CommandName and parameter set $($parameterAttribute.ParameterSetName) has correct ValueFromPipeline attribute"
 				}
 			}
+		}
 
-			foreach ($helpParm in $HelpParameterNames) {
-				if ($helpParm -in $paramBlackList) {
-					continue
-				}
-				# Shouldn't find extra parameters in help.
-				It "finds help parameter in code: $helpParm" {
-					$helpParm -in $parameterNames | Should -BeTrue
-				}
+		foreach ($helpParam in $HelpParameterNames) {
+			if ($helpParam -in $paramBlockList) {
+				continue
 			}
+			$helpParam -in $parameterNames | Should -BeTrue -Because "There should be no extra parameters in help. '$helpParam' was not in '$parameterNames'"
 		}
 	}
 }
diff --git a/Tests/Engine/RuleSuppression.tests.ps1 b/Tests/Engine/RuleSuppression.tests.ps1
index 5aeff14e9..c014dbc12 100644
--- a/Tests/Engine/RuleSuppression.tests.ps1
+++ b/Tests/Engine/RuleSuppression.tests.ps1
@@ -1,43 +1,49 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\RuleSuppression.ps1")
-$violations = Invoke-ScriptAnalyzer "$PSScriptRoot\RuleSuppression.ps1"
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
 
-$ruleSuppressionBad = @'
-Function do-something
-{
-    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "username")]
-    Param(
-    $username,
-    $password
-    )
-}
+    $violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\RuleSuppression.ps1")
+    $violations = Invoke-ScriptAnalyzer "$PSScriptRoot\RuleSuppression.ps1"
+
+    $ruleSuppressionBad = @'
+    Function do-something
+    {
+        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "username")]
+        Param(
+        $username,
+        $password
+        )
+    }
 '@
 
-$ruleSuppressionInConfiguration = @'
-Configuration xFileUpload
-{
-[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")]
-param ([string] $decryptedPassword)
-$securePassword = ConvertTo-SecureString $decryptedPassword -AsPlainText -Force
-}
+    $ruleSuppressionInConfiguration = @'
+    Configuration xFileUpload
+    {
+    [Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingConvertToSecureStringWithPlainText", "")]
+    param ([string] $decryptedPassword)
+    $securePassword = ConvertTo-SecureString $decryptedPassword -AsPlainText -Force
+    }
 '@
 
-# If function doesn't starts at offset 0, then the test case fails before commit b551211
-$ruleSuppressionAvoidUsernameAndPassword = @'
+    # If function doesn't starts at offset 0, then the test case fails before commit b551211
+    $ruleSuppressionAvoidUsernameAndPassword = @'
 
-function SuppressUserAndPwdRule()
-{
-    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "")]
-    [CmdletBinding()]
-    param
-    (
-        [System.String] $username,
-        [System.String] $password
-    )
-}
+    function SuppressUserAndPwdRule()
+    {
+        [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingUserNameAndPassWordParams", "")]
+        [CmdletBinding()]
+        param
+        (
+            [System.String] $username,
+            [System.String] $password
+        )
+    }
 '@
+}
+
 
 Describe "RuleSuppressionWithoutScope" {
     Context "Function" {
@@ -56,7 +62,6 @@ Describe "RuleSuppressionWithoutScope" {
               -SuppressedOnly
             $ruleViolations.Count | Should -Be 1
 	    }
-
     }
 
     Context "Script" {
@@ -94,6 +99,151 @@ function SuppressPwdParam()
               -SuppressedOnly
             $ruleViolations.Count | Should -Be 1
         }
+
+        It "Records multiple suppressions applied to a single diagnostic" {
+            $script = @'
+function MyFunc
+{
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "password1", Justification='a')]
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "password1", Justification='b')]
+    param(
+        [string]$password1,
+        [string]$password2
+    )
+}
+'@
+
+            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $script -IncludeRule 'PSAvoidUsingPlainTextForPassword'
+            $suppressions = Invoke-ScriptAnalyzer -ScriptDefinition $script -SuppressedOnly -IncludeRule 'PSAvoidUsingPlainTextForPassword'
+
+            $diagnostics | Should -HaveCount 1
+            $diagnostics[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[0].RuleSuppressionID | Should -BeExactly "password2"
+            $diagnostics[0].IsSuppressed | Should -BeFalse
+
+            $suppressions | Should -HaveCount 1
+            $suppressions[0].IsSuppressed | Should -BeTrue
+            $suppressions[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $suppressions[0].RuleSuppressionID | Should -BeExactly "password1"
+            $suppressions[0].Suppression | Should -HaveCount 2
+            $suppressions[0].Suppression.Justification | Sort-Object | Should -Be @('a', 'b')
+        }
+
+        It "Records multiple suppressions applied to a single diagnostic when they have identical justifications" {
+            $script = @'
+function MyFunc
+{
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "password1", Justification='a')]
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "password1", Justification='a')]
+    param(
+        [string]$password1,
+        [string]$password2
+    )
+}
+'@
+
+            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $script -IncludeRule 'PSAvoidUsingPlainTextForPassword'
+            $suppressions = Invoke-ScriptAnalyzer -ScriptDefinition $script -SuppressedOnly -IncludeRule 'PSAvoidUsingPlainTextForPassword'
+
+            $diagnostics | Should -HaveCount 1
+            $diagnostics[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[0].RuleSuppressionID | Should -BeExactly "password2"
+
+            $suppressions | Should -HaveCount 1
+            $suppressions[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $suppressions[0].RuleSuppressionID | Should -BeExactly "password1"
+            $suppressions[0].Suppression | Should -HaveCount 2
+            $suppressions[0].Suppression.Justification | Sort-Object | Should -Be @('a', 'a')
+        }
+
+        It "Includes both emitted and suppressed diagnostics when -IncludeSuppressed is used" {
+            $script = @'
+function MyFunc
+{
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "password1", Justification='a')]
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "password1", Justification='a')]
+    param(
+        [string]$password1,
+        [string]$password2
+    )
+}
+'@
+
+            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $script -IncludeRule 'PSAvoidUsingPlainTextForPassword' -IncludeSuppressed
+
+            $diagnostics | Should -HaveCount 2
+            $diagnostics[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[0].RuleSuppressionID | Should -BeExactly "password2"
+            $diagnostics[0].IsSuppressed | Should -BeFalse
+
+            $diagnostics[1].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[1].RuleSuppressionID | Should -BeExactly "password1"
+            $diagnostics[1].Suppression | Should -HaveCount 2
+            $diagnostics[1].Suppression.Justification | Sort-Object | Should -Be @('a', 'a')
+            $diagnostics[1].IsSuppressed | Should -BeTrue
+        }
+
+
+        It "Records no suppressions for a different rule" {
+            $script = @'
+function MyFunc
+{
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("DifferentRule", "password1", Justification='a')]
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("DifferentRule", "password1", Justification='b')]
+    param(
+        [string]$password1,
+        [string]$password2
+    )
+}
+'@
+
+            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $script -IncludeRule 'PSAvoidUsingPlainTextForPassword'
+            $suppressions = Invoke-ScriptAnalyzer -ScriptDefinition $script -SuppressedOnly -IncludeRule 'PSAvoidUsingPlainTextForPassword'
+
+            $diagnostics | Should -HaveCount 2
+            $diagnostics[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[0].RuleSuppressionID | Should -BeExactly "password1"
+            $diagnostics[1].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[1].RuleSuppressionID | Should -BeExactly "password2"
+
+            $suppressions | Should -BeNullOrEmpty
+        }
+
+        It "Issues an error for a unapplied suppression with a suppression ID" {
+            $script = @'
+function MyFunc
+{
+    [System.Diagnostics.CodeAnalysis.SuppressMessage("PSAvoidUsingPlainTextForPassword", "banana")]
+    param(
+        [string]$password1,
+        [string]$password2
+    )
+}
+'@
+
+            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $script -IncludeRule 'PSAvoidUsingPlainTextForPassword' -ErrorVariable diagErr -ErrorAction SilentlyContinue
+            $suppressions = Invoke-ScriptAnalyzer -ScriptDefinition $script -SuppressedOnly -IncludeRule 'PSAvoidUsingPlainTextForPassword' -ErrorVariable suppErr -ErrorAction SilentlyContinue
+
+            $diagnostics | Should -HaveCount 2
+            $diagnostics[0].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[0].RuleSuppressionID | Should -BeExactly "password1"
+            $diagnostics[1].RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+            $diagnostics[1].RuleSuppressionID | Should -BeExactly "password2"
+
+            $suppressions | Should -BeNullOrEmpty
+
+            # For some reason these tests fail in WinPS, but the actual output is as expected
+            if ($PSEdition -eq 'Core')
+            {
+                $diagErr | Should -HaveCount 1
+                $diagErr.TargetObject.RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+                $diagErr.TargetObject.RuleSuppressionID | Should -BeExactly "banana"
+
+                $suppErr | Should -HaveCount 1
+                $suppErr.TargetObject.RuleName | Should -BeExactly "PSAvoidUsingPlainTextForPassword"
+                $suppErr.TargetObject.RuleSuppressionID | Should -BeExactly "banana"
+            }
+        }
     }
 
     Context "Rule suppression within DSC Configuration definition" {
@@ -103,30 +253,27 @@ function SuppressPwdParam()
         }
     }
 
-    if (!$testingLibraryUsage)
-    {
-        Context "Bad Rule Suppression" {
-            It "Throws a non-terminating error" {
-                Invoke-ScriptAnalyzer -ScriptDefinition $ruleSuppressionBad -IncludeRule "PSAvoidUsingUserNameAndPassWordParams" -ErrorVariable errorRecord -ErrorAction SilentlyContinue
-                $errorRecord.Count | Should -Be 1
-                $errorRecord.FullyQualifiedErrorId | Should -Match "suppression message attribute error"
-            }
+    Context "Bad Rule Suppression" -Skip:$testingLibraryUsage {
+        It "Throws a non-terminating error" {
+            Invoke-ScriptAnalyzer -ScriptDefinition $ruleSuppressionBad -IncludeRule "PSAvoidUsingUserNameAndPassWordParams" -ErrorVariable errorRecord -ErrorAction SilentlyContinue
+            $errorRecord.Count | Should -Be 1
+            $errorRecord.FullyQualifiedErrorId | Should -Match "suppression message attribute error"
         }
+    }
 
-        Context "External Rule Suppression" {
+    Context "External Rule Suppression" -Skip:$testingLibraryUsage {
+        It "Suppresses violation of an external ast rule" {
             $externalRuleSuppression = @'
-[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('CommunityAnalyzerRules\Measure-WriteHost','')]
-param() # without the param block, powershell parser throws up!
-Write-Host "write-host"
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('CommunityAnalyzerRules\Measure-WriteHost','')]
+    param() # without the param block, powershell parser throws up!
+    Write-Host "write-host"
 '@
-            It "Suppresses violation of an external ast rule" {
-                Invoke-ScriptAnalyzer `
-                    -ScriptDefinition $externalRuleSuppression `
-                    -CustomRulePath (Join-Path $PSScriptRoot "CommunityAnalyzerRules") `
-                    -OutVariable ruleViolations `
-                    -SuppressedOnly
-                $ruleViolations.Count | Should -Be 1
-            }
+            Invoke-ScriptAnalyzer `
+                -ScriptDefinition $externalRuleSuppression `
+                -CustomRulePath (Join-Path $PSScriptRoot "CommunityAnalyzerRules") `
+                -OutVariable ruleViolations `
+                -SuppressedOnly
+            $ruleViolations.Count | Should -Be 1
         }
     }
 }
diff --git a/Tests/Engine/RuleSuppressionClass.tests.ps1 b/Tests/Engine/RuleSuppressionClass.tests.ps1
index 22e5fcd20..28c3aad22 100644
--- a/Tests/Engine/RuleSuppressionClass.tests.ps1
+++ b/Tests/Engine/RuleSuppressionClass.tests.ps1
@@ -1,10 +1,15 @@
-﻿$script:skipForV3V4 = $true
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
-    $script:skipForV3V4 = $false
-}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $script:skipForV3V4 = $true
+    if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
+        $script:skipForV3V4 = $false
+    }
 
-$violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\RuleSuppression.ps1")
-$violations = Invoke-ScriptAnalyzer "$PSScriptRoot\RuleSuppression.ps1"
+    $violationsUsingScriptDefinition = Invoke-ScriptAnalyzer -ScriptDefinition (Get-Content -Raw "$PSScriptRoot\RuleSuppression.ps1")
+    $violations = Invoke-ScriptAnalyzer "$PSScriptRoot\RuleSuppression.ps1"
+}
 
 Describe "RuleSuppressionWithoutScope" {
 
diff --git a/Tests/Engine/Settings.tests.ps1 b/Tests/Engine/Settings.tests.ps1
index a6fd41eb8..917b4ed8e 100644
--- a/Tests/Engine/Settings.tests.ps1
+++ b/Tests/Engine/Settings.tests.ps1
@@ -1,7 +1,12 @@
-$settingsTestDirectory = [System.IO.Path]::Combine($PSScriptRoot, "SettingsTest")
-$project1Root = [System.IO.Path]::Combine($settingsTestDirectory, "Project1")
-$project2Root = [System.IO.Path]::Combine($settingsTestDirectory, "Project2")
-$settingsTypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Settings'
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $settingsTestDirectory = [System.IO.Path]::Combine($PSScriptRoot, "SettingsTest")
+    $project1Root = [System.IO.Path]::Combine($settingsTestDirectory, "Project1")
+    $project2Root = [System.IO.Path]::Combine($settingsTestDirectory, "Project2")
+    $settingsTypeName = 'Microsoft.Windows.PowerShell.ScriptAnalyzer.Settings'
+}
 
 Describe "Settings Precedence" {
     Context "settings object is explicit" {
@@ -35,6 +40,8 @@ Describe "Settings Precedence" {
     }
 }
 
+$customRuleParameterTestCases = @('IncludeDefaultRules', 'RecurseCustomRulePath').ForEach{ @{ ParamName = $_ } }
+
 Describe "Settings Class" {
     Context "When an empty hashtable is provided" {
 
@@ -43,11 +50,11 @@ Describe "Settings Class" {
             @{ Name = "ExcludeRules" }
             @{ Name = "Severity" }
             @{ Name = "RuleArguments" }
-            ) {
-                Param($Name)
+        ) {
+            Param($Name)
 
-                $settings = New-Object -TypeName $settingsTypeName -ArgumentList @{}
-                ${settings}.${Name}.Count | Should -Be 0
+            $settings = New-Object -TypeName $settingsTypeName -ArgumentList @{}
+            ${settings}.${Name}.Count | Should -Be 0
         }
 
         It "Should be able to parse empty settings hashtable from settings file" {
@@ -72,12 +79,37 @@ Describe "Settings Class" {
         }
     }
 
-    Context "When rule arguments are provided in a hashtable" {
+    Context 'When rule arguments are provided in a hashtable' {
+        BeforeAll {
+            $settingsHashtable = @{
+                Rules = @{
+                    PSAvoidUsingCmdletAliases = @{
+                        AllowList = @('cd', 'cp')
+                    }
+                }
+            }
+            $settings = New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable
+        }
+
+        It 'Should return the rule arguments' {
+            $settings.RuleArguments['PSAvoidUsingCmdletAliases']['AllowList'].Count | Should -Be 2
+            $settings.RuleArguments['PSAvoidUsingCmdletAliases']['AllowList'][0] | Should -Be 'cd'
+            $settings.RuleArguments['PSAvoidUsingCmdletAliases']['AllowList'][1] | Should -Be 'cp'
+        }
+
+        It 'Should Be case insensitive' {
+            $settings.RuleArguments['psAvoidUsingCmdletAliases']['AllowList'].Count | Should -Be 2
+            $settings.RuleArguments['psAvoidUsingCmdletAliases']['AllowList'][0] | Should -Be 'cd'
+            $settings.RuleArguments['psAvoidUsingCmdletAliases']['AllowList'][1] | Should -Be 'cp'
+        }
+    }
+
+    Context 'When rule arguments are provided in a hashtable (legacy argument name)' {
         BeforeAll {
             $settingsHashtable = @{
                 Rules = @{
                     PSAvoidUsingCmdletAliases = @{
-                        WhiteList = @("cd", "cp")
+                        allowlist = @("cd", "cp")
                     }
                 }
             }
@@ -85,36 +117,34 @@ Describe "Settings Class" {
         }
 
         It "Should return the rule arguments" {
-            $settings.RuleArguments["PSAvoidUsingCmdletAliases"]["WhiteList"].Count | Should -Be 2
-            $settings.RuleArguments["PSAvoidUsingCmdletAliases"]["WhiteList"][0] | Should -Be "cd"
-            $settings.RuleArguments["PSAvoidUsingCmdletAliases"]["WhiteList"][1] | Should -Be "cp"
+            $settings.RuleArguments["PSAvoidUsingCmdletAliases"]["allowlist"].Count | Should -Be 2
+            $settings.RuleArguments["PSAvoidUsingCmdletAliases"]["allowlist"][0] | Should -Be "cd"
+            $settings.RuleArguments["PSAvoidUsingCmdletAliases"]["allowlist"][1] | Should -Be "cp"
         }
 
         It "Should Be case insensitive" {
-            $settings.RuleArguments["psAvoidUsingCmdletAliases"]["whiteList"].Count | Should -Be 2
-            $settings.RuleArguments["psAvoidUsingCmdletAliases"]["whiteList"][0] | Should -Be "cd"
-            $settings.RuleArguments["psAvoidUsingCmdletAliases"]["whiteList"][1] | Should -Be "cp"
+            $settings.RuleArguments["psAvoidUsingCmdletAliases"]["allowlist"].Count | Should -Be 2
+            $settings.RuleArguments["psAvoidUsingCmdletAliases"]["allowlist"][0] | Should -Be "cd"
+            $settings.RuleArguments["psAvoidUsingCmdletAliases"]["allowlist"][1] | Should -Be "cp"
         }
     }
 
     Context "When a settings file path is provided" {
         BeforeAll {
             $settings = New-Object -TypeName $settingsTypeName `
-                              -ArgumentList ([System.IO.Path]::Combine($project1Root, "ExplicitSettings.psd1"))
+                -ArgumentList ([System.IO.Path]::Combine($project1Root, "ExplicitSettings.psd1"))
+            $expectedNumberOfIncludeRules = 3
         }
 
-        $expectedNumberOfIncludeRules = 3
-        It "Should return $expectedNumberOfIncludeRules IncludeRules" {
-            $settings.IncludeRules.Count | Should -Be $expectedNumberOfIncludeRules
+        It "Should return correct IncludeRules count" {
+            $settings.IncludeRules.Count | Should -Be 3
         }
 
-        $expectedNumberOfExcludeRules = 3
-        It "Should return $expectedNumberOfExcludeRules ExcludeRules" {
-            $settings.ExcludeRules.Count | Should -Be $expectedNumberOfExcludeRules
+        It "Should return correct ExcludeRules count" {
+            $settings.ExcludeRules.Count | Should -Be 3
         }
 
-        $expectedNumberOfRuleArguments = 3
-        It "Should return $expectedNumberOfRuleArguments rule argument" {
+        It "Should return correct rule argument count" {
             $settings.RuleArguments.Count | Should -Be 3
         }
 
@@ -157,103 +187,48 @@ Describe "Settings Class" {
 
         It "Should detect the parameter in a settings file" {
             $settings = New-Object -TypeName $settingsTypeName `
-                              -ArgumentList ([System.IO.Path]::Combine($project1Root, "CustomRulePathSettings.psd1"))
+                -ArgumentList ([System.IO.Path]::Combine($project1Root, "CustomRulePathSettings.psd1"))
             $settings.CustomRulePath.Count | Should -Be 2
         }
     }
 
-    @("IncludeDefaultRules", "RecurseCustomRulePath") | ForEach-Object {
-        $paramName = $_
-        Context "When $paramName parameter is provided" {
-            It "Should correctly set the value if a boolean is given - true" {
-                $settingsHashtable = @{}
-                $settingsHashtable.Add($paramName, $true)
+    Context "When custom rule path relates parameters are provided" {
+        It "<ParamName>: Should correctly set the value if a boolean is given - true" -TestCases $customRuleParameterTestCases {
+            $settingsHashtable = @{}
+            $settingsHashtable.Add($ParamName, $true)
 
-                $settings = New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable
-                $settings."$paramName" | Should -BeTrue
-            }
+            $settings = New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable
+            $settings."$ParamName" | Should -BeTrue
+        }
 
-            It "Should correctly set the value if a boolean is given - false" {
-                $settingsHashtable = @{}
-                $settingsHashtable.Add($paramName, $false)
+        It "<ParamName>: Should correctly set the value if a boolean is given - false" -TestCases $customRuleParameterTestCases {
+            $settingsHashtable = @{}
+            $settingsHashtable.Add($ParamName, $false)
 
-                $settings = New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable
-                $settings."$paramName" | Should -BeFalse
-            }
+            $settings = New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable
+            $settings."$ParamName" | Should -BeFalse
+        }
 
-            It "Should throw if a non-boolean value is given" {
-                $settingsHashtable = @{}
-                $settingsHashtable.Add($paramName, "some random string")
+        It "<ParamName>: Should throw if a non-boolean value is given" -TestCases $customRuleParameterTestCases {
+            $settingsHashtable = @{}
+            $settingsHashtable.Add($ParamName, "some random string")
 
-                { New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable } | Should -Throw
-            }
+            { New-Object -TypeName $settingsTypeName -ArgumentList $settingsHashtable } | Should -Throw
+        }
 
-            It "Should detect the parameter in a settings file" {
-                $settings = New-Object -TypeName $settingsTypeName `
-                    -ArgumentList ([System.IO.Path]::Combine($project1Root, "CustomRulePathSettings.psd1"))
-                $settings."$paramName" | Should -BeTrue
-            }
+        It "<ParamName>: Should detect the parameter in a settings file" -TestCases $customRuleParameterTestCases {
+            $settings = New-Object -TypeName $settingsTypeName `
+                -ArgumentList ([System.IO.Path]::Combine($project1Root, "CustomRulePathSettings.psd1"))
+            $settings."$ParamName" | Should -BeTrue
         }
     }
 
     Context "Settings GetSafeValue API" {
         BeforeAll {
-            $gsvSimpleTests = @(
-                @{ Expr = '0' }
-                @{ Expr = '-2'}
-                @{ Expr = '-2.5'}
-                @{ Expr = '$true' }
-                @{ Expr = '$false' }
-                @{ Expr = '123124' }
-                @{ Expr = '0.142' }
-                @{ Expr = '"Hello"' }
-                @{ Expr = '"Well then"' }
-                @{ Expr = '$null' }
-            )
-
-            $gsvArrayTests = @(
-                @{ Expr = '1, 2, 3'; Count = 3 }
-                @{ Expr = '"One","Two","Three"'; Count = 3 }
-                @{ Expr = '@(1,2,3,4)'; Count = 4 }
-                @{ Expr = '@("A","B","C")'; Count = 3 }
-                @{ Expr = '@()'; Count = 0 }
-                @{ Expr = '@(7)'; Count = 1 }
-                @{ Expr = "'1',`n'2',`n'3'"; Count = 3 }
-                @{ Expr = "@(1`n3`n5`n7)"; Count = 4 }
-                @{ Expr = "'1',`r`n'2',`r`n'3'"; Count = 3 }
-                @{ Expr = "@(1`r`n3`r`n5`r`n7)"; Count = 4 }
-                @{ Expr = "@(1,2,3`n7,8,9)"; Count = 6 }
-            )
-
-            $gsvHashtableTests = @(
-                @{ Expr = '@{}' }
-                @{ Expr = '@{ Key = "Value" }' }
-                @{ Expr = '@{ Item = @(1, 2, 3) }' }
-                @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = "Hello"; Setting2 = 42 } } }' }
-                @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = 7,4,6,1; Setting2 = 42 } } }' }
-                @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(); Setting2 = 42 } } }' }
-                @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(9, 2, 1, "Hello"); Setting2 = 42 } } }' }
-                @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(9, @(3, 6), 1, "Hello"); Setting2 = 42 } } }' }
-                @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(9, @{ x = 10; y = 11 }, 1, "Hello"); Setting2 = 42 } } }' }
-            )
-
-            $gsvThrowTests = @(
-                @{ Expr = '$var' }
-                @{ Expr = '' }
-                @{ Expr = '3+7' }
-                @{ Expr = '- 2.5'}
-                @{ Expr = '-not $true' }
-                @{ Expr = '@(1, Get-Thing)' }
-                @{ Expr = '@{ Key = Get-Thing }' }
-                @{ Expr = '@{ Thing = $true;7 ' }
-                @{ Expr = '@{ Thing = @(Asset-Thing;10) ' }
-                @{ Expr = ';)' }
-            )
-
             function ShouldBeDeeplyEqual
             {
                 param(
-                    [Parameter(Position=0)]
+                    [Parameter(Position = 0)]
                     $To,
 
                     [Parameter(ValueFromPipeline)]
@@ -273,7 +248,7 @@ Describe "Settings Class" {
                         $inputVal = $InputObject[$toKey]
                         if ($inputVal -is [array])
                         {
-                            @(,$inputVal) | ShouldBeDeeplyEqual -To $To[$toKey]
+                            @(, $inputVal) | ShouldBeDeeplyEqual -To $To[$toKey]
                             continue
                         }
                         $inputVal | ShouldBeDeeplyEqual -To $To[$toKey]
@@ -289,9 +264,9 @@ Describe "Settings Class" {
                         $inputVal = $InputObject[$i]
                         if ($inputVal -is [array])
                         {
-                            @(,$inputVal) | ShouldBeDeeplyEqual -To $To[$i]
+                            @(, $inputVal) | ShouldBeDeeplyEqual -To $To[$i]
                             continue
-            }
+                        }
                         $inputVal | ShouldBeDeeplyEqual -To $To[$i]
                     }
                     return
@@ -301,25 +276,36 @@ Describe "Settings Class" {
             }
         }
 
-        It "Safely gets the simple value <Expr>" -TestCases $gsvSimpleTests {
+        It "Safely gets the simple value <Expr>" {
             param([string]$Expr)
 
             $pwshVal = Invoke-Expression $Expr
 
             $exprAst = [System.Management.Automation.Language.Parser]::ParseInput($Expr, [ref]$null, [ref]$null)
-            $exprAst = $exprAst.Find({$args[0] -is [System.Management.Automation.Language.ExpressionAst]}, $true)
+            $exprAst = $exprAst.Find( { $args[0] -is [System.Management.Automation.Language.ExpressionAst] }, $true)
             $gsvVal = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper]::GetSafeValueFromExpressionAst($exprAst)
 
             $gsvVal | Should -Be $pwshVal
-        }
-
-        It "Safely gets the array value <Expr>" -TestCases $gsvArrayTests {
+        } -TestCases @(
+            @{ Expr = '0' }
+            @{ Expr = '-2' }
+            @{ Expr = '-2.5' }
+            @{ Expr = '$true' }
+            @{ Expr = '$false' }
+            @{ Expr = '123124' }
+            @{ Expr = '0.142' }
+            @{ Expr = '"Hello"' }
+            @{ Expr = '"Well then"' }
+            @{ Expr = '$null' }
+        )
+
+        It "Safely gets the array value <Expr>" {
             param([string]$Expr)
 
             $pwshVal = Invoke-Expression $Expr
 
             $exprAst = [System.Management.Automation.Language.Parser]::ParseInput($Expr, [ref]$null, [ref]$null)
-            $exprAst = $exprAst.Find({$args[0] -is [System.Management.Automation.Language.ExpressionAst]}, $true)
+            $exprAst = $exprAst.Find( { $args[0] -is [System.Management.Automation.Language.ExpressionAst] }, $true)
             $gsvVal = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper]::GetSafeValueFromExpressionAst($exprAst)
 
 
@@ -327,27 +313,49 @@ Describe "Settings Class" {
             # but we also don't create the array ourselves
             $gsvVal.GetType().IsArray | Should -BeTrue
 
-            @(,$gsvVal) | ShouldBeDeeplyEqual -To $pwshVal
-        }
-
-        It "Safely gets the hashtable value <Expr>" -TestCases $gsvHashtableTests {
+            @(, $gsvVal) | ShouldBeDeeplyEqual -To $pwshVal
+        } -TestCases @(
+            @{ Expr = '1, 2, 3'; Count = 3 }
+            @{ Expr = '"One","Two","Three"'; Count = 3 }
+            @{ Expr = '@(1,2,3,4)'; Count = 4 }
+            @{ Expr = '@("A","B","C")'; Count = 3 }
+            @{ Expr = '@()'; Count = 0 }
+            @{ Expr = '@(7)'; Count = 1 }
+            @{ Expr = "'1',`n'2',`n'3'"; Count = 3 }
+            @{ Expr = "@(1`n3`n5`n7)"; Count = 4 }
+            @{ Expr = "'1',`r`n'2',`r`n'3'"; Count = 3 }
+            @{ Expr = "@(1`r`n3`r`n5`r`n7)"; Count = 4 }
+            @{ Expr = "@(1,2,3`n7,8,9)"; Count = 6 }
+        )
+
+        It "Safely gets the hashtable value <Expr>" {
             param([string]$Expr)
 
             $pwshVal = Invoke-Expression $Expr
 
             $exprAst = [System.Management.Automation.Language.Parser]::ParseInput($Expr, [ref]$null, [ref]$null)
-            $exprAst = $exprAst.Find({$args[0] -is [System.Management.Automation.Language.ExpressionAst]}, $true)
+            $exprAst = $exprAst.Find( { $args[0] -is [System.Management.Automation.Language.ExpressionAst] }, $true)
             $gsvVal = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper]::GetSafeValueFromExpressionAst($exprAst)
 
             $gsvVal | Should -BeOfType [hashtable]
             $gsvVal | ShouldBeDeeplyEqual -To $pwshVal
-        }
-
-        It "Rejects the input <Expr>" -TestCases $gsvThrowTests {
+        } -TestCases @(
+            @{ Expr = '@{}' }
+            @{ Expr = '@{ Key = "Value" }' }
+            @{ Expr = '@{ Item = @(1, 2, 3) }' }
+            @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = "Hello"; Setting2 = 42 } } }' }
+            @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = 7,4,6,1; Setting2 = 42 } } }' }
+            @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(); Setting2 = 42 } } }' }
+            @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(9, 2, 1, "Hello"); Setting2 = 42 } } }' }
+            @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(9, @(3, 6), 1, "Hello"); Setting2 = 42 } } }' }
+            @{ Expr = '@{ Rules = @{ MyRule = @{ Setting1 = @(9, @{ x = 10; y = 11 }, 1, "Hello"); Setting2 = 42 } } }' }
+        )
+
+        It "Rejects the input <Expr>" {
             param([string]$Expr)
 
             $exprAst = [System.Management.Automation.Language.Parser]::ParseInput($Expr, [ref]$null, [ref]$null)
-            $exprAst = $exprAst.Find({$args[0] -is [System.Management.Automation.Language.ExpressionAst]}, $true)
+            $exprAst = $exprAst.Find( { $args[0] -is [System.Management.Automation.Language.ExpressionAst] }, $true)
 
             $expectedError = 'InvalidDataException'
             if ($null -eq $exprAst)
@@ -356,6 +364,47 @@ Describe "Settings Class" {
             }
 
             { $gsvVal = [Microsoft.Windows.PowerShell.ScriptAnalyzer.Helper]::GetSafeValueFromExpressionAst($exprAst) } | Should -Throw -ErrorId $expectedError
+        } -TestCases @(
+            @{ Expr = '$var' }
+            @{ Expr = '' }
+            @{ Expr = '3+7' }
+            @{ Expr = '- 2.5' }
+            @{ Expr = '-not $true' }
+            @{ Expr = '@(1, Get-Thing)' }
+            @{ Expr = '@{ Key = Get-Thing }' }
+            @{ Expr = '@{ Thing = $true;7 ' }
+            @{ Expr = '@{ Thing = @(Asset-Thing;10) ' }
+            @{ Expr = ';)' }
+        )
+    }
+
+    Context "FindSettingsMode" {
+        BeforeAll {
+            $findSettingsMode = ($settingsTypeName -as [type]).GetMethod(
+                'FindSettingsMode',
+                [System.Reflection.BindingFlags]::NonPublic -bor [System.Reflection.BindingFlags]::Static)
+
+            $outputObject = [System.Object]::new()
+        }
+
+        It "Should detect hashtable" {
+            $settings = @{}
+            $findSettingsMode.Invoke($null, @($settings, $null, [ref]$outputObject)) | Should -Be "Hashtable"
+        }
+
+        It "Should detect hashtable wrapped by a PSObject" {
+            $settings = [PSObject]@{} # Force the settings hashtable to be wrapped
+            $findSettingsMode.Invoke($null, @($settings, $null, [ref]$outputObject)) | Should -Be "Hashtable"
+        }
+
+        It "Should detect string" {
+            $settings = ""
+            $findSettingsMode.Invoke($null, @($settings, $null, [ref]$outputObject)) | Should -Be "File"
+        }
+
+        It "Should detect string wrapped by a PSObject" {
+            $settings = [PSObject]"" # Force the settings string to be wrapped
+            $findSettingsMode.Invoke($null, @($settings, $null, [ref]$outputObject)) | Should -Be "File"
         }
     }
 }
diff --git a/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1 b/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1
index 9ac432ef9..bc9c33a89 100644
--- a/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1
+++ b/Tests/Engine/SettingsTest/Issue828/PSScriptAnalyzerSettings.psd1
@@ -1,7 +1,7 @@
 @{
     Severity     = @(
-        'Error', 
-        'Warning', 
+        'Error',
+        'Warning',
         'Information'
     )
     ExcludeRules = @(
@@ -14,8 +14,8 @@
             CheckHashtable = $true
         }
         PSAvoidUsingCmdletAliases  = @{
-            # only whitelist verbs from *-Object cmdlets
-            Whitelist = @(
+            # only allowlist verbs from *-Object cmdlets
+            allowlist = @(
                 '%',
                 '?',
                 'compare',
@@ -60,4 +60,4 @@
             CheckSeparator = $true
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Tests/Engine/SettingsTest/Project1/ExplicitSettings.psd1 b/Tests/Engine/SettingsTest/Project1/ExplicitSettings.psd1
index 3e7c8caa3..29fb7bce2 100644
--- a/Tests/Engine/SettingsTest/Project1/ExplicitSettings.psd1
+++ b/Tests/Engine/SettingsTest/Project1/ExplicitSettings.psd1
@@ -3,7 +3,7 @@
     "ExcludeRules" = @("PSShouldProcess", "PSAvoidUsingWMICmdlet", "PSUseCmdletCorrectly")
     "rules"        = @{
         PSAvoidUsingCmdletAliases  = @{
-            WhiteList = @("cd", "cp")
+            allowlist = @("cd", "cp")
         }
 
         PSUseConsistentIndentation = @{
diff --git a/Tests/Engine/TextEdit.tests.ps1 b/Tests/Engine/TextEdit.tests.ps1
index 25239d52a..894a0d0cf 100644
--- a/Tests/Engine/TextEdit.tests.ps1
+++ b/Tests/Engine/TextEdit.tests.ps1
@@ -1,5 +1,7 @@
 Describe "TextEdit Class" {
-    $type = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TextEdit]
+    BeforeAll {
+        $type = [Microsoft.Windows.PowerShell.ScriptAnalyzer.TextEdit]
+    }
 
     Context "Object construction" {
         It "creates the object with correct properties" {
@@ -13,14 +15,14 @@ Describe "TextEdit Class" {
 
         It "throws if end line number is less than start line number" {
             $text = "Get-ChildItem"
-            {New-Object -TypeName $type -ArgumentList @(2, 1, 1, ($text.Length + 1), $text)} |
+            { New-Object -TypeName $type -ArgumentList @(2, 1, 1, ($text.Length + 1), $text) } |
                 Should -Throw
         }
 
         It "throws if end column number is less than start column number for same line" {
             $text = "start-process"
-            {New-Object -TypeName $type -ArgumentList @(1, 2, 1, 1, $text)} |
-                    Should -Throw
-            }
+            { New-Object -TypeName $type -ArgumentList @(1, 2, 1, 1, $text) } |
+                Should -Throw
         }
     }
+}
diff --git a/Tests/Engine/TokenOperations.tests.ps1 b/Tests/Engine/TokenOperations.tests.ps1
new file mode 100644
index 000000000..97fef3958
--- /dev/null
+++ b/Tests/Engine/TokenOperations.tests.ps1
@@ -0,0 +1,21 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+Describe "TokenOperations" {
+    It "Should return correct AST position for assignment operator in hash table" {
+        $scriptText = @'
+$h = @{
+    a = 72
+    b = @{ z = "hi" }
+}
+'@
+        $tokens = $null
+        $parseErrors = $null
+        $scriptAst = [System.Management.Automation.Language.Parser]::ParseInput($scriptText, [ref] $tokens, [ref] $parseErrors)
+        $tokenOperations = New-Object Microsoft.Windows.PowerShell.ScriptAnalyzer.TokenOperations -ArgumentList @($tokens, $scriptAst)
+        $operatorToken = $tokens | Where-Object { $_.Extent.StartLineNumber -eq 3 -and $_.Extent.StartColumnNumber -eq 14}
+        $hashTableAst = $tokenOperations.GetAstPosition($operatorToken)
+        $hashTableAst | Should -BeOfType [System.Management.Automation.Language.HashTableAst]
+        $hashTableAst.Extent.Text | Should -Be '@{ z = "hi" }'
+    }
+}
\ No newline at end of file
diff --git a/Tests/PSScriptAnalyzerTestHelper.psm1 b/Tests/PSScriptAnalyzerTestHelper.psm1
index 1601b5e17..a8c18ab86 100644
--- a/Tests/PSScriptAnalyzerTestHelper.psm1
+++ b/Tests/PSScriptAnalyzerTestHelper.psm1
@@ -1,3 +1,5 @@
+$script:SafeShould = (Get-Command -Module Pester -Name Should -ErrorAction Stop)
+
 Function Get-ExtentTextFromContent
 {
 	    Param(
@@ -48,23 +50,9 @@ Function Test-CorrectionExtentFromContent {
 	$corrections = $diagnosticRecord.SuggestedCorrections
 	$corrections.Count | Should -Be $correctionsCount
 	$corrections[0].Text | Should -Be $correctionText
-	Get-ExtentTextFromContent $corrections[0] $rawContent | `
-		       Should -Be $violationText
-}
-
-Function Test-PSEditionCoreCLR
-{
-    [bool]$IsCoreCLR
-}
+	$extent = Get-ExtentTextFromContent $corrections[0] $rawContent
 
-Function Test-PSVersionV3
-{
-	$PSVersionTable.PSVersion.Major -eq 3
-}
-
-Function Test-PSVersionV4
-{
-	$PSVersionTable.PSVersion.Major -eq 4
+	& $script:SafeShould -ActualValue $extent -Be $violationText
 }
 
 Function Get-Count
@@ -77,7 +65,4 @@ Function Get-Count
 Export-ModuleMember -Function Get-ExtentText
 Export-ModuleMember -Function Test-CorrectionExtent
 Export-ModuleMember -Function Test-CorrectionExtentFromContent
-Export-ModuleMember -Function Test-PSEditionCoreCLR
-Export-ModuleMember -Function Test-PSVersionV3
-Export-ModuleMember -Function Test-PSVersionV4
 Export-ModuleMember -Function Get-Count
diff --git a/Tests/Rules/AlignAssignmentStatement.tests.ps1 b/Tests/Rules/AlignAssignmentStatement.tests.ps1
index 1f3dbad0f..7558abf88 100644
--- a/Tests/Rules/AlignAssignmentStatement.tests.ps1
+++ b/Tests/Rules/AlignAssignmentStatement.tests.ps1
@@ -1,16 +1,20 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
 
-$ruleConfiguration = @{
-    Enable         = $true
-    CheckHashtable = $true
-}
+    $ruleConfiguration = @{
+        Enable         = $true
+        CheckHashtable = $true
+    }
 
-$settings = @{
-    IncludeRules = @("PSAlignAssignmentStatement")
-    Rules        = @{
-        PSAlignAssignmentStatement = $ruleConfiguration
+    $settings = @{
+        IncludeRules = @("PSAlignAssignmentStatement")
+        Rules        = @{
+            PSAlignAssignmentStatement = $ruleConfiguration
+        }
     }
 }
 
@@ -71,6 +75,33 @@ $x = @{ }
             Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Get-Count | Should -Be 0
 
         }
+
+        It "Should ignore if a hashtable has a single key-value pair on a single line" {
+            $def = @'
+$x = @{ 'key'="value" }
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Get-Count | Should -Be 0
+
+        }
+
+        It "Should ignore if a hashtable has a single key-value pair across multiple lines" {
+            $def = @'
+$x = @{ 
+    'key'="value" 
+}
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Get-Count | Should -Be 0
+
+        }
+
+        It "Should ignore if a hashtable has multiple key-value pairs on a single line" {
+            $def = @'
+$x = @{ 'key'="value"; 'key2'="value2"; 'key3WithLongerName'="value3" }
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Get-Count | Should -Be 0
+
+        }
+
     }
 
     Context "When assignment statements are in DSC Configuration" {
diff --git a/Tests/Rules/AllCompatibilityRules.Tests.ps1 b/Tests/Rules/AllCompatibilityRules.Tests.ps1
index 23864cbb5..115be6ebf 100644
--- a/Tests/Rules/AllCompatibilityRules.Tests.ps1
+++ b/Tests/Rules/AllCompatibilityRules.Tests.ps1
@@ -1,89 +1,77 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
-$script:fileContent = @'
-$assetDir = 'C:\ImportantFiles\'
-$archiveDir = 'C:\Archived\'
+BeforeAll {
+    $script:fileContent = @'
+    $assetDir = 'C:\ImportantFiles\'
+    $archiveDir = 'C:\Archived\'
 
-$runningOnWindows = -not ($IsLinux -or $IsMacOS)
-$zipCompressionLevel = 'Optimal'
-$includeBaseDirInZips = $true
+    $runningOnWindows = -not ($IsLinux -or $IsMacOS)
+    $zipCompressionLevel = 'Optimal'
+    $includeBaseDirInZips = $true
 
-if (-not (Test-Path $archiveDir))
-{
-    New-Item -Type Directory $archiveDir
-}
-
-Import-Module -FullyQualifiedName @{ ModuleName = 'MyArchiveUtilities'; ModuleVersion = '2.0' }
-
-$sigs = [System.Collections.Generic.List[System.Management.Automation.Signature]]::new()
-$filePattern = [System.Management.Automation.WildcardPattern]::Get('system*')
-foreach ($file in Get-ChildItem $assetDir -Recurse -Depth 1)
-{
-    if (-not $filePattern.IsMatch($file.Name))
+    if (-not (Test-Path $archiveDir))
     {
-        continue
+        New-Item -Type Directory $archiveDir
     }
 
-    if ($file.Name -like '*.dll')
-    {
-        $sig = Get-AuthenticodeSignature $file
-        $sigs.Add($sig)
-        continue
-    }
+    Import-Module -FullyQualifiedName @{ ModuleName = 'MyArchiveUtilities'; ModuleVersion = '2.0' }
 
-    if (Test-WithFunctionFromMyModule -File $file)
+    $sigs = [System.Collections.Generic.List[System.Management.Automation.Signature]]::new()
+    $filePattern = [System.Management.Automation.WildcardPattern]::Get('system*')
+    foreach ($file in Get-ChildItem $assetDir -Recurse -Depth 1)
     {
-        $destZip = Join-Path $archiveDir $file.BaseName
-        [System.IO.Compression.ZipFile]::CreateFromDirectory($file.FullName, "$destZip.zip", $zipCompressionLevel, $includeBaseDirInZips)
+        if (-not $filePattern.IsMatch($file.Name))
+        {
+            continue
+        }
+
+        if ($file.Name -like '*.dll')
+        {
+            $sig = Get-AuthenticodeSignature $file
+            $sigs.Add($sig)
+            continue
+        }
+
+        if (Test-WithFunctionFromMyModule -File $file)
+        {
+            $destZip = Join-Path $archiveDir $file.BaseName
+            [System.IO.Compression.ZipFile]::CreateFromDirectory($file.FullName, "$destZip.zip", $zipCompressionLevel, $includeBaseDirInZips)
+        }
     }
-}
 
-Write-Output $sigs
+    Write-Output $sigs
 '@
 
-$script:settingsContent = @'
-@{
-    Rules = @{
-        PSUseCompatibleCommands = @{
-            Enable = $true
-            TargetProfiles = @(
-                'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework' # Server 2019 - PS 5.1 (the platform it already runs on)
-                'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework' # Server 2012 - PS 3
-                'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core' # Ubuntu 18.04 - PS 6.1
-            )
-        }
-        PSUseCompatibleTypes = @{
-            Enable = $true
-            # Same as for command targets
-            TargetProfiles = @(
-                'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-                'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
-                'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
-            )
-        }
-        PSUseCompatibleSyntax = @{
-            Enable = $true
-            TargetVersions = @('3.0', '5.1', '7.0')
+    $script:settingsContent = @'
+    @{
+        Rules = @{
+            PSUseCompatibleCommands = @{
+                Enable = $true
+                TargetProfiles = @(
+                    'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework' # Server 2019 - PS 5.1 (the platform it already runs on)
+                    'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework' # Server 2012 - PS 3
+                    'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core' # Ubuntu 18.04 - PS 6.1
+                )
+            }
+            PSUseCompatibleTypes = @{
+                Enable = $true
+                # Same as for command targets
+                TargetProfiles = @(
+                    'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+                    'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
+                    'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
+                )
+            }
+            PSUseCompatibleSyntax = @{
+                Enable = $true
+                TargetVersions = @('3.0', '5.1', '7.0')
+            }
         }
     }
-}
 '@
+}
 
-$script:expectedCommandDiagnostics = @(
-    @{ Command = 'Import-Module'; Parameter = 'FullyQualifiedName'; Line = 13 }
-    @{ Command = 'Get-ChildItem'; Parameter = 'Depth'; Line = 17 }
-    @{ Command = 'Get-AuthenticodeSignature'; Line = 26 }
-)
-
-$script:expectedTypeDiagnostics = @(
-    @{ Type = 'System.Management.Automation.WildcardPattern'; Member = 'Get'; Line = 16 }
-    @{ Type = 'System.IO.Compression.ZipFile'; Line = 34 }
-)
-
-$script:expectedSyntaxDiagnostics = @(
-    @{ Line = 15; CorrectionText = "New-Object 'System.Collections.Generic.List[System.Management.Automation.Signature]'" }
-)
 
 Describe "Running all compatibility rules with a settings file" {
     BeforeAll {
@@ -96,7 +84,7 @@ Describe "Running all compatibility rules with a settings file" {
         $syntaxDiagnostics = $diagnostics.PSUseCompatibleSyntax
     }
 
-    It "Finds the problem with command <Command> on line <Line> in the file" -TestCases $script:expectedCommandDiagnostics {
+    It "Finds the problem with command <Command> on line <Line> in the file" {
         param([string]$Command, [string]$Parameter, [int]$Line)
 
         $actualDiagnostic = $commandDiagnostics | Where-Object { $_.Command -eq $Command -and $_.Line -eq $Line }
@@ -106,9 +94,13 @@ Describe "Running all compatibility rules with a settings file" {
         {
             $actualDiagnostic.Parameter | Should -Be $Parameter
         }
-    }
+    } -TestCases @(
+        @{ Command = 'Import-Module'; Parameter = 'FullyQualifiedName'; Line = 13 }
+        @{ Command = 'Get-ChildItem'; Parameter = 'Depth'; Line = 17 }
+        @{ Command = 'Get-AuthenticodeSignature'; Line = 26 }
+    )
 
-    It "Finds the problem with type <Type> on line <Line> in the file" -TestCases $script:expectedTypeDiagnostics {
+    It "Finds the problem with type <Type> on line <Line> in the file" {
         param([string]$Type, [string]$Member, [int]$Line)
 
         $actualDiagnostic = $typeDiagnostics | Where-Object { $_.Type -eq $Type -and $_.Line -eq $Line }
@@ -118,9 +110,12 @@ Describe "Running all compatibility rules with a settings file" {
         {
             $actualDiagnostic.Member | Should -Be $Member
         }
-    }
+    } -TestCases @(
+        @{ Type = 'System.Management.Automation.WildcardPattern'; Member = 'Get'; Line = 16 }
+        @{ Type = 'System.IO.Compression.ZipFile'; Line = 34 }
+    )
 
-    It "Finds the problem with syntax on line <Line> in the file" -TestCases $script:expectedSyntaxDiagnostics {
+    It "Finds the problem with syntax on line <Line> in the file" {
         param([string]$Suggestion, [int]$Line)
 
         $actualDiagnostic = $syntaxDiagnostics | Where-Object { $_.Line -eq $Line }
@@ -129,5 +124,7 @@ Describe "Running all compatibility rules with a settings file" {
         {
             $actualDiagnostic.Suggestion | Should -Be $Suggestion
         }
-    }
+    } -TestCases @(
+        @{ Line = 15; CorrectionText = "New-Object 'System.Collections.Generic.List[System.Management.Automation.Signature]'" }
+    )
 }
\ No newline at end of file
diff --git a/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1 b/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1
index 127156064..98f82be41 100644
--- a/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1
+++ b/Tests/Rules/AvoidAssignmentToAutomaticVariable.tests.ps1
@@ -1,71 +1,86 @@
-﻿$ruleName = "PSAvoidAssignmentToAutomaticVariable"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "PSAvoidAssignmentToAutomaticVariable"
+}
 
 Describe "AvoidAssignmentToAutomaticVariables" {
     Context "ReadOnly Variables" {
+        BeforeDiscovery {
+            $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Warning'
+            if ($PSVersionTable.PSVersion.Major -ge 6)
+            {
+                $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Error'
+            }
 
-        $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Warning'
-        if ($PSVersionTable.PSVersion.Major -ge 6)
-        {
-            $excpectedSeverityForAutomaticVariablesInPowerShell6 = 'Error'
+            $testCases_AutomaticVariables = @(
+                @{ VariableName = '?'; ExpectedSeverity = 'Error'; IsReadOnly = $true }
+                @{ VariableName = 'Error' ; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'ExecutionContext'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'false'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'Home'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'Host'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'PID'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'PSCulture'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'PSEdition'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'PSHome'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'PSUICulture'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'PSVersionTable'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'ShellId'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                @{ VariableName = 'true'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
+                # Variables introduced only in PowerShell 6+ have a Severity of Warning only
+                @{ VariableName = 'IsCoreCLR'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
+                @{ VariableName = 'IsLinux'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
+                @{ VariableName = 'IsMacOS'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
+                @{ VariableName = 'IsWindows'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
+                @{ VariableName = '_'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'AllNodes'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'Args'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'ConsoleFilename'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'Event'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'EventArgs'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'EventSubscriber'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'ForEach'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'Input'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'Matches'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'MyInvocation'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'NestedPromptLevel'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'Profile'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'PSBoundParameters'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'PsCmdlet'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'PSCommandPath'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'ReportErrorShowExceptionClass'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'ReportErrorShowInnerException'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'ReportErrorShowSource'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'ReportErrorShowStackTrace'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'Sender'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'StackTrace'; ExpectedSeverity = 'Warning' }
+                @{ VariableName = 'This'; ExpectedSeverity = 'Warning' }
+            )
+
+            $testCases_ReadOnlyAutomaticVariables = $testCases_AutomaticVariables | Where-Object { $_.IsReadonly }
         }
 
-        $testCases_AutomaticVariables = @(
-            @{ VariableName = '?'; ExpectedSeverity = 'Error'; IsReadOnly = $true }
-            @{ VariableName = 'Error' ; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'ExecutionContext'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'false'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'Home'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'Host'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'PID'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'PSCulture'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'PSEdition'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'PSHome'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'PSUICulture'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'PSVersionTable'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'ShellId'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            @{ VariableName = 'true'; ExpectedSeverity = 'Error';  IsReadOnly = $true }
-            # Variables introduced only in PowerShell 6+ have a Severity of Warning only
-            @{ VariableName = 'IsCoreCLR'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
-            @{ VariableName = 'IsLinux'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
-            @{ VariableName = 'IsMacOS'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
-            @{ VariableName = 'IsWindows'; ExpectedSeverity = $excpectedSeverityForAutomaticVariablesInPowerShell6; OnlyPresentInCoreClr = $true }
-            @{ VariableName = '_'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'AllNodes'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'Args'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'ConsoleFilename'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'Event'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'EventArgs'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'EventSubscriber'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'ForEach'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'Input'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'Matches'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'MyInvocation'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'NestedPromptLevel'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'Profile'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'PSBoundParameters'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'PsCmdlet'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'PSCommandPath'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'ReportErrorShowExceptionClass'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'ReportErrorShowInnerException'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'ReportErrorShowSource'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'ReportErrorShowStackTrace'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'Sender'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'StackTrace'; ExpectedSeverity = 'Warning' }
-            @{ VariableName = 'This'; ExpectedSeverity = 'Warning' }
-        )
-
-        $testCases_ReadOnlyAutomaticVariables = $testCases_AutomaticVariables | Where-Object { $_.IsReadonly }
-
         It "Variable <VariableName> produces warning of Severity <ExpectedSeverity>" -TestCases $testCases_AutomaticVariables {
             param ($VariableName, $ExpectedSeverity)
 
-            $warnings = Invoke-ScriptAnalyzer -ScriptDefinition "`$${VariableName} = 'foo'" -ExcludeRule PSUseDeclaredVarsMoreThanAssignments
+            [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition "`$${VariableName} = 'foo'" -ExcludeRule PSUseDeclaredVarsMoreThanAssignments
+            $warnings.Count | Should -Be 1
+            $warnings.Severity | Should -Be $ExpectedSeverity
+            $warnings.RuleName | Should -Be $ruleName
+        }
+
+        It "Using Variable <VariableName> as foreach assignment produces warning of Severity <ExpectedSeverity>" -TestCases $testCases_AutomaticVariables {
+            param ($VariableName, $ExpectedSeverity)
+
+            [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition "foreach (`$$VariableName in `$foo) {}"
             $warnings.Count | Should -Be 1
             $warnings.Severity | Should -Be $ExpectedSeverity
             $warnings.RuleName | Should -Be $ruleName
         }
 
-        It "Using Variable <VariableName> as parameter name produces warning of Severity error" -TestCases $testCases_AutomaticVariables {
+        It "Using Variable <VariableName> as parameter name produces warning of Severity <ExpectedSeverity>" -TestCases $testCases_AutomaticVariables {
             param ($VariableName, $ExpectedSeverity)
 
             [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition "function foo{Param(`$$VariableName)}" -ExcludeRule PSReviewUnusedParameter
@@ -74,7 +89,7 @@ Describe "AvoidAssignmentToAutomaticVariables" {
             $warnings.RuleName | Should -Be $ruleName
         }
 
-        It "Using Variable <VariableName> as parameter name in param block produces warning of Severity error" -TestCases $testCases_AutomaticVariables {
+        It "Using Variable <VariableName> as parameter name in param block produces warning of Severity <ExpectedSeverity>" -TestCases $testCases_AutomaticVariables {
             param ($VariableName, $ExpectedSeverity)
 
             [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition "function foo(`$$VariableName){}"
@@ -88,6 +103,13 @@ Describe "AvoidAssignmentToAutomaticVariables" {
             $warnings.Count | Should -Be 0
         }
 
+        It "Does not flag true or false being used in ValidateSet" {
+            # All other read-only automatic variables cannot be used in ValidateSet
+            # they result in a ParseError. $true and $false are permitted however.
+            [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition 'param([ValidateSet($true,$false)]$MyVar)$MyVar' -ExcludeRule PSReviewUnusedParameter
+            $warnings.Count | Should -Be 0
+        }
+
         It "Does not throw a NullReferenceException when using assigning a .Net property to a .Net property (Bug in 1.17.0 - issue 1007)" {
             Invoke-ScriptAnalyzer -ScriptDefinition '[foo]::bar = [baz]::qux' -ErrorAction Stop
         }
@@ -128,6 +150,29 @@ Describe "AvoidAssignmentToAutomaticVariables" {
                 }
             }
         }
+    }
 
+    Context 'Suppression' {
+        BeforeDiscovery {
+            $testCases_RuleSuppression = @(
+                @{ VariableName = 'true'; Type = 'ReadOnlyAutomaticVariableError' }
+                @{ VariableName = 'IsWindows'; Type = 'ReadOnlyAutomaticVariableIntroducedInPowerShell6_0Error' }
+                @{ VariableName = 'ForEach'; Type = 'WritableAutomaticVariableError' }
+            )
+        }
+
+        It 'Variable <VariableName> of type <Type> can be suppressed by RuleSuppressionId' -TestCases $testCases_RuleSuppression {
+            $scriptDef = @"
+function suppressionTest {
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('$ruleName', '$VariableName')]
+    param(
+        `$$VariableName
+    )
+}
+"@
+
+            $warnings = @(Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -ExcludeRule PSReviewUnusedParameter)
+            $warnings.Count | Should -Be 0
+        }
     }
 }
diff --git a/Tests/Rules/AvoidConvertToSecureStringWithPlainText.tests.ps1 b/Tests/Rules/AvoidConvertToSecureStringWithPlainText.tests.ps1
index 0e7f760cb..773d5f84f 100644
--- a/Tests/Rules/AvoidConvertToSecureStringWithPlainText.tests.ps1
+++ b/Tests/Rules/AvoidConvertToSecureStringWithPlainText.tests.ps1
@@ -1,8 +1,13 @@
-﻿Set-Alias ctss ConvertTo-SecureString
-$violationMessage = "File 'AvoidConvertToSecureStringWithPlainText.ps1' uses ConvertTo-SecureString with plaintext. This will expose secure information. Encrypted standard strings should be used instead."
-$violationName = "PSAvoidUsingConvertToSecureStringWithPlainText"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidConvertToSecureStringWithPlainText.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidConvertToSecureStringWithPlainTextNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    Set-Alias ctss ConvertTo-SecureString
+    $violationMessage = "File 'AvoidConvertToSecureStringWithPlainText.ps1' uses ConvertTo-SecureString with plaintext. This will expose secure information. Encrypted standard strings should be used instead."
+    $violationName = "PSAvoidUsingConvertToSecureStringWithPlainText"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidConvertToSecureStringWithPlainText.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidConvertToSecureStringWithPlainTextNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidConvertToSecureStringWithPlainText" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidDefaultTrueValueSwitchParameter.tests.ps1 b/Tests/Rules/AvoidDefaultTrueValueSwitchParameter.tests.ps1
index 6714ace07..e28b23985 100644
--- a/Tests/Rules/AvoidDefaultTrueValueSwitchParameter.tests.ps1
+++ b/Tests/Rules/AvoidDefaultTrueValueSwitchParameter.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = "File 'AvoidDefaultTrueValueSwitchParameter.ps1' has a switch parameter default to true."
-$violationName = "PSAvoidDefaultValueSwitchParameter"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidDefaultTrueValueSwitchParameter.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidDefaultTrueValueSwitchParameterNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "File 'AvoidDefaultTrueValueSwitchParameter.ps1' has a switch parameter default to true."
+    $violationName = "PSAvoidDefaultValueSwitchParameter"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidDefaultTrueValueSwitchParameter.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidDefaultTrueValueSwitchParameterNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidDefaultTrueValueSwitchParameter" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidDefaultValueForMandatoryParameter.tests.ps1 b/Tests/Rules/AvoidDefaultValueForMandatoryParameter.tests.ps1
index c4fa2258d..a087a97f4 100644
--- a/Tests/Rules/AvoidDefaultValueForMandatoryParameter.tests.ps1
+++ b/Tests/Rules/AvoidDefaultValueForMandatoryParameter.tests.ps1
@@ -1,4 +1,9 @@
-﻿$ruleName = 'PSAvoidDefaultValueForMandatoryParameter'
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = 'PSAvoidDefaultValueForMandatoryParameter'
+}
 
 Describe "AvoidDefaultValueForMandatoryParameter" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidEmptyCatchBlock.tests.ps1 b/Tests/Rules/AvoidEmptyCatchBlock.tests.ps1
index 636075099..8af3df7f5 100644
--- a/Tests/Rules/AvoidEmptyCatchBlock.tests.ps1
+++ b/Tests/Rules/AvoidEmptyCatchBlock.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = "Empty catch block is used. Please use Write-Error or throw statements in catch blocks."
-$violationName = "PSAvoidUsingEmptyCatchBlock"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidEmptyCatchBlock.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidEmptyCatchBlockNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Empty catch block is used. Please use Write-Error or throw statements in catch blocks."
+    $violationName = "PSAvoidUsingEmptyCatchBlock"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidEmptyCatchBlock.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidEmptyCatchBlockNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "UseDeclaredVarsMoreThanAssignments" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidExclaimOperator.tests.ps1 b/Tests/Rules/AvoidExclaimOperator.tests.ps1
new file mode 100644
index 000000000..8307aef5a
--- /dev/null
+++ b/Tests/Rules/AvoidExclaimOperator.tests.ps1
@@ -0,0 +1,54 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "PSAvoidExclaimOperator"
+
+    $ruleSettings = @{
+        Enable = $true
+    }
+    $settings = @{
+        IncludeRules = @($ruleName)
+        Rules        = @{ $ruleName = $ruleSettings }
+    }
+}
+
+Describe "AvoidExclaimOperator" {
+    Context "When the rule is not enabled explicitly" {
+        It "Should not find violations" {
+            $def = '!$true'
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def
+            $violations.Count | Should -Be 0
+        }
+    }
+
+    Context "Given a line with the exclaim operator" {
+        It "Should find one violation" {
+            $def = '!$true'
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations.Count | Should -Be 1
+        }
+    }
+
+    Context "Given a line with the exclaim operator" {
+        It "Should replace the exclaim operator with the -not operator" {
+            $def = '!$true'
+            $expected = '-not $true'
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected
+        }
+    }
+    Context "Given a line with the exlaim operator followed by a space" {
+        It "Should replace the exclaim operator without adding an additional space" {
+            $def = '! $true'
+            $expected = '-not $true'
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected
+        }
+    }
+    Context "Given a line with a string containing an exclamation point" {
+        It "Should not replace it" {
+            $def = '$MyVar = "Should not replace!"'
+            $expected = '$MyVar = "Should not replace!"'
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected
+        }
+    }
+}
\ No newline at end of file
diff --git a/Tests/Rules/AvoidGlobalAliases.tests.ps1 b/Tests/Rules/AvoidGlobalAliases.tests.ps1
index 1b8716236..e57b00446 100644
--- a/Tests/Rules/AvoidGlobalAliases.tests.ps1
+++ b/Tests/Rules/AvoidGlobalAliases.tests.ps1
@@ -1,11 +1,14 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$AvoidGlobalAliasesError = "Avoid creating aliases with a Global scope."
-$violationName = "PSAvoidGlobalAliases"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalAliases.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalAliasesNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$IsV3OrV4 = (Test-PSVersionV3) -or (Test-PSVersionV4)
+$IsV3OrV4 = ($PSVersionTable.PSVersion.Major -eq 3) -or ($PSVersionTable.PSVersion.Major -eq 4)
+
+BeforeAll {
+    $AvoidGlobalAliasesError = "Avoid creating aliases with a Global scope."
+    $violationName = "PSAvoidGlobalAliases"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalAliases.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalAliasesNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "$violationName " {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidGlobalFunctions.tests.ps1 b/Tests/Rules/AvoidGlobalFunctions.tests.ps1
index b420f5b83..bbeb83279 100644
--- a/Tests/Rules/AvoidGlobalFunctions.tests.ps1
+++ b/Tests/Rules/AvoidGlobalFunctions.tests.ps1
@@ -1,9 +1,13 @@
-﻿$functionErroMessage = "Avoid creating functions with a Global scope."
-$violationName = "PSAvoidGlobalFunctions"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalFunctions.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalFunctionsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+BeforeAll {
+    $functionErroMessage = "Avoid creating functions with a Global scope."
+    $violationName = "PSAvoidGlobalFunctions"
 
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalFunctions.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalFunctionsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "$violationName " {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidGlobalVars.tests.ps1 b/Tests/Rules/AvoidGlobalVars.tests.ps1
index 2b3297bd0..3b86a2bad 100644
--- a/Tests/Rules/AvoidGlobalVars.tests.ps1
+++ b/Tests/Rules/AvoidGlobalVars.tests.ps1
@@ -1,13 +1,18 @@
-﻿$globalMessage = "Found global variable 'Global:1'."
-$globalName = "PSAvoidGlobalVars"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$nonInitializedMessage = "Variable 'globalVars' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables."
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalOrUnitializedVars.ps1
+BeforeAll {
+    $globalMessage = "Found global variable 'Global:1'."
+    $globalName = "PSAvoidGlobalVars"
 
-$globalViolations = $violations | Where-Object {$_.RuleName -eq $globalName}
+    $nonInitializedMessage = "Variable 'globalVars' is not initialized. Non-global variables must be initialized. To fix a violation of this rule, please initialize non-global variables."
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalOrUnitializedVars.ps1
 
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalOrUnitializedVarsNoViolations.ps1
-$noGlobalViolations = $noViolations | Where-Object {$_.RuleName -eq $globalName}
+    $globalViolations = $violations | Where-Object {$_.RuleName -eq $globalName}
+
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidGlobalOrUnitializedVarsNoViolations.ps1
+    $noGlobalViolations = $noViolations | Where-Object {$_.RuleName -eq $globalName}
+}
 
 Describe "AvoidGlobalVars" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidInvokingEmptyMembers.tests.ps1 b/Tests/Rules/AvoidInvokingEmptyMembers.tests.ps1
index 5e8580068..d1d6d88aa 100644
--- a/Tests/Rules/AvoidInvokingEmptyMembers.tests.ps1
+++ b/Tests/Rules/AvoidInvokingEmptyMembers.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = "() has non-constant members. Invoking non-constant members may cause bugs in the script."
-$violationName = "PSAvoidInvokingEmptyMembers"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidInvokingEmptyMembers.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidInvokingEmptyMembersNonViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "() has non-constant members. Invoking non-constant members may cause bugs in the script."
+    $violationName = "PSAvoidInvokingEmptyMembers"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidInvokingEmptyMembers.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidInvokingEmptyMembersNonViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidInvokingEmptyMembers" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidLongLines.tests.ps1 b/Tests/Rules/AvoidLongLines.tests.ps1
index 5a6c8e189..b2681bee6 100644
--- a/Tests/Rules/AvoidLongLines.tests.ps1
+++ b/Tests/Rules/AvoidLongLines.tests.ps1
@@ -1,11 +1,16 @@
-$ruleName = "PSAvoidLongLines"
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$ruleSettings = @{
-    Enable = $true
-}
-$settings = @{
-    IncludeRules = @($ruleName)
-    Rules        = @{ $ruleName = $ruleSettings }
+BeforeAll {
+    $ruleName =  "PSAvoidLongLines"
+
+    $ruleSettings = @{
+        Enable = $true
+    }
+    $settings = @{
+        IncludeRules = @($ruleName)
+        Rules        = @{ $ruleName = $ruleSettings }
+    }
 }
 
 Describe "AvoidLongLines" {
diff --git a/Tests/Rules/AvoidMultipleTypeAttributes.tests.ps1 b/Tests/Rules/AvoidMultipleTypeAttributes.tests.ps1
new file mode 100644
index 000000000..5d448e64c
--- /dev/null
+++ b/Tests/Rules/AvoidMultipleTypeAttributes.tests.ps1
@@ -0,0 +1,42 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "AvoidMultipleTypeAttributes"
+
+    $settings = @{
+        IncludeRules = @($ruleName)
+    }
+}
+
+Describe 'AvoidMultipleTypeAttributes' {
+    It 'Correctly diagnoses and corrects <Script>' -TestCases @(
+        @{ Script = 'function F1 ($s1, $p1){}' }
+        @{ Script = 'function F2 ([int] $s2, [int] $p2){}' }
+        @{ Script = 'function F3 ([int][switch] $s3, [int] $p3){}';Extent = @{ StartCol = 28; EndCol = 31 }; Message = 'Parameter ''$s3'' has more than one type specifier.' }
+        @{ Script = 'function F4 ([int][ref] $s4, [int] $p4){}';Extent = @{ StartCol = 25; EndCol = 28 }; Message = 'Parameter ''$s4'' has more than one type specifier.' }
+        @{ Script = 'function F5 ([int][switch][boolean] $s5, [int] $p5){}';Extent = @{ StartCol = 37; EndCol = 40 }; Message = 'Parameter ''$s5'' has more than one type specifier.' }
+        @{ Script = 'function F6 ([ValidateSet()][int] $s6, [int] $p6){}' }
+        @{ Script = 'function F7 ([Parameter(Mandatory=$true)][ValidateSet()][int] $s7, [int] $p7){}' }
+    ) {
+        param([string]$Script, $Extent, $Message)
+
+        $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $Script
+
+        if (-not $Extent)
+        {
+            $diagnostics | Should -BeNullOrEmpty
+            return
+        }
+
+        $expectedStartLine = if ($Extent.StartLine) { $Extent.StartLine } else { 1 }
+        $expectedEndLine = if ($Extent.EndLine) { $Extent.EndLine } else { 1 }
+
+        $diagnostics.Extent.StartLineNumber | Should -BeExactly $expectedStartLine
+        $diagnostics.Extent.EndLineNumber | Should -BeExactly $expectedEndLine
+        $diagnostics.Extent.StartColumnNumber | Should -BeExactly $Extent.StartCol
+        $diagnostics.Extent.EndColumnNumber | Should -BeExactly $Extent.EndCol
+
+        $diagnostics.Message | Should -BeExactly $Message
+    }
+}
diff --git a/Tests/Rules/AvoidNullOrEmptyHelpMessageAttribute.tests.ps1 b/Tests/Rules/AvoidNullOrEmptyHelpMessageAttribute.tests.ps1
index a710297aa..75aee3aff 100644
--- a/Tests/Rules/AvoidNullOrEmptyHelpMessageAttribute.tests.ps1
+++ b/Tests/Rules/AvoidNullOrEmptyHelpMessageAttribute.tests.ps1
@@ -1,7 +1,12 @@
-$violationName = "PSAvoidNullOrEmptyHelpMessageAttribute"
-$violationMessage = "HelpMessage parameter attribute should not be null or empty. To fix a violation of this rule, please set its value to a non-empty string."
-$violations = Invoke-ScriptAnalyzer "$PSScriptRoot\AvoidNullOrEmptyHelpMessageAttribute.ps1" -IncludeRule PSAvoidNullOrEmptyHelpMessageAttribute
-$noViolations = Invoke-ScriptAnalyzer "$PSScriptRoot\AvoidNullOrEmptyHelpMessageAttributeNoViolations.ps1" -IncludeRule PSAvoidNullOrEmptyHelpMessageAttribute
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationName = "PSAvoidNullOrEmptyHelpMessageAttribute"
+    $violationMessage = "HelpMessage parameter attribute should not be null or empty. To fix a violation of this rule, please set its value to a non-empty string."
+    $violations = Invoke-ScriptAnalyzer "$PSScriptRoot\AvoidNullOrEmptyHelpMessageAttribute.ps1" -IncludeRule PSAvoidNullOrEmptyHelpMessageAttribute
+    $noViolations = Invoke-ScriptAnalyzer "$PSScriptRoot\AvoidNullOrEmptyHelpMessageAttributeNoViolations.ps1" -IncludeRule PSAvoidNullOrEmptyHelpMessageAttribute
+}
 
 Describe "AvoidNullOrEmptyHelpMessageAttribute" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidOverwritingBuiltInCmdlets.tests.ps1 b/Tests/Rules/AvoidOverwritingBuiltInCmdlets.tests.ps1
index eedebbd28..2a111af0a 100644
--- a/Tests/Rules/AvoidOverwritingBuiltInCmdlets.tests.ps1
+++ b/Tests/Rules/AvoidOverwritingBuiltInCmdlets.tests.ps1
@@ -1,29 +1,34 @@
-﻿$ruleName = "PSAvoidOverwritingBuiltInCmdlets"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$ruleSettingsWindows = @{$ruleName = @{PowerShellVersion = @('desktop-5.1.14393.206-windows') } }
-$ruleSettingsCore = @{$ruleName = @{PowerShellVersion = @('core-6.1.0-windows') } }
-$ruleSettingsBoth = @{$ruleName = @{PowerShellVersion = @('core-6.1.0-windows', 'desktop-5.1.14393.206-windows') } }
+BeforeAll {
+    $ruleName = "PSAvoidOverwritingBuiltInCmdlets"
 
-$settings = @{
-    IncludeRules = @($ruleName)
-}
+    $ruleSettingsWindows = @{$ruleName = @{PowerShellVersion = @('desktop-5.1.14393.206-windows') } }
+    $ruleSettingsCore = @{$ruleName = @{PowerShellVersion = @('core-6.1.0-windows') } }
+    $ruleSettingsBoth = @{$ruleName = @{PowerShellVersion = @('core-6.1.0-windows', 'desktop-5.1.14393.206-windows') } }
 
-# Get-Something is not a built in cmdlet on any platform and should never be flagged
-# Get-ChildItem is available on all versions of PowerShell and should always be flagged
-# Get-Clipboard is available on PowerShell 5 but not 6 and should be flagged conditionally
-$scriptDefinition = @"
-function Get-Something {
-    Write-Output "Get-Something"
-}
+    $settings = @{
+        IncludeRules = @($ruleName)
+    }
 
-function Get-ChildItem {
-    Write-Output "Get-ChildItem"
-}
+    # Get-Something is not a built in cmdlet on any platform and should never be flagged
+    # Get-ChildItem is available on all versions of PowerShell and should always be flagged
+    # Get-Clipboard is available on PowerShell 5 but not 6 and should be flagged conditionally
+    $scriptDefinition = @"
+    function Get-Something {
+        Write-Output "Get-Something"
+    }
 
-function Get-Clipboard {
-    Write-Output "Get-Clipboard"
-}
+    function Get-ChildItem {
+        Write-Output "Get-ChildItem"
+    }
+
+    function Get-Clipboard {
+        Write-Output "Get-Clipboard"
+    }
 "@
+}
 
 describe 'AvoidOverwritingBuiltInCmdlets' {
     context 'No settings specified' {
@@ -43,8 +48,10 @@ describe 'AvoidOverwritingBuiltInCmdlets' {
     }
 
     context 'PowerShellVersion explicitly set to Windows PowerShell' {
-        $settings['Rules'] = $ruleSettingsWindows
-        $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
+        BeforeAll {
+            $settings['Rules'] = $ruleSettingsWindows
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
+        }
 
         it 'should find two violations' {
             $violations.Count | Should -Be 2
@@ -59,8 +66,10 @@ describe 'AvoidOverwritingBuiltInCmdlets' {
     }
 
     context 'PowerShellVersion explicitly set to PowerShell 6' {
-        $settings['Rules'] = $ruleSettingsCore
-        $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
+        BeforeAll {
+            $settings['Rules'] = $ruleSettingsCore
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
+        }
 
         it 'should find one violation' {
             $violations.Count | Should -Be 1
@@ -72,8 +81,10 @@ describe 'AvoidOverwritingBuiltInCmdlets' {
     }
 
     context 'PowerShellVersion explicitly set to both Windows PowerShell and PowerShell 6' {
-        $settings['Rules'] = $ruleSettingsBoth
-        $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
+        BeforeAll {
+            $settings['Rules'] = $ruleSettingsBoth
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
+        }
 
         it 'should find three violations' {
             $violations.Count | Should -Be 3
diff --git a/Tests/Rules/AvoidPositionalParameters.tests.ps1 b/Tests/Rules/AvoidPositionalParameters.tests.ps1
index 03f9368fc..ec5a91e24 100644
--- a/Tests/Rules/AvoidPositionalParameters.tests.ps1
+++ b/Tests/Rules/AvoidPositionalParameters.tests.ps1
@@ -1,8 +1,13 @@
-﻿$violationMessage = "Cmdlet 'Get-Command' has positional parameter. Please use named parameters instead of positional parameters when calling a command."
-$violationName = "PSAvoidUsingPositionalParameters"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidPositionalParameters.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidPositionalParametersNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolationsDSC = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\serviceconfigdisabled.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Cmdlet 'Get-Command' has positional parameter. Please use named parameters instead of positional parameters when calling a command."
+    $violationName = "PSAvoidUsingPositionalParameters"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidPositionalParameters.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidPositionalParametersNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolationsDSC = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\serviceconfigdisabled.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidPositionalParameters" {
     Context "When there are violations" {
@@ -21,6 +26,14 @@ Describe "AvoidPositionalParameters" {
             $violations.RuleName | Should -Contain 'PSAvoidUsingCmdletAliases'
         }
 
+        It "returns violations for command that is not in allow list of settings" {
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition 'Join-Path a b c d' -Settings @{
+                IncludeRules = @('PSAvoidUsingPositionalParameters')
+                Rules        = @{ PSAvoidUsingPositionalParameters = @{ CommandAllowList = 'Test-Path' } }
+            }
+            $violations.Count | Should -Be 1
+            $violations.RuleName | Should -Be 'PSAvoidUsingPositionalParameters'
+        }
     }
 
     Context "When there are no violations" {
@@ -31,6 +44,17 @@ Describe "AvoidPositionalParameters" {
         It "returns no violations for DSC configuration" {
             $noViolationsDSC.Count | Should -Be 0
         }
+
+        It "returns no violations for AZ CLI by default" {
+            Invoke-ScriptAnalyzer -ScriptDefinition 'az group deployment list' | Should -BeNullOrEmpty
+        }
+
+        It "returns no violations for command from allow list defined in settings and is case invariant" {
+            Invoke-ScriptAnalyzer -ScriptDefinition 'join-patH a b c' -Settings @{
+                IncludeRules = @('PSAvoidUsingPositionalParameters')
+                Rules        = @{ PSAvoidUsingPositionalParameters = @{ CommandAllowList = 'az', 'Join-Path' } }
+            } | Should -BeNullOrEmpty
+        }
     }
 
     Context "Function defined and called in script, which has 3 or more positional parameters triggers rule." {
diff --git a/Tests/Rules/AvoidPositionalParametersNoViolations.ps1 b/Tests/Rules/AvoidPositionalParametersNoViolations.ps1
index 9a5cc7d75..52eaf3198 100644
--- a/Tests/Rules/AvoidPositionalParametersNoViolations.ps1
+++ b/Tests/Rules/AvoidPositionalParametersNoViolations.ps1
@@ -3,7 +3,7 @@ Get-ChildItem -Path "Tests"
 Clear-Host
 Split-Path -Path "Random" -leaf
 Get-Process | Where-Object {$_.handles -gt 200}
-get-service-computername localhost | where {($_.status -eq "Running") -and ($_.CanStop -eq $true)}
+get-service -computername localhost | where {($_.status -eq "Running") -and ($_.CanStop -eq $true)}
 1, 2, $null, 4 | ForEach-Object {"Hello"}
 & "$env:Windir\System32\Calc.exe" Parameter1 Parameter2
 
@@ -22,4 +22,4 @@ Write-Output "I don't want to use positional parameters"
 Split-Path "RandomPath" -Leaf
 Get-Process | ForEach-Object {Write-Host $_.name -foregroundcolor cyan}
 
-$srvc = Get-WmiObject Win32_Service -ComputerName $computername -Filter "name=""$service""" -Credential $credential
\ No newline at end of file
+$srvc = Get-WmiObject Win32_Service -ComputerName $computername -Filter "name=""$service""" -Credential $credential
diff --git a/Tests/Rules/AvoidReservedParams.tests.ps1 b/Tests/Rules/AvoidReservedParams.tests.ps1
index 52020df37..b0657429d 100644
--- a/Tests/Rules/AvoidReservedParams.tests.ps1
+++ b/Tests/Rules/AvoidReservedParams.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = [regex]::Escape("Verb-Files' defines the reserved common parameter 'Verbose'.")
-$violationName = "PSReservedParams"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = [regex]::Escape("Verb-Files' defines the reserved common parameter 'Verbose'.")
+    $violationName = "PSReservedParams"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidReservedParams" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidSemicolonsAsLineTerminators.tests.ps1 b/Tests/Rules/AvoidSemicolonsAsLineTerminators.tests.ps1
new file mode 100644
index 000000000..9f88c1957
--- /dev/null
+++ b/Tests/Rules/AvoidSemicolonsAsLineTerminators.tests.ps1
@@ -0,0 +1,135 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "PSAvoidSemicolonsAsLineTerminators"
+
+    $ruleSettings = @{
+        Enable = $true
+    }
+    $settings = @{
+        IncludeRules = @($ruleName)
+        Rules        = @{ $ruleName = $ruleSettings }
+    }
+}
+
+Describe "AvoidSemicolonsAsLineTerminators" {
+    Context "When the rule is not enabled explicitly" {
+        It "Should not find violations" {
+            $def = "'test';"
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def
+            $violations.Count | Should -Be 0
+        }
+    }
+
+    Context "Given a line ending with a semicolon" {
+        It "Should find one violation" {
+            $def = "'test';"
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations.Count | Should -Be 1
+        }
+    }
+
+    Context "Given a line with a semicolon in the middle and one at the end" {
+        It "Should find one violation" {
+            $def = "'test';'test';"
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations[0].Extent.StartLineNumber | Should -Be 1
+            $violations[0].Extent.EndLineNumber | Should -Be 1
+            $violations[0].Extent.StartColumnNumber | Should -Be 14
+            $violations[0].Extent.EndColumnNumber | Should -Be 15
+        }
+    }
+
+
+    Context "Given a multiline string with a line ending with a semicolon" {
+        It "Should get the correct extent of the violation for a single semicolon" {
+            $def = @"
+'this line has no semicolon'
+'test';
+"@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations[0].Extent.StartLineNumber | Should -Be 2
+            $violations[0].Extent.EndLineNumber | Should -Be 2
+            $violations[0].Extent.StartColumnNumber | Should -Be 7
+            $violations[0].Extent.EndColumnNumber | Should -Be 8
+        }
+    }
+
+    Context "Given a multiline string with a line having a semicolon in the middle" {
+        It "Should not find any violations" {
+            $def = @"
+'this line has no semicolon'
+'line with a semicolon; in the middle'
+"@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations.Count | Should -Be 0
+        }
+    }
+
+    Context "Given a multiline string with a line having a semicolon in C# code" {
+        It "Should not find any violations" {
+            $def = @"
+`$calcCode = `@"
+public class Calc{
+    public int Add(int x,int y){
+        return x+y;
+    }
+}
+"`@
+
+Add-Type -TypeDefinition `$calcCode -Language CSharp
+
+`$c = New-Object Calc
+`$c.Add(1,2)
+"@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations.Count | Should -Be 0
+        }
+    }
+
+    Context "Given a multiline string with a line having a semicolon in variable assignment" {
+        It "Should not find any violations" {
+            $def = @"
+`$allowPopupsOption=`@"
+lockPref("dom.disable_open_during_load", false);
+"`@
+    Write `$allowPopupsOption | Out-File -Encoding UTF8 -FilePath `$pathToMozillaCfg -Append
+"@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            $violations.Count | Should -Be 0
+        }
+    }
+
+    Context "Given a line ending with a semicolon" {
+        It "Should remove the semicolon at the end" {
+            $def = "'test';"
+            $expected = "'test'"
+
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected
+        }
+    }
+
+    Context "Given a line with a semicolon in the middle and one at the end" {
+        It "Should remove the semicolon at the end" {
+            $def = "'test';'test';"
+            $expected = "'test';'test'"
+
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected
+        }
+    }
+
+    Context "Given a multiline string with a line ending with a semicolon" {
+        It "Should remove the semicolon at the end of the line with a semicolon" {
+            $def = @"
+'this line has no semicolon at the end'
+'test';
+"@
+            $expected = @"
+'this line has no semicolon at the end'
+'test'
+"@
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings | Should -Be $expected
+        }
+    }
+}
diff --git a/Tests/Rules/AvoidShouldContinueWithoutForce.tests.ps1 b/Tests/Rules/AvoidShouldContinueWithoutForce.tests.ps1
index 7ebff4de5..3d3985d7f 100644
--- a/Tests/Rules/AvoidShouldContinueWithoutForce.tests.ps1
+++ b/Tests/Rules/AvoidShouldContinueWithoutForce.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = "Function 'Verb-Noun2' in file 'AvoidShouldContinueWithoutForce.ps1' uses ShouldContinue but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt"
-$violationName = "PSAvoidShouldContinueWithoutForce"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidShouldContinueWithoutForce.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Function 'Verb-Noun2' in file 'AvoidShouldContinueWithoutForce.ps1' uses ShouldContinue but does not have a boolean force parameter. The force parameter will allow users of the script to bypass ShouldContinue prompt"
+    $violationName = "PSAvoidShouldContinueWithoutForce"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidShouldContinueWithoutForce.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidShouldContinueWithoutForce" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidTrailingWhitespace.tests.ps1 b/Tests/Rules/AvoidTrailingWhitespace.tests.ps1
index b51398984..e5a45f0d3 100644
--- a/Tests/Rules/AvoidTrailingWhitespace.tests.ps1
+++ b/Tests/Rules/AvoidTrailingWhitespace.tests.ps1
@@ -1,10 +1,18 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$ruleName = "PSAvoidTrailingWhitespace"
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
 
-$settings = @{
-    IncludeRules = @($ruleName)
+    $ruleName = "PSAvoidTrailingWhitespace"
+
+    $settings = @{
+        IncludeRules = @($ruleName)
+        Rules = @{
+            $ruleName = @{}
+        }
+    }
 }
 
 Describe "AvoidTrailingWhitespace" {
@@ -29,4 +37,26 @@ Describe "AvoidTrailingWhitespace" {
         $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
         Test-CorrectionExtentFromContent $def $violations 1 $Whitespace ''
     }
+
+    It 'Should be used by Invoke-Formatter, when in settings, replacing trailing <Type>' -TestCases $testCases {
+        param (
+            [string] $Whitespace
+        )
+        # Test also guards against regression where single-character lines, with trailing whitespace
+        # would be removed entirely. See issues #1757, #1992
+        $def = @"
+Function Get-Example {
+    'Example'$Whitespace
+}$Whitespace
+"@
+
+        $expected = @"
+Function Get-Example {
+    'Example'
 }
+"@
+        $formatted = Invoke-Formatter -ScriptDefinition $def -Settings $settings
+        $formatted | Should -Be $expected
+    }
+
+}
\ No newline at end of file
diff --git a/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1 b/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1
index 017382aeb..134f2916a 100644
--- a/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1
+++ b/Tests/Rules/AvoidUnloadableModuleOrMissingRequiredFieldInManifest.tests.ps1
@@ -1,19 +1,24 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
-
-$missingMessage = "The member 'ModuleVersion' is not present in the module manifest."
-$missingMemberRuleName = "PSMissingModuleManifestField"
-$violationFilepath = Join-Path $PSScriptRoot "TestBadModule\TestBadModule.psd1"
-$violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object {$_.RuleName -eq $missingMemberRuleName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\TestGoodModule\TestGoodModule.psd1 | Where-Object {$_.RuleName -eq $missingMemberRuleName}
-$noHashtableFilepath = Join-Path $PSScriptRoot "TestBadModule\NoHashtable.psd1"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+
+    $missingMessage = "The member 'ModuleVersion' is not present in the module manifest."
+    $missingMemberRuleName = "PSMissingModuleManifestField"
+    $violationFilepath = Join-Path $PSScriptRoot "TestBadModule\TestBadModule.psd1"
+    $violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object { $_.RuleName -eq $missingMemberRuleName }
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\TestGoodModule\TestGoodModule.psd1 | Where-Object { $_.RuleName -eq $missingMemberRuleName }
+    $noHashtableFilepath = Join-Path $PSScriptRoot "TestBadModule\NoHashtable.psd1"
+}
 
 Describe "MissingRequiredFieldModuleManifest" {
     BeforeAll {
         Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1") -Force
     }
 
-    AfterAll{
+    AfterAll {
         Remove-Module PSScriptAnalyzerTestHelper
     }
 
@@ -26,19 +31,18 @@ Describe "MissingRequiredFieldModuleManifest" {
             $violations.Message | Should -Match $missingMessage
         }
 
-        $numExpectedCorrections = 1
-        It "has $numExpectedCorrections suggested corrections" {
-            $violations.SuggestedCorrections.Count | Should -Be $numExpectedCorrections
+        It "has correct suggested corrections count" {
+            $violations.SuggestedCorrections.Count | Should -Be 1
         }
 
-	It "has the right suggested correction" {
-        $expectedText = [System.Environment]::NewLine + '# Version number of this module.' +
+        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
+            $violations[0].SuggestedCorrections[0].Text | Should -BeExactly $expectedText
+            Get-ExtentText $violations[0].SuggestedCorrections[0] $violationFilepath | Should -BeNullOrEmpty
+        }
     }
-}
 
     Context "When there are no violations" {
         It "returns no violations" {
@@ -94,4 +98,3 @@ Describe "MissingRequiredFieldModuleManifest" {
         }
     }
 }
-
diff --git a/Tests/Rules/AvoidUserNameAndPasswordParams.tests.ps1 b/Tests/Rules/AvoidUserNameAndPasswordParams.tests.ps1
index 7b3c966e8..bbadcbc8b 100644
--- a/Tests/Rules/AvoidUserNameAndPasswordParams.tests.ps1
+++ b/Tests/Rules/AvoidUserNameAndPasswordParams.tests.ps1
@@ -1,8 +1,12 @@
-﻿
-$violationMessage = "Function 'TestFunction1' has both Username and Password parameters. Either set the type of the Password parameter to SecureString or replace the Username and Password parameters with a Credential parameter of type PSCredential. If using a Credential parameter in PowerShell 4.0 or earlier, please define a credential transformation attribute after the PSCredential type attribute."
-$violationName = "PSAvoidUsingUserNameAndPasswordParams"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUserNameAndPasswordParams.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUserNameAndPasswordParamsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Function 'TestFunction1' has both Username and Password parameters. Either set the type of the Password parameter to SecureString or replace the Username and Password parameters with a Credential parameter of type PSCredential. If using a Credential parameter in PowerShell 4.0 or earlier, please define a credential transformation attribute after the PSCredential type attribute."
+    $violationName = "PSAvoidUsingUserNameAndPasswordParams"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUserNameAndPasswordParams.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUserNameAndPasswordParamsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidUserNameAndPasswordParams" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidUsingAlias.tests.ps1 b/Tests/Rules/AvoidUsingAlias.tests.ps1
index cd0ff4a4d..00db269a0 100644
--- a/Tests/Rules/AvoidUsingAlias.tests.ps1
+++ b/Tests/Rules/AvoidUsingAlias.tests.ps1
@@ -1,11 +1,15 @@
-﻿$violationMessage = "'cls' is an alias of 'Clear-Host'. Alias can introduce possible problems and make scripts hard to maintain. Please consider changing alias to its full content."
-$violationName = "PSAvoidUsingCmdletAliases"
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-$violationFilepath = Join-Path $PSScriptRoot 'AvoidUsingAlias.ps1'
-$violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingAliasNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
-
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "'cls' is an alias of 'Clear-Host'. Alias can introduce possible problems and make scripts hard to maintain. Please consider changing alias to its full content."
+    $violationName = "PSAvoidUsingCmdletAliases"
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    $violationFilepath = Join-Path $PSScriptRoot 'AvoidUsingAlias.ps1'
+    $violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingAliasNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+}
 
 Describe "AvoidUsingAlias" {
     Context "When there are violations" {
@@ -63,38 +67,38 @@ Configuration MyDscConfiguration {
         }
     }
 
-    Context "Settings file provides whitelist" {
+    Context "Settings file provides allowlist" {
         BeforeAll {
-            $whiteListTestScriptDef = 'gci; cd;'
+            $allowListTestScriptDef = 'gci; cd;'
             $settings = @{
                 'Rules' = @{
                     'PSAvoidUsingCmdletAliases' = @{
-                        'Whitelist' = @('cd')
+                        'allowlist' = @('cd')
                     }
                 }
             }
         }
 
-        It "honors the whitelist provided as hashtable" {
+        It "honors the allowlist provided as hashtable" {
             $settings = @{
                 'Rules' = @{
                     'PSAvoidUsingCmdletAliases' = @{
-                        'Whitelist' = @('cd')
+                        'allowlist' = @('cd')
                     }
                 }
             }
-            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $whiteListTestScriptDef -Settings $settings -IncludeRule $violationName
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $allowListTestScriptDef -Settings $settings -IncludeRule $violationName
             $violations.Count | Should -Be 1
         }
 
-        It "honors the whitelist provided through settings file" {
+        It "honors the allowlist provided through settings file" {
             # even though join-path returns string, if we do not use tostring, then invoke-scriptanalyzer cannot cast it to string type
             $settingsFilePath = (Join-Path $PSScriptRoot (Join-Path 'TestSettings' 'AvoidAliasSettings.psd1')).ToString()
-            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $whiteListTestScriptDef -Settings $settingsFilePath -IncludeRule $violationName
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $allowListTestScriptDef -Settings $settingsFilePath -IncludeRule $violationName
             $violations.Count | Should -Be 1
         }
 
-        It "honors the whitelist in a case-insensitive manner" {
+        It "honors the allowlist in a case-insensitive manner" {
             $violations = Invoke-ScriptAnalyzer -ScriptDefinition "CD" -Settings $settings -IncludeRule $violationName
             $violations.Count | Should -Be 0
         }
@@ -113,5 +117,12 @@ Configuration MyDscConfiguration {
 
             $violations.Count | Should -Be $expectedViolations
         }
+
+        It 'Warn about incorrect syntax around process block' {
+            $scriptDefinition = { function foo { IShouldNotBeHere; process {} } }
+            $violations = Invoke-ScriptAnalyzer -IncludeRule PSAvoidUsingCmdletAliases -ScriptDefinition "$scriptDefinition"
+            $violations.Count | Should -Be 1
+            $violations.Severity | Should -Be ([Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticSeverity]::ParseError)
+        }
     }
 }
diff --git a/Tests/Rules/AvoidUsingAllowUnencryptedAuthentication.tests.ps1 b/Tests/Rules/AvoidUsingAllowUnencryptedAuthentication.tests.ps1
new file mode 100644
index 000000000..ca89b280c
--- /dev/null
+++ b/Tests/Rules/AvoidUsingAllowUnencryptedAuthentication.tests.ps1
@@ -0,0 +1,38 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $settings = @{
+        IncludeRules = @('PSAvoidUsingAllowUnencryptedAuthentication')
+        Rules        = @{
+            PSAvoidUsingAllowUnencryptedAuthentication = @{
+                Enable = $true
+            }
+        }
+    }
+}
+
+Describe "AvoidUsingAllowUnencryptedAuthentication" {
+    Context "When there are violations" {
+        It "detects unencrypted authentication violations" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-WebRequest foo -AllowUnencryptedAuthentication' -Settings $settings).Count | Should -Be 1
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-RestMethod foo -AllowUnencryptedAuthentication' -Settings $settings).Count | Should -Be 1
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'iwr foo -AllowUnencryptedAuthentication' -Settings $settings).Count | Should -Be 1
+        }
+
+        It "detects arbitrary cmdlets" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-CustomWebRequest foo -AllowUnencryptedAuthentication' -Settings $settings).Count | Should -Be 1
+        }
+
+    }
+
+    Context "When there are no violations" {
+        It "does not flag safe usage" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-WebRequest foo' -Settings $settings).Count | Should -Be 0
+        }
+
+        It "does not flag cases with unrelated parameters" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Invoke-WebRequest foo -Method Get' -Settings $settings).Count | Should -Be 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/Tests/Rules/AvoidUsingBrokenHashAlgorithms.tests.ps1 b/Tests/Rules/AvoidUsingBrokenHashAlgorithms.tests.ps1
new file mode 100644
index 000000000..d6f0059c7
--- /dev/null
+++ b/Tests/Rules/AvoidUsingBrokenHashAlgorithms.tests.ps1
@@ -0,0 +1,51 @@
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $settings = @{
+        IncludeRules = @('PSAvoidUsingBrokenHashAlgorithms')
+        Rules        = @{
+            PSAvoidUsingBrokenHashAlgorithms = @{
+                Enable = $true
+            }
+        }
+    }
+
+    $violationMessageMD5 = [regex]::Escape("The Algorithm parameter of cmdlet 'Get-FileHash' was used with the broken algorithm 'MD5'.")
+    $violationMessageSHA1 = [regex]::Escape("The Algorithm parameter of cmdlet 'Get-FileHash' was used with the broken algorithm 'SHA1'.")
+}
+
+Describe "AvoidUsingBrokenHashAlgorithms" {
+    Context "When there are violations" {
+        It "detects broken hash algorithms violations" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm MD5' -Settings $settings).Count | Should -Be 1
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm SHA1' -Settings $settings).Count | Should -Be 1
+        }
+
+        It "has the correct description message for MD5" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm MD5' -Settings $settings).Message | Should -Match $violationMessageMD5
+        }
+
+        It "has the correct description message for SHA-1" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm SHA1' -Settings $settings).Message | Should -Match $violationMessageSHA1
+        }
+
+        It "detects arbitrary cmdlets" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Fake-Cmdlet foo -Algorithm MD5' -Settings $settings).Count | Should -Be 1
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Fake-Cmdlet foo -Algorithm SHA1' -Settings $settings).Count | Should -Be 1
+        }
+
+    }
+
+    Context "When there are no violations" {
+        It "does not flag default algorithm" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo' -Settings $settings).Count | Should -Be 0
+        }
+        
+        It "does not flag safe algorithms" {
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm SHA256' -Settings $settings).Count | Should -Be 0
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm SHA384' -Settings $settings).Count | Should -Be 0
+            (Invoke-ScriptAnalyzer -ScriptDefinition 'Get-FileHash foo -Algorithm SHA512' -Settings $settings).Count | Should -Be 0
+        }
+    }
+}
\ No newline at end of file
diff --git a/Tests/Rules/AvoidUsingComputerNameHardcoded.tests.ps1 b/Tests/Rules/AvoidUsingComputerNameHardcoded.tests.ps1
index 3c0fc58a7..6b9bb30f6 100644
--- a/Tests/Rules/AvoidUsingComputerNameHardcoded.tests.ps1
+++ b/Tests/Rules/AvoidUsingComputerNameHardcoded.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = [regex]::Escape("The ComputerName parameter of cmdlet 'Invoke-Command' is hardcoded. This will expose sensitive information about the system if the script is shared.")
-$violationName = "PSAvoidUsingComputerNameHardcoded"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingComputerNameHardcoded.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingComputerNameHardcodedNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = [regex]::Escape("The ComputerName parameter of cmdlet 'Invoke-Command' is hardcoded. This will expose sensitive information about the system if the script is shared.")
+    $violationName = "PSAvoidUsingComputerNameHardcoded"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingComputerNameHardcoded.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingComputerNameHardcodedNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidUsingComputerNameHardcoded" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1 b/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1
index 9a04b96d5..2abd76be8 100644
--- a/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1
+++ b/Tests/Rules/AvoidUsingDeprecatedManifestFields.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationName = "PSAvoidUsingDeprecatedManifestFields"
-$violations = Invoke-ScriptAnalyzer "$PSScriptRoot\TestBadModule\TestDeprecatedManifestFields.psd1" | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer "$PSScriptRoot\TestGoodModule\TestGoodModule.psd1" | Where-Object {$_.RuleName -eq $violationName}
-$noViolations2 = Invoke-ScriptAnalyzer "$PSScriptRoot\TestGoodModule\TestDeprecatedManifestFieldsWithVersion2.psd1" | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationName = "PSAvoidUsingDeprecatedManifestFields"
+    $violations = Invoke-ScriptAnalyzer "$PSScriptRoot\TestBadModule\TestDeprecatedManifestFields.psd1" | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer "$PSScriptRoot\TestGoodModule\TestGoodModule.psd1" | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations2 = Invoke-ScriptAnalyzer "$PSScriptRoot\TestGoodModule\TestDeprecatedManifestFieldsWithVersion2.psd1" | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidUsingDeprecatedManifestFields" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidUsingDoubleQuotesForConstantString.tests.ps1 b/Tests/Rules/AvoidUsingDoubleQuotesForConstantString.tests.ps1
new file mode 100644
index 000000000..fcfab21bc
--- /dev/null
+++ b/Tests/Rules/AvoidUsingDoubleQuotesForConstantString.tests.ps1
@@ -0,0 +1,104 @@
+﻿BeforeAll {
+    $settings = @{
+        IncludeRules = @('PSAvoidUsingDoubleQuotesForConstantString')
+        Rules        = @{
+            PSAvoidUsingDoubleQuotesForConstantString = @{
+                Enable = $true
+            }
+        }
+    }
+}
+
+Describe 'AvoidUsingDoubleQuotesForConstantString' {
+    Context 'One line string' {
+        It 'Should warn if string is constant and double quotes are used' {
+            (Invoke-ScriptAnalyzer -ScriptDefinition '$item = "value"' -Settings $settings).Count | Should -Be 1
+        }
+
+        It 'Should correctly format if string is constant and double quotes are used' {
+            Invoke-Formatter -ScriptDefinition '$item = "value"' -Settings $settings | Should -Be "`$item = 'value'"
+        }
+
+        It 'Should not warn if string is interpolated and double quotes are used but single quotes are in value' {
+            Invoke-ScriptAnalyzer -ScriptDefinition "`$item = 'value'" -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It 'Should not warn if string is interpolated and double quotes are used but backtick character is in value' {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$item = "foo-`$-bar"' -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It 'Should not warn if string is constant and single quotes are used' {
+            Invoke-ScriptAnalyzer -ScriptDefinition "`$item = 'value'" -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It 'Should not warn if string is interpolated and double quotes are used' {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$item = "$(Get-Item)"' -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It 'Should not warn if string is interpolated and double quotes are used' {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$item = "$(Get-Item)"' -Settings $settings | Should -BeNullOrEmpty
+        }
+    }
+
+    # TODO: check escape strings
+
+    Context 'Here string' {
+        It 'Should warn if string is constant and double quotes are used' {
+            $scriptDefinition = @'
+$item=@"
+value
+"@
+'@
+            (Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings).Count | Should -Be 1
+        }
+
+        It 'Should correctly format if string is constant and double quotes are used' {
+            $scriptDefinition = @'
+$item=@"
+value
+"@
+'@
+            Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings | Should -Be @"
+`$item=@'
+value
+'@
+"@
+        }
+
+        It 'Should not warn if string is constant and double quotes are used but @'' is used in value' {
+            $scriptDefinition = @'
+$item=@"
+value1@'value2
+"@
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings | Should -BeNullOrEmpty
+        }
+        It 'Should not warn if string is constant and double quotes are used but backtick is used in value' {
+            $scriptDefinition = @'
+$item=@"
+foo-`$-bar
+"@
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It 'Should not warn if string is constant and single quotes are used' {
+            $scriptDefinition = @"
+`$item=@'
+value
+'@
+"@
+            Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It 'Should not warn if string is interpolated' {
+            $scriptDefinition = @'
+$item=@"
+$(Get-Process)
+"@
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings | Should -BeNullOrEmpty
+        }
+    }
+
+}
diff --git a/Tests/Rules/AvoidUsingInvokeExpression.tests.ps1 b/Tests/Rules/AvoidUsingInvokeExpression.tests.ps1
index 322a52b0a..2d2fe36a9 100644
--- a/Tests/Rules/AvoidUsingInvokeExpression.tests.ps1
+++ b/Tests/Rules/AvoidUsingInvokeExpression.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = "Invoke-Expression is used. Please remove Invoke-Expression from script and find other options instead."
-$violationName = "PSAvoidUsingInvokeExpression"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingInvokeExpression.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidConvertToSecureStringWithPlainTextNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Invoke-Expression is used. Please remove Invoke-Expression from script and find other options instead."
+    $violationName = "PSAvoidUsingInvokeExpression"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingInvokeExpression.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidConvertToSecureStringWithPlainTextNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "AvoidUsingInvokeExpression" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidUsingPlainTextForPassword.tests.ps1 b/Tests/Rules/AvoidUsingPlainTextForPassword.tests.ps1
index 2824a8088..340893f96 100644
--- a/Tests/Rules/AvoidUsingPlainTextForPassword.tests.ps1
+++ b/Tests/Rules/AvoidUsingPlainTextForPassword.tests.ps1
@@ -1,28 +1,32 @@
-﻿$violationMessage = [regex]::Escape("Parameter '`$password' should use SecureString, otherwise this will expose sensitive information. See ConvertTo-SecureString for more information.")
-$violationName = "PSAvoidUsingPlainTextForPassword"
-$violationFilepath = Join-Path $PSScriptRoot 'AvoidUsingPlainTextForPassword.ps1'
-$violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingPlainTextForPasswordNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
-Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1")
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = [regex]::Escape("Parameter '`$password' should not use String type but either ")
+    $violationName = "PSAvoidUsingPlainTextForPassword"
+    $violationFilepath = Join-Path $PSScriptRoot 'AvoidUsingPlainTextForPassword.ps1'
+    $violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object { $_.RuleName -eq $violationName }
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingPlainTextForPasswordNoViolations.ps1 | Where-Object { $_.RuleName -eq $violationName }
+    Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1")
+}
 
 Describe "AvoidUsingPlainTextForPassword" {
     Context "When there are violations" {
-    $expectedNumViolations = 7
-        It "has $expectedNumViolations violations" {
-            $violations.Count | Should -Be $expectedNumViolations
+        It "has expected violations count" {
+            $violations.Count | Should -Be 7
         }
 
-	It "suggests corrections" {
-	    Test-CorrectionExtent $violationFilepath $violations[0] 1 '$passphrases' '[SecureString] $passphrases'
-	    $violations[0].SuggestedCorrections[0].Description | Should -Be 'Set $passphrases type to SecureString'
+        It "suggests corrections" {
+            Test-CorrectionExtent $violationFilepath $violations[0] 2 '$passphrases' '[SecureString] $passphrases'
+            $violations[0].SuggestedCorrections[0].Description | Should -Be 'Set $passphrases type to SecureString'
 
-	    Test-CorrectionExtent $violationFilepath $violations[1] 1 '$passwordparam' '[SecureString] $passwordparam'
-	    Test-CorrectionExtent $violationFilepath $violations[2] 1 '$credential' '[SecureString] $credential'
-	    Test-CorrectionExtent $violationFilepath $violations[3] 1 '$password' '[SecureString] $password'
-	    Test-CorrectionExtent $violationFilepath $violations[4] 1 '[string]' '[SecureString]'
-	    Test-CorrectionExtent $violationFilepath $violations[5] 1 '[string[]]' '[SecureString[]]'
-	    Test-CorrectionExtent $violationFilepath $violations[6] 1 '[string]' '[SecureString]'
-	}
+            Test-CorrectionExtent $violationFilepath $violations[1] 2 '$passwordparam' '[SecureString] $passwordparam'
+            Test-CorrectionExtent $violationFilepath $violations[2] 2 '$credential' '[SecureString] $credential'
+            Test-CorrectionExtent $violationFilepath $violations[3] 2 '$password' '[SecureString] $password'
+            Test-CorrectionExtent $violationFilepath $violations[4] 2 '[string]' '[SecureString]'
+            Test-CorrectionExtent $violationFilepath $violations[5] 2 '[string[]]' '[SecureString[]]'
+            Test-CorrectionExtent $violationFilepath $violations[6] 2 '[string]' '[SecureString]'
+        }
 
         It "has the correct violation message" {
             $violations[3].Message | Should -Match $violationMessage
diff --git a/Tests/Rules/AvoidUsingReservedCharNames.tests.ps1 b/Tests/Rules/AvoidUsingReservedCharNames.tests.ps1
index 4321c97f9..0cd799bec 100644
--- a/Tests/Rules/AvoidUsingReservedCharNames.tests.ps1
+++ b/Tests/Rules/AvoidUsingReservedCharNames.tests.ps1
@@ -1,7 +1,12 @@
-﻿$reservedCharMessage = "The cmdlet 'Use-#Reserved' uses a reserved char in its name."
-$reservedCharName = "PSReservedCmdletChar"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingReservedCharNames.ps1 | Where-Object {$_.RuleName -eq $reservedCharName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $reservedCharName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $reservedCharMessage = "The cmdlet 'Use-#Reserved' uses a reserved char in its name."
+    $reservedCharName = "PSReservedCmdletChar"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingReservedCharNames.ps1 | Where-Object {$_.RuleName -eq $reservedCharName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $reservedCharName}
+}
 
 Describe "Avoid Using Reserved Char" {
     Context "When there are violations" {
diff --git a/Tests/Rules/AvoidUsingWMICmdlet.tests.ps1 b/Tests/Rules/AvoidUsingWMICmdlet.tests.ps1
index 688707121..174adf009 100644
--- a/Tests/Rules/AvoidUsingWMICmdlet.tests.ps1
+++ b/Tests/Rules/AvoidUsingWMICmdlet.tests.ps1
@@ -1,7 +1,12 @@
-﻿$WMIRuleName = "PSAvoidUsingWMICmdlet"
-$violationMessage = "File 'AvoidUsingWMICmdlet.ps1' uses WMI cmdlet. For PowerShell 3.0 and above, use CIM cmdlet which perform the same tasks as the WMI cmdlets. The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, which enables the cmdlets to use the same techniques to manage Windows computers and those running other operating systems."
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWMICmdlet.ps1 -IncludeRule $WMIRuleName
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWMICmdletNoViolations.ps1 -IncludeRule $WMIRuleName
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $WMIRuleName = "PSAvoidUsingWMICmdlet"
+    $violationMessage = "File 'AvoidUsingWMICmdlet.ps1' uses WMI cmdlet. For PowerShell 3.0 and above, use CIM cmdlet which perform the same tasks as the WMI cmdlets. The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model (CIM) standard, which enables the cmdlets to use the same techniques to manage Windows computers and those running other operating systems."
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWMICmdlet.ps1 -IncludeRule $WMIRuleName
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWMICmdletNoViolations.ps1 -IncludeRule $WMIRuleName
+}
 
 Describe "AvoidUsingWMICmdlet" {
     Context "Script contains references to WMI cmdlets - Violation" {
diff --git a/Tests/Rules/AvoidUsingWriteHost.tests.ps1 b/Tests/Rules/AvoidUsingWriteHost.tests.ps1
index 947328cdd..9d0a0847b 100644
--- a/Tests/Rules/AvoidUsingWriteHost.tests.ps1
+++ b/Tests/Rules/AvoidUsingWriteHost.tests.ps1
@@ -1,8 +1,13 @@
-﻿Set-Alias ctss ConvertTo-SecureString
-$writeHostMessage = [Regex]::Escape("File 'AvoidUsingWriteHost.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information.")
-$writeHostName = "PSAvoidUsingWriteHost"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWriteHost.ps1 | Where-Object {$_.RuleName -eq $writeHostName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWriteHostNoViolations.ps1 | Where-Object {$_.RuleName -eq $clearHostName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    Set-Alias ctss ConvertTo-SecureString
+    $writeHostMessage = [Regex]::Escape("File 'AvoidUsingWriteHost.ps1' uses Write-Host. Avoid using Write-Host because it might not work in all hosts, does not work when there is no host, and (prior to PS 5.0) cannot be suppressed, captured, or redirected. Instead, use Write-Output, Write-Verbose, or Write-Information.")
+    $writeHostName = "PSAvoidUsingWriteHost"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWriteHost.ps1 | Where-Object {$_.RuleName -eq $writeHostName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\AvoidUsingWriteHostNoViolations.ps1 | Where-Object {$_.RuleName -eq $clearHostName}
+}
 
 Describe "AvoidUsingWriteHost" {
     Context "When there are violations" {
diff --git a/Tests/Rules/DscExamplesPresent.tests.ps1 b/Tests/Rules/DscExamplesPresent.tests.ps1
index c8f52dd85..fd98c00dd 100644
--- a/Tests/Rules/DscExamplesPresent.tests.ps1
+++ b/Tests/Rules/DscExamplesPresent.tests.ps1
@@ -1,16 +1,21 @@
-$ruleName = "PSDSCDscExamplesPresent"
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
-
- Describe "DscExamplesPresent rule in class based resource" {
+BeforeAll {
+    $ruleName = "PSDSCDscExamplesPresent"
+}
 
-    $examplesPath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\Examples"
-    $classResourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1"
+ Describe "DscExamplesPresent rule in class based resource" -Skip:($PSVersionTable.PSVersion -lt '5.0')  {
+    BeforeAll {
+        $examplesPath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\Examples"
+        $classResourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1"
+    }
 
     Context "When examples absent" {
-
-        $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
-        $violationMessage = "No examples found for resource 'FileResource'"
+        BeforeAll {
+            $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
+            $violationMessage = "No examples found for resource 'FileResource'"
+        }
 
         It "has 1 missing examples violation" {
             $violations.Count | Should -Be 1
@@ -22,29 +27,31 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
     }
 
     Context "When examples present" {
-        New-Item -Path $examplesPath -ItemType Directory -force
-        New-Item -Path "$examplesPath\FileResource_Example.psm1" -ItemType File -force
-
-        $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
-
         It "returns no violations" {
+            New-Item -Path $examplesPath -ItemType Directory -force
+            New-Item -Path "$examplesPath\FileResource_Example.psm1" -ItemType File -force
+
+            $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
             $noViolations.Count | Should -Be 0
         }
 
-        Remove-Item -Path $examplesPath -Recurse -Force
+        AfterAll {
+            Remove-Item -Path $examplesPath -Recurse -Force
+        }
     }
- }
 }
 
 Describe "DscExamplesPresent rule in regular (non-class) based resource" {
-
-    $examplesPath = "$PSScriptRoot\DSCResourceModule\Examples"
-    $resourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
+    BeforeAll {
+        $examplesPath = "$PSScriptRoot\DSCResourceModule\Examples"
+        $resourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
+    }
 
     Context "When examples absent" {
-
-        $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
-        $violationMessage = "No examples found for resource 'MSFT_WaitForAll'"
+        BeforeAll {
+            $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
+            $violationMessage = "No examples found for resource 'MSFT_WaitForAll'"
+        }
 
         It "has 1 missing examples violation" {
             $violations.Count | Should -Be 1
@@ -56,15 +63,18 @@ Describe "DscExamplesPresent rule in regular (non-class) based resource" {
     }
 
     Context "When examples present" {
-        New-Item -Path $examplesPath -ItemType Directory -force
-        New-Item -Path "$examplesPath\MSFT_WaitForAll_Example.psm1" -ItemType File -force
-
-        $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
+        BeforeAll {
+            New-Item -Path $examplesPath -ItemType Directory -force
+            New-Item -Path "$examplesPath\MSFT_WaitForAll_Example.psm1" -ItemType File -force
+            $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
+        }
 
         It "returns no violations" {
             $noViolations.Count | Should -Be 0
         }
 
-        Remove-Item -Path $examplesPath -Recurse -Force
+        AfterAll {
+            Remove-Item -Path $examplesPath -Recurse -Force
+        }
     }
 }
diff --git a/Tests/Rules/DscTestsPresent.tests.ps1 b/Tests/Rules/DscTestsPresent.tests.ps1
index d9af9da94..b81104d1d 100644
--- a/Tests/Rules/DscTestsPresent.tests.ps1
+++ b/Tests/Rules/DscTestsPresent.tests.ps1
@@ -1,16 +1,21 @@
-$ruleName = "PSDSCDscTestsPresent"
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
-
- Describe "DscTestsPresent rule in class based resource" {
+BeforeAll {
+    $ruleName = "PSDSCDscTestsPresent"
+}
 
-    $testsPath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\Tests"
-    $classResourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1"
+ Describe "DscTestsPresent rule in class based resource" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
+    BeforeAll {
+        $testsPath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\Tests"
+        $classResourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1"
+    }
 
     Context "When tests absent" {
-
-        $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
-        $violationMessage = "No tests found for resource 'FileResource'"
+        BeforeAll {
+            $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
+            $violationMessage = "No tests found for resource 'FileResource'"
+        }
 
         It "has 1 missing test violation" {
             $violations.Count | Should -Be 1
@@ -22,29 +27,32 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
     }
 
     Context "When tests present" {
-        New-Item -Path $testsPath -ItemType Directory -force
-        New-Item -Path "$testsPath\FileResource_Test.psm1" -ItemType File -force
-
-        $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
+        BeforeAll {
+            New-Item -Path $testsPath -ItemType Directory -force
+            New-Item -Path "$testsPath\FileResource_Test.psm1" -ItemType File -force
+            $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $classResourcePath | Where-Object {$_.RuleName -eq $ruleName}
+        }
 
         It "returns no violations" {
             $noViolations.Count | Should -Be 0
         }
 
-        Remove-Item -Path $testsPath -Recurse -Force
+        AfterAll {
+            Remove-Item -Path $testsPath -Recurse -Force
+        }
     }
- }
 }
 
 Describe "DscTestsPresent rule in regular (non-class) based resource" {
-
-    $testsPath = "$PSScriptRoot\DSCResourceModule\Tests"
-    $resourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
+    BeforeAll {
+        $resourcePath = "$PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1"
+    }
 
     Context "When tests absent" {
-
-        $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
-        $violationMessage = "No tests found for resource 'MSFT_WaitForAll'"
+        BeforeAll {
+            $violations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
+            $violationMessage = "No tests found for resource 'MSFT_WaitForAll'"
+        }
 
         It "has 1 missing tests violation" {
             $violations.Count | Should -Be 1
@@ -56,15 +64,19 @@ Describe "DscTestsPresent rule in regular (non-class) based resource" {
     }
 
     Context "When tests present" {
-        New-Item -Path $testsPath -ItemType Directory -force
-        New-Item -Path "$testsPath\MSFT_WaitForAll_Test.psm1" -ItemType File -force
-
-        $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
+        BeforeAll {
+            $testsPath = "$PSScriptRoot\DSCResourceModule\Tests"
+            New-Item -Path $testsPath -ItemType Directory -force
+            New-Item -Path "$testsPath\MSFT_WaitForAll_Test.psm1" -ItemType File -force
+            $noViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $resourcePath | Where-Object {$_.RuleName -eq $ruleName}
+        }
 
         It "returns no violations" {
             $noViolations.Count | Should -Be 0
         }
 
-        Remove-Item -Path $testsPath -Recurse -Force
+        AfterAll {
+            Remove-Item -Path $testsPath -Recurse -Force
+        }
     }
 }
diff --git a/Tests/Rules/MisleadingBacktick.tests.ps1 b/Tests/Rules/MisleadingBacktick.tests.ps1
index b640e8b04..a042bbb89 100644
--- a/Tests/Rules/MisleadingBacktick.tests.ps1
+++ b/Tests/Rules/MisleadingBacktick.tests.ps1
@@ -1,8 +1,13 @@
-$writeHostName = "PSMisleadingBacktick"
-$violationFilepath = Join-Path $PSScriptRoot 'MisleadingBacktick.ps1'
-$violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object {$_.RuleName -eq $writeHostName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\NoMisleadingBacktick.ps1 | Where-Object {$_.RuleName -eq $clearHostName}
-Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1")
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $writeHostName = "PSMisleadingBacktick"
+    $violationFilepath = Join-Path $PSScriptRoot 'MisleadingBacktick.ps1'
+    $violations = Invoke-ScriptAnalyzer $violationFilepath | Where-Object {$_.RuleName -eq $writeHostName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\NoMisleadingBacktick.ps1 | Where-Object {$_.RuleName -eq $clearHostName}
+    Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1")
+}
 
 Describe "Avoid Misleading Backticks" {
     Context "When there are violations" {
diff --git a/Tests/Rules/PSCredentialType.tests.ps1 b/Tests/Rules/PSCredentialType.tests.ps1
index fb339d29d..ceb04e3ee 100644
--- a/Tests/Rules/PSCredentialType.tests.ps1
+++ b/Tests/Rules/PSCredentialType.tests.ps1
@@ -1,18 +1,22 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$violationMessage = "The Credential parameter in 'Credential' must be of type PSCredential. For PowerShell 4.0 and earlier, please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute."
-$violationName = "PSUsePSCredentialType"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\PSCredentialType.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\PSCredentialTypeNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+BeforeAll {
+    $violationMessage = "The Credential parameter in 'Credential' must be of type PSCredential. For PowerShell 4.0 and earlier, please define a credential transformation attribute, e.g. [System.Management.Automation.Credential()], after the PSCredential type attribute."
+    $violationName = "PSUsePSCredentialType"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\PSCredentialType.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\PSCredentialTypeNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "PSCredentialType" {
     Context "When there are violations" {
-        $expectedViolations = 1
-        if ((Test-PSVersionV3) -or (Test-PSVersionV4)) {
-            $expectedViolations = 2
+        BeforeAll {
+            $expectedViolations = 1
+            if (($PSVersionTable.PSVersion.Major -eq 3) -or ($PSVersionTable.PSVersion.Major -eq 4)) {
+                $expectedViolations = 2
+            }
         }
-        It ("has {0} PSCredential type violation" -f $expectedViolations) {
+        It ("has correct count of PSCredential type violations" -f $expectedViolations) {
             $violations.Count | Should -Be $expectedViolations
         }
 
diff --git a/Tests/Rules/PlaceCloseBrace.tests.ps1 b/Tests/Rules/PlaceCloseBrace.tests.ps1
index 94c65473f..85ccb8979 100644
--- a/Tests/Rules/PlaceCloseBrace.tests.ps1
+++ b/Tests/Rules/PlaceCloseBrace.tests.ps1
@@ -1,17 +1,22 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
-
-$ruleConfiguration = @{
-    Enable             = $true
-    NoEmptyLineBefore  = $true
-    IgnoreOneLineBlock = $true
-    NewLineAfter       = $true
-}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+
+    $ruleConfiguration = @{
+        Enable             = $true
+        NoEmptyLineBefore  = $true
+        IgnoreOneLineBlock = $true
+        NewLineAfter       = $true
+    }
 
-$settings = @{
-    IncludeRules = @("PSPlaceCloseBrace")
-    Rules        = @{
-        PSPlaceCloseBrace = $ruleConfiguration
+    $settings = @{
+        IncludeRules = @("PSPlaceCloseBrace")
+        Rules        = @{
+            PSPlaceCloseBrace = $ruleConfiguration
+        }
     }
 }
 
@@ -196,7 +201,7 @@ if (Test-Path "blah") {
         }
 
         It "Should find a violation for a close brace followed by a catch statement" {
-             $def = @'
+            $def = @'
 try {
     "try"
 } catch {
@@ -268,7 +273,7 @@ else {
     $false
 }
 '@
-             $expected = @'
+            $expected = @'
 if ($true) {
     $true
 } else {
@@ -279,14 +284,14 @@ if ($true) {
         }
 
         It "Should correct violation if the close brace and following keyword are apart by less than a space" {
-$def = @'
+            $def = @'
 if ($true) {
     $true
 }else {
     $false
 }
 '@
-             $expected = @'
+            $expected = @'
 if ($true) {
     $true
 } else {
@@ -297,14 +302,14 @@ if ($true) {
         }
 
         It "Should correct violation if the close brace and following keyword are apart by more than a space" {
-$def = @'
+            $def = @'
 if ($true) {
     $true
 }     else {
     $false
 }
 '@
-             $expected = @'
+            $expected = @'
 if ($true) {
     $true
 } else {
@@ -327,7 +332,7 @@ else {
     "3"
 }
 '@
-             $expected = @'
+            $expected = @'
 $x = 1
 if ($x -eq 1) {
     "1"
diff --git a/Tests/Rules/PlaceOpenBrace.tests.ps1 b/Tests/Rules/PlaceOpenBrace.tests.ps1
index 1635fd3ae..4c8206102 100644
--- a/Tests/Rules/PlaceOpenBrace.tests.ps1
+++ b/Tests/Rules/PlaceOpenBrace.tests.ps1
@@ -1,17 +1,23 @@
-﻿$ruleConfiguration = @{
-    Enable = $true
-    OnSameLine = $true
-    NewLineAfter = $true
-    IgnoreOneLineIf = $true
-}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleConfiguration = @{
+        Enable          = $true
+        OnSameLine      = $true
+        NewLineAfter    = $true
+        IgnoreOneLineIf = $true
+    }
 
-$settings = @{
-    IncludeRules = @("PSPlaceOpenBrace")
-    Rules = @{
-        PSPlaceOpenBrace = $ruleConfiguration
+    $settings = @{
+        IncludeRules = @("PSPlaceOpenBrace")
+        Rules        = @{
+            PSPlaceOpenBrace = $ruleConfiguration
+        }
     }
 }
 
+
 Describe "PlaceOpenBrace" {
     Context "When an open brace must be on the same line" {
         BeforeAll {
diff --git a/Tests/Rules/PossibleIncorrectComparisonWithNull.tests.ps1 b/Tests/Rules/PossibleIncorrectComparisonWithNull.tests.ps1
index ff00080d8..e2d3add21 100644
--- a/Tests/Rules/PossibleIncorrectComparisonWithNull.tests.ps1
+++ b/Tests/Rules/PossibleIncorrectComparisonWithNull.tests.ps1
@@ -1,7 +1,12 @@
-﻿$violationMessage = [regex]::Escape('$null should be on the left side of equality comparisons.')
-$violationName = "PSPossibleIncorrectComparisonWithNull"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\PossibleIncorrectComparisonWithNull.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\PossibleIncorrectComparisonWithNullNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = [regex]::Escape('$null should be on the left side of equality comparisons.')
+    $violationName = "PSPossibleIncorrectComparisonWithNull"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\PossibleIncorrectComparisonWithNull.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\PossibleIncorrectComparisonWithNullNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "PossibleIncorrectComparisonWithNull" {
     Context "When there are violations" {
diff --git a/Tests/Rules/PossibleIncorrectUsageOfAssignmentOperator.tests.ps1 b/Tests/Rules/PossibleIncorrectUsageOfAssignmentOperator.tests.ps1
index 8d5996965..0612a8922 100644
--- a/Tests/Rules/PossibleIncorrectUsageOfAssignmentOperator.tests.ps1
+++ b/Tests/Rules/PossibleIncorrectUsageOfAssignmentOperator.tests.ps1
@@ -1,4 +1,9 @@
-$ruleName = "PSPossibleIncorrectUsageOfAssignmentOperator"
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "PSPossibleIncorrectUsageOfAssignmentOperator"
+}
 
 Describe "PossibleIncorrectUsageOfComparisonOperator" {
     Context "When there are violations" {
diff --git a/Tests/Rules/PossibleIncorrectUsageOfRedirectionOperator.tests.ps1 b/Tests/Rules/PossibleIncorrectUsageOfRedirectionOperator.tests.ps1
index 3b1a4791d..8dd09d4eb 100644
--- a/Tests/Rules/PossibleIncorrectUsageOfRedirectionOperator.tests.ps1
+++ b/Tests/Rules/PossibleIncorrectUsageOfRedirectionOperator.tests.ps1
@@ -1,5 +1,9 @@
-Import-Module PSScriptAnalyzer
-$ruleName = "PSPossibleIncorrectUsageOfRedirectionOperator"
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "PSPossibleIncorrectUsageOfRedirectionOperator"
+}
 
 Describe "PossibleIncorrectUsageOfComparisonOperator" {
     Context "When there are violations" {
diff --git a/Tests/Rules/ProvideCommentHelp.tests.ps1 b/Tests/Rules/ProvideCommentHelp.tests.ps1
index 6ab2504e9..2216f15f0 100644
--- a/Tests/Rules/ProvideCommentHelp.tests.ps1
+++ b/Tests/Rules/ProvideCommentHelp.tests.ps1
@@ -1,45 +1,50 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
-
-$violationMessage = "The cmdlet 'Comment' does not have a help comment."
-$violationName = "PSProvideCommentHelp"
-$ruleSettings = @{
-    Enable = $true
-    ExportedOnly = $false
-    BlockComment = $true
-    Placement = "before"
-    VSCodeSnippetCorrection = $false
-}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+
+    $violationMessage = "The cmdlet 'Comment' does not have a help comment."
+    $violationName = "PSProvideCommentHelp"
+    $ruleSettings = @{
+        Enable = $true
+        ExportedOnly = $false
+        BlockComment = $true
+        Placement = "before"
+        VSCodeSnippetCorrection = $false
+    }
 
-$settings = @{
-    IncludeRules = @("PSProvideCommentHelp")
-    Rules = @{ PSProvideCommentHelp = $ruleSettings }
-}
+    $settings = @{
+        IncludeRules = @("PSProvideCommentHelp")
+        Rules = @{ PSProvideCommentHelp = $ruleSettings }
+    }
 
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
 
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
-    $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
-}
+    if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
+        $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    }
 
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
 
-function Test-Correction {
-    param($scriptDef, $expectedCorrection, $settings)
+    function Test-Correction {
+        param($scriptDef, $expectedCorrection, $settings)
 
-    $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -Settings $settings
-    $violations.Count | Should -Be 1
+        $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -Settings $settings
+        $violations.Count | Should -Be 1
 
-    # We split the lines because appveyor checks out files with "\n" endings
-    # on windows, which results in inconsistent line endings between corrections
-    # and result.
-    $resultLines = $violations[0].SuggestedCorrections[0].Text -split "\r?\n"
-    $expectedLines = $expectedCorrection -split "\r?\n"
-    $resultLines.Count | Should -Be $expectedLines.Count
-    for ($i = 0; $i -lt $resultLines.Count; $i++) {
-        $resultLine = $resultLines[$i]
-        $expectedLine = $expectedLines[$i]
-        $resultLine | Should -Be $expectedLine
+        # We split the lines because appveyor checks out files with "\n" endings
+        # on windows, which results in inconsistent line endings between corrections
+        # and result.
+        $resultLines = $violations[0].SuggestedCorrections[0].Text -split "\r?\n"
+        $expectedLines = $expectedCorrection -split "\r?\n"
+        $resultLines.Count | Should -Be $expectedLines.Count
+        for ($i = 0; $i -lt $resultLines.Count; $i++) {
+            $resultLine = $resultLines[$i]
+            $expectedLine = $expectedLines[$i]
+            $resultLine | Should -Be $expectedLine
+        }
     }
 }
 
@@ -329,10 +334,8 @@ $s$s$s$s
         }
 
 
-        if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
-            It "Does not count violation in DSC class" {
-                $dscViolations.Count | Should -Be 0
-            }
+        It "Does not count violation in DSC class" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
+            $dscViolations.Count | Should -Be 0
         }
     }
 
diff --git a/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1 b/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1
index 78b5f91e2..1ed4f610f 100644
--- a/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1
+++ b/Tests/Rules/ReturnCorrectTypesForDSCFunctions.tests.ps1
@@ -1,13 +1,18 @@
-﻿$violationMessageDSCResource = "Test-TargetResource function in DSC Resource should return object of type System.Boolean instead of System.Collections.Hashtable"
-$violationMessageDSCClass = "Get function in DSC Class FileResource should return object of type FileResource instead of type System.Collections.Hashtable"
-$violationName = "PSDSCReturnCorrectTypesForDSCFunctions"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
-
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
-{
-    $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
-    $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessageDSCResource = "Test-TargetResource function in DSC Resource should return object of type System.Boolean instead of System.Collections.Hashtable"
+    $violationMessageDSCClass = "Get function in DSC Class FileResource should return object of type FileResource instead of type System.Collections.Hashtable"
+    $violationName = "PSDSCReturnCorrectTypesForDSCFunctions"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+
+    if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
+    {
+        $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+        $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    }
 }
 
 Describe "ReturnCorrectTypesForDSCFunctions" {
@@ -28,8 +33,7 @@ Describe "ReturnCorrectTypesForDSCFunctions" {
     }
 }
 
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
- Describe "StandardDSCFunctionsInClass" {
+ Describe "StandardDSCFunctionsInClass" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
     Context "When there are violations" {
         It "has 4 return correct types for DSC functions violations" {
             $classViolations.Count | Should -Be 4
@@ -45,5 +49,4 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
             $noClassViolations.Count | Should -Be 0
         }
     }
- }
 }
diff --git a/Tests/Rules/ReviewUnusedParameter.tests.ps1 b/Tests/Rules/ReviewUnusedParameter.tests.ps1
index f5d6004cc..9e4202dcf 100644
--- a/Tests/Rules/ReviewUnusedParameter.tests.ps1
+++ b/Tests/Rules/ReviewUnusedParameter.tests.ps1
@@ -1,3 +1,6 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
 Describe "ReviewUnusedParameter" {
     BeforeAll {
         $RuleName = 'PSReviewUnusedParameter'
@@ -17,6 +20,30 @@ Describe "ReviewUnusedParameter" {
             $Violations.Count | Should -Be 2
         }
 
+        It "has 1 violation - function with 1 parameter with ValueFromPipeline set to false and `$_ usage inside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline = $false)] $Param1) process {$_}}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 1
+        }
+
+        It "has 1 violation - function with 1 parameter with ValueFromPipeline set to false and `$PSItem usage inside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline = $false)] $Param1) process {$PSItem}}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 1
+        }
+
+        It "has 1 violation - function with 1 parameter with ValueFromPipeline set to true and `$_ usage outside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline = $true)] $Param1) $_}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 1
+        }
+
+        It "has 1 violation - function with 1 parameter with ValueFromPipeline set to true and `$PSItem usage outside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline = $true)] $Param1) $PSItem}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 1
+        }
+
         It "has 1 violation - scriptblock with 1 unused parameter" {
             $ScriptDefinition = '{ param ($Param1) }'
             $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
@@ -29,6 +56,12 @@ Describe "ReviewUnusedParameter" {
             $Violations.Count | Should -Be 1
         }
 
+		It "doesn't traverse scriptblock scope for a random command" {
+            $ScriptDefinition = '{ param ($Param1) 1..3 | Invoke-Parallel { $Param1 }}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 1
+        }
+
         It "violations have correct rule and severity" {
             $ScriptDefinition = 'function BadFunc1 { param ($Param1, $Param2) $Param1}'
             $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
@@ -50,12 +83,48 @@ Describe "ReviewUnusedParameter" {
             $Violations.Count | Should -Be 0
         }
 
+        It "has no violation - function with 1 parameter with ValueFromPipeline explictly set to true and `$_ usage inside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline = $true)] $Param1) process {$_}}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
+        It "has no violation - function with 1 parameter with ValueFromPipeline explictly set to true and `$PSItem usage inside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline = $true)] $Param1) process {$PSItem}}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
+        It "has no violation - function with 1 parameter with ValueFromPipeline implicitly set to true and `$_ usage inside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline)] $Param1) process{$_}}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
+        It "has no violation - function with 1 parameter with ValueFromPipeline implicitly set to true and `$PSItem usage inside process block" {
+            $ScriptDefinition = 'function BadFunc1 { param ([Parameter(ValueFromPipeline)] $Param1) process{$PSItem}}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
         It "has no violations when using PSBoundParameters" {
             $ScriptDefinition = 'function Bound { param ($Param1) Get-Foo @PSBoundParameters }'
             $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
             $Violations.Count | Should -Be 0
         }
 
+        It "has no violations when using MyInvocation.BoundParameters" {
+            $ScriptDefinition = 'function Bound { param ($Param1) $splat = $MyInvocation.BoundParameters; Get-Foo @splat }'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
+        It "has no violations when using PSCmdlet.MyInvocation.BoundParameters" {
+            $ScriptDefinition = 'function Bound { param ($Param1) $splat = $PSCmdlet.MyInvocation.BoundParameters; Get-Foo @splat }'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
         It "has no violations when parameter is called in child scope" -skip {
             $ScriptDefinition = 'function foo { param ($Param1) function Child { $Param1 } }'
             $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
@@ -66,6 +135,24 @@ Describe "ReviewUnusedParameter" {
             $ScriptDefinition = 'function foo { param ($Param1, $param2) $param1; $Param2}'
             $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
             $Violations.Count | Should -Be 0
+        }
+
+		It "does traverse scriptblock scope for Foreach-Object" {
+            $ScriptDefinition = '{ param ($Param1) 1..3 | ForEach-Object { $Param1 }}'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName
+            $Violations.Count | Should -Be 0
+        }
+
+		It "does traverse scriptblock scope for commands added to the traversal list" {
+            $ScriptDefinition = '{ param ($Param1) Invoke-PSFProtectedCommand { $Param1 } }'
+            $Violations = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptDefinition -IncludeRule $RuleName -Settings @{
+				Rules = @{
+					PSReviewUnusedParameter = @{
+						CommandsToTraverse = @('Invoke-PSFProtectedCommand')
+					}
+				}
+			}
+            $Violations.Count | Should -Be 0
         }
     }
-}
+}
\ No newline at end of file
diff --git a/Tests/Rules/TestSettings/AvoidAliasSettings.psd1 b/Tests/Rules/TestSettings/AvoidAliasSettings.psd1
index e5a4cb1af..ada212196 100644
--- a/Tests/Rules/TestSettings/AvoidAliasSettings.psd1
+++ b/Tests/Rules/TestSettings/AvoidAliasSettings.psd1
@@ -1,7 +1,7 @@
 @{
     'Rules' = @{
         'PSAvoidUsingCmdletAliases' = @{
-            'Whitelist' = @('cd')
+            'allowlist' = @('cd')
         }
     }
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/UseBOMForUnicodeEncodedFile.tests.ps1 b/Tests/Rules/UseBOMForUnicodeEncodedFile.tests.ps1
index ba992d43e..bf325ef06 100644
--- a/Tests/Rules/UseBOMForUnicodeEncodedFile.tests.ps1
+++ b/Tests/Rules/UseBOMForUnicodeEncodedFile.tests.ps1
@@ -1,10 +1,15 @@
-﻿$violationMessageOne = "Missing BOM encoding for non-ASCII encoded file 'BOMAbsent_UTF16EncodedScript.ps1'"
-$violationMessageTwo = "Missing BOM encoding for non-ASCII encoded file 'BOMAbsent_UnknownEncodedScript.ps1'"
-$violationName = "PSUseBOMForUnicodeEncodedFile"
-$violationsOne = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMAbsent_UTF16EncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
-$violationsTwo = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMAbsent_UnknownEncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
-$noViolationsOne = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMPresent_UTF16EncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
-$noViolationsTwo = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMAbsent_ASCIIEncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessageOne = "Missing BOM encoding for non-ASCII encoded file 'BOMAbsent_UTF16EncodedScript.ps1'"
+    $violationMessageTwo = "Missing BOM encoding for non-ASCII encoded file 'BOMAbsent_UnknownEncodedScript.ps1'"
+    $violationName = "PSUseBOMForUnicodeEncodedFile"
+    $violationsOne = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMAbsent_UTF16EncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
+    $violationsTwo = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMAbsent_UnknownEncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
+    $noViolationsOne = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMPresent_UTF16EncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
+    $noViolationsTwo = Invoke-ScriptAnalyzer "$PSScriptRoot\TestFiles\BOMAbsent_ASCIIEncodedScript.ps1" | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "UseBOMForUnicodeEncodedFile" {
     Context "When there are violations" {
diff --git a/Tests/Rules/UseCmdletCorrectly.tests.ps1 b/Tests/Rules/UseCmdletCorrectly.tests.ps1
index 207036eb1..145821326 100644
--- a/Tests/Rules/UseCmdletCorrectly.tests.ps1
+++ b/Tests/Rules/UseCmdletCorrectly.tests.ps1
@@ -1,7 +1,13 @@
-﻿$violationMessage = "Cmdlet 'Write-Warning' may be used incorrectly. Please check that all mandatory parameters are supplied."
-$violationName = "PSUseCmdletCorrectly"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\UseCmdletCorrectly.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Cmdlet 'Write-Warning' may be used incorrectly. Please check that all mandatory parameters are supplied."
+    $violationName = "PSUseCmdletCorrectly"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\UseCmdletCorrectly.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "UseCmdletCorrectly" {
     Context "When there are violations" {
diff --git a/Tests/Rules/UseCompatibleCmdlets.tests.ps1 b/Tests/Rules/UseCompatibleCmdlets.tests.ps1
index d4db68502..787e0b8c3 100644
--- a/Tests/Rules/UseCompatibleCmdlets.tests.ps1
+++ b/Tests/Rules/UseCompatibleCmdlets.tests.ps1
@@ -1,63 +1,100 @@
-﻿$ruleName = "PSUseCompatibleCmdlets"
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-$ruleTestDirectory = Join-Path $PSScriptRoot 'UseCompatibleCmdlets'
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+$testCases = @(
+    # Microsoft.PowerShell.Core
+    @{
+        Command = 'Enter-PSSession'
+    }
+    @{
+        Command = 'Foreach-Object'
+    }
+    @{
+        Command = 'Get-Command'
+    }
+    # Non-builtin commands
+    @{
+        Command = 'get-foo'
+    }
+    @{
+        Command = 'get-bar'
+    }
+    @{
+        Command = 'get-baz'
+    }
+    # Aliases
+    @{
+        Command = 'where'
+    }
+    @{
+        Command = 'select'
+    }
+    @{
+        Command = 'cd'
+    }
+    # Commands present in reference platform but not in target platform
+    @{
+        Command              = 'Start-VM'
+        ExpectedOneViolation = $true
+    }
+    @{
+        Command              = 'New-SmbShare'
+        ExpectedOneViolation = $true
+    }
+    @{
+        Command              = 'Get-Disk'
+        ExpectedOneViolation = $true
+    }
+    # Default reference can also be used as target platform
+    @{
+        Command              = 'Remove-Service'
+        ExpectedOneViolation = $true
+        Settings             = @{ rules = @{ PSUseCompatibleCmdlets = @{ compatibility = @('desktop-5.1.14393.206-windows') } } }
+    }
+)
 
 Describe "UseCompatibleCmdlets" {
-    Context "script has violation" {
-        It "detects violation" {
-            $violationFilePath = Join-Path $ruleTestDirectory 'ScriptWithViolation.ps1'
-            $settingsFilePath =  [System.IO.Path]::Combine($ruleTestDirectory, 'PSScriptAnalyzerSettings.psd1');
-            $diagnosticRecords = Invoke-ScriptAnalyzer -Path $violationFilePath -IncludeRule $ruleName -Settings $settingsFilePath
-            $diagnosticRecords.Count | Should -Be 1
-        }
-    }
+    BeforeAll {
+        $ruleName = 'PSUseCompatibleCmdlets'
+        $settings = @{ rules = @{ PSUseCompatibleCmdlets = @{ compatibility = @('core-6.1.0-windows') } } }
 
-    Function Test-Command
-    {
-        param (
-            [Parameter(ValueFromPipeline)]
-            $command,
-            $settings,
-            $expectedViolations
-        )
-        process
+        Function Test-Command
         {
-            It ("found {0} violations for '{1}'" -f $expectedViolations, $command) {
-                $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $command -IncludeRule $ruleName -Settings $settings
-                $warnings.Count | Should -Be  $expectedViolations
-                $warnings | ForEach-Object {
-                    $_.RuleName | Should -Be 'PSUseCompatibleCmdlets'
-                }
+            Param (
+                [string] $Command,
+                [hashtable] $Settings,
+                [switch] $ExpectedOneViolation
+            )
+
+            $ruleName = 'PSUseCompatibleCmdlets'
+            $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $Command -IncludeRule $ruleName -Settings $Settings
+            if ($ExpectedOneViolation.IsPresent) {
+                $warnings.Count | Should -Be 1
+            }
+            else {
+                $warnings.Count | Should -Be 0
+            }
+            $warnings | ForEach-Object {
+                $_.RuleName | Should -Be $ruleName
             }
         }
-    }
-
-    $settings = @{rules=@{PSUseCompatibleCmdlets=@{compatibility=@("core-6.1.0-windows")}}}
-
-    Context "Microsoft.PowerShell.Core" {
-         @('Enter-PSSession', 'Foreach-Object', 'Get-Command') | `
-            Test-Command -Settings $settings -ExpectedViolations 0
-    }
 
-    Context "Non-builtin commands" {
-        @('get-foo', 'get-bar', 'get-baz') | `
-            Test-Command -Settings $settings -ExpectedViolations 0
+        $settings = @{rules = @{PSUseCompatibleCmdlets = @{compatibility = @('core-6.1.0-windows') } } }
     }
 
-    Context "Aliases" {
-        @('where', 'select', 'cd') | `
-            Test-Command -Settings $settings -ExpectedViolations 0
-    }
-
-    Context "Commands present in reference platform but not in target platform" {
-        @("Start-VM", "New-SmbShare", "Get-Disk") | `
-            Test-Command -Settings $settings -ExpectedViolations 1
+    Context "script has violation" {
+        It "detects violation" {
+            $ruleTestDirectory = Join-Path $PSScriptRoot 'UseCompatibleCmdlets'
+            $violationFilePath = Join-Path $ruleTestDirectory 'ScriptWithViolation.ps1'
+            $settingsFilePath = Join-Path $ruleTestDirectory 'PSScriptAnalyzerSettings.psd1'
+            $diagnosticRecords = Invoke-ScriptAnalyzer -Path $violationFilePath -IncludeRule $ruleName -Settings $settingsFilePath
+            $diagnosticRecords.Count | Should -Be 1
+        }
     }
 
-    Context "Default reference can also be used as target platform" {
-        $settings = @{rules=@{PSUseCompatibleCmdlets=@{compatibility=@("desktop-5.1.14393.206-windows")}}}
-        @("Remove-Service") | Test-Command -Settings $settings -ExpectedViolations 1
+    Context 'Correct Violations for commands' {
+        It "Command '<Command>' - Settings '<Settings>'" -TestCases $testCases {
+            Test-Command -Command $Command -Settings $settings -ExpectedOneViolation:$ExpectedOneViolation
+        }
     }
 }
diff --git a/Tests/Rules/UseCompatibleCommands.Tests.ps1 b/Tests/Rules/UseCompatibleCommands.Tests.ps1
index e2ac6ca68..cb49f3c1f 100644
--- a/Tests/Rules/UseCompatibleCommands.Tests.ps1
+++ b/Tests/Rules/UseCompatibleCommands.Tests.ps1
@@ -1,258 +1,278 @@
 ﻿# Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
-$script:RunningInCIOnUbuntu = $IsLinux -and ($env:TF_BUILD -or $env:APPVEYOR) # some test cases randomly start and stop to fail in Ubuntu CI tests
-$script:RuleName = 'PSUseCompatibleCommands'
-$script:AnyProfileConfigKey = 'AnyProfilePath'
-$script:TargetProfileConfigKey = 'TargetProfiles'
-
-$script:Srv2012_3_profile = 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
-$script:Srv2012r2_4_profile = 'win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework'
-$script:Srv2016_5_profile = 'win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework'
-$script:Srv2016_6_2_profile = 'win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core'
-$script:Srv2016_7_profile = 'win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core'
-$script:Srv2019_5_profile = 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-$script:Srv2019_6_2_profile = 'win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core'
-$script:Srv2019_7_profile = 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
-$script:Win10_5_profile = 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-$script:Win10_6_2_profile = 'win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core'
-$script:Win10_7_profile = 'win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core'
-$script:Ubuntu1804_6_2_profile = 'ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core'
-$script:Ubuntu1804_7_profile = 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
-
-$script:AzF_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azurefunctions.json").Path
-$script:AzA_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azureautomation.json").Path
-
-$script:CompatibilityTestCases = @(
-    @{ Target = $script:Srv2012_3_profile; Script = 'Write-Information "Information"'; Commands = @("Write-Information"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '"Hello World" | ConvertFrom-String | Get-Member'; Commands = @("ConvertFrom-String"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Compress-Archive -LiteralPath C:\Reference\Draftdoc.docx, C:\Reference\Images\diagram2.vsd -CompressionLevel Optimal -DestinationPath C:\Archives\Draft.Zip'; Commands = @("Compress-Archive"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Runspace -Id 2'; Commands = @("Get-Runspace"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '$Protected = "Hello World" | Protect-CmsMessage -To "*youralias@emailaddress.com*"'; Commands = @("Protect-CmsMessage"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Format-Hex -Path "C:\temp\temp.t7f"'; Commands = @("Format-Hex"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Clear-RecycleBin -Force'; Commands = @("Clear-RecycleBin"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '$TempFile = New-TemporaryFile'; Commands = @("New-TemporaryFile"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'New-Guid | Out-String'; Commands = @("New-Guid"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Enter-PSHostProcess -Name powershell_ise'; Commands = @("Enter-PSHostProcess"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Wait-Debugger'; Commands = @("Wait-Debugger"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Start-Job { Write-Host "Hello" } | Debug-Job'; Commands = @("Debug-Job"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase'; Commands = @("Get-ItemPropertyValue"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-FileHash $pshome\powershell.exe | Format-List'; Commands = @("Get-FileHash"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Save-Help -Module $m -DestinationPath "C:\SavedHelp"'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'gci .'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Write-Information "Information"'; Commands = @("Write-Information"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = '"Hello World" | ConvertFrom-String | Get-Member'; Commands = @("ConvertFrom-String"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Compress-Archive -LiteralPath C:\Reference\Draftdoc.docx, C:\Reference\Images\diagram2.vsd -CompressionLevel Optimal -DestinationPath C:\Archives\Draft.Zip'; Commands = @("Compress-Archive"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-Runspace -Id 2'; Commands = @("Get-Runspace"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Format-Hex -Path "C:\temp\temp.t7f"'; Commands = @("Format-Hex"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Clear-RecycleBin -Force'; Commands = @("Clear-RecycleBin"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = '$TempFile = New-TemporaryFile'; Commands = @("New-TemporaryFile"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'New-Guid | Out-String'; Commands = @("New-Guid"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Enter-PSHostProcess -Name powershell_ise'; Commands = @("Enter-PSHostProcess"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Wait-Debugger'; Commands = @("Wait-Debugger"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Start-Job { Write-Host "Hello" } | Debug-Job'; Commands = @("Debug-Job"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase'; Commands = @("Get-ItemPropertyValue"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'gci .'; Commands = @(); Version = "4.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "4.0"; OS = "Windows"; ProblemCount = 0 }
-
-    @{ Target = $script:Srv2019_5_profile; Script = "Remove-Alias gcm"; Commands = @("Remove-Alias"); Version = "5.1"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = "Get-Uptime"; Commands = @("Get-Uptime"); Version = "5.1"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = "Remove-Service 'MyService'"; Commands = @("Remove-Service"); Version = "5.1"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'gci .'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'fhx $filePath'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 }
-
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Add-PSSnapIn MySnapIn"; Commands = @("Add-PSSnapIn"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Get-PSSnapIn MySnapIn"; Commands = @("Get-PSSnapIn"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Get-Content $pshome\about_signing.help.txt | Out-Printer"; Commands = @("Out-Printer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'New-PSWorkflowSession -ComputerName "ServerNode01" -Name "WorkflowTests" -SessionOption (New-PSSessionOption -OutputBufferingMode Drop)'; Commands = @("New-PSWorkflowSession"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Get-Process | Out-GridView"; Commands = @("Out-GridView"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Get-Process | ogv"; Commands = @("ogv"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Remove-PSSnapIn MySnapIn"; Commands = @("Remove-PSSnapIn"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Show-Command"; Commands = @("Show-Command"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = '$composers | Convert-String -Example "first middle last=last, first"'; Commands = @("Convert-String"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Export-Console -Path $pshome\Consoles\ConsoleS1.psc1'; Commands = @("Export-Console"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-Counter "\Processor(*)\% Processor Time" | Export-Counter -Path $home\Counters.blg'; Commands = @("Get-Counter", "Export-Counter"); Version = "6.2"; OS = "Windows"; ProblemCount = 2 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'curl $uri'; Commands = @("curl"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'gci .'; Commands = @(); Version = "6.2"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2016_6_2_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "6.2"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Clear-RecycleBin'; Commands = @("Clear-RecycleBin"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "6.2"; OS = "Windows"; ProblemCount = 2 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @("Get-HotFix"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_7_profile; Script = "Add-PSSnapIn MySnapIn"; Commands = @("Add-PSSnapIn"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Get-PSSnapIn MySnapIn"; Commands = @("Get-PSSnapIn"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Get-Content $pshome\about_signing.help.txt | Out-Printer"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'New-PSWorkflowSession -ComputerName "ServerNode01" -Name "WorkflowTests" -SessionOption (New-PSSessionOption -OutputBufferingMode Drop)'; Commands = @("New-PSWorkflowSession"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Get-Process | Out-GridView"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Get-Process | ogv"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Remove-PSSnapIn MySnapIn"; Commands = @("Remove-PSSnapIn"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Show-Command"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = '$composers | Convert-String -Example "first middle last=last, first"'; Commands = @("Convert-String"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Export-Console -Path $pshome\Consoles\ConsoleS1.psc1'; Commands = @("Export-Console"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'gci .'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2016_7_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Clear-RecycleBin'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "7.0"; OS = "Windows"; ProblemCount = 2 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'Get-AuthenticodeSignature ./script.ps1'; Commands = @("Get-AuthenticodeSignature"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'Get-Service systemd'; Commands = @("Get-Service"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'Start-Service -Name "sshd"'; Commands = @("Start-Service"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'Get-PSSessionConfiguration -Name Full  | Format-List -Property *'; Commands = @("Get-PSSessionConfiguration"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'Get-CimInstance Win32_StartupCommand'; Commands = @("Get-CimInstance"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "6.2"; OS = "Linux"; ProblemCount = 0 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'gci .'; Commands = @(); Version = "6.2"; OS = "Linux"; ProblemCount = 0 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "6.2"; OS = "Linux"; ProblemCount = 0 }
-
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'Get-AuthenticodeSignature ./script.ps1'; Commands = @("Get-AuthenticodeSignature"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'Get-Service systemd'; Commands = @("Get-Service"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'Start-Service -Name "sshd"'; Commands = @("Start-Service"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'Get-PSSessionConfiguration -Name Full  | Format-List -Property *'; Commands = @("Get-PSSessionConfiguration"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'Get-CimInstance Win32_StartupCommand'; Commands = @("Get-CimInstance"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "7.0"; OS = "Linux"; ProblemCount = 0 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'gci .'; Commands = @(); Version = "7.0"; OS = "Linux"; ProblemCount = 0 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "7.0"; OS = "Linux"; ProblemCount = 0 }
-
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Clear-RecycleBin'; Commands = @("Clear-RecycleBin"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "6.2"; OS = "Windows"; ProblemCount = 2 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @("Get-HotFix"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_7_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Clear-RecycleBin'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "7.0"; OS = "Windows"; ProblemCount = 2 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
-)
-
-$script:ParameterCompatibilityTestCases = @(
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Item -Path ./ -InformationVariable i'; Commands = @('Get-Item'); Parameters = @('InformationVariable'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-ChildItem -Path ./ -Recurse -Depth 3'; Commands = @('Get-ChildItem'); Parameters = @('Depth'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Copy-Item -Path C:\myFile.txt -ToSession $s -DestinationFolder d:\destinationFolder'; Commands = @('Copy-Item', 'Copy-Item'); Parameters = @('ToSession', 'DestinationFolder'); Version = '3.0'; OS = 'Windows'; ProblemCount = 2 }
-    @{ Target = $script:Srv2012_3_profile; Script = '"File content" | Out-File ./file.txt -NoNewline'; Commands = @('Out-File'); Parameters = @('NoNewline'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Set-Content "Hi" -Path C:/path/to/thing.ps1 -NoNewline'; Commands = @('Set-Content'); Parameters = @('NoNewline'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Command -ShowCommandInfo'; Commands = @('Get-Command'); Parameters = @('ShowCommandInfo'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Import-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Import-Module'); Parameters = @('FullyQualifiedName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Remove-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Remove-Module'); Parameters = @('FullyQualifiedName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Register-ScheduledJob -RunNow -Trigger $t'; Commands = @('Register-ScheduledJob'); Parameters = @('RunNow'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'New-JobTrigger -At "1/20/2012 3:00 AM" -RepeatIndefinitely'; Commands = @('New-JobTrigger'); Parameters = @('RepeatIndefinitely'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '$t = Get-ScheduledJob | Get-JobTrigger | Enable-JobTrigger -PassThru'; Commands = @('Enable-JobTrigger'); Parameters = @('PassThru'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Save-Help -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Save-Help'); Parameters = @('FullyQualifiedModule'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Export-PSSession -FullyQualifiedModule @{ ModuleName = "MyModule"; RequiredVersion = $reqVer }'; Commands = @('Export-PSSession'); Parameters = @('FullyQualifiedModule'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Command -FullyQualifiedModule @{ ModuleName = $m; MaximumVersion = $maxVer }'; Commands = @('Get-Command'); Parameters = @('FullyQualifiedModule'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Module -FullyQualifiedName @{ ModuleName = $m; ModuleVersion = $v }'; Commands = @('Get-Module'); Parameters = @('FullyQualifiedName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Process -PipelineVariable proc | ForEach-Object { Format-Table $Proc }'; Commands = @('Get-Process'); Parameters = @('PipelineVariable'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = 'Get-Process -IncludeUserName'; Commands = @('Get-Process'); Parameters = @('IncludeUserName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-Item -Path ./ -InformationVariable i'; Commands = @('Get-Item'); Parameters = @('InformationVariable'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-ChildItem -Path ./ -Recurse -Depth 3'; Commands = @('Get-ChildItem'); Parameters = @('Depth'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Copy-Item -Path C:\myFile.txt -ToSession $s -DestinationFolder d:\destinationFolder'; Commands = @('Copy-Item', 'Copy-Item'); Parameters = @('ToSession', 'DestinationFolder'); Version = '4.0'; OS = 'Windows'; ProblemCount = 2 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = '"File content" | Out-File ./file.txt -NoNewline'; Commands = @('Out-File'); Parameters = @('NoNewline'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Set-Content "Hi" -Path C:/path/to/thing.ps1 -NoNewline'; Commands = @('Set-Content'); Parameters = @('NoNewline'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-Command -ShowCommandInfo'; Commands = @('Get-Command'); Parameters = @('ShowCommandInfo'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Import-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Import-Module'); Parameters = @('FullyQualifiedName'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Remove-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Remove-Module'); Parameters = @('FullyQualifiedName'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Save-Help -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Save-Help'); Parameters = @('FullyQualifiedModule'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Export-PSSession -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Export-PSSession'); Parameters = @('FullyQualifiedModule'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-Command -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Get-Command'); Parameters = @('FullyQualifiedModule'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Register-ScheduledJob -RunNow -Trigger $t'; Commands = @('Register-ScheduledJob'); Parameters = @('RunNow'); Version = '4.0'; OS = 'Windows'; ProblemCount = 0 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'Get-Module -FullyQualifiedName @{ ModuleName = $m; ModuleVersion = $v }'; Commands = @('Get-Module'); Parameters = @('FullyQualifiedName'); Version = '4.0'; OS = 'Windows'; ProblemCount = 0 }
-
-    @{ Target = $script:Srv2019_5_profile; Script = 'Invoke-RestMethod "https://example.com" -FollowRelLink -MaximumFollowRelLink 10 -CustomMethod "Squash"'; Commands = @('Invoke-RestMethod', 'Invoke-RestMethod', 'Invoke-RestMethod'); Parameters = @('FollowRelLink', 'MaximumFollowRelLink', 'CustomMethod'); Version = '5.1'; OS = 'Windows'; ProblemCount = 3 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Invoke-WebRequest "https://microsoft.com" -NoProxy -ContentType "something-strange" -SkipHeaderValidation'; Commands = @('Invoke-WebRequest', 'Invoke-WebRequest'); Parameters = @('NoProxy', 'SkipHeaderValidation'); Version = '5.1'; OS = 'Windows'; ProblemCount = 2 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Invoke-RestMethod "https://mywebsite.com/auth" -Authentication OAuth -Token $tok -ResponseHeadersVariable resp'; Commands = @('Invoke-RestMethod', 'Invoke-RestMethod', 'Invoke-RestMethod'); Parameters = @('Authentication', 'Token', 'ResponseHeadersVariable'); Version = '5.1'; OS = 'Windows'; ProblemCount = 3 }
-    @{ Target = $script:Srv2019_5_profile; Script = '$obj = ConvertFrom-Json $json -AsHashtable'; Commands = @('ConvertFrom-Json'); Parameters = @('AsHashtable'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Get-ChildItem . -FollowSymLink'; Commands = @('Get-ChildItem'); Parameters = @('FollowSymLink'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Import-Module "MyModule" -ErrorAction SilentlyContinue'; Commands = @(); Parameters = @(); Version = '5.1'; OS = 'Windows'; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Get-Location | Split-Path -LeafBase'; Commands = @('Split-Path'); Parameters = @('LeafBase'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Get-Process | sort PagedMemorySize -Top 10'; Commands = @('sort'); Parameters = @('Top'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = 'Get-Process | select -first 1 | Out-String -NoNewline'; Commands = @('Out-String'); Parameters = @('NoNewline'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Get-Help "Invoke-WebRequest" -ShowWindow'; Commands = @('Get-Help'); Parameters = @('ShowWindow'); Version = "6.2"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'Start-Service "eventlog" -ComputerName "MyComputer"'; Commands = @('Start-Service'); Parameters = @('ComputerName'); Version = "6.2"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_7_profile; Script = 'Get-Help "Invoke-WebRequest" -ShowWindow'; Commands = @(); Parameters = @(); Version = "7.0"; OS = 'Windows'; ProblemCount = 0 }
-    @{ Target = $script:Srv2019_7_profile; Script = 'Start-Service "eventlog" -ComputerName "MyComputer"'; Commands = @('Start-Service'); Parameters = @('ComputerName'); Version = "7.0"; OS = 'Windows'; ProblemCount = 1 }
-)
+BeforeDiscovery {
+    $RunningInCIOnUbuntu = $IsLinux -and ($env:TF_BUILD -or $env:APPVEYOR) # some test cases randomly start and stop to fail in Ubuntu CI tests
+
+    $Srv2012_3_profile = 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
+    $Srv2012r2_4_profile = 'win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework'
+    $Srv2016_5_profile = 'win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework'
+    $Srv2016_6_2_profile = 'win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core'
+    $Srv2016_7_profile = 'win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core'
+    $Srv2019_5_profile = 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+    $Srv2019_6_2_profile = 'win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core'
+    $Srv2019_7_profile = 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
+    $Win10_5_profile = 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+    $Win10_6_2_profile = 'win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core'
+    $Win10_7_profile = 'win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core'
+    $Ubuntu1804_6_2_profile = 'ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core'
+    $Ubuntu1804_7_profile = 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
+
+    $CompatibilityTestCases = @(
+        @{ Target = $Srv2012_3_profile; Script = 'Write-Information "Information"'; Commands = @("Write-Information"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '"Hello World" | ConvertFrom-String | Get-Member'; Commands = @("ConvertFrom-String"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Compress-Archive -LiteralPath C:\Reference\Draftdoc.docx, C:\Reference\Images\diagram2.vsd -CompressionLevel Optimal -DestinationPath C:\Archives\Draft.Zip'; Commands = @("Compress-Archive"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Runspace -Id 2'; Commands = @("Get-Runspace"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '$Protected = "Hello World" | Protect-CmsMessage -To "*youralias@emailaddress.com*"'; Commands = @("Protect-CmsMessage"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Format-Hex -Path "C:\temp\temp.t7f"'; Commands = @("Format-Hex"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Clear-RecycleBin -Force'; Commands = @("Clear-RecycleBin"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '$TempFile = New-TemporaryFile'; Commands = @("New-TemporaryFile"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'New-Guid | Out-String'; Commands = @("New-Guid"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Enter-PSHostProcess -Name powershell_ise'; Commands = @("Enter-PSHostProcess"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Wait-Debugger'; Commands = @("Wait-Debugger"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Start-Job { Write-Host "Hello" } | Debug-Job'; Commands = @("Debug-Job"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase'; Commands = @("Get-ItemPropertyValue"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-FileHash $pshome\powershell.exe | Format-List'; Commands = @("Get-FileHash"); Version = "3.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2012_3_profile; Script = 'Save-Help -Module $m -DestinationPath "C:\SavedHelp"'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2012_3_profile; Script = 'gci .'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2012_3_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+
+        @{ Target = $Srv2012r2_4_profile; Script = 'Write-Information "Information"'; Commands = @("Write-Information"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = '"Hello World" | ConvertFrom-String | Get-Member'; Commands = @("ConvertFrom-String"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Compress-Archive -LiteralPath C:\Reference\Draftdoc.docx, C:\Reference\Images\diagram2.vsd -CompressionLevel Optimal -DestinationPath C:\Archives\Draft.Zip'; Commands = @("Compress-Archive"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-Runspace -Id 2'; Commands = @("Get-Runspace"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Format-Hex -Path "C:\temp\temp.t7f"'; Commands = @("Format-Hex"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Clear-RecycleBin -Force'; Commands = @("Clear-RecycleBin"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = '$TempFile = New-TemporaryFile'; Commands = @("New-TemporaryFile"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'New-Guid | Out-String'; Commands = @("New-Guid"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Enter-PSHostProcess -Name powershell_ise'; Commands = @("Enter-PSHostProcess"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Wait-Debugger'; Commands = @("Wait-Debugger"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Start-Job { Write-Host "Hello" } | Debug-Job'; Commands = @("Debug-Job"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-ItemPropertyValue -Path HKLM:\SOFTWARE\Microsoft\PowerShell\3\PowerShellEngine -Name ApplicationBase'; Commands = @("Get-ItemPropertyValue"); Version = "4.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'gci .'; Commands = @(); Version = "4.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "4.0"; OS = "Windows"; ProblemCount = 0 }
+
+        @{ Target = $Srv2019_5_profile; Script = "Remove-Alias gcm"; Commands = @("Remove-Alias"); Version = "5.1"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = "Get-Uptime"; Commands = @("Get-Uptime"); Version = "5.1"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = "Remove-Service 'MyService'"; Commands = @("Remove-Service"); Version = "5.1"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_5_profile; Script = 'gci .'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_5_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_5_profile; Script = 'fhx $filePath'; Commands = @(); Version = "5.1"; OS = "Windows"; ProblemCount = 0 }
+
+        @{ Target = $Srv2019_6_2_profile; Script = "Add-PSSnapIn MySnapIn"; Commands = @("Add-PSSnapIn"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Get-PSSnapIn MySnapIn"; Commands = @("Get-PSSnapIn"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Get-Content $pshome\about_signing.help.txt | Out-Printer"; Commands = @("Out-Printer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'New-PSWorkflowSession -ComputerName "ServerNode01" -Name "WorkflowTests" -SessionOption (New-PSSessionOption -OutputBufferingMode Drop)'; Commands = @("New-PSWorkflowSession"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Get-Process | Out-GridView"; Commands = @("Out-GridView"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Get-Process | ogv"; Commands = @("ogv"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Remove-PSSnapIn MySnapIn"; Commands = @("Remove-PSSnapIn"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Show-Command"; Commands = @("Show-Command"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = '$composers | Convert-String -Example "first middle last=last, first"'; Commands = @("Convert-String"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Export-Console -Path $pshome\Consoles\ConsoleS1.psc1'; Commands = @("Export-Console"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-Counter "\Processor(*)\% Processor Time" | Export-Counter -Path $home\Counters.blg'; Commands = @("Get-Counter", "Export-Counter"); Version = "6.2"; OS = "Windows"; ProblemCount = 2 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'curl $uri'; Commands = @("curl"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "3.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'gci .'; Commands = @(); Version = "6.2"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2016_6_2_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "6.2"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Clear-RecycleBin'; Commands = @("Clear-RecycleBin"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "6.2"; OS = "Windows"; ProblemCount = 2 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @("Get-HotFix"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_7_profile; Script = "Add-PSSnapIn MySnapIn"; Commands = @("Add-PSSnapIn"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Get-PSSnapIn MySnapIn"; Commands = @("Get-PSSnapIn"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Get-Content $pshome\about_signing.help.txt | Out-Printer"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = 'New-PSWorkflowSession -ComputerName "ServerNode01" -Name "WorkflowTests" -SessionOption (New-PSSessionOption -OutputBufferingMode Drop)'; Commands = @("New-PSWorkflowSession"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Get-Process | Out-GridView"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = "Get-Process | ogv"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = "Remove-PSSnapIn MySnapIn"; Commands = @("Remove-PSSnapIn"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Show-Command"; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = '$composers | Convert-String -Example "first middle last=last, first"'; Commands = @("Convert-String"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Export-Console -Path $pshome\Consoles\ConsoleS1.psc1'; Commands = @("Export-Console"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = 'gci .'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2016_7_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Clear-RecycleBin'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "7.0"; OS = "Windows"; ProblemCount = 2 }
+        @{ Target = $Srv2019_7_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'Get-AuthenticodeSignature ./script.ps1'; Commands = @("Get-AuthenticodeSignature"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'Get-Service systemd'; Commands = @("Get-Service"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'Start-Service -Name "sshd"'; Commands = @("Start-Service"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'Get-PSSessionConfiguration -Name Full  | Format-List -Property *'; Commands = @("Get-PSSessionConfiguration"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'Get-CimInstance Win32_StartupCommand'; Commands = @("Get-CimInstance"); Version = "6.2"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "6.2"; OS = "Linux"; ProblemCount = 0 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'gci .'; Commands = @(); Version = "6.2"; OS = "Linux"; ProblemCount = 0 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "6.2"; OS = "Linux"; ProblemCount = 0 }
+
+        @{ Target = $Ubuntu1804_7_profile; Script = 'Get-AuthenticodeSignature ./script.ps1'; Commands = @("Get-AuthenticodeSignature"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'Get-Service systemd'; Commands = @("Get-Service"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'Start-Service -Name "sshd"'; Commands = @("Start-Service"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'Get-PSSessionConfiguration -Name Full  | Format-List -Property *'; Commands = @("Get-PSSessionConfiguration"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'Get-CimInstance Win32_StartupCommand'; Commands = @("Get-CimInstance"); Version = "7.0"; OS = "Linux"; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'Get-ChildItem ./ | Format-List'; Commands = @(); Version = "7.0"; OS = "Linux"; ProblemCount = 0 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'gci .'; Commands = @(); Version = "7.0"; OS = "Linux"; ProblemCount = 0 }
+        @{ Target = $Ubuntu1804_7_profile; Script = 'iex $expr | % { Transform $_ }'; Commands = @(); Version = "7.0"; OS = "Linux"; ProblemCount = 0 }
+
+        @{ Target = $Srv2019_6_2_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @("Set-Clipboard"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Clear-RecycleBin'; Commands = @("Clear-RecycleBin"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "6.2"; OS = "Windows"; ProblemCount = 2 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @("Get-HotFix"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "6.2"; OS = "Windows"; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_7_profile; Script = 'ConvertFrom-String $str'; Commands = @("ConvertFrom-String"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Get-WmiObject -Class Win32_Process"; Commands = @("Get-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = "Invoke-WmiMethod -Path win32_process -Name create -ArgumentList notepad.exe"; Commands = @("Invoke-WmiMethod"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = '$np | Remove-WmiObject'; Commands = @("Remove-WmiObject"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Set-Clipboard -Value "This is a test string"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = "Set-WmiInstance -Class Win32_WMISetting -Argument @{LoggingLevel=2}"; Commands = @("Set-WmiInstance"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Add-Computer -DomainName "Domain01" -Restart'; Commands = @("Add-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Checkpoint-Computer -Description "Install MyApp"'; Commands = @("Checkpoint-Computer"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Clear-EventLog "Windows PowerShell"'; Commands = @("Clear-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Clear-RecycleBin'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = 'Start-Transaction; New-Item MyCompany -UseTransaction; Complete-Transaction'; Commands = @("Start-Transaction", "Complete-Transaction"); Version = "7.0"; OS = "Windows"; ProblemCount = 2 }
+        @{ Target = $Srv2019_7_profile; Script = 'Disable-ComputerRestore -Drive "C:\"'; Commands = @("Disable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Enable-ComputerRestore -Drive "C:\", "D:\"'; Commands = @("Enable-ComputerRestore"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-ControlPanelItem -Name "*Program*", "*App*"'; Commands = @("Get-ControlPanelItem"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-EventLog -Newest 5 -LogName "Application"'; Commands = @("Get-EventLog"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+        @{ Target = $Srv2019_7_profile; Script = 'Get-HotFix -Description "Security*" -ComputerName "Server01", "Server02" -Cred "Server01\admin01"'; Commands = @(); Version = "7.0"; OS = "Windows"; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = '$zip = New-WebServiceProxy -Uri "http://www.webservicex.net/uszip.asmx?WSDL"'; Commands = @("New-WebServiceProxy"); Version = "7.0"; OS = "Windows"; ProblemCount = 1 }
+    )
+
+    $ParameterCompatibilityTestCases = @(
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Item -Path ./ -InformationVariable i'; Commands = @('Get-Item'); Parameters = @('InformationVariable'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-ChildItem -Path ./ -Recurse -Depth 3'; Commands = @('Get-ChildItem'); Parameters = @('Depth'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Copy-Item -Path C:\myFile.txt -ToSession $s -DestinationFolder d:\destinationFolder'; Commands = @('Copy-Item', 'Copy-Item'); Parameters = @('ToSession', 'DestinationFolder'); Version = '3.0'; OS = 'Windows'; ProblemCount = 2 }
+        @{ Target = $Srv2012_3_profile; Script = '"File content" | Out-File ./file.txt -NoNewline'; Commands = @('Out-File'); Parameters = @('NoNewline'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Set-Content "Hi" -Path C:/path/to/thing.ps1 -NoNewline'; Commands = @('Set-Content'); Parameters = @('NoNewline'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Command -ShowCommandInfo'; Commands = @('Get-Command'); Parameters = @('ShowCommandInfo'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Import-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Import-Module'); Parameters = @('FullyQualifiedName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Remove-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Remove-Module'); Parameters = @('FullyQualifiedName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Register-ScheduledJob -RunNow -Trigger $t'; Commands = @('Register-ScheduledJob'); Parameters = @('RunNow'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'New-JobTrigger -At "1/20/2012 3:00 AM" -RepeatIndefinitely'; Commands = @('New-JobTrigger'); Parameters = @('RepeatIndefinitely'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '$t = Get-ScheduledJob | Get-JobTrigger | Enable-JobTrigger -PassThru'; Commands = @('Enable-JobTrigger'); Parameters = @('PassThru'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Save-Help -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Save-Help'); Parameters = @('FullyQualifiedModule'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Export-PSSession -FullyQualifiedModule @{ ModuleName = "MyModule"; RequiredVersion = $reqVer }'; Commands = @('Export-PSSession'); Parameters = @('FullyQualifiedModule'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Command -FullyQualifiedModule @{ ModuleName = $m; MaximumVersion = $maxVer }'; Commands = @('Get-Command'); Parameters = @('FullyQualifiedModule'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Module -FullyQualifiedName @{ ModuleName = $m; ModuleVersion = $v }'; Commands = @('Get-Module'); Parameters = @('FullyQualifiedName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Process -PipelineVariable proc | ForEach-Object { Format-Table $Proc }'; Commands = @('Get-Process'); Parameters = @('PipelineVariable'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = 'Get-Process -IncludeUserName'; Commands = @('Get-Process'); Parameters = @('IncludeUserName'); Version = '3.0'; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-Item -Path ./ -InformationVariable i'; Commands = @('Get-Item'); Parameters = @('InformationVariable'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-ChildItem -Path ./ -Recurse -Depth 3'; Commands = @('Get-ChildItem'); Parameters = @('Depth'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Copy-Item -Path C:\myFile.txt -ToSession $s -DestinationFolder d:\destinationFolder'; Commands = @('Copy-Item', 'Copy-Item'); Parameters = @('ToSession', 'DestinationFolder'); Version = '4.0'; OS = 'Windows'; ProblemCount = 2 }
+        @{ Target = $Srv2012r2_4_profile; Script = '"File content" | Out-File ./file.txt -NoNewline'; Commands = @('Out-File'); Parameters = @('NoNewline'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Set-Content "Hi" -Path C:/path/to/thing.ps1 -NoNewline'; Commands = @('Set-Content'); Parameters = @('NoNewline'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-Command -ShowCommandInfo'; Commands = @('Get-Command'); Parameters = @('ShowCommandInfo'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Import-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Import-Module'); Parameters = @('FullyQualifiedName'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Remove-Module -FullyQualifiedName @{ ModuleName = "PSScriptAnalyzer"; ModuleVersion = "1.17" }'; Commands = @('Remove-Module'); Parameters = @('FullyQualifiedName'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Save-Help -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Save-Help'); Parameters = @('FullyQualifiedModule'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Export-PSSession -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Export-PSSession'); Parameters = @('FullyQualifiedModule'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-Command -FullyQualifiedModule @{ ModuleName = "MyModule"; MaximumVersion = "2.7" }'; Commands = @('Get-Command'); Parameters = @('FullyQualifiedModule'); Version = '4.0'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Register-ScheduledJob -RunNow -Trigger $t'; Commands = @('Register-ScheduledJob'); Parameters = @('RunNow'); Version = '4.0'; OS = 'Windows'; ProblemCount = 0 }
+        @{ Target = $Srv2012r2_4_profile; Script = 'Get-Module -FullyQualifiedName @{ ModuleName = $m; ModuleVersion = $v }'; Commands = @('Get-Module'); Parameters = @('FullyQualifiedName'); Version = '4.0'; OS = 'Windows'; ProblemCount = 0 }
+
+        @{ Target = $Srv2019_5_profile; Script = 'Invoke-RestMethod "https://example.com" -FollowRelLink -MaximumFollowRelLink 10 -CustomMethod "Squash"'; Commands = @('Invoke-RestMethod', 'Invoke-RestMethod', 'Invoke-RestMethod'); Parameters = @('FollowRelLink', 'MaximumFollowRelLink', 'CustomMethod'); Version = '5.1'; OS = 'Windows'; ProblemCount = 3 }
+        @{ Target = $Srv2019_5_profile; Script = 'Invoke-WebRequest "https://microsoft.com" -NoProxy -ContentType "something-strange" -SkipHeaderValidation'; Commands = @('Invoke-WebRequest', 'Invoke-WebRequest'); Parameters = @('NoProxy', 'SkipHeaderValidation'); Version = '5.1'; OS = 'Windows'; ProblemCount = 2 }
+        @{ Target = $Srv2019_5_profile; Script = 'Invoke-RestMethod "https://mywebsite.com/auth" -Authentication OAuth -Token $tok -ResponseHeadersVariable resp'; Commands = @('Invoke-RestMethod', 'Invoke-RestMethod', 'Invoke-RestMethod'); Parameters = @('Authentication', 'Token', 'ResponseHeadersVariable'); Version = '5.1'; OS = 'Windows'; ProblemCount = 3 }
+        @{ Target = $Srv2019_5_profile; Script = '$obj = ConvertFrom-Json $json -AsHashtable'; Commands = @('ConvertFrom-Json'); Parameters = @('AsHashtable'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = 'Get-ChildItem . -FollowSymLink'; Commands = @('Get-ChildItem'); Parameters = @('FollowSymLink'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = 'Import-Module "MyModule" -ErrorAction SilentlyContinue'; Commands = @(); Parameters = @(); Version = '5.1'; OS = 'Windows'; ProblemCount = 0 }
+        @{ Target = $Srv2019_5_profile; Script = 'Get-Location | Split-Path -LeafBase'; Commands = @('Split-Path'); Parameters = @('LeafBase'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = 'Get-Process | sort PagedMemorySize -Top 10'; Commands = @('sort'); Parameters = @('Top'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = 'Get-Process | select -first 1 | Out-String -NoNewline'; Commands = @('Out-String'); Parameters = @('NoNewline'); Version = '5.1'; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_6_2_profile; Script = 'Get-Help "Invoke-WebRequest" -ShowWindow'; Commands = @('Get-Help'); Parameters = @('ShowWindow'); Version = "6.2"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_6_2_profile; Script = 'Start-Service "eventlog" -ComputerName "MyComputer"'; Commands = @('Start-Service'); Parameters = @('ComputerName'); Version = "6.2"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_7_profile; Script = 'Get-Help "Invoke-WebRequest" -ShowWindow'; Commands = @(); Parameters = @(); Version = "7.0"; OS = 'Windows'; ProblemCount = 0 }
+        @{ Target = $Srv2019_7_profile; Script = 'Start-Service "eventlog" -ComputerName "MyComputer"'; Commands = @('Start-Service'); Parameters = @('ComputerName'); Version = "7.0"; OS = 'Windows'; ProblemCount = 1 }
+    )
+}
 
 Describe 'UseCompatibleCommands' {
+    BeforeAll {
+        $RuleName = 'PSUseCompatibleCommands'
+
+        $Srv2012_3_profile = 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
+        $Srv2012r2_4_profile = 'win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework'
+        $Srv2016_5_profile = 'win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework'
+        $Srv2016_6_2_profile = 'win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core'
+        $Srv2016_7_profile = 'win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core'
+        $Srv2019_5_profile = 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+        $Srv2019_6_2_profile = 'win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core'
+        $Srv2019_7_profile = 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
+        $Win10_5_profile = 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+        $Win10_6_2_profile = 'win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core'
+        $Win10_7_profile = 'win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core'
+        $Ubuntu1804_6_2_profile = 'ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core'
+        $Ubuntu1804_7_profile = 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
+
+        $AzF_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azurefunctions.json").Path
+        $AzA_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azureautomation.json").Path
+
+        $TargetProfileConfigKey = 'TargetProfiles'
+
+    }
+
     Context 'Targeting a single profile' {
-        It "Reports <ProblemCount> command incompatibilties with '<Script>' on <OS> with PowerShell <Version>" -TestCases $script:CompatibilityTestCases -Skip:$script:RunningInCIOnUbuntu {
+        It "Reports <ProblemCount> command incompatibilties with '<Script>' on <OS> with PowerShell <Version>" -TestCases $CompatibilityTestCases -Skip:$RunningInCIOnUbuntu {
             param($Script, [string]$Target, [string[]]$Commands, [version]$Version, [string]$OS, [int]$ProblemCount)
 
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @($Target)
+                        $TargetProfileConfigKey = @($Target)
                     }
                 }
             }
 
-            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -ScriptDefinition $Script -Settings $settings `
+            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $RuleName -ScriptDefinition $Script -Settings $settings `
                 | Where-Object { -not $_.Parameter } # Filter out diagnostics about incompatible parameters
 
             $diagnostics.Count | Should -Be $ProblemCount -Because ($diagnostics.RuleName -join ', ')
@@ -266,19 +286,19 @@ Describe 'UseCompatibleCommands' {
             }
         }
 
-        It "Reports <ProblemCount> parameter incompatibilties for '<Parameters>' on '<Commands>' with '<Script>' on <OS> with PowerShell <Version>" -TestCases $script:ParameterCompatibilityTestCases -Skip:$script:RunningInCIOnUbuntu {
+        It "Reports <ProblemCount> parameter incompatibilties for '<Parameters>' on '<Commands>' with '<Script>' on <OS> with PowerShell <Version>" -TestCases $ParameterCompatibilityTestCases -Skip:$RunningInCIOnUbuntu {
             param($Script, [string]$Target, [string[]]$Commands, [string[]]$Parameters, [version]$Version, [string]$OS, [int]$ProblemCount)
 
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @($Target)
+                        $TargetProfileConfigKey = @($Target)
                     }
                 }
             }
 
-            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -ScriptDefinition $Script -Settings $settings `
+            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $RuleName -ScriptDefinition $Script -Settings $settings `
                 | Where-Object { $_.Parameter } # Filter out diagnostics about incompatible parameters
 
             $diagnostics.Count | Should -Be $ProblemCount -Because ($diagnostics.RuleName -join ', ')
@@ -294,25 +314,25 @@ Describe 'UseCompatibleCommands' {
     }
 
     Context "Checking a file against many targets" {
-        It "Finds all command problems" -Skip:$script:RunningInCIOnUbuntu {
+        It "Finds all command problems" -Skip:$RunningInCIOnUbuntu {
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @(
-                            $script:Srv2012_3_profile
-                            $script:Srv2012r2_4_profile
-                            $script:Srv2019_5_profile
-                            $script:Srv2019_6_2_profile
-                            $script:Srv2019_7_profile
-                            $script:Ubuntu1804_6_2_profile
-                            $script:Ubuntu1804_7_profile
+                        $TargetProfileConfigKey = @(
+                            $Srv2012_3_profile
+                            $Srv2012r2_4_profile
+                            $Srv2019_5_profile
+                            $Srv2019_6_2_profile
+                            $Srv2019_7_profile
+                            $Ubuntu1804_6_2_profile
+                            $Ubuntu1804_7_profile
                         )
                     }
                 }
             }
 
-            $diagnostics = Invoke-ScriptAnalyzer -Path "$PSScriptRoot/CompatibilityRuleAssets/IncompatibleScript.ps1" -IncludeRule $script:RuleName -Settings $settings -Severity Information,Warning,Error
+            $diagnostics = Invoke-ScriptAnalyzer -Path "$PSScriptRoot/CompatibilityRuleAssets/IncompatibleScript.ps1" -IncludeRule $RuleName -Settings $settings -Severity Information,Warning,Error
 
             # Classes cause diagnostics to be emitted in PS 3 and 4
             $expectedNumber = 17
@@ -363,24 +383,27 @@ Describe 'UseCompatibleCommands' {
         It "Ensures that PSSA build scripts are cross compatible with everything" {
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @(
-                            $script:Srv2012_3_profile
-                            $script:Srv2012r2_4_profile
-                            $script:Srv2016_5_profile
-                            $script:Srv2016_6_2_profile
-                            $script:Srv2019_5_profile
-                            $script:Srv2019_6_2_profile
-                            $script:Srv2019_7_profile
-                            $script:Win10_5_profile
-                            $script:Win10_6_2_profile
-                            $script:Win10_7_profile
-                            $script:Ubuntu1804_6_2_profile
-                            $script:Ubuntu1804_7_profile
+                        $TargetProfileConfigKey = @(
+                            $Srv2012_3_profile
+                            $Srv2012r2_4_profile
+                            $Srv2016_5_profile
+                            $Srv2016_6_2_profile
+                            $Srv2019_5_profile
+                            $Srv2019_6_2_profile
+                            $Srv2019_7_profile
+                            $Win10_5_profile
+                            $Win10_6_2_profile
+                            $Win10_7_profile
+                            $Ubuntu1804_6_2_profile
+                            $Ubuntu1804_7_profile
                         )
                         IgnoreCommands = @(
                             'Install-Module'
+                            'Publish-Module'
+                            'Register-PSRepository'
+                            'Unregister-PSRepository'
                             # Some PowerShell profiles have Pester installed by default
                             # So Pester is legitimately flagged
                             'Describe'
@@ -399,7 +422,7 @@ Describe 'UseCompatibleCommands' {
                 }
             }
 
-            $diagnostics = Invoke-ScriptAnalyzer -Path "$PSScriptRoot/../../" -IncludeRule $script:RuleName -Settings $settings
+            $diagnostics = Invoke-ScriptAnalyzer -Path "$PSScriptRoot/../../" -IncludeRule $RuleName -Settings $settings
             $diagnostics.Count | Should -Be 0 -Because ($diagnostics.Message -join ', ')
         }
     }
@@ -408,12 +431,12 @@ Describe 'UseCompatibleCommands' {
         BeforeAll {
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @(
-                            $script:AzF_profile
-                            $script:AzA_profile
-                            $script:Win10_5_profile
+                        $TargetProfileConfigKey = @(
+                            $AzF_profile
+                            $AzA_profile
+                            $Win10_5_profile
                         )
                     }
                 }
@@ -421,7 +444,7 @@ Describe 'UseCompatibleCommands' {
         }
 
         It "Finds AzF problems with a script" {
-            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -Settings $settings -ScriptDefinition '
+            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $RuleName -Settings $settings -ScriptDefinition '
                 Get-WmiObject Win32_Process
                 New-SelfSignedCertificate
                 Invoke-MySpecialFunction
diff --git a/Tests/Rules/UseCompatibleSyntax.Tests.ps1 b/Tests/Rules/UseCompatibleSyntax.Tests.ps1
index 150ef2ecf..64ac464ae 100644
--- a/Tests/Rules/UseCompatibleSyntax.Tests.ps1
+++ b/Tests/Rules/UseCompatibleSyntax.Tests.ps1
@@ -1,70 +1,75 @@
 # Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
-$script:RuleName = 'PSUseCompatibleSyntax'
-
-Describe "PSUseCompatibleSyntax" {
-    BeforeAll {
-        $testCases = @(
-            @{ Script = '$x = [MyClass]::new()'; Versions = @(3,4) }
-            @{ Script = '$member = "Hi"; $x.$member'; Versions = @() }
-            @{ Script = 'Write-Host "Banana"'; Versions = @() }
-            @{ Script = '[System.VeryInnocuousType]::RunApiMethod($obj)'; Versions = @() }
-            @{ Script = '$y.$methodWithAVeryLongName()'; Versions = @(3) }
-            @{ Script = '$typeExpression::$staticMember'; Versions = @() }
-            @{ Script = '$typeExpression::$dynamicStaticMethodName()'; Versions = @(3) }
+BeforeDiscovery {
+    $RuleName = 'PSUseCompatibleSyntax'
+
+    $testCases = @(
+        @{ Script = '$x = [MyClass]::new()'; Versions = @(3,4) }
+        @{ Script = '$member = "Hi"; $x.$member'; Versions = @() }
+        @{ Script = 'Write-Host "Banana"'; Versions = @() }
+        @{ Script = '[System.VeryInnocuousType]::RunApiMethod($obj)'; Versions = @() }
+        @{ Script = '$y.$methodWithAVeryLongName()'; Versions = @(3) }
+        @{ Script = '$typeExpression::$staticMember'; Versions = @() }
+        @{ Script = '$typeExpression::$dynamicStaticMethodName()'; Versions = @(3) }
+    )
+    # PS v3/4 won't parse classes or enums
+    if ($PSVersionTable.PSVersion.Major -ge 5)
+    {
+        $testCases += @(
+            @{ Script = "class MyClass { }"; Versions = @(3,4) }
+            @{ Script = "enum MyEnum { One; Two }"; Versions = @(3,4) }
+        )
+    }
+    # PS v6+ won't parse workflows
+    if ($PSVersionTable.PSVersion.Major -le 5)
+    {
+        $testCases += @(
+            @{ Script = 'workflow Banana { Do-ExpensiveCommandOnAnotherMachine -Argument "Banana" }'; Versions = @(6) }
+        )
+    }
+    if ($PSVersionTable.PSVersion.Major -ge 7)
+    {
+        $testCases += @(
+            @{ Script = '$x = $path ? (Get-Content -Raw $path) : "default"'; Versions = @(3,4,5,6) }
+            @{ Script = '$x ??= 7'; Versions = @(3,4,5,6) }
+            @{ Script = 'git pull origin master && git pull upstream master'; Versions = @(3,4,5,6) }
         )
 
-        # PS v3/4 won't parse classes or enums
-        if ($PSVersionTable.PSVersion.Major -ge 5)
-        {
-            $testCases += @(
-                @{ Script = "class MyClass { }"; Versions = @(3,4) }
-                @{ Script = "enum MyEnum { One; Two }"; Versions = @(3,4) }
-            )
-        }
-
-        # PS v6+ won't parse workflows
-        if ($PSVersionTable.PSVersion.Major -le 5)
+        if ((Get-ExperimentalFeature -Name 'PSNullConditionalOperators').Enabled)
         {
             $testCases += @(
-                @{ Script = 'workflow Banana { Do-ExpensiveCommandOnAnotherMachine -Argument "Banana" }'; Versions = @(6) }
+                @{ Script = '${item}?.Invoke()'; Versions = @(3,4,5,6) }
+                @{ Script = '${object}?.Member'; Versions = @(3,4,5,6) }
             )
         }
-
-        if ($PSVersionTable.PSVersion.Major -ge 7)
-        {
-            $testCases += @(
-                @{ Script = '$x = $path ? (Get-Content -Raw $path) : "default"'; Versions = @(3,4,5,6) }
-                @{ Script = '$x ??= 7'; Versions = @(3,4,5,6) }
-                @{ Script = 'git pull origin master && git pull upstream master'; Versions = @(3,4,5,6) }
-            )
-
-            if ((Get-ExperimentalFeature -Name 'PSNullConditionalOperators').Enabled)
-            {
-                $testCases += @(
-                    @{ Script = '${item}?.Invoke()'; Versions = @(3,4,5,6) }
-                    @{ Script = '${object}?.Member'; Versions = @(3,4,5,6) }
-                )
+    }
+    $testCasesAllPSVersions = foreach ($version in 3, 4, 5, 6) {
+        foreach($testCase in $testCases) {
+            @{
+                Script = $testCase.Script
+                Versions = $testCase.Versions
+                TargetVersion = $version
             }
         }
     }
+}
 
-    foreach ($v in 3,4,5,6)
-    {
-        It "Finds issues for PSv$v in '<Script>'" -TestCases $testCases {
-            param([string]$Script, $Versions)
+Describe "PSUseCompatibleSyntax" {
+    It "Finds issues for PSv<TargetVersion> in '<Script>'" -TestCases $testCasesAllPSVersions {
+        param([string]$Script, $Versions, $TargetVersion)
 
-            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $Script -IncludeRule PSUseCompatibleSyntax -Settings @{ Rules = @{ PSUseCompatibleSyntax = @{ Enable = $true; TargetVersions = @("$v.0") } } }
+        $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $Script -IncludeRule PSUseCompatibleSyntax -Settings @{
+            Rules = @{ PSUseCompatibleSyntax = @{ Enable = $true; TargetVersions = @("$TargetVersion.0") } }
+        }
 
-            if ($Versions -contains $v)
-            {
-                $diagnostics.Count | Should -Be 1
-            }
-            else
-            {
-                $diagnostics.Count | Should -Be 0
-            }
+        if ($Versions -contains $TargetVersion)
+        {
+            $diagnostics.Count | Should -Be 1
+        }
+        else
+        {
+            $diagnostics.Count | Should -Be 0
         }
     }
 
@@ -94,4 +99,4 @@ Describe "PSUseCompatibleSyntax" {
 
         $diagnostics.Count | Should -Be 0
     }
-}
\ No newline at end of file
+}
diff --git a/Tests/Rules/UseCompatibleTypes.Tests.ps1 b/Tests/Rules/UseCompatibleTypes.Tests.ps1
index 9d7a191a4..d454dd356 100644
--- a/Tests/Rules/UseCompatibleTypes.Tests.ps1
+++ b/Tests/Rules/UseCompatibleTypes.Tests.ps1
@@ -1,87 +1,105 @@
 ﻿# Copyright (c) Microsoft Corporation. All rights reserved.
 # Licensed under the MIT License.
 
-$script:RuleName = 'PSUseCompatibleTypes'
-$script:AnyProfileConfigKey = 'AnyProfilePath'
-$script:TargetProfileConfigKey = 'TargetProfiles'
-
-$script:Srv2012_3_profile = 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
-$script:Srv2012r2_4_profile = 'win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework'
-$script:Srv2016_5_profile = 'win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework'
-$script:Srv2016_6_2_profile = 'win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core'
-$script:Srv2016_7_profile = 'win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core'
-$script:Srv2019_5_profile = 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-$script:Srv2019_6_2_profile = 'win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core'
-$script:Srv2019_7_profile = 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
-$script:Win10_5_profile = 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
-$script:Win10_6_2_profile = 'win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core'
-$script:Win10_7_profile = 'win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core'
-$script:Ubuntu1804_6_2_profile = 'ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core'
-$script:Ubuntu1804_7_profile = 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
-
-$script:AzF_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azurefunctions.json").Path
-$script:AzA_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azureautomation.json").Path
-
-$script:TypeCompatibilityTestCases = @(
-    @{ Target = $script:Srv2012_3_profile; Script = '[System.Management.Automation.ModuleIntrinsics]::GetModulePath("here", "there", "everywhere")'; Types = @('System.Management.Automation.ModuleIntrinsics'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '$ast -is [System.Management.Automation.Language.FunctionMemberAst]'; Types = @('System.Management.Automation.Language.FunctionMemberAst'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '$version = [System.Management.Automation.SemanticVersion]::Parse($version)'; Types = @('System.Management.Automation.SemanticVersion'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '$kw = New-Object "System.Management.Automation.Language.DynamicKeyword"'; Types = @('System.Management.Automation.Language.DynamicKeyword'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '& { param([Parameter(Position=0)][ArgumentCompleter({"Banana"})][string]$Hello) $Hello } "Banana"'; Types = @('ArgumentCompleter'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2012r2_4_profile; Script = '[WildcardPattern]"bicycle*"'; Types = @('WildcardPattern'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = '$client = [System.Net.Http.HttpClient]::new()'; Types = @('System.Net.Http.HttpClient'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = '[Microsoft.PowerShell.EditMode]"Vi"'; Types = @('Microsoft.PowerShell.EditMode'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_5_profile; Script = '[Microsoft.PowerShell.Commands.WebSslProtocol]::Default -eq "Tls12"'; Types = @('Microsoft.PowerShell.Commands.WebSslProtocol'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = '[System.Collections.Immutable.ImmutableList[string]]::Empty'; Types = @('System.Collections.Immutable.ImmutableList'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = '[System.Collections.Generic.TreeSet[string]]::new(@("duck", "goose", "banana"))'; Types = @('System.Collections.Generic.TreeSet'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_6_2_profile; Script = 'function CertFunc { param([System.Net.ICertificatePolicy]$Policy) Do-Something $Policy }'; Types = @('System.Net.ICertificatePolicy'); Version = "6.2"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_7_profile; Script = 'function CertFunc { param([System.Net.ICertificatePolicy]$Policy) Do-Something $Policy }'; Types = @('System.Net.ICertificatePolicy'); Version = "7.0"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Security.SystemEnforcementMode]$enforcementMode = "Audit"'; Types = @('System.Management.Automation.Security.SystemEnforcementMode'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = '$ci = New-Object "Microsoft.PowerShell.Commands.ComputerInfo"'; Types = @('Microsoft.PowerShell.Commands.ComputerInfo'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
-
-    @{ Target = $script:Ubuntu1804_7_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = '[System.Management.Automation.Security.SystemEnforcementMode]$enforcementMode = "Audit"'; Types = @('System.Management.Automation.Security.SystemEnforcementMode'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
-    @{ Target = $script:Ubuntu1804_7_profile; Script = '$ci = New-Object "Microsoft.PowerShell.Commands.ComputerInfo"'; Types = @('Microsoft.PowerShell.Commands.ComputerInfo'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
-)
-
-$script:MemberCompatibilityTestCases = @(
-    @{ Target = $script:Srv2012_3_profile; Script = '[System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("System.String")'; Types = @('System.Management.Automation.LanguagePrimitives'); Members = @('ConvertTypeNameToPSTypeName'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012_3_profile; Script = '[System.Management.Automation.WildcardPattern]::Get("banana*", "None").IsMatch("bananaduck")'; Types = @('System.Management.Automation.WildcardPattern'); Members = @('Get'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2012r2_4_profile; Script = 'if (-not [Microsoft.PowerShell.Commands.ModuleSpecification]::TryParse($msStr, [ref]$modSpec)){ throw "Bad!" }'; Types = @('Microsoft.PowerShell.Commands.ModuleSpecification'); Members = @('TryParse'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2012r2_4_profile; Script = '[System.Management.Automation.LanguagePrimitives]::IsObjectEnumerable($obj)'; Types = @('System.Management.Automation.LanguagePrimitives'); Members = @('IsObjectEnumerable'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Srv2019_5_profile; Script = '$socket = [System.Net.WebSockets.WebSocket]::CreateFromStream($stream, $true, "http", [timespan]::FromMinutes(10))'; Types = @('System.Net.WebSockets.WebSocket'); Members = @('CreateFromStream'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
-    @{ Target = $script:Srv2019_5_profile; Script = '[System.Management.Automation.HostUtilities]::InvokeOnRunspace($command, $runspace)'; Types = @('System.Management.Automation.HostUtilities'); Members = @('InvokeOnRunspace'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
-
-    @{ Target = $script:Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Tracing.Tracer]::GetExceptionString($e)'; Types = @('System.Management.Automation.Tracing.Tracer'); Members = @('GetExceptionString'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
-
-    @{ Target = $script:Ubuntu1804_7_profile; Script = '[System.Management.Automation.Tracing.Tracer]::GetExceptionString($e)'; Types = @('System.Management.Automation.Tracing.Tracer'); Members = @('GetExceptionString'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
-)
+BeforeDiscovery {
+    $Srv2012_3_profile = 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
+    $Srv2012r2_4_profile = 'win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework'
+    $Srv2016_5_profile = 'win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework'
+    $Srv2016_6_2_profile = 'win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core'
+    $Srv2016_7_profile = 'win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core'
+    $Srv2019_5_profile = 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+    $Srv2019_6_2_profile = 'win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core'
+    $Srv2019_7_profile = 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
+    $Win10_5_profile = 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+    $Win10_6_2_profile = 'win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core'
+    $Win10_7_profile = 'win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core'
+    $Ubuntu1804_6_2_profile = 'ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core'
+    $Ubuntu1804_7_profile = 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
+
+    $TypeCompatibilityTestCases = @(
+        @{ Target = $Srv2012_3_profile; Script = '[System.Management.Automation.ModuleIntrinsics]::GetModulePath("here", "there", "everywhere")'; Types = @('System.Management.Automation.ModuleIntrinsics'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '$ast -is [System.Management.Automation.Language.FunctionMemberAst]'; Types = @('System.Management.Automation.Language.FunctionMemberAst'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '$version = [System.Management.Automation.SemanticVersion]::Parse($version)'; Types = @('System.Management.Automation.SemanticVersion'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '$kw = New-Object "System.Management.Automation.Language.DynamicKeyword"'; Types = @('System.Management.Automation.Language.DynamicKeyword'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '& { param([Parameter(Position=0)][ArgumentCompleter({"Banana"})][string]$Hello) $Hello } "Banana"'; Types = @('ArgumentCompleter'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2012r2_4_profile; Script = '[WildcardPattern]"bicycle*"'; Types = @('WildcardPattern'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = '$client = [System.Net.Http.HttpClient]::new()'; Types = @('System.Net.Http.HttpClient'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = '[Microsoft.PowerShell.EditMode]"Vi"'; Types = @('Microsoft.PowerShell.EditMode'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_5_profile; Script = '[Microsoft.PowerShell.Commands.WebSslProtocol]::Default -eq "Tls12"'; Types = @('Microsoft.PowerShell.Commands.WebSslProtocol'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = '[System.Collections.Immutable.ImmutableList[string]]::Empty'; Types = @('System.Collections.Immutable.ImmutableList'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = '[System.Collections.Generic.TreeSet[string]]::new(@("duck", "goose", "banana"))'; Types = @('System.Collections.Generic.TreeSet'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_6_2_profile; Script = 'function CertFunc { param([System.Net.ICertificatePolicy]$Policy) Do-Something $Policy }'; Types = @('System.Net.ICertificatePolicy'); Version = "6.2"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_7_profile; Script = 'function CertFunc { param([System.Net.ICertificatePolicy]$Policy) Do-Something $Policy }'; Types = @('System.Net.ICertificatePolicy'); Version = "7.0"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Security.SystemEnforcementMode]$enforcementMode = "Audit"'; Types = @('System.Management.Automation.Security.SystemEnforcementMode'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_6_2_profile; Script = '$ci = New-Object "Microsoft.PowerShell.Commands.ComputerInfo"'; Types = @('Microsoft.PowerShell.Commands.ComputerInfo'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
+
+        @{ Target = $Ubuntu1804_7_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = '[System.Management.Automation.Security.SystemPolicy]::GetSystemLockdownPolicy()'; Types = @('System.Management.Automation.Security.SystemPolicy'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = '[System.Management.Automation.Security.SystemEnforcementMode]$enforcementMode = "Audit"'; Types = @('System.Management.Automation.Security.SystemEnforcementMode'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
+        @{ Target = $Ubuntu1804_7_profile; Script = '$ci = New-Object "Microsoft.PowerShell.Commands.ComputerInfo"'; Types = @('Microsoft.PowerShell.Commands.ComputerInfo'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
+    )
+
+    $MemberCompatibilityTestCases = @(
+        @{ Target = $Srv2012_3_profile; Script = '[System.Management.Automation.LanguagePrimitives]::ConvertTypeNameToPSTypeName("System.String")'; Types = @('System.Management.Automation.LanguagePrimitives'); Members = @('ConvertTypeNameToPSTypeName'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012_3_profile; Script = '[System.Management.Automation.WildcardPattern]::Get("banana*", "None").IsMatch("bananaduck")'; Types = @('System.Management.Automation.WildcardPattern'); Members = @('Get'); Version = "3.0"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2012r2_4_profile; Script = 'if (-not [Microsoft.PowerShell.Commands.ModuleSpecification]::TryParse($msStr, [ref]$modSpec)){ throw "Bad!" }'; Types = @('Microsoft.PowerShell.Commands.ModuleSpecification'); Members = @('TryParse'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2012r2_4_profile; Script = '[System.Management.Automation.LanguagePrimitives]::IsObjectEnumerable($obj)'; Types = @('System.Management.Automation.LanguagePrimitives'); Members = @('IsObjectEnumerable'); Version = "4.0"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Srv2019_5_profile; Script = '$socket = [System.Net.WebSockets.WebSocket]::CreateFromStream($stream, $true, "http", [timespan]::FromMinutes(10))'; Types = @('System.Net.WebSockets.WebSocket'); Members = @('CreateFromStream'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
+        @{ Target = $Srv2019_5_profile; Script = '[System.Management.Automation.HostUtilities]::InvokeOnRunspace($command, $runspace)'; Types = @('System.Management.Automation.HostUtilities'); Members = @('InvokeOnRunspace'); Version = "5.1"; OS = 'Windows'; ProblemCount = 1 }
+
+        @{ Target = $Ubuntu1804_6_2_profile; Script = '[System.Management.Automation.Tracing.Tracer]::GetExceptionString($e)'; Types = @('System.Management.Automation.Tracing.Tracer'); Members = @('GetExceptionString'); Version = "6.2"; OS = 'Linux'; ProblemCount = 1 }
+
+        @{ Target = $Ubuntu1804_7_profile; Script = '[System.Management.Automation.Tracing.Tracer]::GetExceptionString($e)'; Types = @('System.Management.Automation.Tracing.Tracer'); Members = @('GetExceptionString'); Version = "7.0"; OS = 'Linux'; ProblemCount = 1 }
+    )
+}
 
 Describe 'UseCompatibleTypes' {
+    BeforeAll {
+        $RuleName = 'PSUseCompatibleTypes'
+
+        $TargetProfileConfigKey = 'TargetProfiles'
+
+        $Srv2012_3_profile = 'win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework'
+        $Srv2012r2_4_profile = 'win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework'
+        $Srv2016_5_profile = 'win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework'
+        $Srv2016_6_2_profile = 'win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core'
+        $Srv2016_7_profile = 'win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core'
+        $Srv2019_5_profile = 'win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+        $Srv2019_6_2_profile = 'win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core'
+        $Srv2019_7_profile = 'win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core'
+        $Win10_5_profile = 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+        $Win10_6_2_profile = 'win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core'
+        $Win10_7_profile = 'win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core'
+        $Ubuntu1804_6_2_profile = 'ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core'
+        $Ubuntu1804_7_profile = 'ubuntu_x64_18.04_7.0.0_x64_3.1.2_core'
+
+        $AzF_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azurefunctions.json").Path
+        $AzA_profile = (Resolve-Path "$PSScriptRoot/../../PSCompatibilityCollector/optional_profiles/azureautomation.json").Path
+    }
+
     Context 'Targeting a single profile' {
-        It "Reports <ProblemCount> problem(s) with <Script> on <OS> with PowerShell <Version> targeting <Target>" -TestCases $script:TypeCompatibilityTestCases {
+        It "Reports <ProblemCount> problem(s) with <Script> on <OS> with PowerShell <Version> targeting <Target>" -TestCases $TypeCompatibilityTestCases {
             param($Script, [string]$Target, [string[]]$Types, [version]$Version, [string]$OS, [int]$ProblemCount)
 
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @($Target)
+                        $TargetProfileConfigKey = @($Target)
                     }
                 }
             }
 
-            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -ScriptDefinition $Script -Settings $settings
+            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $RuleName -ScriptDefinition $Script -Settings $settings
 
             $diagnostics.Count | Should -Be $ProblemCount
 
@@ -94,19 +112,19 @@ Describe 'UseCompatibleTypes' {
             }
         }
 
-        It "Reports <ProblemCount> problem(s) with <Script> on <OS> with PowerShell <Version> targeting <Target>" -TestCases $script:MemberCompatibilityTestCases {
+        It "Reports <ProblemCount> problem(s) with <Script> on <OS> with PowerShell <Version> targeting <Target>" -TestCases $MemberCompatibilityTestCases {
             param($Script, [string]$Target, [string[]]$Types, [string[]]$Members, [version]$Version, [string]$OS, [int]$ProblemCount)
 
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @($Target)
+                        $TargetProfileConfigKey = @($Target)
                     }
                 }
             }
 
-            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -ScriptDefinition $Script -Settings $settings
+            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $RuleName -ScriptDefinition $Script -Settings $settings
 
             $diagnostics.Count | Should -Be $ProblemCount
 
@@ -125,18 +143,18 @@ Describe 'UseCompatibleTypes' {
         It "Finds all incompatibilities in the script" {
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @(
-                            $script:Srv2012_3_profile
-                            $script:Srv2012r2_4_profile
-                            $script:Srv2016_5_profile
-                            $script:Srv2016_6_2_profile
-                            $script:Srv2019_5_profile
-                            $script:Srv2019_6_2_profile
-                            $script:Win10_5_profile
-                            $script:Win10_6_2_profile
-                            $script:Ubuntu1804_6_2_profile
+                        $TargetProfileConfigKey = @(
+                            $Srv2012_3_profile
+                            $Srv2012r2_4_profile
+                            $Srv2016_5_profile
+                            $Srv2016_6_2_profile
+                            $Srv2019_5_profile
+                            $Srv2019_6_2_profile
+                            $Win10_5_profile
+                            $Win10_6_2_profile
+                            $Ubuntu1804_6_2_profile
                         )
                     }
                 }
@@ -158,20 +176,20 @@ Describe 'UseCompatibleTypes' {
         It "Checks that there are no incompatibilities in PSSA build scripts" {
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @(
-                            $script:Srv2012_3_profile
-                            $script:Srv2012r2_4_profile
-                            $script:Srv2016_5_profile
-                            $script:Srv2016_6_2_profile
-                            $script:Srv2019_7_profile
-                            $script:Srv2019_5_profile
-                            $script:Srv2019_6_2_profile
-                            $script:Win10_5_profile
-                            $script:Win10_6_2_profile
-                            $script:Ubuntu1804_6_2_profile
-                            $script:Ubuntu1804_7_profile
+                        $TargetProfileConfigKey = @(
+                            $Srv2012_3_profile
+                            $Srv2012r2_4_profile
+                            $Srv2016_5_profile
+                            $Srv2016_6_2_profile
+                            $Srv2019_7_profile
+                            $Srv2019_5_profile
+                            $Srv2019_6_2_profile
+                            $Win10_5_profile
+                            $Win10_6_2_profile
+                            $Ubuntu1804_6_2_profile
+                            $Ubuntu1804_7_profile
                         )
                         IgnoreTypes = @('System.IO.Compression.ZipFile')
                     }
@@ -187,12 +205,12 @@ Describe 'UseCompatibleTypes' {
         BeforeAll {
             $settings = @{
                 Rules = @{
-                    $script:RuleName = @{
+                    $RuleName = @{
                         Enable = $true
-                        $script:TargetProfileConfigKey = @(
-                            $script:AzF_profile
-                            $script:AzA_profile
-                            $script:Win10_5_profile
+                        $TargetProfileConfigKey = @(
+                            $AzF_profile
+                            $AzA_profile
+                            $Win10_5_profile
                         )
                     }
                 }
@@ -200,7 +218,7 @@ Describe 'UseCompatibleTypes' {
         }
 
         It "Finds AzF problems with a script" {
-            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $script:RuleName -Settings $settings -ScriptDefinition '
+            $diagnostics = Invoke-ScriptAnalyzer -IncludeRule $RuleName -Settings $settings -ScriptDefinition '
             [System.Collections.Immutable.ImmutableList[string]]::Empty
             [Microsoft.PowerShell.ToStringCodeMethods]::PropertyValueCollection($obj)
             '
diff --git a/Tests/Rules/UseConsistentIndentation.tests.ps1 b/Tests/Rules/UseConsistentIndentation.tests.ps1
index 3f527b2f0..0d26ff39d 100644
--- a/Tests/Rules/UseConsistentIndentation.tests.ps1
+++ b/Tests/Rules/UseConsistentIndentation.tests.ps1
@@ -1,13 +1,17 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+}
 
 Describe "UseConsistentIndentation" {
     BeforeAll {
         function Invoke-FormatterAssertion {
             param(
                 [string] $ScriptDefinition,
-                [string] $ExcpectedScriptDefinition,
+                [string] $ExpectedScriptDefinition,
                 [int] $NumberOfExpectedWarnings,
                 [hashtable] $Settings
             )
@@ -15,9 +19,9 @@ Describe "UseConsistentIndentation" {
             # Unit test just using this rule only
             $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings
             $violations.Count | Should -Be $NumberOfExpectedWarnings -Because $ScriptDefinition
-            Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings | Should -Be $expected -Because $ScriptDefinition
+            Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings | Should -Be $ExpectedScriptDefinition -Because $ScriptDefinition
             # Integration test with all default formatting rules
-            Invoke-Formatter -ScriptDefinition $scriptDefinition | Should -Be $expected -Because $ScriptDefinition
+            Invoke-Formatter -ScriptDefinition $scriptDefinition | Should -Be $ExpectedScriptDefinition -Because $ScriptDefinition
         }
     }
     BeforeEach {
@@ -109,6 +113,84 @@ $param3
         }
     }
 
+    Context 'LParen indentation' {
+        It 'Should preserve script when line starts with LParen' {
+            $IdempotentScriptDefinition = @'
+function test {
+    (foo | bar {
+        baz
+    })
+    Do-Something
+}
+'@
+            Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition | Should -Be $idempotentScriptDefinition
+        }
+
+            It 'Should preserve script when line starts and ends with LParen' {
+                $IdempotentScriptDefinition = @'
+function test {
+    (
+        foo | bar {
+            baz
+        }
+    )
+    Do-Something
+}
+'@
+                Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition | Should -Be $idempotentScriptDefinition
+            }
+
+            It 'Should preserve script when line starts and ends with LParen but trailing comment' {
+                $IdempotentScriptDefinition = @'
+function test {
+    ( # comment
+        foo | bar {
+            baz
+        }
+    )
+    Do-Something
+}
+'@
+                Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition | Should -Be $idempotentScriptDefinition
+            }
+
+        It 'Should preserve script when there is Newline after LParen' {
+            $IdempotentScriptDefinition = @'
+function test {
+    $result = (
+        Get-Something
+    ).Property
+    Do-Something
+}
+'@
+            Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition | Should -Be $idempotentScriptDefinition
+        }
+
+    It 'Should preserve script when there is a comment and Newline after LParen' {
+        $IdempotentScriptDefinition = @'
+function test {
+    $result = ( # comment
+        Get-Something
+    ).Property
+    Do-Something
+}
+'@
+        Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition | Should -Be $idempotentScriptDefinition
+    }
+
+    It 'Should find violation in script when LParen is first token on a line and is not followed by Newline' {
+        $ScriptDefinition = @'
+     (foo)
+     (bar)
+'@
+        $ExpectedScriptDefinition = @'
+(foo)
+(bar)
+'@
+    Invoke-FormatterAssertion $ScriptDefinition $ExpectedScriptDefinition 2 $settings
+    }
+}
+
     Context "When a sub-expression is provided" {
         It "Should not find a violations" {
             $def = @'
@@ -235,6 +317,40 @@ baz
             Test-CorrectionExtentFromContent @params
         }
 
+        It "Should indent hashtable correctly using <PipelineIndentation> option" -TestCases @(
+            @{
+                PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
+            },
+            @{
+                PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline'
+            },
+            @{
+                PipelineIndentation = 'NoIndentation'
+            }
+            @{
+                PipelineIndentation = 'None'
+            }
+        ) {
+            Param([string] $PipelineIndentation)
+            $scriptDefinition = @'
+@{
+        foo = "value1"
+    bar = "value2"
+}
+'@
+            $settings = @{
+                IncludeRules = @('PSUseConsistentIndentation')
+                Rules = @{ PSUseConsistentIndentation = @{ Enable = $true; PipelineIndentation = $PipelineIndentation } }
+            }
+            Invoke-Formatter -Settings $settings -ScriptDefinition $scriptDefinition | Should -Be @'
+@{
+    foo = "value1"
+    bar = "value2"
+}
+'@
+
+        }
+
         It "Should indent pipelines correctly using <PipelineIndentation> option" -TestCases @(
             @{
                 PipelineIndentation = 'IncreaseIndentationForFirstPipeline'
@@ -286,6 +402,18 @@ bar
             @{ IdempotentScriptDefinition = @'
 foo |
     bar
+'@
+            },
+            @{ IdempotentScriptDefinition = @'
+foo |
+    bar -Parameter1
+'@
+            },
+            @{ IdempotentScriptDefinition = @'
+Get-TransportRule |
+Where-Object @{ $_.name -match "a"} |
+Select-Object @{ E = $SenderDomainIs | Sort-Object }
+Foreach-Object { $_.FullName }
 '@
             }
             ) {
@@ -295,6 +423,20 @@ foo |
         Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition -Settings $settings | Should -Be $idempotentScriptDefinition
     }
 
+        It 'Should preserve script when using PipelineIndentation IncreaseIndentationAfterEveryPipeline' -TestCases @(
+            @{ PipelineIndentation = 'IncreaseIndentationForFirstPipeline' }
+            @{ PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline' }
+            ) {
+        param ($PipelineIndentation)
+            $IdempotentScriptDefinition = @'
+Get-TransportRule |
+    Select-Object @{ Key = $SenderDomainIs | Sort-Object }
+baz
+'@
+            $settings.Rules.PSUseConsistentIndentation.PipelineIndentation = $PipelineIndentation
+            Invoke-Formatter -ScriptDefinition $IdempotentScriptDefinition -Settings $settings | Should -Be $idempotentScriptDefinition
+        }
+
         It "Should preserve script when using PipelineIndentation <PipelineIndentation>" -TestCases @(
                 @{ PipelineIndentation = 'IncreaseIndentationForFirstPipeline' }
                 @{ PipelineIndentation = 'IncreaseIndentationAfterEveryPipeline' }
@@ -388,7 +530,6 @@ foo |
             Test-CorrectionExtentFromContent @params
         }
 
-
         It "Should indent properly after line continuation (backtick) character with pipeline" {
             $def = @'
 foo |
diff --git a/Tests/Rules/UseConsistentWhitespace.tests.ps1 b/Tests/Rules/UseConsistentWhitespace.tests.ps1
index 23bf18350..952e49909 100644
--- a/Tests/Rules/UseConsistentWhitespace.tests.ps1
+++ b/Tests/Rules/UseConsistentWhitespace.tests.ps1
@@ -1,25 +1,31 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
-
-$ruleName = "PSUseConsistentWhitespace"
-$ruleConfiguration = @{
-    Enable          = $true
-    CheckInnerBrace = $false
-    CheckOpenBrace  = $false
-    CheckOpenParen  = $false
-    CheckOperator   = $false
-    CheckPipe       = $false
-    CheckSeparator  = $false
-    CheckParameter  = $false
-}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+
+    $ruleName = "PSUseConsistentWhitespace"
+    $ruleConfiguration = @{
+        Enable          = $true
+        CheckInnerBrace = $false
+        CheckOpenBrace  = $false
+        CheckOpenParen  = $false
+        CheckOperator   = $false
+        CheckPipe       = $false
+        CheckSeparator  = $false
+        CheckParameter  = $false
+    }
 
-$settings = @{
-    IncludeRules = @($ruleName)
-    Rules        = @{
-        PSUseConsistentWhitespace = $ruleConfiguration
+    $settings = @{
+        IncludeRules = @($ruleName)
+        Rules        = @{
+            PSUseConsistentWhitespace = $ruleConfiguration
+        }
     }
 }
 
+
 Describe "UseWhitespace" {
     Context "When an open brace follows a keyword" {
         BeforeAll {
@@ -39,19 +45,38 @@ Describe "UseWhitespace" {
 
         It "Should not find violation if an open brace follows a whitespace" {
             $def = 'if($true) {}'
-            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -BeNullOrEmpty
         }
 
         It "Should not find violation if an open brace follows a foreach member invocation" {
             $def = '(1..5).foreach{$_}'
-            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -BeNullOrEmpty
         }
 
         It "Should not find violation if an open brace follows a where member invocation" {
             $def = '(1..5).where{$_}'
-            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It "Should not find violation if an open brace is on the next line" {
+            $def = @'
+if ($true)
+{
+    foo
+}
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -BeNullOrEmpty
         }
 
+        It 'Should not find a violation if an open paren is before an opening brace' {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$ast.Find({ $oneAst -is [TypeExpressionAst] })' -Settings $settings |
+                Should -BeNullOrEmpty
+        }
+
+        It 'Should not find a violation if an open paren is preceded by a Dot token' {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$foo.{bar}' -Settings $settings |
+                Should -BeNullOrEmpty
+        }
     }
 
     Context "When a parenthesis follows a keyword" {
@@ -111,6 +136,7 @@ function foo($param) {
             $ruleConfiguration.CheckOperator = $true
             $ruleConfiguration.CheckPipe = $false
             $ruleConfiguration.CheckSeparator = $false
+            $ruleConfiguration.IgnoreAssignmentOperatorInsideHashTable = $false
         }
 
         It "Should find a violation if no whitespace around an assignment operator" {
@@ -164,6 +190,72 @@ $x = $true -and
             Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
         }
 
+        It "Should find violation if not asked to ignore assignment operator in hash table" {
+            $def = @'
+$ht = @{
+    variable = 3
+    other    = 4
+}
+'@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            Test-CorrectionExtentFromContent $def $violations 1 '    ' ' '
+        }
+    }
+
+    Context "When asked to ignore assignment operator inside hash table" {
+        BeforeAll {
+            $ruleConfiguration.CheckInnerBrace = $false
+            $ruleConfiguration.CheckOpenParen = $false
+            $ruleConfiguration.CheckOpenBrace = $false
+            $ruleConfiguration.CheckOperator = $true
+            $ruleConfiguration.CheckPipe = $false
+            $ruleConfiguration.CheckSeparator = $false
+            $ruleConfiguration.IgnoreAssignmentOperatorInsideHashTable = $true
+        }
+
+        It "Should not find violation if assignment operator is in multi-line hash table and a using statement is present" {
+            $def = @'
+using namespace System.IO
+
+$ht = @{
+    variable = 3
+    other    = 4
+}
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -BeNullOrEmpty
+        }
+
+        It "Should not find violation if assignment operator is in multi-line hash table" {
+            $def = @'
+$ht = @{
+    variable = 3
+    other    = 4
+}
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+        }
+
+        It "Should find violation if assignment operator has extra space in single-line hash table" {
+            $def = @'
+$h = @{
+    ht = @{a = 3; b   = 4}
+    eb = 33
+}
+'@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            Test-CorrectionExtentFromContent $def $violations 1 '   ' ' '
+        }
+
+        It "Should find violation for extra space around non-assignment operator inside hash table" {
+            $def = @'
+$ht = @{
+    variable = 3
+    other    = 4 +  7
+}
+'@
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
+            Test-CorrectionExtentFromContent $def $violations 1 '  ' ' '
+        }
     }
 
     Context "When a comma is not followed by a space" {
@@ -429,6 +521,52 @@ if ($true) { Get-Item `
 '@
             Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
         }
+
+        It 'Should not throw when analysing a line starting with a scriptblock' {
+            { Invoke-ScriptAnalyzer -ScriptDefinition '{ }' -Settings $settings -ErrorAction Stop } | Should -Not -Throw
+        }
+    }
+
+    Context "CheckSeparator" {
+        BeforeAll {
+            $ruleConfiguration.CheckInnerBrace = $false
+            $ruleConfiguration.CheckOpenBrace = $false
+            $ruleConfiguration.CheckOpenParen = $false
+            $ruleConfiguration.CheckOperator = $false
+            $ruleConfiguration.CheckPipe = $false
+            $ruleConfiguration.CheckSeparator = $true
+        }
+
+        It "Should find a violation if there is no space after a comma" {
+            $def = '$Array = @(1,2)'
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -HaveCount 1
+        }
+
+        It "Should not find a violation if there is a space after a comma" {
+            $def = '$Array = @(1, 2)'
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+        }
+
+        It "Should not find a violation if there is a new-line after a comma" {
+            $def = @'
+$Array = @(
+    1,
+    2
+)
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+        }
+
+        It "Should not find a violation if there is a comment after the separator" {
+            $def = @'
+$Array = @(
+    'foo',     # Comment Line 1
+    'FizzBuzz' # Comment Line 2
+)
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -BeNullOrEmpty
+        }
+
     }
 
 
@@ -452,11 +590,17 @@ bar -h i `
             Invoke-ScriptAnalyzer -ScriptDefinition "$def" -Settings $settings | Should -Be $null
         }
 
-        It "Should not find no violation if there is always 1 space between parameters except when using colon syntax" {
+        It "Should not find a violation if there is always 1 space between parameters except when using colon syntax" {
             $def = 'foo -bar $baz @splattedVariable -bat -parameterName:$parameterValue'
             Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
         }
 
+        It "Should not find a violation when redirect operators, spearated by 1 space, are used and not in stream order" {
+            # Related to Issue #2000
+            $def = 'foo 3>&1 1>$null 2>&1'
+            Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings | Should -Be $null
+        }
+
         It "Should find 1 violation if there is 1 space too much before a parameter" {
             $def = 'foo  -bar'
             $violations = Invoke-ScriptAnalyzer -ScriptDefinition $def -Settings $settings
@@ -474,11 +618,11 @@ bar -h i `
         }
 
         It "Should fix script to always have 1 space between parameters except when using colon syntax but not by default" {
-            $def = 'foo  -bar   $baz  -ParameterName:  $ParameterValue'
+            $def = 'foo  -bar   $baz  -ParameterName:  $ParameterValue "$PSScriptRoot\module.psd1"'
             Invoke-Formatter -ScriptDefinition $def |
                 Should -BeExactly $def -Because 'CheckParameter configuration is not turned on by default (yet) as the setting is new'
             Invoke-Formatter -ScriptDefinition $def -Settings $settings |
-                Should -BeExactly 'foo -bar $baz -ParameterName:  $ParameterValue'
+                Should -BeExactly 'foo -bar $baz -ParameterName:  $ParameterValue "$PSScriptRoot\module.psd1"'
         }
 
         It "Should fix script when newlines are involved" {
@@ -495,5 +639,49 @@ bar -h i `
             Invoke-Formatter -ScriptDefinition "$def" -Settings $settings |
                 Should -Be "$expected"
         }
+
+        It "Should fix script when a parameter value is a script block spanning multiple lines" {
+            $def = {foo {
+    bar
+}     -baz}
+
+            $expected = {foo {
+    bar
+} -baz}
+            Invoke-Formatter -ScriptDefinition "$def" -Settings $settings |
+                Should -Be "$expected"
+        }
+
+        It "Should fix script when a parameter value is a hashtable spanning multiple lines" {
+            $def = {foo @{
+    a = 1
+}     -baz}
+
+            $expected = {foo @{
+    a = 1
+} -baz}
+            Invoke-Formatter -ScriptDefinition "$def" -Settings $settings |
+                Should -Be "$expected"
+        }
+
+        It "Should fix script when a parameter value is an array spanning multiple lines" {
+            $def = {foo @(
+    1
+)     -baz}
+
+            $expected = {foo @(
+    1
+) -baz}
+            Invoke-Formatter -ScriptDefinition "$def" -Settings $settings |
+                Should -Be "$expected"
+        }
+
+        It "Should fix script when redirects are involved and whitespace is not consistent" {
+            # Related to Issue #2000
+            $def = 'foo   3>&1  1>$null   2>&1'
+            $expected = 'foo 3>&1 1>$null 2>&1'
+            Invoke-Formatter -ScriptDefinition $def -Settings $settings |
+                Should -Be $expected
+        }
     }
 }
diff --git a/Tests/Rules/UseCorrectCasing.tests.ps1 b/Tests/Rules/UseCorrectCasing.tests.ps1
index 61d75b408..c142dd2da 100644
--- a/Tests/Rules/UseCorrectCasing.tests.ps1
+++ b/Tests/Rules/UseCorrectCasing.tests.ps1
@@ -1,29 +1,32 @@
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
 Describe "UseCorrectCasing" {
     It "corrects case of simple cmdlet" {
-        Invoke-Formatter 'get-childitem' | Should -Be 'Get-ChildItem'
+        Invoke-Formatter 'get-childitem' | Should -BeExactly 'Get-ChildItem'
     }
 
     It "corrects case of fully qualified cmdlet" {
-        Invoke-Formatter 'Microsoft.PowerShell.management\get-childitem' | Should -Be 'Microsoft.PowerShell.Management\Get-ChildItem'
+        Invoke-Formatter 'Microsoft.PowerShell.management\get-childitem' | Should -BeExactly 'Microsoft.PowerShell.Management\Get-ChildItem'
     }
 
     It "corrects case of of cmdlet inside interpolated string" {
-        Invoke-Formatter '"$(get-childitem)"' | Should -Be '"$(get-childitem)"'
+        Invoke-Formatter '"$(get-childitem)"' | Should -BeExactly '"$(Get-ChildItem)"'
     }
 
     It "Corrects alias correctly" {
-        Invoke-Formatter 'Gci' | Should -Be 'gci'
-        Invoke-Formatter '?' | Should -Be '?'
+        Invoke-Formatter 'Gci' | Should -BeExactly 'gci'
+        Invoke-Formatter '?' | Should -BeExactly '?'
     }
 
     It "Does not corrects applications on the PATH" -Skip:($IsLinux -or $IsMacOS) {
-        Invoke-Formatter 'Cmd' | Should -Be 'Cmd'
-        Invoke-Formatter 'MORE' | Should -Be 'MORE'
+        Invoke-Formatter 'Git' | Should -BeExactly 'Git'
+        Invoke-Formatter 'SSH' | Should -BeExactly 'SSH'
     }
 
     It "Preserves extension of applications on Windows" -Skip:($IsLinux -or $IsMacOS) {
-        Invoke-Formatter 'cmd.exe' | Should -Be 'cmd.exe'
-        Invoke-Formatter 'more.com' | Should -Be 'more.com'
+        Invoke-Formatter 'cmd.exe' | Should -BeExactly 'cmd.exe'
+        Invoke-Formatter 'more.com' | Should -BeExactly 'more.com'
     }
 
     It "Preserves full application path" {
@@ -33,41 +36,77 @@ Describe "UseCorrectCasing" {
         else {
             $applicationPath = "${env:WINDIR}\System32\cmd.exe"
         }
-        Invoke-Formatter ". $applicationPath" | Should -Be ". $applicationPath"
+        Invoke-Formatter ". $applicationPath" | Should -BeExactly ". $applicationPath"
     }
 
-    It "Corrects case of script function" {
-        function Invoke-DummyFunction { }
-        Invoke-Formatter 'invoke-dummyFunction' | Should -Be 'Invoke-DummyFunction'
+    # TODO: Can we make this work?
+    # There is a limitation in the Helper's CommandCache: it doesn't see commands that are (only temporarily) defined in the current scope
+    It "Corrects case of script function" -Skip {
+        function global:Invoke-DummyFunction { }
+        Invoke-Formatter 'invoke-dummyFunction' | Should -BeExactly 'Invoke-DummyFunction'
     }
 
     It "Preserves script path" {
         $path = Join-Path $TestDrive "$([guid]::NewGuid()).ps1"
         New-Item -ItemType File -Path $path
         $scriptDefinition = ". $path"
-        Invoke-Formatter $scriptDefinition | Should -Be $scriptDefinition
+        Invoke-Formatter $scriptDefinition | Should -BeExactly $scriptDefinition
     }
 
     It "Preserves UNC script path" -Skip:($IsLinux -or $IsMacOS) {
         $uncPath = [System.IO.Path]::Combine("\\$(HOSTNAME.EXE)\C$\", $TestDrive, "$([guid]::NewGuid()).ps1")
         New-Item -ItemType File -Path $uncPath
         $scriptDefinition = ". $uncPath"
-        Invoke-Formatter $scriptDefinition | Should -Be $scriptDefinition
+        Invoke-Formatter $scriptDefinition | Should -BeExactly $scriptDefinition
     }
 
     It "Corrects parameter casing" {
-        function Invoke-DummyFunction ($ParameterName) { }
-
-        Invoke-Formatter 'Invoke-DummyFunction -parametername $parameterValue' |
-            Should -Be 'Invoke-DummyFunction -ParameterName $parameterValue'
-        Invoke-Formatter 'Invoke-DummyFunction -parametername:$parameterValue' |
-            Should -Be 'Invoke-DummyFunction -ParameterName:$parameterValue'
-        Invoke-Formatter 'Invoke-DummyFunction -parametername: $parameterValue' |
-            Should -Be 'Invoke-DummyFunction -ParameterName: $parameterValue'
+        # Without messing up the spacing or use of semicolons
+        Invoke-Formatter 'Get-ChildItem -literalpath $parameterValue' |
+            Should -BeExactly 'Get-ChildItem -LiteralPath $parameterValue'
+        Invoke-Formatter 'Get-ChildItem -literalpath:$parameterValue' |
+            Should -BeExactly 'Get-ChildItem -LiteralPath:$parameterValue'
+        Invoke-Formatter 'Get-ChildItem -literalpath: $parameterValue' |
+            Should -BeExactly 'Get-ChildItem -LiteralPath: $parameterValue'
     }
 
     It "Should not throw when using parameter name that does not exist" {
         Invoke-Formatter 'Get-Process -NonExistingParameterName' -ErrorAction Stop
     }
 
+    It "Does not throw when correcting certain cmdlets (issue 1516)" {
+        $scriptDefinition = 'Get-Content;Test-Path;Get-ChildItem;Get-Content;Test-Path;Get-ChildItem'
+        $settings = @{ 'Rules' = @{ 'PSUseCorrectCasing' = @{ 'Enable' = $true; CheckCommands = $true; CheckKeywords = $true; CheckOperators = $true } } }
+        {
+            1..100 |
+            ForEach-Object { $null = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -Settings $settings -ErrorAction Stop }
+        } |
+        Should -Not -Throw
+    }
+
+    It "Corrects uppercase operators" {
+        Invoke-Formatter '$ENV:PATH -SPLIT ";"' |
+            Should -BeExactly '$ENV:PATH -split ";"'
+    }
+
+    It "Corrects mixed case operators" {
+        Invoke-Formatter '$ENV:PATH -Split ";" -Join ":"' |
+            Should -BeExactly '$ENV:PATH -split ";" -join ":"'
+    }
+
+    It "Corrects unary operators" {
+        Invoke-Formatter '-Split "Hello World"' |
+            Should -BeExactly '-split "Hello World"'
+    }
+    It "Does not break PlusPlus or MinusMinus" {
+        Invoke-Formatter '$A++; $B--' |
+            Should -BeExactly '$A++; $B--'
+    }
+
+    Context "Inconsistent Keywords" {
+        It "Corrects keyword case" {
+            Invoke-Formatter 'ForEach ($x IN $y) { $x }' |
+                Should -BeExactly 'foreach ($x in $y) { $x }'
+        }
+    }
 }
diff --git a/Tests/Rules/UseDSCResourceFunctions.tests.ps1 b/Tests/Rules/UseDSCResourceFunctions.tests.ps1
index f88801a21..2efc16ec0 100644
--- a/Tests/Rules/UseDSCResourceFunctions.tests.ps1
+++ b/Tests/Rules/UseDSCResourceFunctions.tests.ps1
@@ -1,16 +1,21 @@
-﻿
-$violationMessage = "Missing 'Get-TargetResource' function. DSC Resource must implement Get, Set and Test-TargetResource functions."
-$classViolationMessage = "Missing 'Set' function. DSC Class must implement Get, Set and Test functions."
-$violationName = "PSDSCStandardDSCFunctionsInResource"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
-
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
-{
-    $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
-    $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Missing 'Get-TargetResource' function. DSC Resource must implement Get, Set and Test-TargetResource functions."
+    $classViolationMessage = "Missing 'Set' function. DSC Class must implement Get, Set and Test functions."
+    $violationName = "PSDSCStandardDSCFunctionsInResource"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+
+    if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
+    {
+        $classViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\BadDscResource\BadDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+        $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    }
 }
 
+
 Describe "StandardDSCFunctionsInResource" {
     Context "When there are violations" {
         It "has 1 missing standard DSC functions violation" {
@@ -29,8 +34,7 @@ Describe "StandardDSCFunctionsInResource" {
     }
 }
 
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
- Describe "StandardDSCFunctionsInClass" {
+Describe "StandardDSCFunctionsInClass" -Skip:($PSVersionTable.PSVersion -lt '5.0') {
     Context "When there are violations" {
         It "has 1 missing standard DSC functions violation" {
             $classViolations.Count | Should -Be 1
@@ -46,5 +50,4 @@ if ($PSVersionTable.PSVersion -ge [Version]'5.0.0') {
             $noClassViolations.Count | Should -Be 0
         }
     }
- }
 }
diff --git a/Tests/Rules/UseDeclaredVarsMoreThanAssignments.tests.ps1 b/Tests/Rules/UseDeclaredVarsMoreThanAssignments.tests.ps1
index c81fc74f7..113563796 100644
--- a/Tests/Rules/UseDeclaredVarsMoreThanAssignments.tests.ps1
+++ b/Tests/Rules/UseDeclaredVarsMoreThanAssignments.tests.ps1
@@ -1,10 +1,15 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$violationMessage = "The variable 'declaredVar2' is assigned but never used."
-$violationName = "PSUseDeclaredVarsMoreThanAssignments"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\UseDeclaredVarsMoreThanAssignments.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\UseDeclaredVarsMoreThanAssignmentsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+
+    $violationMessage = "The variable 'declaredVar2' is assigned but never used."
+    $violationName = "PSUseDeclaredVarsMoreThanAssignments"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\UseDeclaredVarsMoreThanAssignments.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\UseDeclaredVarsMoreThanAssignmentsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "UseDeclaredVarsMoreThanAssignments" {
     Context "When there are violations" {
@@ -53,6 +58,54 @@ function MyFunc2() {
             Should -Be 0
         }
 
+        It "does not flag `$PSNativeCommandArgumentPassing variable" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$PSNativeCommandArgumentPassing=None' -IncludeRule $violationName | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "does not flag global variable" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$global:x=$null' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "does not flag global variable in block" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$global:x=$null;{$global:x=$null}' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "does not flag env variable" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$env:x=$null' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "does not flag env variable in block" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$env:x=$null;{$env:x=$null}' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "does not flag script variable" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$script:x=$null' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "does not flag script variable in block" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$script:x=$null;{$script:x=$null}' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 0
+        }
+
+        It "flags private variable" {
+            Invoke-ScriptAnalyzer -ScriptDefinition '$private:x=$null' -IncludeRule $violationName  | `
+            Get-Count | `
+            Should -Be 1
+        }
+
         It "flags a variable that is defined twice but never used" {
             Invoke-ScriptAnalyzer -ScriptDefinition '$myvar=1;$myvar=2' -IncludeRule $violationName | `
             Get-Count | `
@@ -67,6 +120,11 @@ function MyFunc2() {
     }
 
     Context "When there are no violations" {
+        It "No warning is issued for assignment without use of preference variable ErrorView" {
+            $results = Invoke-ScriptAnalyzer -ScriptDefinition '$ErrorView = NormalView'
+            $results.Count | Should -Be 0
+        }
+
         It "returns no violations" {
             $noViolations.Count | Should -Be 0
         }
diff --git a/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1 b/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1
index d8e96c709..6e22acc32 100644
--- a/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1
+++ b/Tests/Rules/UseIdenticalMandatoryParametersForDSC.tests.ps1
@@ -1,11 +1,15 @@
-$ruleName = 'PSDSCUseIdenticalMandatoryParametersForDSC'
-$resourceBasepath = "$PSScriptRoot\DSCResourceModule\DSCResources"
-$badResourceFilepath = [System.IO.Path]::Combine(
-    $resourceBasepath,
-    'MSFT_WaitForAnyNoIdenticalMandatoryParameter',
-    'MSFT_WaitForAnyNoIdenticalMandatoryParameter.psm1');
-$goodResourceFilepath = [System.IO.Path]::Combine($resourceBasepath,'MSFT_WaitForAny','MSFT_WaitForAny.psm1');
-
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = 'PSDSCUseIdenticalMandatoryParametersForDSC'
+    $resourceBasepath = "$PSScriptRoot\DSCResourceModule\DSCResources"
+    $badResourceFilepath = [System.IO.Path]::Combine(
+        $resourceBasepath,
+        'MSFT_WaitForAnyNoIdenticalMandatoryParameter',
+        'MSFT_WaitForAnyNoIdenticalMandatoryParameter.psm1')
+    $goodResourceFilepath = [System.IO.Path]::Combine($resourceBasepath,'MSFT_WaitForAny','MSFT_WaitForAny.psm1')
+}
 
 Describe "UseIdenticalMandatoryParametersForDSC" {
     Context "When a mandatory parameters are not present" {
diff --git a/Tests/Rules/UseIdenticalParametersDSC.tests.ps1 b/Tests/Rules/UseIdenticalParametersDSC.tests.ps1
index 36250cd04..c47a2bf56 100644
--- a/Tests/Rules/UseIdenticalParametersDSC.tests.ps1
+++ b/Tests/Rules/UseIdenticalParametersDSC.tests.ps1
@@ -1,13 +1,19 @@
-﻿$violationMessage = "The Test and Set-TargetResource functions of DSC Resource must have the same parameters."
-$violationName = "PSDSCUseIdenticalParametersForDSC"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
-
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
-{
-    $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "The Test and Set-TargetResource functions of DSC Resource must have the same parameters."
+    $violationName = "PSDSCUseIdenticalParametersForDSC"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+
+    if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
+    {
+        $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    }
 }
 
+
 Describe "UseIdenticalParametersDSC" {
     Context "When there are violations" {
         It "has 1 Use Identical Parameters For DSC violations" {
diff --git a/Tests/Rules/UseLiteralInitializerForHashtable.tests.ps1 b/Tests/Rules/UseLiteralInitializerForHashtable.tests.ps1
index 24ce1d574..04a2c55f4 100644
--- a/Tests/Rules/UseLiteralInitializerForHashtable.tests.ps1
+++ b/Tests/Rules/UseLiteralInitializerForHashtable.tests.ps1
@@ -1,4 +1,9 @@
-﻿$ruleName = "PSUseLiteralInitializerForHashtable"
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $ruleName = "PSUseLiteralInitializerForHashtable"
+}
 
 Describe "UseLiteralInitlializerForHashtable" {
     Context "When new-object hashtable is used to create a hashtable" {
diff --git a/Tests/Rules/UseOutputTypeCorrectly.tests.ps1 b/Tests/Rules/UseOutputTypeCorrectly.tests.ps1
index 8674643d5..8cc657e0b 100644
--- a/Tests/Rules/UseOutputTypeCorrectly.tests.ps1
+++ b/Tests/Rules/UseOutputTypeCorrectly.tests.ps1
@@ -1,13 +1,17 @@
-﻿$violationMessage = "The cmdlet 'Verb-Files' returns an object of type 'System.Collections.Hashtable' but this type is not declared in the OutputType attribute."
-$violationName = "PSUseOutputTypeCorrectly"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
-{
-    $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+BeforeAll {
+    $violationMessage = "The cmdlet 'Verb-Files' returns an object of type 'System.Collections.Hashtable' but this type is not declared in the OutputType attribute."
+    $violationName = "PSUseOutputTypeCorrectly"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    if ($PSVersionTable.PSVersion -ge [Version]'5.0.0')
+    {
+        $dscViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    }
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
 }
 
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
 
 Describe "UseOutputTypeCorrectly" {
     Context "When there are violations" {
diff --git a/Tests/Rules/UseProcessBlockForPipelineCommand.tests.ps1 b/Tests/Rules/UseProcessBlockForPipelineCommand.tests.ps1
index c4caf2c0c..340338a20 100644
--- a/Tests/Rules/UseProcessBlockForPipelineCommand.tests.ps1
+++ b/Tests/Rules/UseProcessBlockForPipelineCommand.tests.ps1
@@ -1,4 +1,7 @@
-﻿Describe "UseProcessBlockForPipelineCommand" {
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+Describe "UseProcessBlockForPipelineCommand" {
     BeforeAll {
         $RuleName = 'PSUseProcessBlockForPipelineCommand'
     }
diff --git a/Tests/Rules/UseShouldProcessCorrectly.tests.ps1 b/Tests/Rules/UseShouldProcessCorrectly.tests.ps1
index d870c69ae..2c0314f70 100644
--- a/Tests/Rules/UseShouldProcessCorrectly.tests.ps1
+++ b/Tests/Rules/UseShouldProcessCorrectly.tests.ps1
@@ -1,11 +1,15 @@
-﻿$violationMessage = "'Verb-Files' has the ShouldProcess attribute but does not call ShouldProcess/ShouldContinue."
-$violationName = "PSShouldProcess"
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$IsV3OrV4 = (Test-PSVersionV3) -or (Test-PSVersionV4)
+$IsV3OrV4 = ($PSVersionTable.PSVersion.Major -eq 3) -or ($PSVersionTable.PSVersion.Major -eq 4)
+
+BeforeAll {
+    $violationMessage = "'Verb-Files' has the ShouldProcess attribute but does not call ShouldProcess/ShouldContinue."
+    $violationName = "PSShouldProcess"
+
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "UseShouldProcessCorrectly" {
     Context "When there are violations" {
diff --git a/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1 b/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1
index ed377f1c0..c4718f300 100644
--- a/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1
+++ b/Tests/Rules/UseShouldProcessForStateChangingFunctions.tests.ps1
@@ -1,30 +1,51 @@
-﻿$violationMessage = "Function 'Set-MyObject' has verb that could change system state. Therefore, the function has to support 'ShouldProcess'"
-$violationName = "PSUseShouldProcessForStateChangingFunctions"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\UseShouldProcessForStateChangingFunctions.ps1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\UseShouldProcessForStateChangingFunctionsNoViolations.ps1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "Function 'Set-MyObject' has verb that could change system state. Therefore, the function has to support 'ShouldProcess'"
+    $violationName = "PSUseShouldProcessForStateChangingFunctions"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\UseShouldProcessForStateChangingFunctions.ps1 | Where-Object { $_.RuleName -eq $violationName }
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\UseShouldProcessForStateChangingFunctionsNoViolations.ps1 | Where-Object { $_.RuleName -eq $violationName }
+}
 
 Describe "It checks UseShouldProcess is enabled when there are state changing verbs in the function names" {
     Context "When function name has state changing verb" {
-
-        Function Test-Verb([string] $verb)
-        {
-            $scriptDefinitionGeneric = @'
-Function New-{0} () {{ }}
-'@
-            $scriptDef = $scriptDefinitionGeneric -f $verb
-            It ('finds "{0}" verb in function name' -f $verb) {
-                $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef -IncludeRule $violationName
-                $violations.Count | Should -Be 1
+        It 'Finds verb "<Verb>" in function name' {
+            Param($Verb)
+            $scriptDefinition = "Function New-${Verb} () {{ }}"
+            $violations = Invoke-ScriptAnalyzer -ScriptDefinition $scriptDefinition -IncludeRule $violationName
+            $violations.Count | Should -Be 1
+        } -TestCases @(
+            @{
+                Verb = 'New'
             }
-        }
-
-        $verbs = @('New', 'Set', 'Remove', 'Start', 'Stop', 'Restart', 'Reset', 'Update')
-        $verbs | ForEach-Object {Test-Verb $_}
+            @{
+                Verb = 'Set'
+            }
+            @{
+                Verb = 'Remove'
+            }
+            @{
+                Verb = 'Start'
+            }
+            @{
+                Verb = 'Stop'
+            }
+            @{
+                Verb = 'Restart'
+            }
+            @{
+                Verb = 'Reset'
+            }
+            @{
+                Verb = 'Update'
+            }
+        )
     }
+
     Context "When there are violations" {
-    	$numViolations = 5
-        It ("has {0} violations where ShouldProcess is not supported" -f $numViolations) {
-            $violations.Count | Should -Be $numViolations
+        It "has correct number of violations where ShouldProcess is not supported" {
+            $violations.Count | Should -Be 5
         }
 
         It "has the correct description message" {
@@ -32,7 +53,7 @@ Function New-{0} () {{ }}
         }
 
         It "has the correct extent" {
-        $violations[0].Extent.Text | Should -Be "Set-MyObject"
+            $violations[0].Extent.Text | Should -Be "Set-MyObject"
         }
     }
 
diff --git a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1 b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1
index 7bd3e432f..6d4724236 100644
--- a/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1
+++ b/Tests/Rules/UseSingularNounsReservedVerbs.tests.ps1
@@ -1,52 +1,128 @@
-$nounViolationMessage = "The cmdlet 'Verb-Files' uses a plural noun. A singular noun should be used instead."
-$verbViolationMessage = "The cmdlet 'Verb-Files' uses an unapproved verb."
-$nounViolationName = "PSUseSingularNouns"
-$verbViolationName = "PSUseApprovedVerbs"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1
-$nounViolations = $violations | Where-Object {$_.RuleName -eq $nounViolationName}
-$verbViolations = $violations | Where-Object {$_.RuleName -eq $verbViolationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1
-$nounNoViolations = $noViolations | Where-Object {$_.RuleName -eq $nounViolationName}
-$verbNoViolations = $noViolations | Where-Object {$_.RuleName -eq $verbViolationName}
-
-# this rule doesn't exist in the non desktop version of PSScriptAnalyzer
-if (-not $IsCoreCLR)
-{
-    Describe "UseSingularNouns" {
-        Context "When there are violations" {
-            It "has a cmdlet singular noun violation" {
-                $nounViolations.Count | Should -Be 1
-            }
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-            It "has the correct description message" {
-                $nounViolations[0].Message | Should -Match $nounViolationMessage
-            }
+BeforeAll {
+    $nounViolationMessage = "The cmdlet 'Verb-Files' uses a plural noun. A singular noun should be used instead."
+    $verbViolationMessage = "The cmdlet 'Verb-Files' uses an unapproved verb."
+    $nounViolationName = "PSUseSingularNouns"
+    $verbViolationName = "PSUseApprovedVerbs"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\BadCmdlet.ps1
+    $nounViolations = $violations | Where-Object {$_.RuleName -eq $nounViolationName}
+    $verbViolations = $violations | Where-Object {$_.RuleName -eq $verbViolationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\GoodCmdlet.ps1
+    $nounNoViolations = $noViolations | Where-Object {$_.RuleName -eq $nounViolationName}
+    $verbNoViolations = $noViolations | Where-Object {$_.RuleName -eq $verbViolationName}
+}
 
-            It "has the correct extent" {
-            $nounViolations[0].Extent.Text | Should -Be "Verb-Files"
-            }
+# UseSingularNouns rule doesn't exist in the non desktop version of PSScriptAnalyzer due to missing .Net Pluralization API
+Describe "UseSingularNouns" {
+    Context "When there are violations" {
+        It "has a cmdlet singular noun violation" {
+            $nounViolations.Count | Should -Be 1
+        }
+
+        It "has the correct description message" {
+            $nounViolations[0].Message | Should -Match $nounViolationMessage
+        }
+
+        It "has the correct extent" {
+        $nounViolations[0].Extent.Text | Should -Be "Verb-Files"
         }
+    }
 
-        Context "When function names have nouns from whitelist" {
+    Context "When function names have nouns from allowlist" {
 
-            It "ignores function name ending with Data" {
-                $nounViolationScript = @'
+        It "ignores function name ending with Data by default" {
+            $nounViolationScript = @'
 Function Add-SomeData
 {
-    Write-Output "Adding some data"
+Write-Output "Adding some data"
 }
 '@
-                Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript `
-                    -IncludeRule "PSUseSingularNouns" `
-                    -OutVariable violations
-                $violations.Count | Should -Be 0
-            }
+            Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript `
+                -IncludeRule "PSUseSingularNouns" `
+                -OutVariable violations
+            $violations.Count | Should -Be 0
+        }
+
+        It "ignores function name ending with Windows by default" {
+            $nounViolationScript = @'
+Function Test-Windows
+{
+Write-Output "Testing Microsoft Windows"
+}
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript `
+                -IncludeRule "PSUseSingularNouns" `
+                -OutVariable violations
+            $violations.Count | Should -Be 0
         }
 
-        Context "When there are no violations" {
-            It "returns no violations" {
-                $nounNoViolations.Count | Should -Be 0
+        It "ignores function names defined in settings" {
+            $nounViolationScript = @'
+Function Get-Bananas
+{
+Write-Output "Bananas"
+}
+'@
+            Invoke-ScriptAnalyzer -ScriptDefinition $nounViolationScript -Settings @{
+                IncludeRules = @("PSUseSingularNouns")
+                Rules        = @{ PSUseSingularNouns = @{ NounAllowList = "Bananas" } }
+            } | Should -BeNullOrEmpty
+        }
+
+    }
+
+    Context "When there are no violations" {
+        It "returns no violations" {
+            $nounNoViolations.Count | Should -Be 0
+        }
+    }
+
+    Context "Inline tests" {
+        It 'Correctly diagnoses and corrects <Script>' -TestCases @(
+            @{ Script = 'function Get-Bananas { "bananas" }'; Extent = @{ StartCol = 10; EndCol = 21 }; Correction = 'Get-Banana' }
+            @{ Script = 'function ConvertTo-StartingCriteria { "criteria" }'; Extent = @{ StartCol = 10; EndCol = 36 }; Correction = 'ConvertTo-StartingCriterion' }
+            @{ Script = 'function Invoke-Data { "data" }' }
+            @{ Script = 'function Get-Banana { "bananas" }' }
+            @{ Script = 'function get-banana { "bananas" }' }
+            @{ Script = 'function banana { "bananas" }' }
+        ) {
+            param([string]$Script, $Extent, $Correction)
+
+            $diagnostics = Invoke-ScriptAnalyzer -ScriptDefinition $Script
+
+            if (-not $Extent)
+            {
+                $diagnostics | Should -BeNullOrEmpty
+                return
             }
+
+            $expectedStartLine = if ($Extent.StartLine) { $Extent.StartLine } else { 1 }
+            $expectedEndLine = if ($Extent.EndLine) { $Extent.EndLine } else { 1 }
+
+            $diagnostics.Extent.StartLineNumber | Should -BeExactly $expectedStartLine
+            $diagnostics.Extent.EndLineNumber | Should -BeExactly $expectedEndLine
+            $diagnostics.Extent.StartColumnNumber | Should -BeExactly $Extent.StartCol
+            $diagnostics.Extent.EndColumnNumber | Should -BeExactly $Extent.EndCol
+
+            $diagnostics.SuggestedCorrections.StartLineNumber | Should -BeExactly $expectedStartLine
+            $diagnostics.SuggestedCorrections.EndLineNumber | Should -BeExactly $expectedEndLine
+            $diagnostics.SuggestedCorrections.StartColumnNumber | Should -BeExactly $Extent.StartCol
+            $diagnostics.SuggestedCorrections.EndColumnNumber | Should -BeExactly $Extent.EndCol
+            $diagnostics.SuggestedCorrections.Text | Should -BeExactly $Correction
+        }
+    }
+    Context 'Suppression' {
+        It 'Can be suppressed by RuleSuppressionId' {
+            $scriptDef = @"
+function Get-Elements {
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('$nounViolationName', 'Get-Elements')]
+    param()
+}
+"@
+            $warnings = @(Invoke-ScriptAnalyzer -ScriptDefinition $scriptDef)
+            $warnings.Count | Should -Be 0
         }
     }
 }
diff --git a/Tests/Rules/UseSupportsShouldProcess.tests.ps1 b/Tests/Rules/UseSupportsShouldProcess.tests.ps1
index ba43c06b0..891ac5e45 100644
--- a/Tests/Rules/UseSupportsShouldProcess.tests.ps1
+++ b/Tests/Rules/UseSupportsShouldProcess.tests.ps1
@@ -1,11 +1,16 @@
-﻿$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
 
-$settings = @{
-    IncludeRules = @("PSUseSupportsShouldProcess")
-    Rules = @{
-        PSUseSupportsShouldProcess = @{
-            Enable = $true
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory "PSScriptAnalyzerTestHelper.psm1")
+
+    $settings = @{
+        IncludeRules = @("PSUseSupportsShouldProcess")
+        Rules = @{
+            PSUseSupportsShouldProcess = @{
+                Enable = $true
+            }
         }
     }
 }
diff --git a/Tests/Rules/UseToExportFieldsInManifest.tests.ps1 b/Tests/Rules/UseToExportFieldsInManifest.tests.ps1
index 3edb6b54f..5fa68aa68 100644
--- a/Tests/Rules/UseToExportFieldsInManifest.tests.ps1
+++ b/Tests/Rules/UseToExportFieldsInManifest.tests.ps1
@@ -1,29 +1,35 @@
-$testRootDirectory = Split-Path -Parent $PSScriptRoot
-Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
-
-$testManifestPath = Join-Path $PSScriptRoot "TestManifest"
-$testManifestBadFunctionsWildcardPath = "ManifestBadFunctionsWildcard.psd1"
-$testManifestBadFunctionsWildcardInArrayPath = "ManifestBadFunctionsWildcardInArray.psd1"
-$testManifestBadFunctionsNullPath = "ManifestBadFunctionsNull.psd1"
-$testManifestBadCmdletsWildcardPath = "ManifestBadCmdletsWildcard.psd1"
-$testManifestBadAliasesWildcardPath = "ManifestBadAliasesWildcard.psd1"
-$testManifestBadVariablesWildcardPath = "ManifestBadVariablesWildcard.psd1"
-$testManifestBadAllPath = "ManifestBadAll.psd1"
-$testManifestGoodPath = "ManifestGood.psd1"
-$testManifestInvalidPath = "ManifestInvalid.psd1"
-Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1")
-
-Function Run-PSScriptAnalyzerRule
-{
-    Param(
-        [Parameter(Mandatory)]
-        [String] $ManifestPath
-    )
-
-    Invoke-ScriptAnalyzer -Path (Resolve-Path (Join-Path $testManifestPath $ManifestPath))`
-                            -IncludeRule PSUseToExportFieldsInManifest
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $testRootDirectory = Split-Path -Parent $PSScriptRoot
+    Import-Module (Join-Path $testRootDirectory 'PSScriptAnalyzerTestHelper.psm1')
+
+    $testManifestPath = Join-Path $PSScriptRoot "TestManifest"
+    $testManifestBadFunctionsWildcardPath = "ManifestBadFunctionsWildcard.psd1"
+    $testManifestBadFunctionsWildcardInArrayPath = "ManifestBadFunctionsWildcardInArray.psd1"
+    $testManifestBadFunctionsNullPath = "ManifestBadFunctionsNull.psd1"
+    $testManifestBadCmdletsWildcardPath = "ManifestBadCmdletsWildcard.psd1"
+    $testManifestBadAliasesWildcardPath = "ManifestBadAliasesWildcard.psd1"
+    $testManifestBadVariablesWildcardPath = "ManifestBadVariablesWildcard.psd1"
+    $testManifestBadAllPath = "ManifestBadAll.psd1"
+    $testManifestGoodPath = "ManifestGood.psd1"
+    $testManifestInvalidPath = "ManifestInvalid.psd1"
+    Import-Module (Join-Path $PSScriptRoot "PSScriptAnalyzerTestHelper.psm1")
+
+    Function Run-PSScriptAnalyzerRule
+    {
+        Param(
+            [Parameter(Mandatory)]
+            [String] $ManifestPath
+        )
+
+        Invoke-ScriptAnalyzer -Path (Resolve-Path (Join-Path $testManifestPath $ManifestPath))`
+                                -IncludeRule PSUseToExportFieldsInManifest
+    }
 }
 
+
 Describe "UseManifestExportFields" {
 
     Context "Invalid manifest file" {
@@ -81,7 +87,7 @@ Describe "UseManifestExportFields" {
             $results[0].Extent.Text | Should -Be "'*'"
         }
 
-        It "suggests corrections for AliasesToExport with wildcard" -pending:($IsCoreCLR) {
+        It "suggests corrections for AliasesToExport with wildcard" -pending:($IsCoreClr) {
             $violations = Run-PSScriptAnalyzerRule $testManifestBadAliasesWildcardPath
             $violationFilepath = Join-path $testManifestPath $testManifestBadAliasesWildcardPath
             Test-CorrectionExtent $violationFilepath $violations[0] 1  "'*'" "@('gbar', 'gfoo')"
@@ -110,5 +116,3 @@ Describe "UseManifestExportFields" {
         }
     }
 }
-
-
diff --git a/Tests/Rules/UseUTF8EncodingForHelpFile.tests.ps1 b/Tests/Rules/UseUTF8EncodingForHelpFile.tests.ps1
index 6404dcab8..b5471f439 100644
--- a/Tests/Rules/UseUTF8EncodingForHelpFile.tests.ps1
+++ b/Tests/Rules/UseUTF8EncodingForHelpFile.tests.ps1
@@ -1,4 +1,7 @@
-﻿Describe "UseUTF8EncodingForHelpFile" {
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+Describe "UseUTF8EncodingForHelpFile" {
     BeforeAll {
         $violationMessage = "File about_utf16.help.txt has to use UTF8 instead of System.Text.UTF32Encoding encoding because it is a powershell help file."
         $violationName = "PSUseUTF8EncodingForHelpFile"
diff --git a/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1 b/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1
index 66452baf6..65ba1fdec 100644
--- a/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1
+++ b/Tests/Rules/UseUsingScopeModifierInNewRunspaces.tests.ps1
@@ -1,140 +1,139 @@
-$settings = @{
-    IncludeRules = "PSUseUsingScopeModifierInNewRunspaces"
-    Severity     = "warning" # because we need to prevent ParseErrors from being reported, so 'workflow' keyword will not be flagged when running test on Pwsh.
+# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $settings = @{
+        IncludeRules = "PSUseUsingScopeModifierInNewRunspaces"
+        Severity     = "warning" # because we need to prevent ParseErrors from being reported, so 'workflow' keyword will not be flagged when running test on Pwsh.
+    }
 }
 
 Describe "UseUsingScopeModifierInNewRunspaces" {
     Context "Should detect something" {
-        BeforeAll {
-            [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','')]
-            $testCases = @(
-                # Test: Foreach-Object -Parallel {}
-                @{
-                    Description = "Foreach-Object -Parallel with undeclared var"
-                    ScriptBlock = '{
+        It "should emit for: <Description>" {
+            [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptBlock -Settings $settings
+            $warnings.Count | Should -Be 1
+        } -TestCases @(
+            # Test: Foreach-Object -Parallel {}
+            @{
+                Description = "Foreach-Object -Parallel with undeclared var"
+                ScriptBlock = '{
+                    1..2 | ForEach-Object -Parallel { $var }
+                }'
+            }
+            @{
+                Description = "foreach -parallel alias with undeclared var"
+                ScriptBlock = '{
+                    1..2 | ForEach -Parallel { $var }
+                }'
+            }
+            @{
+                Description = "% -parallel alias with undeclared var"
+                ScriptBlock = '{
+                    1..2 | % -Parallel { $var }
+                }'
+            }
+            @{
+                Description = "Foreach-Object -pa abbreviated param with undeclared var"
+                ScriptBlock = '{
+                    1..2 | foreach-object -pa { $var }
+                }'
+            }
+            @{
+                Description = "Foreach-Object -Parallel nested with undeclared var"
+                ScriptBlock = '{
+                    $myNestedScriptBlock = {
                         1..2 | ForEach-Object -Parallel { $var }
-                    }'
-                }
-                @{
-                    Description = "foreach -parallel alias with undeclared var"
-                    ScriptBlock = '{
-                        1..2 | ForEach -Parallel { $var }
-                    }'
-                }
-                @{
-                    Description = "% -parallel alias with undeclared var"
-                    ScriptBlock = '{
-                        1..2 | % -Parallel { $var }
-                    }'
-                }
-                @{
-                    Description = "Foreach-Object -pa abbreviated param with undeclared var"
-                    ScriptBlock = '{
-                        1..2 | foreach-object -pa { $var }
-                    }'
-                }
-                @{
-                    Description = "Foreach-Object -Parallel nested with undeclared var"
-                    ScriptBlock = '{
-                        $myNestedScriptBlock = {
-                            1..2 | ForEach-Object -Parallel { $var }
+                    }
+                }'
+            }
+            # Start-Job / Start-ThreadJob
+            @{
+                Description = 'Start-Job without $using:'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-Job {$foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            @{
+                Description = 'Start-ThreadJob without $using:'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-ThreadJob -ScriptBlock {$foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            @{
+                Description = 'Start-Job with -InitializationScript with a variable'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-Job -ScriptBlock {$foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            @{
+                Description = 'Start-ThreadJob with -InitializationScript with a variable'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-ThreadJob -ScriptBlock {$foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            # workflow/inlinescript
+            @{
+                Description = "Workflow/InlineScript"
+                ScriptBlock = '{
+                    $foo = "bar"
+                    workflow baz { InlineScript {$foo} }
+                }'
+            }
+            # Invoke-Command
+            @{
+                Description = 'Invoke-Command with -ComputerName'
+                ScriptBlock = '{
+                    Invoke-Command -ScriptBlock {Write-Output $foo} -ComputerName "bar"
+                }'
+            }
+            @{
+                Description = 'Invoke-Command with two different sessions, where var is declared in wrong session'
+                ScriptBlock = '{
+                    $session = new-PSSession -ComputerName "baz"
+                    $otherSession = new-PSSession -ComputerName "bar"
+                    Invoke-Command -session $session -ScriptBlock {[string]$foo = "foo" }
+                    Invoke-Command -session $otherSession -ScriptBlock {Write-Output $foo}
+                }'
+            }
+            @{
+                Description = 'Invoke-Command with session, where var is declared after use'
+                ScriptBlock = '{
+                    $session = new-PSSession -ComputerName "baz"
+                    Invoke-Command -session $session -ScriptBlock {Write-Output $foo}
+                    Invoke-Command -session $session -ScriptBlock {$foo = "foo" }
+                }'
+            }
+            # DSC Script resource
+            @{
+                Description = 'DSC Script resource with GetScript {}'
+                ScriptBlock = 'Script ReturnFoo {
+                        GetScript = {
+                            return @{ "Result" = "$foo" }
                         }
                     }'
-                }
-                # Start-Job / Start-ThreadJob
-                @{
-                    Description = 'Start-Job without $using:'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-Job {$foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                @{
-                    Description = 'Start-ThreadJob without $using:'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-ThreadJob -ScriptBlock {$foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                @{
-                    Description = 'Start-Job with -InitializationScript with a variable'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-Job -ScriptBlock {$foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                @{
-                    Description = 'Start-ThreadJob with -InitializationScript with a variable'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-ThreadJob -ScriptBlock {$foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                # workflow/inlinescript
-                @{
-                    Description = "Workflow/InlineScript"
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        workflow baz { InlineScript {$foo} }
-                    }'
-                }
-                # Invoke-Command
-                @{
-                    Description = 'Invoke-Command with -ComputerName'
-                    ScriptBlock = '{
-                        Invoke-Command -ScriptBlock {Write-Output $foo} -ComputerName "bar"
-                    }'
-                }
-                @{
-                    Description = 'Invoke-Command with two different sessions, where var is declared in wrong session'
-                    ScriptBlock = '{
-                        $session = new-PSSession -ComputerName "baz"
-                        $otherSession = new-PSSession -ComputerName "bar"
-                        Invoke-Command -session $session -ScriptBlock {[string]$foo = "foo" }
-                        Invoke-Command -session $otherSession -ScriptBlock {Write-Output $foo}
+            }
+            @{
+                Description = 'DSC Script resource with TestScript {}'
+                ScriptBlock = 'Script TestFoo {
+                        TestScript = {
+                            return [bool]$foo
+                        }
                     }'
-                }
-                @{
-                    Description = 'Invoke-Command with session, where var is declared after use'
-                    ScriptBlock = '{
-                        $session = new-PSSession -ComputerName "baz"
-                        Invoke-Command -session $session -ScriptBlock {Write-Output $foo}
-                        Invoke-Command -session $session -ScriptBlock {$foo = "foo" }
+            }
+            @{
+                Description = 'DSC Script resource with SetScript {}'
+                ScriptBlock = 'Script SetFoo {
+                        SetScript = {
+                            $foo | Set-Content -path "~\nonexistent\foo.txt"
+                        }
                     }'
-                }
-                # DSC Script resource
-                @{
-                    Description = 'DSC Script resource with GetScript {}'
-                    ScriptBlock = 'Script ReturnFoo {
-                            GetScript = {
-                                return @{ "Result" = "$foo" }
-                            }
-                        }'
-                }
-                @{
-                    Description = 'DSC Script resource with TestScript {}'
-                    ScriptBlock = 'Script TestFoo {
-                            TestScript = {
-                                return [bool]$foo
-                            }
-                        }'
-                }
-                @{
-                    Description = 'DSC Script resource with SetScript {}'
-                    ScriptBlock = 'Script SetFoo {
-                            SetScript = {
-                                $foo | Set-Content -path "~\nonexistent\foo.txt"
-                            }
-                        }'
-                }
-            )
-        }
-
-        It "should emit for: <Description>" -TestCases $testCases {
-            param($Description, $ScriptBlock)
-            [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptBlock -Settings $settings
-            $warnings.Count | Should -Be 1
-        }
+            }
+        )
 
         It "should emit suggested correction" {
             $ScriptBlock = '{
@@ -147,140 +146,153 @@ Describe "UseUsingScopeModifierInNewRunspaces" {
     }
 
     Context "Should not detect anything" {
-        BeforeAll {
-            [Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseDeclaredVarsMoreThanAssignments','')]
-            $testCases = @(
-                @{
-                    Description = "Foreach-Object with uninitialized var inside"
-                    ScriptBlock = '{
-                        1..2 | ForEach-Object { $var }
-                    }'
-                }
-                @{
-                    Description = "Foreach-Object -Parallel with uninitialized `$using: var"
-                    ScriptBlock = '{
-                        1..2 | foreach-object -Parallel { $using:var }
-                    }'
-                }
-                @{
-                    Description = "Foreach-Object -Parallel with var assigned locally"
-                    ScriptBlock = '{
-                        1..2 | ForEach-Object -Parallel { [string]$var="somevalue" }
-                    }'
-                }
-                @{
-                    Description = "Foreach-Object -Parallel with built-in var '`$PSBoundParameters' inside"
-                    ScriptBlock = '{
-                        1..2 | ForEach-Object -Parallel{ $PSBoundParameters }
-                    }'
-                }
-                @{
-                    Description = "Foreach-Object -Parallel with vars in other parameters"
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        ForEach-Object -Parallel {$_} -InputObject $foo
-                    }'
-                }
-                # Start-Job / Start-ThreadJob
-                @{
-                    Description = 'Start-Job with $using:'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-Job -ScriptBlock {$using:foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                @{
-                    Description = 'Start-ThreadJob with $using:'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-ThreadJob -ScriptBlock {$using:foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                @{
-                    Description = 'Start-Job with -InitializationScript with a variable'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-Job -ScriptBlock {$using:foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                @{
-                    Description = 'Start-ThreadJob with -InitializationScript with a variable'
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        Start-ThreadJob -ScriptBlock {$using:foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
-                    }'
-                }
-                # workflow/inlinescript
-                @{
-                    Description = "Workflow/InlineScript"
-                    ScriptBlock = '{
-                        $foo = "bar"
-                        workflow baz { InlineScript {$using:foo} }
-                    }'
-                }
-                # Invoke-Command
-                @{
-                    Description = 'Invoke-Command -Session, var declared in same session, other scriptblock'
-                    ScriptBlock = '{
-                        $session = new-PSSession -ComputerName "baz"
-                        Invoke-Command -session $session -ScriptBlock {$foo = "foo" }
-                        Invoke-Command -session $session -ScriptBlock {Write-Output $foo}
-                    }'
-                }
-                @{
-                    Description = 'Invoke-Command without -ComputerName'
-                    ScriptBlock = '{
-                        Invoke-Command -ScriptBlock {Write-Output $foo}
-                    }'
-                }
-                # Unsupported scenarios
-                @{
-                    Description = 'Rule should skip analysis when Command Name cannot be resolved'
-                    ScriptBlock = '{
-                        $commandName = "Invoke-Command"
-                        & $commandName -ComputerName -ScriptBlock { $foo }
-                    }'
-                }
-                # DSC Script resource
-                @{
-                    Description = 'DSC Script resource with GetScript {}'
-                    ScriptBlock = 'Script ReturnFoo {
-                        GetScript = {
-                            return @{ "Result" = "$using:foo" }
-                        }
-                    }'
-                }
-                @{
-                    Description = 'DSC Script resource with TestScript {}'
-                    ScriptBlock = 'Script TestFoo {
-                        TestScript = {
-                            return [bool]$using:foo
-                        }
-                    }'
-                }
-                @{
-                    Description = 'DSC Script resource with SetScript {}'
-                    ScriptBlock = 'Script SetFoo {
-                        SetScript = {
-                            $using:foo | Set-Content -path "~\nonexistent\foo.txt"
-                        }
-                    }'
-                }
-                @{
-                    Description = 'Non-DSC function with the name SetScript {}'
-                    ScriptBlock = '{
-                        SetScript -ScriptBlock {
-                            $foo | Set-Content -path "~\nonexistent\foo.txt"
-                        }
-                    }'
-                }
-            )
-        }
 
-        It "should not emit anything for: <Description>" -TestCases $testCases {
-            param($Description, $ScriptBlock)
+        It "should not emit anything for: <Description>" {
             [System.Array] $warnings = Invoke-ScriptAnalyzer -ScriptDefinition $ScriptBlock -Settings $settings
             $warnings.Count | Should -Be 0
-        }
+        } -TestCases @(
+            @{
+                Description = "Foreach-Object with uninitialized var inside"
+                ScriptBlock = '{
+                    1..2 | ForEach-Object { $var }
+                }'
+            }
+            @{
+                Description = "Foreach-Object -Parallel with uninitialized `$using: var"
+                ScriptBlock = '{
+                    1..2 | foreach-object -Parallel { $using:var }
+                }'
+            }
+            @{
+                Description = "Foreach-Object -Parallel with var assigned locally"
+                ScriptBlock = '{
+                    1..2 | ForEach-Object -Parallel { [string]$var="somevalue" }
+                }'
+            }
+            @{
+                Description = "Foreach-Object -Parallel with built-in var '`$PSBoundParameters' inside"
+                ScriptBlock = '{
+                    1..2 | ForEach-Object -Parallel{ $PSBoundParameters }
+                }'
+            }
+            @{
+                Description = "Foreach-Object -Parallel with vars in other parameters"
+                ScriptBlock = '{
+                    $foo = "bar"
+                    ForEach-Object -Parallel {$_} -InputObject $foo
+                }'
+            }
+            # Start-Job / Start-ThreadJob
+            @{
+                Description = 'Start-Job with $using:'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-Job -ScriptBlock {$using:foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            @{
+                Description = 'Start-ThreadJob with $using:'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-ThreadJob -ScriptBlock {$using:foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            @{
+                Description = 'Start-Job with -InitializationScript with a variable'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-Job -ScriptBlock {$using:foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            @{
+                Description = 'Start-ThreadJob with -InitializationScript with a variable'
+                ScriptBlock = '{
+                    $foo = "bar"
+                    Start-ThreadJob -ScriptBlock {$using:foo} -InitializationScript {$foo} | Receive-Job -Wait -AutoRemoveJob
+                }'
+            }
+            # workflow/inlinescript
+            @{
+                Description = "Workflow/InlineScript"
+                ScriptBlock = '{
+                    $foo = "bar"
+                    workflow baz { InlineScript {$using:foo} }
+                }'
+            }
+            # Invoke-Command
+            @{
+                Description = 'Invoke-Command -Session, var declared in same session, other scriptblock'
+                ScriptBlock = '{
+                    $session = new-PSSession -ComputerName "baz"
+                    Invoke-Command -session $session -ScriptBlock {$foo = "foo" }
+                    Invoke-Command -session $session -ScriptBlock {Write-Output $foo}
+                }'
+            }
+            @{
+                Description = 'Invoke-Command without -ComputerName'
+                ScriptBlock = '{
+                    Invoke-Command -ScriptBlock {Write-Output $foo}
+                }'
+            }
+            # Unsupported scenarios
+            @{
+                Description = 'Rule should skip analysis when Command Name cannot be resolved'
+                ScriptBlock = '{
+                    $commandName = "Invoke-Command"
+                    & $commandName -ComputerName -ScriptBlock { $foo }
+                }'
+            }
+            # DSC Script resource
+            @{
+                Description = 'DSC Script resource with GetScript {}'
+                ScriptBlock = 'Script ReturnFoo {
+                    GetScript = {
+                        return @{ "Result" = "$using:foo" }
+                    }
+                }'
+            }
+            @{
+                Description = 'DSC Script resource with TestScript {}'
+                ScriptBlock = 'Script TestFoo {
+                    TestScript = {
+                        return [bool]$using:foo
+                    }
+                }'
+            }
+            @{
+                Description = 'DSC Script resource with SetScript {}'
+                ScriptBlock = 'Script SetFoo {
+                    SetScript = {
+                        $using:foo | Set-Content -path "~\nonexistent\foo.txt"
+                    }
+                }'
+            }
+            @{
+                Description = 'Non-DSC function with the name SetScript {}'
+                ScriptBlock = '{
+                    SetScript -ScriptBlock {
+                        $foo | Set-Content -path "~\nonexistent\foo.txt"
+                    }
+                }'
+            }
+            # Issue 1492: https://github.com/PowerShell/PSScriptAnalyzer/issues/1492
+            @{
+                Description = 'Does not throw when the same variable name is used in two different sessions'
+                ScriptBlock = @'
+function Get-One{
+    Invoke-Command -Session $sourceRemoteSession {
+        $a = $sccmModule
+        foo $a
+    }
+}
+function Get-Two{
+    Invoke-Command -Session $sourceRemoteSession {
+        $a = $sccmModule
+        foo $a
+    }
+}
+'@
+            }
+        )
     }
 }
diff --git a/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1 b/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1
index c7440c37a..a47ede852 100644
--- a/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1
+++ b/Tests/Rules/UseVerboseMessageInDSCResource.Tests.ps1
@@ -1,8 +1,13 @@
-﻿$violationMessage = "There is no call to Write-Verbose in DSC function 'Test-TargetResource'. If you are using Write-Verbose in a helper function, suppress this rule application."
-$violationName = "PSDSCUseVerboseMessageInDSCResource"
-$violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
-$noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+﻿# Copyright (c) Microsoft Corporation. All rights reserved.
+# Licensed under the MIT License.
+
+BeforeAll {
+    $violationMessage = "There is no call to Write-Verbose in DSC function 'Test-TargetResource'. If you are using Write-Verbose in a helper function, suppress this rule application."
+    $violationName = "PSDSCUseVerboseMessageInDSCResource"
+    $violations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAll\MSFT_WaitForAll.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noViolations = Invoke-ScriptAnalyzer $PSScriptRoot\DSCResourceModule\DSCResources\MSFT_WaitForAny\MSFT_WaitForAny.psm1 | Where-Object {$_.RuleName -eq $violationName}
+    $noClassViolations = Invoke-ScriptAnalyzer -ErrorAction SilentlyContinue $PSScriptRoot\DSCResourceModule\DSCResources\MyDscResource\MyDscResource.psm1 | Where-Object {$_.RuleName -eq $violationName}
+}
 
 Describe "UseVerboseMessageInDSCResource" {
     Context "When there are violations" {
diff --git a/Utils/ReleaseMaker.psm1 b/Utils/ReleaseMaker.psm1
deleted file mode 100644
index ac59dbb32..000000000
--- a/Utils/ReleaseMaker.psm1
+++ /dev/null
@@ -1,198 +0,0 @@
-Function Get-SolutionPath
-{
-    Split-Path $PSScriptRoot -Parent
-}
-
-Function Get-ChangeLogPath
-{
-    Join-Path (Get-SolutionPath) 'CHANGELOG.MD'
-}
-
-Function Get-EngineProjectPath
-{
-    Join-Path (Get-SolutionPath) 'Engine'
-}
-
-Function Get-ModuleManifestPath
-{
-    Join-Path (Get-EngineProjectPath) 'PSScriptAnalyzer.psd1'
-}
-
-Function New-Release
-{
-    [CmdletBinding()]
-    param($newVer, $oldVer)
-
-    $isVersionGiven = $true
-    if ($null -eq $newVer -or $null -eq $oldVer)
-    {
-        Write-Warning "Parameters are null. Checking changelog for version..."
-        $isVersionGiven = $false
-    }
-
-    $solutionRoot = Get-SolutionPath
-    $enginePath = Get-EngineProjectPath
-    $versions = Get-VersionsFromChangeLog
-    if ($versions.Count -le 2)
-    {
-        throw "This edge condition for the number versions less that 2 is not implemented."
-    }
-
-    if ($isVersionGiven)
-    {
-        Function Test-IfNotPresentInChangelog
-        {
-            param($extractedVersion, $inputVersion)
-            if ($extractedVersion -ne $inputVersion)
-            {
-                throw ("Version {0} does not exist in changelog. Please update changelog." -f $inputVersion)
-            }
-        }
-
-        Test-IfNotPresentInChangelog $versions[0] $newVer
-        Test-IfNotPresentInChangelog $versions[1] $oldVer
-    }
-    else
-    {
-        $newVer = $versions[0]
-        $oldVer = $versions[1]
-        $caption = "Version Check"
-        $query = "Is version {0} the next release and version {1} the previous release ?" -f $newVer,$oldVer
-        [bool] $yesToAll = $false
-        [bool] $noToAll = $false
-
-        if (!$PSCmdlet.ShouldContinue($query, $caption, $false, [ref] $yesToAll, [ref] $noToAll))
-        {
-            return "Aborting..."
-        }
-    }
-
-    # update version
-    Update-Version $newVer $oldVer $solutionRoot
-
-    # copy release notes from changelog to module manifest
-    Update-ReleaseNotesInModuleManifest $newVer $oldVer
-
-    # build the module
-    New-ReleaseBuild
-}
-
-function Get-VersionsFromChangeLog
-{
-    $moduleManifestPath = Get-ModuleManifestPath
-    $changelogPath = Get-ChangeLogPath
-    $matches = [regex]::new("\[(\d+\.\d+\.\d+)\]").Matches((get-content $changelogPath -raw))
-    $versions = $matches | ForEach-Object {$_.Groups[1].Value}
-    $versions
-}
-
-function New-ReleaseBuild
-{
-    $solutionPath = Get-SolutionPath
-    Push-Location $solutionPath
-    try
-    {
-        if ( test-path out ) { remove-item out/ -recurse -force }
-        .\build.ps1 -All -Configuration Release
-        .\PSCompatibilityCollector\build.ps1 -Clean -Configuration Release
-        Copy-Item -Recurse .\PSCompatibilityCollector\out\* .\out\
-    }
-    finally
-    {
-        Pop-Location
-    }
-}
-
-function Update-ReleaseNotesInModuleManifest
-{
-    [CmdletBinding()]
-    param($newVer, $oldVer)
-
-    $moduleManifestPath = Get-ModuleManifestPath
-    Write-Verbose ("Module manifest: {0}" -f $moduleManifestPath)
-    $changelogPath = Get-ChangeLogPath
-    Write-Verbose ("CHANGELOG: {0}" -f $changelogPath)
-    $changelogRegexPattern = "##\s\[{0}\].*\n((?:.*\n)+)##\s\[{1}\].*" `
-                                -f [regex]::Escape($newVer),[regex]::Escape($oldVer)
-    $changelogRegex = [regex]::new($changelogRegexPattern)
-    $matches = $changelogRegex.Match((get-content $changelogPath -raw))
-    $changelogWithHyperlinks = $matches.Groups[1].Value.Trim()
-
-    Write-Verbose 'CHANGELOG:'
-    Write-Verbose $changelogWithHyperlinks
-
-    # Remove hyperlinks from changelog to make is suitable for publishing on powershellgallery.com
-    Write-Verbose "Removing hyperlinks from changelog"
-    $changelog = Remove-MarkdownHyperlink $changelogWithHyperlinks
-    Write-Verbose "CHANGELOG without hyperlinks:"
-    Write-Verbose $changelog
-
-    $releaseNotesPattern = `
-        "(?<releaseNotesBegin>ReleaseNotes\s*=\s*@')(?<releaseNotes>(?:.*\n)*)(?<releaseNotesEnd>'@)"
-    $replacement = "`${releaseNotesBegin}" `
-                    + [environment]::NewLine `
-                    + $changelog `
-                    + [environment]::NewLine `
-                    + "`${releaseNotesEnd}"
-    $r = [regex]::new($releaseNotesPattern)
-    $updatedManifestContent = $r.Replace([System.IO.File]::ReadAllText($moduleManifestPath), $replacement)
-    Set-ContentUtf8NoBom $moduleManifestPath $updatedManifestContent
-}
-
-function Remove-MarkdownHyperlink
-{
-    param($markdownContent)
-    $markdownContent -replace "\[(.*?)\]\(.*?\)",'$1'
-}
-
-function Combine-Path
-{
-    if ($args.Count -lt 2)
-    {
-        throw "give more 1 argument"
-    }
-
-    $path = Join-Path $args[0] $args[1]
-    for ($k = 2; $k -lt $args.Count; $k++)
-    {
-        $path = Join-Path $path $args[$k]
-    }
-
-    $path
-}
-
-function Update-Version
-{
-    param(
-        [string] $newVer,
-        [string] $oldVer,
-        [string] $solutionPath
-    )
-
-    $ruleJson = Combine-Path $solutionPath 'Rules' 'Rules.csproj'
-    $engineJson = Combine-Path $solutionPath 'Engine' 'Engine.csproj'
-    $pssaManifest = Combine-Path $solutionPath 'Engine' 'PSScriptAnalyzer.psd1'
-
-    Update-PatternInFile $ruleJson '"version": "{0}"' $oldVer $newVer
-    Update-PatternInFile $ruleJson '"Engine": "{0}"' $oldVer $newVer
-    Update-PatternInFile $engineJson '"version": "{0}"' $oldVer $newVer
-    Update-PatternInFile $pssaManifest "ModuleVersion = '{0}'" $oldVer $newVer
-}
-
-function Update-PatternInFile
-{
-    param ($path, $unformattedPattern, $oldVal, $newVal)
-
-    $content = Get-Content $path
-    $newcontent = $content -replace ($unformattedPattern -f $oldVal),($unformattedPattern -f $newVal)
-    Set-ContentUtf8NoBom $path $newcontent
-}
-
-function Set-ContentUtf8NoBom {
-    param($path, $content)
-    $utfNoBom = [System.Text.UTF8Encoding]::new($false)
-    [System.IO.File]::WriteAllLines($path, $content, $utfNoBom)
-}
-
-Export-ModuleMember -Function New-Release
-Export-ModuleMember -Function New-ReleaseBuild
diff --git a/Utils/RuleMaker.psm1 b/Utils/RuleMaker.psm1
index c3cad6622..71a5d551f 100644
--- a/Utils/RuleMaker.psm1
+++ b/Utils/RuleMaker.psm1
@@ -344,7 +344,6 @@ Function Add-RuleTest($Rule)
     $ruleTestFilePath = Get-RuleTestFilePath $Rule
     New-Item -Path $ruleTestFilePath -ItemType File
     $ruleTestTemplate = @'
-Import-Module PSScriptAnalyzer
 $ruleName = "{0}"
 
 Describe "{0}" {{
diff --git a/appveyor.yml b/appveyor.yml
deleted file mode 100644
index 884efd718..000000000
--- a/appveyor.yml
+++ /dev/null
@@ -1,55 +0,0 @@
-environment:
-  PSVersion: 5
-  BuildConfiguration: Release
-  DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true # For faster CI builds
-  matrix:
-    - APPVEYOR_BUILD_WORKER_IMAGE: WMF 4
-      PowerShellEdition: WindowsPowerShell
-      PSVersion: 4
-  ## Only the tests for WMF4 remain active in AppVeyor due to Azure DevOps not offering such images ##
-  # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2019
-  #   PowerShellEdition: PowerShellCore
-  # - APPVEYOR_BUILD_WORKER_IMAGE: Visual Studio 2017
-  #   PowerShellEdition: WindowsPowerShell
-  # - APPVEYOR_BUILD_WORKER_IMAGE: Ubuntu
-  #   PowerShellEdition: PowerShellCore
-
-# cache Nuget packages and dotnet CLI cache
-cache:
-  - '%USERPROFILE%\.nuget\packages -> appveyor.yml'
-
-install:
-  - ps:   if ($env:PowerShellEdition -eq 'WindowsPowerShell') { Import-Module .\tools\appveyor.psm1; Invoke-AppveyorInstall }
-  - pwsh: if ($env:PowerShellEdition -eq 'PowerShellCore')    { Import-Module .\tools\appveyor.psm1; Invoke-AppveyorInstall }
-
-build_script:
-  - ps:   |
-      if ( $env:PowerShellEdition -eq 'WindowsPowerShell' ) {
-          Set-Location $env:APPVEYOR_BUILD_FOLDER
-          if ( $env:PSVersion -eq "4" ) { # On WMF4: Also build for v3 to check it builds at least since we do not have a WMF3 image
-             ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 3
-          }
-          ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion "$env:PSVersion"
-          ./PSCompatibilityCollector/build.ps1 -Configuration "$env:BuildConfiguration" -Framework 'net452'
-      }
-  - pwsh: |
-      if ($env:PowerShellEdition -eq 'PowerShellCore') {
-          Set-Location $env:APPVEYOR_BUILD_FOLDER
-          ./build.ps1 -Configuration "$env:BuildConfiguration" -PSVersion 6
-          ./PSCompatibilityCollector/build.ps1 -Configuration "$env:BuildConfiguration" -Framework 'netstandard2.0'
-      }
-
-test_script:
-  - ps:   |
-      if ($env:PowerShellEdition -eq 'WindowsPowerShell') {
-          Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER
-      }
-  - pwsh: |
-      if ($env:PowerShellEdition -eq 'PowerShellCore') {
-          Import-Module .\tools\appveyor.psm1 # Appveyor does not persist pwsh sessions like it does for ps
-          Invoke-AppveyorTest -CheckoutPath $env:APPVEYOR_BUILD_FOLDER
-      }
-
-# Upload the project along with test results as a zip archive
-on_finish:
-  - ps: Import-Module "${env:APPVEYOR_BUILD_FOLDER}\tools\appveyor.psm1"; Invoke-AppveyorFinish
diff --git a/build.ps1 b/build.ps1
index 3cf8cad8e..5dade48fe 100644
--- a/build.ps1
+++ b/build.ps1
@@ -7,7 +7,7 @@ param(
     [switch]$All,
 
     [Parameter(ParameterSetName="BuildOne")]
-    [ValidateRange(3, 7)]
+    [ValidateSet(5, 7)]
     [int]$PSVersion = $PSVersionTable.PSVersion.Major,
 
     [Parameter(ParameterSetName="BuildOne")]
@@ -32,12 +32,13 @@ param(
 
     [Parameter(ParameterSetName='Test')]
     [switch] $InProcess,
-
-    [Parameter(ParameterSetName='Bootstrap')]
-    [switch] $Bootstrap,
+    [string] $WithPowerShell,
 
     [Parameter(ParameterSetName='BuildAll')]
-    [switch] $Catalog
+    [switch] $Catalog,
+
+    [Parameter(ParameterSetName='Package')]
+    [switch] $BuildNupkg
 
 )
 
@@ -81,12 +82,16 @@ END {
             }
             Start-ScriptAnalyzerBuild @buildArgs
         }
-        "Bootstrap" {
-            Install-DotNet
-            return
+        "Package" {
+            Start-CreatePackage
         }
         "Test" {
-            Test-ScriptAnalyzer -InProcess:$InProcess
+            $testArgs = @{
+                InProcess = $InProcess
+                WithPowerShell = $WithPowerShell
+                Verbose = $verboseWanted
+            }
+            Test-ScriptAnalyzer @testArgs
             return
         }
         default {
diff --git a/build.psm1 b/build.psm1
index 17b584c3c..5daba36ba 100644
--- a/build.psm1
+++ b/build.psm1
@@ -7,9 +7,8 @@ $analyzerName = "PSScriptAnalyzer"
 
 function Get-AnalyzerVersion
 {
-    $csprojPath = [io.path]::Combine($projectRoot,"Engine","Engine.csproj")
-    $xml = [xml](Get-Content "${csprojPath}")
-    $xml.SelectSingleNode(".//VersionPrefix")."#text"
+    [xml]$xml = Get-Content $([io.path]::Combine($projectRoot, "Directory.Build.props"))
+    $xml.Project.PropertyGroup.ModuleVersion
 }
 
 $analyzerVersion = Get-AnalyzerVersion
@@ -29,61 +28,6 @@ function Publish-File
     }
 }
 
-# attempt to get the users module directory
-function Get-UserModulePath
-{
-    if ( $IsCoreCLR -and -not $IsWindows )
-    {
-        $platformType = "System.Management.Automation.Platform" -as [Type]
-        if ( $platformType ) {
-            ${platformType}::SelectProductNameForDirectory("USER_MODULES")
-        }
-        else {
-            throw "Could not determine users module path"
-        }
-    }
-    else {
-        "${HOME}/Documents/WindowsPowerShell/Modules"
-    }
-}
-
-
-function Uninstall-ScriptAnalyzer
-{
-    [CmdletBinding(SupportsShouldProcess)]
-    param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath ${analyzerName}) )
-    END {
-        if ( $PSCmdlet.ShouldProcess("$modulePath") ) {
-            Remove-Item -Recurse -Path "$ModulePath" -Force
-        }
-    }
-}
-
-# install script analyzer, by default into the users module path
-function Install-ScriptAnalyzer
-{
-    [CmdletBinding(SupportsShouldProcess)]
-    param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath ${analyzerName}) )
-    END {
-        if ( $PSCmdlet.ShouldProcess("$modulePath") ) {
-            Copy-Item -Recurse -Path "$script:destinationDir" -Destination "$ModulePath\." -Force
-        }
-    }
-}
-
-# if script analyzer is installed, remove it
-function Uninstall-ScriptAnalyzer
-{
-    [CmdletBinding(SupportsShouldProcess)]
-    param ( $ModulePath = $(Join-Path -Path (Get-UserModulePath) -ChildPath ${analyzerName}) )
-    END {
-        if ((Test-Path $ModulePath) -and (Get-Item $ModulePath).PSIsContainer )
-        {
-            Remove-Item -Force -Recurse $ModulePath
-        }
-    }
-}
-
 # Clean up the build location
 function Remove-Build
 {
@@ -102,7 +46,7 @@ function Remove-Build
 function Start-DocumentationBuild
 {
     $docsPath = Join-Path $projectRoot docs
-    $markdownDocsPath = Join-Path $docsPath markdown
+    $markdownDocsPath = Join-Path $docsPath Cmdlets
     $outputDocsPath = Join-Path $script:destinationDir en-US
     $platyPS = Get-Module -ListAvailable platyPS
     if ($null -eq $platyPS -or ($platyPS | Sort-Object Version -Descending | Select-Object -First 1).Version -lt [version]0.12)
@@ -144,7 +88,7 @@ function Start-ScriptAnalyzerBuild
     param (
         [switch]$All,
 
-        [ValidateRange(3, 7)]
+        [ValidateSet(5, 7)]
         [int]$PSVersion = $PSVersionTable.PSVersion.Major,
 
         [ValidateSet("Debug", "Release")]
@@ -157,11 +101,8 @@ function Start-ScriptAnalyzerBuild
 
     BEGIN {
         # don't allow the build to be started unless we have the proper Cli version
-        # this will not actually install dotnet if it's already present, but it will
-        # install the proper version
-        Install-Dotnet
         if ( -not (Test-SuitableDotnet) ) {
-            $requiredVersion = Get-GlobalJsonSdkVersion
+            $requiredVersion = $script:wantedVersion
             $foundVersion = Get-InstalledCLIVersion
             Write-Warning "No suitable dotnet CLI found, requires version '$requiredVersion' found only '$foundVersion'"
         }
@@ -183,7 +124,8 @@ function Start-ScriptAnalyzerBuild
         if ( $All )
         {
             # Build all the versions of the analyzer
-            foreach($psVersion in 3..7) {
+            foreach ($psVersion in 5, 7) {
+                Write-Verbose -Verbose -Message "Configuration: $Configuration PSVersion: $psVersion"
                 Start-ScriptAnalyzerBuild -Configuration $Configuration -PSVersion $psVersion -Verbose:$verboseWanted
             }
             if ( $Catalog ) {
@@ -200,20 +142,9 @@ function Start-ScriptAnalyzerBuild
             Set-Variable -Name profilesCopied -Value $true -Scope 1
         }
 
+        $framework = 'net462'
         if ($PSVersion -eq 7) {
-            $framework = 'netcoreapp3.1'
-        }
-        elseif ($PSVersion -eq 6) {
-            $framework = 'netstandard2.0'
-        }
-        else {
-            $framework = "net452"
-        }
-
-        # build the appropriate assembly
-        if ($PSVersion -match "[34]" -and $Framework -ne "net452")
-        {
-            throw ("ScriptAnalyzer for PS version '{0}' is not applicable to {1} framework" -f $PSVersion,$Framework)
+            $framework = 'net8'
         }
 
         Push-Location -Path $projectRoot
@@ -222,29 +153,27 @@ function Start-ScriptAnalyzerBuild
             throw "Not in solution root"
         }
 
+        # "Copy" the module file with the version placeholder replaced
+        $manifestContent = Get-Content -LiteralPath "$projectRoot\Engine\PSScriptAnalyzer.psd1" -Raw
+        $newManifestContent = $manifestContent -replace '{{ModuleVersion}}', $analyzerVersion
+        Set-Content -LiteralPath "$script:destinationDir\PSScriptAnalyzer.psd1" -Encoding utf8 -Value $newManifestContent
+
         $itemsToCopyCommon = @(
-            "$projectRoot\Engine\PSScriptAnalyzer.psd1", "$projectRoot\Engine\PSScriptAnalyzer.psm1",
-            "$projectRoot\Engine\ScriptAnalyzer.format.ps1xml", "$projectRoot\Engine\ScriptAnalyzer.types.ps1xml"
+            "$projectRoot\LICENSE",
+            "$projectRoot\README.md",
+            "$projectRoot\SECURITY.md",
+            "$projectRoot\ThirdPartyNotices.txt",
+            "$projectRoot\Engine\PSScriptAnalyzer.psm1",
+            "$projectRoot\Engine\ScriptAnalyzer.format.ps1xml",
+            "$projectRoot\Engine\ScriptAnalyzer.types.ps1xml"
             )
 
         switch ($PSVersion)
         {
-            3
-            {
-                $destinationDirBinaries = "$script:destinationDir\PSv3"
-            }
-            4
-            {
-                $destinationDirBinaries = "$script:destinationDir\PSv4"
-            }
             5
             {
                 $destinationDirBinaries = "$script:destinationDir"
             }
-            6
-            {
-                $destinationDirBinaries = "$script:destinationDir\PSv6"
-            }
             7
             {
                 $destinationDirBinaries = "$script:destinationDir\PSv7"
@@ -256,7 +185,7 @@ function Start-ScriptAnalyzerBuild
         }
 
         $buildConfiguration = $Configuration
-        if ((3, 4, 6, 7) -contains $PSVersion) {
+        if ($PSVersion -eq 7) {
             $buildConfiguration = "PSV${PSVersion}${Configuration}"
         }
 
@@ -280,12 +209,17 @@ function Start-ScriptAnalyzerBuild
                 $dotnetArgs += "${PSScriptRoot}\bin\${buildConfiguration}\${framework}"
             }
             $buildOutput = & $script:DotnetExe $dotnetArgs 2>&1
-            if ( $LASTEXITCODE -ne 0 ) { throw "$buildOutput" }
+            if ( $LASTEXITCODE -ne 0 ) {
+                Write-Verbose -Verbose -Message "dotnet is $(${script:DotnetExe}.Source)"
+                $dotnetArgs | Foreach-Object {"dotnetArg: $_"} | Write-Verbose -Verbose
+                Get-PSCallStack | Write-Verbose -Verbose
+                throw $buildOutput
+            }
             Write-Verbose -Verbose:$verboseWanted -message "$buildOutput"
         }
         catch {
-            Write-Warning $_
-            Write-Error "Failure to build for PSVersion '$PSVersion' using framework '$framework' and configuration '$config'"
+            $_.TargetObject | Write-Warning
+            Write-Error "Failure to build for PSVersion '$PSVersion' using framework '$framework' and configuration '$buildConfiguration'"
             throw
         }
         finally {
@@ -308,20 +242,30 @@ function Start-ScriptAnalyzerBuild
                 "$projectRoot\Rules\bin\${buildConfiguration}\${framework}\Microsoft.PowerShell.CrossCompatibility.dll"
                 )
         }
+        if ($Configuration -eq 'Debug') {
+            $itemsToCopyBinaries += @(
+                "$projectRoot\Engine\bin\${buildConfiguration}\${Framework}\Microsoft.Windows.PowerShell.ScriptAnalyzer.pdb",
+                "$projectRoot\Rules\bin\${buildConfiguration}\${Framework}\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.pdb"
+                "$projectRoot\Rules\bin\${buildConfiguration}\${framework}\Microsoft.PowerShell.CrossCompatibility.pdb"
+            )
+        }
         Publish-File $itemsToCopyBinaries $destinationDirBinaries
 
         $settingsFiles = Get-Childitem "$projectRoot\Engine\Settings" | ForEach-Object -MemberName FullName
         Publish-File $settingsFiles (Join-Path -Path $script:destinationDir -ChildPath Settings)
 
-        if ($framework -eq 'net452') {
-            if ( $env:TF_BUILD ) {
-                $nsoft =  "$projectRoot\bin\${buildConfiguration}\${framework}\Newtonsoft.Json.dll"
-            }
-            else {
-                $nsoft =  "$projectRoot\Rules\bin\${buildConfiguration}\${framework}\Newtonsoft.Json.dll"
-            }
+        $rulesProjectOutputDir = if ($env:TF_BUILD) {
+            "$projectRoot\bin\${buildConfiguration}\${framework}" }
+        else {
+            "$projectRoot\Rules\bin\${buildConfiguration}\${framework}"
+        }
+        if ($framework -eq 'net462') {
+            $nsoft = Join-Path $rulesProjectOutputDir 'Newtonsoft.Json.dll'
             Copy-Item -path $nsoft -Destination $destinationDirBinaries
         }
+        else {
+            Copy-Item -Path (Join-Path $rulesProjectOutputDir 'Pluralize.NET.dll') -Destination $destinationDirBinaries
+        }
 
         Pop-Location
     }
@@ -350,7 +294,10 @@ function New-Catalog
 function Test-ScriptAnalyzer
 {
     [CmdletBinding()]
-    param ( [Parameter()][switch]$InProcess, [switch]$ShowAll )
+    param (
+        [switch] $InProcess,
+        [string] $WithPowerShell
+    )
 
     END {
         # versions 3 and 4 don't understand versioned module paths, so we need to rename the directory of the version to
@@ -379,29 +326,29 @@ function Test-ScriptAnalyzer
         else {
             $testModulePath = Join-Path "${projectRoot}" -ChildPath out
         }
-        $testResultsFile = "'$(Join-Path ${projectRoot} -childPath TestResults.xml)'"
-        $testScripts = "'${projectRoot}\Tests\Engine','${projectRoot}\Tests\Rules','${projectRoot}\Tests\Documentation'"
+        $testScripts = "'${projectRoot}\Tests\Build','${projectRoot}\Tests\Engine','${projectRoot}\Tests\Rules','${projectRoot}\Tests\Documentation'"
         try {
             if ( $major -lt 5 ) {
                 Rename-Item $script:destinationDir ${testModulePath}
             }
             $savedModulePath = $env:PSModulePath
             $env:PSModulePath = "${testModulePath}{0}${env:PSModulePath}" -f [System.IO.Path]::PathSeparator
-            $importPesterV4 = 'Import-Module -Name Pester -MaximumVersion 4.99'
-            if ($ShowAll)
-            {
-                $scriptBlock = [scriptblock]::Create("$importPesterV4; Invoke-Pester -Path $testScripts -OutputFormat NUnitXml -OutputFile $testResultsFile")
-            }
-            else
-            {
-                $scriptBlock = [scriptblock]::Create("$importPesterV4; Invoke-Pester -Path $testScripts -OutputFormat NUnitXml -OutputFile $testResultsFile -Show Describe,Summary,Failed")
-            }
+            $analyzerPsd1Path = Join-Path -Path $script:destinationDir -ChildPath "$analyzerName.psd1"
+            $scriptBlock = [scriptblock]::Create("Import-Module '$analyzerPsd1Path'; Invoke-Pester -Path $testScripts -CI")
             if ( $InProcess ) {
+                Write-Verbose "Testing with PowerShell $($PSVersionTable.PSVersion)"
                 & $scriptBlock
             }
+            elseif ( $WithPowerShell ) {
+                $pwshVersion = & $WithPowerShell --version
+                Write-Verbose "Testing with $pwshVersion"
+                & $WithPowerShell -Command $scriptBlock
+            }
             else {
                 $powershell = (Get-Process -id $PID).MainModule.FileName
-                & ${powershell} -Command $scriptBlock
+                $pwshVersion = & $powershell --version
+                Write-Verbose "Testing with $pwshVersion"
+                & $powershell -NoProfile -Command $scriptBlock
             }
         }
         finally {
@@ -426,55 +373,12 @@ function Get-TestResults
 # it's not a filter of the results of Get-TestResults because this is faster
 function Get-TestFailures
 {
-    param ( $logfile = (Join-Path -Path ${projectRoot} -ChildPath TestResults.xml) )
+    param ( $logfile = (Join-Path -Path ${projectRoot} -ChildPath testResults.xml) )
     $logPath = (Resolve-Path $logfile).Path
     $results = [xml](Get-Content $logPath)
     $results.SelectNodes(".//test-case[@result='Failure']")
 }
 
-# BOOTSTRAPPING CODE FOR INSTALLING DOTNET
-# install dotnet cli tools based on the version mentioned in global.json
-function Install-Dotnet
-{
-    [CmdletBinding(SupportsShouldProcess=$true)]
-    param (
-        [Parameter()][Switch]$Force,
-        [Parameter()]$version = $( Get-GlobalJsonSdkVersion -Raw )
-        )
-
-    if ( Test-DotnetInstallation -requestedversion $version ) {
-        if ( $Force ) {
-            Write-Verbose -Verbose "Installing again"
-        }
-        else {
-            return
-        }
-    }
-
-    try {
-        Push-Location $PSScriptRoot
-        $installScriptPath = Receive-DotnetInstallScript
-        $installScriptName = [System.IO.Path]::GetFileName($installScriptPath)
-        If ( $PSCmdlet.ShouldProcess("$installScriptName for $version")) {
-            & "${installScriptPath}" -c release -version $version
-        }
-        # this may be the first time that dotnet has been installed,
-        # set up the executable variable
-        if ( -not $script:DotnetExe ) {
-            $script:DotnetExe = Get-DotnetExe
-        }
-    }
-    catch {
-        throw $_
-    }
-    finally {
-        if ( Test-Path $installScriptPath ) {
-            Remove-Item $installScriptPath
-        }
-        Pop-Location
-    }
-}
-
 function Get-GlobalJsonSdkVersion {
     param ( [switch]$Raw )
     $json = Get-Content -raw (Join-Path $PSScriptRoot global.json) | ConvertFrom-Json
@@ -546,12 +450,12 @@ function ConvertTo-PortableVersion {
     }
 }
 
-# see https://docs.microsoft.com/en-us/dotnet/core/tools/global-json for rules
+# see https://learn.microsoft.com/dotnet/core/tools/global-json for rules
 # on how version checks are done
 function Test-SuitableDotnet {
     param (
         $availableVersions = $( Get-InstalledCliVersion),
-        $requiredVersion = $( Get-GlobalJsonSdkVersion )
+        $requiredVersion = $script:wantedVersion
         )
 
     if ( $requiredVersion -is [String] -or $requiredVersion -is [Version] ) {
@@ -613,71 +517,10 @@ function Get-InstalledCLIVersion {
     return (ConvertTo-PortableVersion $installedVersions)
 }
 
-function Test-DotnetInstallation
-{
-    param (
-        $requestedVersion = $( Get-GlobalJsonSdkVersion ),
-        $installedVersions = $( Get-InstalledCLIVersion )
-        )
-    return (Test-SuitableDotnet -availableVersions $installedVersions -requiredVersion $requestedVersion )
-}
-
-function Receive-File {
-    param ( [Parameter(Mandatory,Position=0)]$uri )
-
-    # enable Tls12 for the request
-    # -SslProtocol parameter for Invoke-WebRequest wasn't in PSv3
-    $securityProtocol = [System.Net.ServicePointManager]::SecurityProtocol
-    $tls12 = [System.Net.SecurityProtocolType]::Tls12
-    try {
-        if ( ([System.Net.ServicePointManager]::SecurityProtocol -band $tls12) -eq 0 ) {
-            [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor $tls12
-        }
-        $null = Invoke-WebRequest -Uri ${uri} -OutFile "${installScriptName}"
-    }
-    finally {
-        [System.Net.ServicePointManager]::SecurityProtocol = $securityProtocol
-    }
-    if ( (Test-Path Variable:IsWindows) -and -not $IsWindows ) {
-        chmod +x $installScriptName
-    }
-    $installScript = Get-Item $installScriptName -ErrorAction Stop
-    if ( -not $installScript ) {
-        throw "Download failure of ${uri}"
-    }
-    return $installScript
-}
-
-function Receive-DotnetInstallScript
-{
-    # param '$platform' is a hook to enable forcing download of a specific
-    # install script, generally it should not be used except in testing.
-    param ( $platform = "" )
-
-    # if $platform has been set, it has priority
-    # if it's not set to Windows or NonWindows, it will be ignored
-    if ( $platform -eq "Windows" ) {
-        $installScriptName = "dotnet-install.ps1"
-    }
-    elseif ( $platform -eq "NonWindows" ) {
-        $installScriptName = "dotnet-install.sh"
-    }
-    elseif ( ((Test-Path Variable:IsWindows) -and -not $IsWindows) ) {
-        # if the variable IsWindows exists and it is set to false
-        $installScriptName = "dotnet-install.sh"
-    }
-    else { # the default case - we're running on a Windows system
-        $installScriptName = "dotnet-install.ps1"
-    }
-    $uri = "https://dot.net/v1/${installScriptName}"
-
-    $installScript = Receive-File -Uri $uri
-    return $installScript.FullName
-}
-
 function Get-DotnetExe
 {
-    $discoveredDotnet = Get-Command -CommandType Application dotnet -ErrorAction SilentlyContinu
+    param ( $version = $script:wantedVersion )
+    $discoveredDotnet = Get-Command -CommandType Application dotnet -ErrorAction SilentlyContinue -All
     if ( $discoveredDotnet ) {
         # it's possible that there are multiples. Take the highest version we find
         # the problem is that invoking dotnet on a version which is lower than the specified
@@ -688,13 +531,17 @@ function Get-DotnetExe
         # file points to a version of the sdk which is *not* installed. However, the format of the new list
         # with --version has a couple of spaces at the beginning of the line, so we need to be resilient
         # against that.
-        $latestDotnet = $discoveredDotNet |
-            Where-Object { try { & $_ --version 2>$null } catch { } } |
-            Sort-Object { $pv = ConvertTo-PortableVersion (& $_ --version 2>$null| %{$_.Trim().Split()[0]}); "$pv" } |
+        $properDotnet = $discoveredDotNet |
+            Where-Object {
+                & $_ --list-sdks |
+                    Where-Object {
+                        $_ -match $version
+                    }
+            } |
             Select-Object -Last 1
-        if ( $latestDotnet ) {
-            $script:DotnetExe = $latestDotnet
-            return $latestDotnet
+        if ( $properDotnet ) {
+            $script:DotnetExe = $properDotnet
+            return $properDotnet
         }
     }
     # it's not in the path, try harder to find it by checking some usual places
@@ -705,6 +552,13 @@ function Get-DotnetExe
             $script:DotnetExe = $dotnetHuntPath
             return $dotnetHuntPath
         }
+
+        $dotnetHuntPath = "C:\Program Files\dotnet\dotnet.exe"
+        Write-Verbose -Verbose "checking Windows $dotnetHuntPath"
+        if ( test-path $dotnetHuntPath ) {
+            $script:DotnetExe = $dotnetHuntPath
+            return $dotnetHuntPath
+        }
     }
     else {
         $dotnetHuntPath = "$HOME/.dotnet/dotnet"
@@ -713,12 +567,28 @@ function Get-DotnetExe
             $script:DotnetExe = $dotnetHuntPath
             return $dotnetHuntPath
         }
+
+        $dotnetHuntPath = "/usr/share/dotnet/dotnet"
+        Write-Verbose -Verbose "checking non-Windows $dotnetHuntPath"
+        if ( test-path $dotnetHuntPath ) {
+            $script:DotnetExe = $dotnetHuntPath
+            return $dotnetHuntPath
+        }
     }
 
     Write-Warning "Could not find dotnet executable"
     return [String]::Empty
 }
-$script:DotnetExe = Get-DotnetExe
+
+try {
+    # The version we want based on the global.JSON file
+    # suck this before getting the dotnet exe
+    $script:wantedVersion = Get-GlobalJsonSdkVersion -Raw
+    $script:DotnetExe = Get-DotnetExe
+}
+catch {
+    Write-Warning "The dotnet CLI was not found, please install it: https://aka.ms/dotnet-cli"
+}
 
 # Copies the built PSCompatibilityCollector module to the output destination for PSSA
 function Copy-CrossCompatibilityModule
@@ -766,3 +636,21 @@ function Copy-CrossCompatibilityModule
         }
     }
 }
+
+# creates the nuget package which can be used for publishing to the gallery
+function Start-CreatePackage
+{
+    try {
+        $buildRoot = "out"
+        $repoName = [guid]::NewGuid().ToString()
+        $nupkgDir = Join-Path $PSScriptRoot $buildRoot
+        $null = Register-PSRepository -Name $repoName -InstallationPolicy Trusted -SourceLocation $nupkgDir
+        Push-Location $nupkgDir
+
+        Publish-Module -Path $PWD/PSScriptAnalyzer -Repository $repoName
+    }
+    finally {
+       Pop-Location
+       Unregister-PSRepository -Name $repoName
+    }
+}
diff --git a/docs/Cmdlets/Get-ScriptAnalyzerRule.md b/docs/Cmdlets/Get-ScriptAnalyzerRule.md
new file mode 100644
index 000000000..3d815b2c3
--- /dev/null
+++ b/docs/Cmdlets/Get-ScriptAnalyzerRule.md
@@ -0,0 +1,189 @@
+---
+external help file: Microsoft.Windows.PowerShell.ScriptAnalyzer.dll-Help.xml
+Module Name: PSScriptAnalyzer
+ms.date: 12/12/2024
+online version: https://learn.microsoft.com/powershell/module/psscriptanalyzer/get-scriptanalyzerrule?view=ps-modules&wt.mc_id=ps-gethelp
+schema: 2.0.0
+---
+
+# Get-ScriptAnalyzerRule
+
+## SYNOPSIS
+Gets the script analyzer rules on the local computer.
+
+## SYNTAX
+
+```
+Get-ScriptAnalyzerRule [[-Name] <string[]>] [-CustomRulePath <string[]>] [-RecurseCustomRulePath]
+ [-Severity <string[]>] [<CommonParameters>]
+```
+
+## DESCRIPTION
+
+Gets the script analyzer rules on the local computer. You can select rules by Name, Severity,
+Source, or SourceType, or even particular words in the rule description.
+
+Use this cmdlet to create collections of rules to include and exclude when running the
+`Invoke-ScriptAnalyzer` cmdlet.
+
+To get information about the rules, see the value of the Description property of each rule.
+
+The PSScriptAnalyzer module tests the PowerShell code in a script, module, or DSC resource to
+determine if it fulfils best practice standards.
+
+## EXAMPLES
+
+### EXAMPLE 1 - Get all Script Analyzer rules on the local computer
+
+```powershell
+Get-ScriptAnalyzerRule
+```
+
+### EXAMPLE 2 - Gets only rules with the Error severity
+
+```powershell
+Get-ScriptAnalyzerRule -Severity Error
+```
+
+### EXAMPLE 3 - Run only the DSC rules with the Error severity
+
+This example runs only the DSC rules with the Error severity on the files in the **MyDSCModule**
+module.
+
+```powershell
+$DSCError = Get-ScriptAnalyzerRule -Severity Error | Where-Object SourceName -eq PSDSC
+$Path = "$home\Documents\WindowsPowerShell\Modules\MyDSCModule\*"
+Invoke-ScriptAnalyzerRule -Path $Path -IncludeRule $DSCError -Recurse
+```
+
+Using the **IncludeRule** parameter of `Invoke-ScriptAnalyzerRule` is more efficient than using its
+**Severity** parameter, which is applied only after using all rules to analyze all module files.
+
+### EXAMPLE 4 - Get rules by name and severity
+
+This example gets rules with "Parameter" or "Alias" in the name that generate an Error or Warning.
+You can use this set of rules to test the parameters of your script or module.
+
+```powershell
+$TestParameters = Get-ScriptAnalyzerRule -Severity Error, Warning -Name *Parameter*, *Alias*
+```
+
+### EXAMPLE 5 - Get custom rules
+
+This example gets the standard rules and the rules in the **VeryStrictRules** and
+**ExtremelyStrictRules** modules. The command uses the **RecurseCustomRulePath** parameter to get
+rules defined in subdirectories of the matching paths.
+
+```powershell
+Get-ScriptAnalyzerRule -CustomRulePath $home\Documents\WindowsPowerShell\Modules\*StrictRules -RecurseCustomRulePath
+```
+
+## PARAMETERS
+
+### -CustomRulePath
+
+By default, PSScriptAnalyzer gets only the standard rules specified in the
+`Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll` file in the module. Use this
+parameter to get the custom Script Analyzer rules in the specified path and the standard Script
+Analyzer rules.
+
+Enter the path to a .NET assembly or module that contains Script Analyzer rules. You can enter only
+one value, but wildcards are supported. To get rules in subdirectories of the path, use the
+**RecurseCustomRulePath** parameter.
+
+You can create custom rules using a .NET assembly or a PowerShell module, such as the
+[Community Analyzer Rules](https://github.com/PowerShell/PSScriptAnalyzer/tree/main/Tests/Engine/CommunityAnalyzerRules)
+in the GitHub repository.
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases: CustomizedRulePath
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: True
+```
+
+### -Name
+
+Gets only rules with the specified names or name patterns. Wildcards are supported. If you list
+multiple names or patterns, it gets all rules that match any of the name patterns.
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: All rules
+Accept pipeline input: False
+Accept wildcard characters: True
+```
+
+### -RecurseCustomRulePath
+
+Searches the **CustomRulePath** location recursively to add rules defined in files in subdirectories
+of the path. By default, `Get-ScriptAnalyzerRule` adds only the custom rules in the specified path.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Severity
+
+Gets only rules with the specified severity values. Valid values are:
+
+- Information
+- Warning
+- Error
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: All rules
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### CommonParameters
+
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable,
+-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose,
+-WarningAction, and -WarningVariable. For more information, see
+[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+### None
+
+You can't pipe input to this cmdlet.
+
+## OUTPUTS
+
+### Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.RuleInfo
+
+The **RuleInfo** object is a custom object created specifically for Script Analyzer.
+
+## NOTES
+
+## RELATED LINKS
+
+[Invoke-ScriptAnalyzer](Invoke-ScriptAnalyzer.md)
+
+[PSScriptAnalyzer on GitHub](https://github.com/PowerShell/PSScriptAnalyzer)
diff --git a/docs/Cmdlets/Invoke-Formatter.md b/docs/Cmdlets/Invoke-Formatter.md
new file mode 100644
index 000000000..1ffb766ce
--- /dev/null
+++ b/docs/Cmdlets/Invoke-Formatter.md
@@ -0,0 +1,160 @@
+---
+external help file: Microsoft.Windows.PowerShell.ScriptAnalyzer.dll-Help.xml
+Module Name: PSScriptAnalyzer
+ms.date: 10/07/2021
+online version: https://learn.microsoft.com/powershell/module/psscriptanalyzer/invoke-formatter?view=ps-modules&wt.mc_id=ps-gethelp
+schema: 2.0.0
+---
+
+# Invoke-Formatter
+
+## SYNOPSIS
+Formats a script text based on the input settings or default settings.
+
+## SYNTAX
+
+```
+Invoke-Formatter [-ScriptDefinition] <string> [[-Settings] <Object>] [[-Range] <int[]>]
+ [<CommonParameters>]
+```
+
+## DESCRIPTION
+
+The `Invoke-Formatter` cmdlet takes a string input and formats it according to defined settings. If
+no **Settings** parameter is provided, the cmdlet assumes the default code formatting settings as
+defined in `Settings/CodeFormatting.psd1`.
+
+## EXAMPLES
+
+### EXAMPLE 1 - Format the input script text using the default settings
+
+```powershell
+$scriptDefinition = @'
+function foo {
+"hello"
+  }
+'@
+
+Invoke-Formatter -ScriptDefinition $scriptDefinition
+```
+
+```Output
+function foo {
+    "hello"
+}
+```
+
+### EXAMPLE 2 - Format the input script using the settings defined in a hashtable
+
+```powershell
+$scriptDefinition = @'
+function foo {
+"hello"
+}
+'@
+
+$settings = @{
+    IncludeRules = @("PSPlaceOpenBrace", "PSUseConsistentIndentation")
+    Rules = @{
+        PSPlaceOpenBrace = @{
+            Enable = $true
+            OnSameLine = $false
+        }
+        PSUseConsistentIndentation = @{
+            Enable = $true
+        }
+    }
+}
+
+Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings
+```
+
+```Output
+function foo
+{
+    "hello"
+}
+```
+
+### EXAMPLE 3 - Format the input script text using the settings defined a `.psd1` file
+
+```powershell
+Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings /path/to/settings.psd1
+```
+
+## PARAMETERS
+
+### -Range
+
+The range within which formatting should take place. The value of this parameter must be an array of
+four integers. These numbers must be greater than 0. The four integers represent the following four
+values in this order:
+
+- starting line number
+- starting column number
+- ending line number
+- ending column number
+
+```yaml
+Type: Int32[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: 3
+Default value: None
+Accept pipeline input: True
+Accept wildcard characters: False
+```
+
+### -ScriptDefinition
+
+The text of the script to be formatted represented as a string. This is not a **ScriptBlock**
+object.
+
+```yaml
+Type: String
+Parameter Sets: (All)
+Aliases:
+
+Required: True
+Position: 1
+Default value: None
+Accept pipeline input: True (ByPropertyName, ByValue)
+Accept wildcard characters: False
+```
+
+### -Settings
+
+A settings hashtable or a path to a PowerShell data file (`.psd1`) that contains the settings.
+
+```yaml
+Type: Object
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: 2
+Default value: CodeFormatting
+Accept pipeline input: True
+Accept wildcard characters: False
+```
+
+### CommonParameters
+
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable,
+-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose,
+-WarningAction, and -WarningVariable. For more information, see
+[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+## OUTPUTS
+
+### System.String
+
+The formatted string result.
+
+## NOTES
+
+## RELATED LINKS
diff --git a/docs/Cmdlets/Invoke-ScriptAnalyzer.md b/docs/Cmdlets/Invoke-ScriptAnalyzer.md
new file mode 100644
index 000000000..b3e72a337
--- /dev/null
+++ b/docs/Cmdlets/Invoke-ScriptAnalyzer.md
@@ -0,0 +1,644 @@
+---
+external help file: Microsoft.Windows.PowerShell.ScriptAnalyzer.dll-Help.xml
+Module Name: PSScriptAnalyzer
+ms.date: 10/07/2021
+online version: https://learn.microsoft.com/powershell/module/psscriptanalyzer/invoke-scriptanalyzer?view=ps-modules&wt.mc_id=ps-gethelp
+schema: 2.0.0
+---
+
+# Invoke-ScriptAnalyzer
+
+## SYNOPSIS
+Evaluates a script or module based on selected best practice rules
+
+## SYNTAX
+
+### Path_SuppressedOnly (Default)
+
+```
+Invoke-ScriptAnalyzer [-Path] <string> [-CustomRulePath <string[]>] [-RecurseCustomRulePath]
+ [-IncludeDefaultRules] [-ExcludeRule <string[]>] [-IncludeRule <string[]>] [-Severity <string[]>]
+ [-Recurse] [-SuppressedOnly] [-Fix] [-EnableExit] [-Settings <Object>] [-SaveDscDependency]
+ [-ReportSummary] [-WhatIf] [-Confirm] [<CommonParameters>]
+```
+
+### Path_IncludeSuppressed
+
+```
+Invoke-ScriptAnalyzer [-Path] <string> -IncludeSuppressed [-CustomRulePath <string[]>]
+ [-RecurseCustomRulePath] [-IncludeDefaultRules] [-ExcludeRule <string[]>]
+ [-IncludeRule <string[]>] [-Severity <string[]>] [-Recurse] [-Fix] [-EnableExit]
+ [-Settings <Object>] [-SaveDscDependency] [-ReportSummary] [-WhatIf] [-Confirm]
+ [<CommonParameters>]
+```
+
+### ScriptDefinition_IncludeSuppressed
+
+```
+Invoke-ScriptAnalyzer [-ScriptDefinition] <string> -IncludeSuppressed [-CustomRulePath <string[]>]
+ [-RecurseCustomRulePath] [-IncludeDefaultRules] [-ExcludeRule <string[]>]
+ [-IncludeRule <string[]>] [-Severity <string[]>] [-Recurse] [-EnableExit] [-Settings <Object>]
+ [-SaveDscDependency] [-ReportSummary] [-WhatIf] [-Confirm] [<CommonParameters>]
+```
+
+### ScriptDefinition_SuppressedOnly
+
+```
+Invoke-ScriptAnalyzer [-ScriptDefinition] <string> [-CustomRulePath <string[]>]
+ [-RecurseCustomRulePath] [-IncludeDefaultRules] [-ExcludeRule <string[]>]
+ [-IncludeRule <string[]>] [-Severity <string[]>] [-Recurse] [-SuppressedOnly] [-EnableExit]
+ [-Settings <Object>] [-SaveDscDependency] [-ReportSummary] [-WhatIf] [-Confirm]
+ [<CommonParameters>]
+```
+
+## DESCRIPTION
+
+`Invoke-ScriptAnalyzer` evaluates scripts or module files (`.ps1`, `.psm1`, and `.psd1` files) based
+on a collection of best practice rules and returns objects that represent rule violations. It also
+includes special rules to analyze DSC resources.
+
+`Invoke-ScriptAnalyzer` comes with a set of built-in rules. By default, it uses all rules. You can
+use the **IncludeRule** and **ExcludeRule** parameters to select the rules you want. You can use the
+`Get-ScriptAnalyzerRule` cmdlet to examine and select the rules you want to include or exclude from
+the evaluation.
+
+You can also use customized rules that you write in PowerShell scripts, or compile in assemblies
+using C#. Custom rules can also be selected using the **IncludeRule** and **ExcludeRule**
+parameters.
+
+You can also include a rule in the analysis, but suppress the output of that rule for selected
+functions or scripts. This feature should be used only when necessary. To get rules that were
+suppressed, run `Invoke-ScriptAnalyzer` with the **SuppressedOnly** parameter.
+
+For usage in CI systems, the **EnableExit** exits the shell with an exit code equal to the number of
+error records.
+
+## EXAMPLES
+
+### EXAMPLE 1 - Run all Script Analyzer rules on a script
+
+```powershell
+Invoke-ScriptAnalyzer -Path C:\Scripts\Get-LogData.ps1
+```
+
+### EXAMPLE 2 - Run all Script Analyzer rules on all files in the Modules directory
+
+This example runs all Script Analyzer rules on all `.ps1` and `.psm1` files in your user-based
+`Modules` directory and its subdirectories.
+
+```powershell
+Invoke-ScriptAnalyzer -Path $home\Documents\WindowsPowerShell\Modules -Recurse
+```
+
+### EXAMPLE 3 - Run a single rule on a module
+
+This example runs only the **PSAvoidUsingPositionalParameters** rule on the files in the
+`PSDiagnostics` module folder. You can use a command like this to find all instances of a particular
+rule violation.
+
+```powershell
+Invoke-ScriptAnalyzer -Path C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSDiagnostics -IncludeRule PSAvoidUsingPositionalParameters
+```
+
+### EXAMPLE 4 - Run all rules except two on your modules
+
+This example runs all rules except for **PSAvoidUsingCmdletAliases** and
+**PSAvoidUsingInternalURLs** on the `.ps1` and `.psm1` files in the `MyModules` directory and in its
+subdirectories.
+
+```powershell
+Invoke-ScriptAnalyzer -Path C:\ps-test\MyModule -Recurse -ExcludeRule PSAvoidUsingCmdletAliases, PSAvoidUsingInternalURLs
+```
+
+### EXAMPLE 5 - Run Script Analyzer with custom rules
+
+This example runs Script Analyzer on `Test-Script.ps1` with the standard rules and rules in the
+`C:\CommunityAnalyzerRules` path.
+
+```powershell
+Invoke-ScriptAnalyzer -Path D:\test_scripts\Test-Script.ps1 -CustomRulePath C:\CommunityAnalyzerRules -IncludeDefaultRules
+```
+
+### EXAMPLE 6 - Run only the rules that are Error severity and have the PSDSC source name
+
+```powershell
+$DSCError = Get-ScriptAnalyzerRule -Severity Error | Where SourceName -eq PSDSC
+$Path = "$home\Documents\WindowsPowerShell\Modules\MyDSCModule"
+Invoke-ScriptAnalyzerRule -Path $Path -IncludeRule $DSCError -Recurse
+```
+
+### EXAMPLE 7 - Suppressing rule violations
+
+This example shows how to suppress the reporting of rule violations in a function and how to
+discover rule violations that are suppressed.
+
+The example uses the `SuppressMessageAttribute` attribute to suppress the **PSUseSingularNouns** and
+**PSAvoidUsingCmdletAliases** rules for the `Get-Widgets` function in the `Get-Widgets.ps1` script.
+You can use this attribute to suppress a rule for a module, script, class, function, parameter, or
+line.
+
+The first command runs Script Analyzer on the script file containing the function. The output
+reports a rule violation. Even though more rules are violated, neither suppressed rule is reported.
+
+```powershell
+function Get-Widgets
+{
+    [CmdletBinding()]
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingCmdletAliases", "", Justification="Resolution in progress.")]
+    Param()
+
+    dir $pshome
+    ...
+}
+
+Invoke-ScriptAnalyzer -Path .\Get-Widgets.ps1
+```
+
+```Output
+RuleName                            Severity     FileName   Line  Message
+--------                            --------     --------   ----  -------
+PSProvideCommentHelp                Information  ManageProf 14    The cmdlet 'Get-Widget' does not have a help comment.
+                                                 iles.psm1
+```
+
+```powershell
+Invoke-ScriptAnalyzer -Path .\Get-Widgets.ps1 -SuppressedOnly
+```
+
+```Output
+Rule Name                           Severity     File Name  Line  Justification
+---------                           --------     ---------  ----  -------------
+PSAvoidUsingCmdletAliases           Warning      ManageProf 21    Resolution in progress.
+                                                 iles.psm1
+PSUseSingularNouns                  Warning      ManageProf 14
+                                                 iles.psm1
+```
+
+The second command uses the **SuppressedOnly** parameter to report violations of the rules that are
+suppressed script file.
+
+### EXAMPLE 8 - Analyze script files using a profile definition
+
+In this example, we create a Script Analyzer profile and save it in the `ScriptAnalyzerProfile.txt`
+file in the current directory. We run `Invoke-ScriptAnalyzer` on the **BitLocker** module files. The
+value of the **Profile** parameter is the path to the Script Analyzer profile.
+
+```powershell
+# In .\ScriptAnalyzerProfile.txt
+@{
+    Severity = @('Error', 'Warning')
+    IncludeRules = 'PSAvoid*'
+    ExcludeRules = '*WriteHost'
+}
+
+Invoke-ScriptAnalyzer -Path $pshome\Modules\BitLocker -Settings .\ScriptAnalyzerProfile.txt
+```
+
+If you include a conflicting parameter in the `Invoke-ScriptAnalyzer` command, such as
+`-Severity Error`, the cmdlet uses the profile value and ignores the parameter.
+
+### EXAMPLE 9 - Analyze a script stored as a string
+
+This example uses the **ScriptDefinition** parameter to analyze a function at the command line. The
+function string is enclosed in quotation marks.
+
+```powershell
+Invoke-ScriptAnalyzer -ScriptDefinition "function Get-Widgets {Write-Host 'Hello'}"
+```
+
+```Output
+RuleName                            Severity     FileName   Line  Message
+--------                            --------     --------   ----  -------
+PSAvoidUsingWriteHost               Warning                 1     Script
+                                                                  because
+                                                                  there i
+                                                                  suppres
+                                                                  Write-O
+PSUseSingularNouns                  Warning                 1     The cmd
+                                                                  noun sh
+```
+
+When you use the **ScriptDefinition** parameter, the **FileName** property of the
+**DiagnosticRecord** object is `$null`.
+
+## PARAMETERS
+
+### -CustomRulePath
+
+Enter the path to a file that defines rules or a directory that contains files that define rules.
+Wildcard characters are supported. When **CustomRulePath** is specified, only the custom rules found
+in the specified paths are used for the analysis. If `Invoke-ScriptAnalyzer` cannot find rules in
+the , it runs the standard rules without notice.
+
+To add rules defined in subdirectories of the path, use the **RecurseCustomRulePath** parameter. To
+include the built-in rules, add the **IncludeDefaultRules** parameter.
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases: CustomizedRulePath
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: True
+```
+
+### -EnableExit
+
+On completion of the analysis, this parameter exits the PowerShell sessions and returns an exit code
+equal to the number of error records. This can be useful in continuous integration (CI) pipeline.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -ExcludeRule
+
+Omits the specified rules from the Script Analyzer test. Wildcard characters are supported.
+
+Enter a comma-separated list of rule names, a variable that contains rule names, or a command that
+gets rule names. You can also specify a list of excluded rules in a Script Analyzer profile file.
+You can exclude standard rules and rules in a custom rule path.
+
+When you exclude a rule, the rule does not run on any of the files in the path. To exclude a rule on
+a particular line, parameter, function, script, or class, adjust the Path parameter or suppress the
+rule. For information about suppressing a rule, see the examples.
+
+If a rule is specified in both the **ExcludeRule** and **IncludeRule** collections, the rule is
+excluded.
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: All rules are included.
+Accept pipeline input: False
+Accept wildcard characters: True
+```
+
+### -Fix
+
+Fixes certain warnings that contain a fix in their **DiagnosticRecord**.
+
+When you used **Fix**, `Invoke-ScriptAnalyzer` applies the fixes before running the analysis. Make
+sure that you have a backup of your files when using this parameter. It tries to preserve the file
+encoding but there are still some cases where the encoding can change.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: Path_SuppressedOnly, Path_IncludeSuppressed
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -IncludeDefaultRules
+
+Invoke default rules along with Custom rules.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -IncludeRule
+
+Runs only the specified rules in the Script Analyzer test. By default, PSScriptAnalyzer runs all
+rules.
+
+Enter a comma-separated list of rule names, a variable that contains rule names, or a command that
+gets rule names. Wildcard characters are supported. You can also specify rule names in a Script
+Analyzer profile file.
+
+When you use the **CustomizedRulePath** parameter, you can use this parameter to include standard
+rules and rules in the custom rule paths.
+
+If a rule is specified in both the **ExcludeRule** and **IncludeRule** collections, the rule is
+excluded.
+
+The **Severity** parameter takes precedence over **IncludeRule**. For example, if **Severity** is
+`Error`, you cannot use **IncludeRule** to include a `Warning` rule.
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: All rules are included.
+Accept pipeline input: False
+Accept wildcard characters: True
+```
+
+### -IncludeSuppressed
+
+Include suppressed diagnostics in output.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: Path_IncludeSuppressed, ScriptDefinition_IncludeSuppressed
+Aliases:
+
+Required: True
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Path
+
+Specifies the path to the scripts or module to be analyzed. Wildcard characters are supported.
+
+Enter the path to a script (`.ps1`) or module file (`.psm1`) or to a directory that contains scripts
+or modules. If the directory contains other types of files, they are ignored.
+
+To analyze files that are not in the root directory of the specified path, use a wildcard character
+(`C:\Modules\MyModule\*`) or the **Recurse** parameter.
+
+```yaml
+Type: String
+Parameter Sets: Path_SuppressedOnly, Path_IncludeSuppressed
+Aliases: PSPath
+
+Required: True
+Position: 0
+Default value: None
+Accept pipeline input: True (ByPropertyName, ByValue)
+Accept wildcard characters: True
+```
+
+### -Recurse
+
+Runs Script Analyzer on the files in the **Path** directory and all subdirectories recursively.
+
+Recurse applies only to the Path parameter value. To search the **CustomRulePath** recursively, use
+the **RecurseCustomRulePath** parameter.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -RecurseCustomRulePath
+
+Adds rules defined in subdirectories of the **CustomRulePath** location. By default,
+`Invoke-ScriptAnalyzer` uses only the custom rules defined in the specified file or directory. To
+include the built-in rules, use the **IncludeDefaultRules** parameter.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -ReportSummary
+
+Write a summary of the violations found to the host.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -SaveDscDependency
+
+Resolve DSC resource dependencies.
+
+When `Invoke-ScriptAnalyzer` is run with this parameter, it looks for instances of
+`Import-DSCResource -ModuleName <somemodule>`. If `<somemodule>` is cannot be found by searching the
+`$env:PSModulePath`, `Invoke-ScriptAnalyzer` returns parse error. This error is caused by the
+PowerShell parser not being able to find the symbol for `<somemodule>`.
+
+If `Invoke-ScriptAnalyzer` finds the module in the PowerShell Gallery, it downloads the missing
+module to a temp path. The temp path is then added to `$env:PSModulePath` for duration of the scan.
+The temp location can be found in `$LOCALAPPDATA/PSScriptAnalyzer/TempModuleDir`.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -ScriptDefinition
+
+Runs the analysis on commands, functions, or expressions in a string. You can use this feature to
+analyze statements, expressions, and functions, independent of their script context.
+
+```yaml
+Type: String
+Parameter Sets: ScriptDefinition_IncludeSuppressed, ScriptDefinition_SuppressedOnly
+Aliases:
+
+Required: True
+Position: 0
+Default value: None
+Accept pipeline input: True (ByPropertyName, ByValue)
+Accept wildcard characters: False
+```
+
+### -Settings
+
+A path to a file containing a user-defined profile or a hashtable object containing settings for
+ScriptAnalyzer.
+
+Runs `Invoke-ScriptAnalyzer` with the parameters and values specified in the file or hashtable.
+
+If the path or the content of the file or hashtable is invalid, it is ignored. The parameters and
+values in the profile take precedence over the same parameter and values specified at the command
+line.
+
+A Script Analyzer profile file is a text file that contains a hashtable with one or more of the
+following keys:
+
+- CustomRulePath
+- ExcludeRules
+- IncludeDefaultRules
+- IncludeRules
+- RecurseCustomRulePath
+- Rules
+- Severity
+
+The keys and values in the profile are interpreted as if they were standard parameters and values of
+`Invoke-ScriptAnalyzer`, similar to splatting. For more information, see
+[about_Splatting](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_splatting).
+
+```yaml
+Type: Object
+Parameter Sets: (All)
+Aliases: Profile
+
+Required: False
+Position: Named
+Default value: None
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Severity
+
+After running Script Analyzer with all rules, this parameter selects rule violations with the
+specified severity.
+
+Valid values are:
+
+- Error
+- Warning
+- Information.
+
+You can specify one ore more severity values.
+
+The parameter filters the rules violations only after running all rules. To filter rules
+efficiently, use `Get-ScriptAnalyzerRule` to select the rules you want to run.
+
+The **Severity** parameter takes precedence over **IncludeRule**. For example, if **Severity** is
+`Error`, you cannot use **IncludeRule** to include a `Warning` rule.
+
+```yaml
+Type: String[]
+Parameter Sets: (All)
+Aliases:
+
+Required: False
+Position: Named
+Default value: All rule violations
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -SuppressedOnly
+
+Returns violations only for rules that are suppressed.
+
+Returns a **SuppressedRecord** object
+(**Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.SuppressedRecord**).
+
+To suppress a rule, use the **SuppressMessageAttribute**. For help, see the examples.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: Path_SuppressedOnly, ScriptDefinition_SuppressedOnly
+Aliases:
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -Confirm
+
+Prompts you for confirmation before running the cmdlet.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases: cf
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### -WhatIf
+
+Shows what would happen if the cmdlet runs. The cmdlet is not run.
+
+```yaml
+Type: SwitchParameter
+Parameter Sets: (All)
+Aliases: wi
+
+Required: False
+Position: Named
+Default value: False
+Accept pipeline input: False
+Accept wildcard characters: False
+```
+
+### CommonParameters
+
+This cmdlet supports the common parameters: -Debug, -ErrorAction, -ErrorVariable,
+-InformationAction, -InformationVariable, -OutVariable, -OutBuffer, -PipelineVariable, -Verbose,
+-WarningAction, and -WarningVariable. For more information, see
+[about_CommonParameters](http://go.microsoft.com/fwlink/?LinkID=113216).
+
+## INPUTS
+
+### None
+
+You cannot pipe input to this cmdlet.
+
+## OUTPUTS
+
+### Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord
+
+By default, `Invoke-ScriptAnalyzer` returns one **DiagnosticRecord** object for each rule violation.
+
+### Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.SuppressedRecord
+
+If you use the **SuppressedOnly** parameter, `Invoke-ScriptAnalyzer` instead returns a
+**SuppressedRecord** objects.
+
+## NOTES
+
+## RELATED LINKS
+
+[Get-ScriptAnalyzerRule](Get-ScriptAnalyzerRule.md)
+
+[PSScriptAnalyzer on GitHub](https://github.com/PowerShell/PSScriptAnalyzer)
diff --git a/docs/Cmdlets/PSScriptAnalyzer.md b/docs/Cmdlets/PSScriptAnalyzer.md
new file mode 100644
index 000000000..0af4bf2b5
--- /dev/null
+++ b/docs/Cmdlets/PSScriptAnalyzer.md
@@ -0,0 +1,33 @@
+---
+Download Help Link: https://aka.ms/ps-modules-help
+Help Version: 1.24.0
+Locale: en-US
+Module Guid: d6245802-193d-4068-a631-8863a4342a18
+Module Name: PSScriptAnalyzer
+ms.date: 10/07/2021
+---
+
+# PSScriptAnalyzer Module
+
+## Description
+
+PSScriptAnalyzer is a static code checker for PowerShell modules and scripts. PSScriptAnalyzer
+checks the quality of PowerShell code by running a set of rules.
+
+> [!NOTE]
+> Support for the module is limited. Please file issues in the source repository using the **This
+> product** button in the Feedback section at the bottom of the page.
+
+## PSScriptAnalyzer Cmdlets
+
+### [Get-ScriptAnalyzerRule](Get-ScriptAnalyzerRule.md)
+
+Gets the script analyzer rules on the local computer.
+
+### [Invoke-Formatter](Invoke-Formatter.md)
+
+Formats a script text based on the input settings or default settings.
+
+### [Invoke-ScriptAnalyzer](Invoke-ScriptAnalyzer.md)
+
+Evaluates a script or module based on selected best practice rules
diff --git a/docs/Rules/AlignAssignmentStatement.md b/docs/Rules/AlignAssignmentStatement.md
new file mode 100644
index 000000000..c2709ac1a
--- /dev/null
+++ b/docs/Rules/AlignAssignmentStatement.md
@@ -0,0 +1,59 @@
+---
+description: Align assignment statement
+ms.date: 06/28/2023
+ms.topic: reference
+title: AlignAssignmentStatement
+---
+# AlignAssignmentStatement
+
+**Severity Level: Warning**
+
+## Description
+
+Consecutive assignment statements are more readable if they are aligned. By aligned, we imply that
+the `equal` sign for all the assignment statements should be in the same column.
+
+The rule looks for key (property) value pairs in a hashtable (DSC configuration) to check if they
+are aligned or not. Consider the following example in which the key value pairs are not aligned.
+
+```powershell
+$hashtable = @{
+    property1 = 'value'
+    anotherProperty = 'another value'
+}
+```
+
+Alignment in this case would look like the following.
+
+```powershell
+$hashtable = @{
+    property1       = 'value'
+    anotherProperty = 'another value'
+}
+```
+
+The rule ignores hashtables in which the assignment statements are on the same line. For example,
+the rule ignores `$h = {a = 1; b = 2}`.
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSAlignAssignmentStatement = @{
+        Enable = $true
+        CheckHashtable = $true
+    }
+}
+```
+
+### Parameters
+
+#### Enable: bool (Default value is `$false`)
+
+Enable or disable the rule during ScriptAnalyzer invocation.
+
+#### CheckHashtable: bool (Default value is `$false`)
+
+Enforce alignment of assignment statements in a hashtable and in a DSC Configuration. There is only
+one switch for hasthable and DSC configuration because the property value pairs in a DSC
+configuration are parsed as key-value pairs of a hashtable.
diff --git a/docs/Rules/AvoidAssignmentToAutomaticVariable.md b/docs/Rules/AvoidAssignmentToAutomaticVariable.md
new file mode 100644
index 000000000..60d520d07
--- /dev/null
+++ b/docs/Rules/AvoidAssignmentToAutomaticVariable.md
@@ -0,0 +1,47 @@
+---
+description: Changing automatic variables might have undesired side effects
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidAssignmentToAutomaticVariable
+---
+# AvoidAssignmentToAutomaticVariable
+
+**Severity Level: Warning**
+
+## Description
+
+PowerShell has built-in variables known as automatic variables. Many of them are read-only and
+PowerShell throws an error when trying to assign an value on those. Other automatic variables should
+only be assigned in certain special cases to achieve a certain effect as a special technique.
+
+To understand more about automatic variables, see `Get-Help about_Automatic_Variables`.
+
+<!-- TODO
+Ability to suppress was added in https://github.com/PowerShell/PSScriptAnalyzer/pull/1896
+Need documentation for how to configure suppression of this rule.
+-->
+
+## How
+
+Use variable names in functions or their parameters that do not conflict with automatic variables.
+
+## Example
+
+### Wrong
+
+The variable `$Error` is an automatic variables that exists in the global scope and should therefore
+never be used as a variable or parameter name.
+
+```powershell
+function foo($Error){ }
+```
+
+```powershell
+function Get-CustomErrorMessage($ErrorMessage){ $Error = "Error occurred: $ErrorMessage" }
+```
+
+### Correct
+
+```powershell
+function Get-CustomErrorMessage($ErrorMessage){ $FinalErrorMessage = "Error occurred: $ErrorMessage" }
+```
diff --git a/RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md b/docs/Rules/AvoidDefaultValueForMandatoryParameter.md
similarity index 58%
rename from RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md
rename to docs/Rules/AvoidDefaultValueForMandatoryParameter.md
index 6b1a3eb57..19c9aa732 100644
--- a/RuleDocumentation/AvoidDefaultValueForMandatoryParameter.md
+++ b/docs/Rules/AvoidDefaultValueForMandatoryParameter.md
@@ -1,16 +1,24 @@
+---
+description: Avoid Default Value For Mandatory Parameter
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidDefaultValueForMandatoryParameter
+---
 # AvoidDefaultValueForMandatoryParameter
 
 **Severity Level: Warning**
 
 ## Description
 
-Mandatory parameters should not have a default values because there is no scenario where the default can be used because `PowerShell` will prompt anyway if the parameter value is not specified when calling the function.
+Mandatory parameters should not have a default values because there is no scenario where the default
+can be used. PowerShell prompts for a value if the parameter value is not specified when calling the
+function.
 
 ## Example
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Test
 {
 
@@ -25,7 +33,7 @@ function Test
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Test
 {
     [CmdletBinding()]
diff --git a/docs/Rules/AvoidDefaultValueSwitchParameter.md b/docs/Rules/AvoidDefaultValueSwitchParameter.md
new file mode 100644
index 000000000..9cc1ba855
--- /dev/null
+++ b/docs/Rules/AvoidDefaultValueSwitchParameter.md
@@ -0,0 +1,77 @@
+---
+description: Switch Parameters Should Not Default To True
+ms.date: 12/05/2024
+ms.topic: reference
+title: AvoidDefaultValueSwitchParameter
+---
+# AvoidDefaultValueSwitchParameter
+
+**Severity Level: Warning**
+
+## Description
+
+If your parameter takes only `true` and `false`, define the parameter as type `[Switch]`. PowerShell
+treats a switch parameter as `true` when it's used with a command. If the parameter isn't included
+with the command, PowerShell considers the parameter to be false. Don't define `[Boolean]`
+parameters.
+
+You shouldn't define a switch parameter with a default value of `$true` because this isn't the
+expected behavior of a switch parameter.
+
+## How
+
+Change the default value of the switch parameter to be `$false` or don't provide a default value.
+Write the logic of the script to assume that the switch parameter default value is `$false` or not
+provided.
+
+## Example
+
+### Wrong
+
+```powershell
+function Test-Script
+{
+    [CmdletBinding()]
+    Param
+    (
+        [String]
+        $Param1,
+
+        [switch]
+        $Switch=$True
+    )
+    ...
+}
+```
+
+### Correct
+
+```powershell
+function Test-Script
+{
+    [CmdletBinding()]
+    Param
+    (
+        [String]
+        $Param1,
+
+        [switch]
+        $Switch
+    )
+
+    begin {
+        # Ensure that the $Switch is set to false if not provided
+        if (-not $PSBoundParameters.ContainsKey('Switch')) {
+            $Switch = $false
+        }
+    }
+    ...
+}
+```
+
+## More information
+
+- [Strongly Encouraged Development Guidelines][01]
+
+<!-- link references -->
+[01]: https://learn.microsoft.com/powershell/scripting/developer/cmdlet/strongly-encouraged-development-guidelines#parameters-that-take-true-and-false
diff --git a/docs/Rules/AvoidExclaimOperator.md b/docs/Rules/AvoidExclaimOperator.md
new file mode 100644
index 000000000..11d078d6b
--- /dev/null
+++ b/docs/Rules/AvoidExclaimOperator.md
@@ -0,0 +1,48 @@
+---
+description: Avoid exclaim operator
+ms.date: 03/26/2024
+ms.topic: reference
+title: AvoidExclaimOperator
+---
+# AvoidExclaimOperator
+
+**Severity Level: Warning**
+
+## Description
+
+Avoid using the negation operator (`!`). Use `-not` for improved readability.
+
+> [!NOTE]
+> This rule is not enabled by default. The user needs to enable it through settings.
+
+## How to Fix
+
+## Example
+
+### Wrong
+
+```powershell
+$MyVar = !$true
+```
+
+### Correct
+
+```powershell
+$MyVar = -not $true
+```
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSAvoidExclaimOperator  = @{
+        Enable = $true
+    }
+}
+```
+
+### Parameters
+
+- `Enable`: **bool** (Default value is `$false`)
+
+  Enable or disable the rule during ScriptAnalyzer invocation.
diff --git a/docs/Rules/AvoidGlobalAliases.md b/docs/Rules/AvoidGlobalAliases.md
new file mode 100644
index 000000000..5157ec6f1
--- /dev/null
+++ b/docs/Rules/AvoidGlobalAliases.md
@@ -0,0 +1,37 @@
+---
+description: Avoid global aliases.
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidGlobalAliases
+---
+# AvoidGlobalAliases
+
+**Severity Level: Warning**
+
+## Description
+
+Globally scoped aliases override existing aliases within the sessions with matching names. This name
+collision can cause difficult to debug issues for consumers of modules and scripts.
+
+To understand more about scoping, see `Get-Help about_Scopes`.
+
+**NOTE** This rule is not available in PowerShell version 3 or 4 because it uses the
+`StaticParameterBinder.BindCommand` API.
+
+## How
+
+Use other scope modifiers for new aliases.
+
+## Example
+
+### Wrong
+
+```powershell
+New-Alias -Name Name -Value Value -Scope Global
+```
+
+### Correct
+
+```powershell
+New-Alias -Name Name1 -Value Value
+```
diff --git a/docs/Rules/AvoidGlobalFunctions.md b/docs/Rules/AvoidGlobalFunctions.md
new file mode 100644
index 000000000..929466cb6
--- /dev/null
+++ b/docs/Rules/AvoidGlobalFunctions.md
@@ -0,0 +1,34 @@
+---
+description: Avoid global functions and aliases
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidGlobalFunctions
+---
+# AvoidGlobalFunctions
+
+**Severity Level: Warning**
+
+## Description
+
+Globally scoped functions override existing functions within the sessions with matching names. This
+name collision can cause difficult to debug issues for consumers of modules.
+
+To understand more about scoping, see `Get-Help about_Scopes`.
+
+## How
+
+Use other scope modifiers for functions.
+
+## Example
+
+### Wrong
+
+```powershell
+function global:functionName {}
+```
+
+### Correct
+
+```powershell
+function functionName {}
+```
diff --git a/docs/Rules/AvoidGlobalVars.md b/docs/Rules/AvoidGlobalVars.md
new file mode 100644
index 000000000..7fa0f6d2f
--- /dev/null
+++ b/docs/Rules/AvoidGlobalVars.md
@@ -0,0 +1,49 @@
+---
+description: No Global Variables
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidGlobalVars
+---
+# AvoidGlobalVars
+
+**Severity Level: Warning**
+
+## Description
+
+A variable is a unit of memory in which values are stored. PowerShell controls access to variables,
+functions, aliases, and drives through a mechanism known as scoping. Variables and functions that
+are present when PowerShell starts have been created in the global scope.
+
+Globally scoped variables include:
+
+- Automatic variables
+- Preference variables
+- Variables, aliases, and functions that are in your PowerShell profiles
+
+To understand more about scoping, see `Get-Help about_Scopes`.
+
+## How
+
+Use other scope modifiers for variables.
+
+## Example
+
+### Wrong
+
+```powershell
+$Global:var1 = $null
+function Test-NotGlobal ($var)
+{
+    $a = $var + $var1
+}
+```
+
+### Correct
+
+```powershell
+$var1 = $null
+function Test-NotGlobal ($var1, $var2)
+{
+    $a = $var1 + $var2
+}
+```
diff --git a/RuleDocumentation/AvoidInvokingEmptyMembers.md b/docs/Rules/AvoidInvokingEmptyMembers.md
similarity index 53%
rename from RuleDocumentation/AvoidInvokingEmptyMembers.md
rename to docs/Rules/AvoidInvokingEmptyMembers.md
index 814cc131e..6049e869b 100644
--- a/RuleDocumentation/AvoidInvokingEmptyMembers.md
+++ b/docs/Rules/AvoidInvokingEmptyMembers.md
@@ -1,10 +1,17 @@
+---
+description: Avoid Invoking Empty Members
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidInvokingEmptyMembers
+---
 # AvoidInvokingEmptyMembers
 
 **Severity Level: Warning**
 
 ## Description
 
-Invoking non-constant members can cause potential bugs. Please double check the syntax to make sure that invoked members are constants.
+Invoking non-constant members can cause potential bugs. Please double check the syntax to make sure
+that invoked members are constants.
 
 ## How
 
@@ -14,14 +21,14 @@ Provide the requested members for a given type or class.
 
 ### Wrong
 
-``` PowerShell
-$MyString = "abc"
+```powershell
+$MyString = 'abc'
 $MyString.('len'+'gth')
 ```
 
 ### Correct
 
-``` PowerShell
-$MyString = "abc"
+```powershell
+$MyString = 'abc'
 $MyString.('length')
 ```
diff --git a/RuleDocumentation/AvoidLongLines.md b/docs/Rules/AvoidLongLines.md
similarity index 66%
rename from RuleDocumentation/AvoidLongLines.md
rename to docs/Rules/AvoidLongLines.md
index 0ea2c9a65..cc2603c51 100644
--- a/RuleDocumentation/AvoidLongLines.md
+++ b/docs/Rules/AvoidLongLines.md
@@ -1,22 +1,29 @@
+---
+description: Avoid long lines
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidLongLines
+---
 # AvoidLongLines
 
 **Severity Level: Warning**
 
 ## Description
 
-Lines should be no longer than a configured number of characters (default: 120), including leading whitespace (indentation).
+Lines should be no longer than a configured number of characters (default: 120), including leading
+whitespace (indentation).
 
 **Note**: This rule is not enabled by default. The user needs to enable it through settings.
 
 ## Configuration
 
 ```powershell
-    Rules = @{
-        PSAvoidLongLines  = @{
-            Enable     = $true
-            LineLength = 120
-        }
+Rules = @{
+    PSAvoidLongLines  = @{
+        Enable     = $true
+        MaximumLineLength = 120
     }
+}
 ```
 
 ### Parameters
diff --git a/docs/Rules/AvoidMultipleTypeAttributes.md b/docs/Rules/AvoidMultipleTypeAttributes.md
new file mode 100644
index 000000000..9ccd478c5
--- /dev/null
+++ b/docs/Rules/AvoidMultipleTypeAttributes.md
@@ -0,0 +1,49 @@
+---
+description: Avoid multiple type specifiers on parameters.
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidMultipleTypeAttributes
+---
+# AvoidMultipleTypeAttributes
+
+**Severity Level: Warning**
+
+## Description
+
+Parameters should not have more than one type specifier. Multiple type specifiers on parameters
+can cause runtime errors.
+
+## How
+
+Ensure each parameter has only 1 type specifier.
+
+## Example
+
+### Wrong
+
+```powershell
+function Test-Script
+{
+    [CmdletBinding()]
+    Param
+    (
+        [switch]
+        [int]
+        $Switch
+    )
+}
+```
+
+### Correct
+
+```powershell
+function Test-Script
+{
+    [CmdletBinding()]
+    Param
+    (
+        [switch]
+        $Switch
+    )
+}
+```
diff --git a/docs/Rules/AvoidNullOrEmptyHelpMessageAttribute.md b/docs/Rules/AvoidNullOrEmptyHelpMessageAttribute.md
new file mode 100644
index 000000000..386c96050
--- /dev/null
+++ b/docs/Rules/AvoidNullOrEmptyHelpMessageAttribute.md
@@ -0,0 +1,72 @@
+---
+description: Avoid using null or empty HelpMessage parameter attribute.
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidNullOrEmptyHelpMessageAttribute
+---
+# AvoidNullOrEmptyHelpMessageAttribute
+
+**Severity Level: Warning**
+
+## Description
+
+The value of the `HelpMessage` attribute should not be an empty string or a null value as this
+causes PowerShell's interpreter to throw an error when executing the function or cmdlet.
+
+## How
+
+Specify a value for the `HelpMessage` attribute.
+
+## Example
+
+### Wrong
+
+```powershell
+Function BadFuncEmptyHelpMessageEmpty
+{
+    Param(
+        [Parameter(HelpMessage='')]
+        [String]
+        $Param
+    )
+
+    $Param
+}
+
+Function BadFuncEmptyHelpMessageNull
+{
+    Param(
+        [Parameter(HelpMessage=$null)]
+        [String]
+        $Param
+    )
+
+    $Param
+}
+
+Function BadFuncEmptyHelpMessageNoAssignment
+{
+    Param(
+        [Parameter(HelpMessage)]
+        [String]
+        $Param
+    )
+
+    $Param
+}
+```
+
+### Correct
+
+```powershell
+Function GoodFuncHelpMessage
+{
+    Param(
+        [Parameter(HelpMessage='This is helpful')]
+        [String]
+        $Param
+    )
+
+    $Param
+}
+```
diff --git a/docs/Rules/AvoidOverwritingBuiltInCmdlets.md b/docs/Rules/AvoidOverwritingBuiltInCmdlets.md
new file mode 100644
index 000000000..10e1ad30a
--- /dev/null
+++ b/docs/Rules/AvoidOverwritingBuiltInCmdlets.md
@@ -0,0 +1,53 @@
+---
+description: Avoid overwriting built in cmdlets
+ms.date: 12/12/2024
+ms.topic: reference
+title: AvoidOverwritingBuiltInCmdlets
+---
+# AvoidOverwritingBuiltInCmdlets
+
+**Severity Level: Warning**
+
+## Description
+
+This rule flags cmdlets that are available in a given edition/version of PowerShell on a given
+operating system which are overwritten by a function declaration. It works by comparing function
+declarations against a set of allowlists that ship with PSScriptAnalyzer. These allowlist files are
+used by other PSScriptAnalyzer rules. More information can be found in the documentation for the
+[UseCompatibleCmdlets][01] rule.
+
+## Configuration
+
+To enable the rule to check if your script is compatible on PowerShell Core on Windows, put the
+following your settings file.
+
+```powershell
+@{
+    'Rules' = @{
+        'PSAvoidOverwritingBuiltInCmdlets' = @{
+            'PowerShellVersion' = @('core-6.1.0-windows')
+        }
+    }
+}
+```
+
+### Parameters
+
+#### PowerShellVersion
+
+The parameter `PowerShellVersion` is a list of allowlists that ship with PSScriptAnalyzer.
+
+> [!NOTE]
+> The default value for `PowerShellVersion` is `core-6.1.0-windows` if PowerShell 6 or
+> later is installed, and `desktop-5.1.14393.206-windows` if it's not.
+
+Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major
+and minor versions of PowerShell are supplied. One can also create a custom settings file as well
+with the [New-CommandDataFile.ps1][02] script and use it by placing the created `JSON` into the
+`Settings` folder of the `PSScriptAnalyzer` module installation folder, then the `PowerShellVersion`
+parameter is just its filename (that can also be changed if desired). Note that the `core-6.0.2-*`
+files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0 reached end of life.
+
+<!-- link references -->
+[01]: ./UseCompatibleCmdlets.md
+[02]: https://github.com/PowerShell/PSScriptAnalyzer/blob/main/Utils/New-CommandDataFile.ps1
diff --git a/docs/Rules/AvoidSemicolonsAsLineTerminators.md b/docs/Rules/AvoidSemicolonsAsLineTerminators.md
new file mode 100644
index 000000000..4716238ce
--- /dev/null
+++ b/docs/Rules/AvoidSemicolonsAsLineTerminators.md
@@ -0,0 +1,56 @@
+---
+description: Avoid semicolons as line terminators
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidSemicolonsAsLineTerminators
+---
+# AvoidSemicolonsAsLineTerminators
+
+**Severity Level: Warning**
+
+## Description
+
+Lines should not end with a semicolon.
+
+> [!NOTE]
+> This rule is not enabled by default. The user needs to enable it through settings.
+
+## Example
+
+### Wrong
+
+```powershell
+Install-Module -Name PSScriptAnalyzer; $a = 1 + $b;
+```
+
+```powershell
+Install-Module -Name PSScriptAnalyzer;
+$a = 1 + $b
+```
+
+### Correct
+
+```powershell
+Install-Module -Name PSScriptAnalyzer; $a = 1 + $b
+```
+
+```powershell
+Install-Module -Name PSScriptAnalyzer
+$a = 1 + $b
+```
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSAvoidSemicolonsAsLineTerminators  = @{
+        Enable     = $true
+    }
+}
+```
+
+### Parameters
+
+#### Enable: bool (Default value is `$false`)
+
+Enable or disable the rule during ScriptAnalyzer invocation.
diff --git a/RuleDocumentation/AvoidShouldContinueWithoutForce.md b/docs/Rules/AvoidShouldContinueWithoutForce.md
similarity index 60%
rename from RuleDocumentation/AvoidShouldContinueWithoutForce.md
rename to docs/Rules/AvoidShouldContinueWithoutForce.md
index 546fac7d8..189989a89 100644
--- a/RuleDocumentation/AvoidShouldContinueWithoutForce.md
+++ b/docs/Rules/AvoidShouldContinueWithoutForce.md
@@ -1,3 +1,9 @@
+---
+description: Avoid Using ShouldContinue Without Boolean Force Parameter
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidShouldContinueWithoutForce
+---
 # AvoidShouldContinueWithoutForce
 
 **Severity Level: Warning**
@@ -6,7 +12,8 @@
 
 Functions that use ShouldContinue should have a boolean force parameter to allow user to bypass it.
 
-You can get more details by running `Get-Help about_Functions_CmdletBindingAttribute` and `Get-Help about_Functions_Advanced_Methods` command in Windows PowerShell.
+You can get more details by running `Get-Help about_Functions_CmdletBindingAttribute` and
+`Get-Help about_Functions_Advanced_Methods` command in PowerShell.
 
 ## How
 
@@ -16,7 +23,7 @@ Call the `ShouldContinue` method in advanced functions when `ShouldProcess` meth
 
 ### Wrong
 
-``` PowerShell
+```powershell
 Function Test-ShouldContinue
 {
     [CmdletBinding(SupportsShouldProcess=$true)]
@@ -25,8 +32,8 @@ Function Test-ShouldContinue
         $MyString = 'blah'
     )
 
-    if ($PsCmdlet.ShouldContinue("ShouldContinue Query", "ShouldContinue Caption"))
-	{
+    if ($PsCmdlet.ShouldContinue('ShouldContinue Query', 'ShouldContinue Caption'))
+    {
         ...
     }
 }
@@ -34,7 +41,7 @@ Function Test-ShouldContinue
 
 ### Correct
 
-``` PowerShell
+```powershell
 Function Test-ShouldContinue
 {
     [CmdletBinding(SupportsShouldProcess=$true)]
@@ -44,8 +51,8 @@ Function Test-ShouldContinue
         [Switch]$Force
     )
 
-    if ($Force -or $PsCmdlet.ShouldContinue("ShouldContinue Query", "ShouldContinue Caption"))
-	{
+    if ($Force -or $PsCmdlet.ShouldContinue('ShouldContinue Query', 'ShouldContinue Caption'))
+    {
         ...
     }
 }
diff --git a/docs/Rules/AvoidTrailingWhitespace.md b/docs/Rules/AvoidTrailingWhitespace.md
new file mode 100644
index 000000000..416948c3b
--- /dev/null
+++ b/docs/Rules/AvoidTrailingWhitespace.md
@@ -0,0 +1,14 @@
+---
+description: Avoid trailing whitespace
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidTrailingWhitespace
+---
+# AvoidTrailingWhitespace
+
+**Severity Level: Information**
+
+## Description
+
+Lines should not end with whitespace characters. This can cause problems with the line-continuation
+backtick, and also clutters up future commits to source control.
diff --git a/docs/Rules/AvoidUsingAllowUnencryptedAuthentication.md b/docs/Rules/AvoidUsingAllowUnencryptedAuthentication.md
new file mode 100644
index 000000000..20451e66f
--- /dev/null
+++ b/docs/Rules/AvoidUsingAllowUnencryptedAuthentication.md
@@ -0,0 +1,35 @@
+---
+description: Avoid sending credentials and secrets over unencrypted connections
+ms.date: 02/28/2024
+ms.topic: reference
+title: AvoidUsingAllowUnencryptedAuthentication
+---
+# AvoidUsingAllowUnencryptedAuthentication
+
+**Severity Level: Warning**
+
+## Description
+
+Avoid using the **AllowUnencryptedAuthentication** parameter of `Invoke-WebRequest` and
+`Invoke-RestMethod`. When using this parameter, the cmdlets send credentials and secrets over
+unencrypted connections. This should be avoided except for compatibility with legacy systems.
+
+For more details, see [Invoke-RestMethod](xref:Microsoft.PowerShell.Utility.Invoke-RestMethod).
+
+## How
+
+Avoid using the **AllowUnencryptedAuthentication** parameter.
+
+## Example 1
+
+### Wrong
+
+```powershell
+Invoke-WebRequest foo -AllowUnencryptedAuthentication
+```
+
+### Correct
+
+```powershell
+Invoke-WebRequest foo
+```
diff --git a/docs/Rules/AvoidUsingBrokenHashAlgorithms.md b/docs/Rules/AvoidUsingBrokenHashAlgorithms.md
new file mode 100644
index 000000000..32bb464af
--- /dev/null
+++ b/docs/Rules/AvoidUsingBrokenHashAlgorithms.md
@@ -0,0 +1,47 @@
+---
+description: Avoid using broken hash algorithms
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingBrokenHashAlgorithms
+---
+# AvoidUsingBrokenHashAlgorithms
+
+**Severity Level: Warning**
+
+## Description
+
+Avoid using the broken algorithms MD5 or SHA-1.
+
+## How
+
+Replace broken algorithms with secure alternatives. MD5 and SHA-1 should be replaced with SHA256,
+SHA384, SHA512, or other safer algorithms when possible, with MD5 and SHA-1 only being utilized by
+necessity for backwards compatibility.
+
+## Example 1
+
+### Wrong
+
+```powershell
+Get-FileHash foo.txt -Algorithm MD5
+```
+
+### Correct
+
+```powershell
+Get-FileHash foo.txt -Algorithm SHA256
+```
+
+## Example 2
+
+### Wrong
+
+```powershell
+Get-FileHash foo.txt -Algorithm SHA1
+```
+
+### Correct
+
+```powershell
+Get-FileHash foo.txt
+```
diff --git a/docs/Rules/AvoidUsingCmdletAliases.md b/docs/Rules/AvoidUsingCmdletAliases.md
new file mode 100644
index 000000000..9a33149ad
--- /dev/null
+++ b/docs/Rules/AvoidUsingCmdletAliases.md
@@ -0,0 +1,63 @@
+---
+description: Avoid Using Cmdlet Aliases or omitting the 'Get-' prefix.
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingCmdletAliases
+---
+# AvoidUsingCmdletAliases
+
+**Severity Level: Warning**
+
+## Description
+
+An alias is an alternate name or nickname for a cmdlet or for a command element, such as a function,
+script, file, or executable file. You can use the alias instead of the command name in any
+PowerShell commands.
+
+There are also implicit aliases. When PowerShell cannot find the cmdlet name, it will try to append
+`Get-` to the command as a last resort. Therefore using the command `verb` will execute `Get-Verb`.
+
+Every PowerShell author learns the actual command names, but different authors learn and use
+different aliases. Aliases can make code difficult to read, understand and impact availability.
+
+Using the full command name makes it easier to maintain your scripts in the the future.
+
+Using the full command names also allows for syntax highlighting in sites and applications like
+GitHub and Visual Studio Code.
+
+## How to Fix
+
+Use the full cmdlet name and not an alias.
+
+## Alias Allowlist
+
+To prevent `PSScriptAnalyzer` from flagging your preferred aliases, create an allowlist of the
+aliases in your settings file and point `PSScriptAnalyzer` to use the settings file. For example, to
+disable `PSScriptAnalyzer` from flagging `cd`, which is an alias of `Set-Location`, set the settings
+file content to the following.
+
+```powershell
+# PSScriptAnalyzerSettings.psd1
+
+@{
+    'Rules' = @{
+        'PSAvoidUsingCmdletAliases' = @{
+            'allowlist' = @('cd')
+        }
+    }
+}
+```
+
+## Example
+
+### Wrong
+
+```powershell
+gps | Where-Object {$_.WorkingSet -gt 20000000}
+```
+
+### Correct
+
+```powershell
+Get-Process | Where-Object {$_.WorkingSet -gt 20000000}
+```
diff --git a/docs/Rules/AvoidUsingComputerNameHardcoded.md b/docs/Rules/AvoidUsingComputerNameHardcoded.md
new file mode 100644
index 000000000..83a60c950
--- /dev/null
+++ b/docs/Rules/AvoidUsingComputerNameHardcoded.md
@@ -0,0 +1,58 @@
+---
+description: Avoid Using ComputerName Hardcoded
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingComputerNameHardcoded
+---
+# AvoidUsingComputerNameHardcoded
+
+**Severity Level: Error**
+
+## Description
+
+The names of computers should never be hard coded as this will expose sensitive information. The
+`ComputerName` parameter should never have a hard coded value.
+
+## How
+
+Remove hard coded computer names.
+
+## Example 1
+
+### Wrong
+
+```powershell
+Function Invoke-MyRemoteCommand ()
+{
+    Invoke-Command -Port 343 -ComputerName hardcoderemotehostname
+}
+```
+
+### Correct
+
+```powershell
+Function Invoke-MyCommand ($ComputerName)
+{
+    Invoke-Command -Port 343 -ComputerName $ComputerName
+}
+```
+
+## Example 2
+
+### Wrong
+
+```powershell
+Function Invoke-MyLocalCommand ()
+{
+    Invoke-Command -Port 343 -ComputerName hardcodelocalhostname
+}
+```
+
+### Correct
+
+```powershell
+Function Invoke-MyLocalCommand ()
+{
+    Invoke-Command -Port 343 -ComputerName $env:COMPUTERNAME
+}
+```
diff --git a/docs/Rules/AvoidUsingConvertToSecureStringWithPlainText.md b/docs/Rules/AvoidUsingConvertToSecureStringWithPlainText.md
new file mode 100644
index 000000000..d25fce124
--- /dev/null
+++ b/docs/Rules/AvoidUsingConvertToSecureStringWithPlainText.md
@@ -0,0 +1,40 @@
+---
+description: Avoid Using SecureString With Plain Text
+ms.date: 01/28/2025
+ms.topic: reference
+title: AvoidUsingConvertToSecureStringWithPlainText
+---
+# AvoidUsingConvertToSecureStringWithPlainText
+
+**Severity Level: Error**
+
+## Description
+
+The use of the `AsPlainText` parameter with the `ConvertTo-SecureString` command can expose secure
+information.
+
+## How
+
+Use a standard encrypted variable to perform any SecureString conversions.
+
+## Recommendations
+
+If you do need an ability to retrieve the password from somewhere without prompting the user,
+consider using the
+[SecretStore](https://www.powershellgallery.com/packages/Microsoft.PowerShell.SecretStore)
+module from the PowerShell Gallery.
+
+## Example
+
+### Wrong
+
+```powershell
+$UserInput = Read-Host 'Please enter your secure code'
+$EncryptedInput = ConvertTo-SecureString -String $UserInput -AsPlainText -Force
+```
+
+### Correct
+
+```powershell
+$SecureUserInput = Read-Host 'Please enter your secure code' -AsSecureString
+```
diff --git a/RuleDocumentation/AvoidUsingDeprecatedManifestFields.md b/docs/Rules/AvoidUsingDeprecatedManifestFields.md
similarity index 69%
rename from RuleDocumentation/AvoidUsingDeprecatedManifestFields.md
rename to docs/Rules/AvoidUsingDeprecatedManifestFields.md
index a814ea205..802304dfc 100644
--- a/RuleDocumentation/AvoidUsingDeprecatedManifestFields.md
+++ b/docs/Rules/AvoidUsingDeprecatedManifestFields.md
@@ -1,10 +1,16 @@
+---
+description: Avoid Using Deprecated Manifest Fields
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingDeprecatedManifestFields
+---
 # AvoidUsingDeprecatedManifestFields
 
 **Severity Level: Warning**
 
 ## Description
 
-In PowerShell 5.0, a number of fields in module manifest files (.psd1) have been changed.
+In PowerShell 5.0, a number of fields in module manifest files (`.psd1`) have been changed.
 
 The field `ModuleToProcess` has been replaced with the `RootModule` field.
 
@@ -16,7 +22,7 @@ Replace `ModuleToProcess` with `RootModule` in the module manifest.
 
 ### Wrong
 
-``` PowerShell
+```powershell
 ModuleToProcess ='psscriptanalyzer'
 
 ModuleVersion = '1.0'
@@ -24,7 +30,7 @@ ModuleVersion = '1.0'
 
 ### Correct
 
-``` PowerShell
+```powershell
 RootModule ='psscriptanalyzer'
 
 ModuleVersion = '1.0'
diff --git a/docs/Rules/AvoidUsingDoubleQuotesForConstantString.md b/docs/Rules/AvoidUsingDoubleQuotesForConstantString.md
new file mode 100644
index 000000000..19c83fad7
--- /dev/null
+++ b/docs/Rules/AvoidUsingDoubleQuotesForConstantString.md
@@ -0,0 +1,36 @@
+---
+description: Avoid using double quotes if the string is constant.
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingDoubleQuotesForConstantString
+---
+# AvoidUsingDoubleQuotesForConstantString
+
+**Severity Level: Information**
+
+## Description
+
+Single quotes should be used when the value of a string is constant. A constant string doesn't
+contain variables or expressions intended to insert values into the string, such as
+`"$PID-$(hostname)"`).
+
+This makes the intent clearer that the string is a constant and makes it easier to use some special
+characters such as `$` within that string expression without needing to escape them.
+
+There are exceptions to that when double quoted strings are more readable. For example, when the
+string value itself must contain a single quote or other special characters, such as newline
+(`` "`n" ``), are already being escaped. The rule does not warn in these cases.
+
+## Example
+
+### Wrong
+
+```powershell
+$constantValue = "I Love PowerShell"
+```
+
+### Correct
+
+```powershell
+$constantValue = 'I Love PowerShell'
+```
diff --git a/docs/Rules/AvoidUsingEmptyCatchBlock.md b/docs/Rules/AvoidUsingEmptyCatchBlock.md
new file mode 100644
index 000000000..198341758
--- /dev/null
+++ b/docs/Rules/AvoidUsingEmptyCatchBlock.md
@@ -0,0 +1,54 @@
+---
+description: Avoid Using Empty Catch Block
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingEmptyCatchBlock
+---
+# AvoidUsingEmptyCatchBlock
+
+**Severity Level: Warning**
+
+## Description
+
+Empty catch blocks are considered a poor design choice because any errors occurring in a
+`try` block cannot be handled.
+
+## How
+
+Use `Write-Error` or `throw` statements within the catch block.
+
+## Example
+
+### Wrong
+
+```powershell
+try
+{
+    1/0
+}
+catch [DivideByZeroException]
+{
+}
+```
+
+### Correct
+
+```powershell
+try
+{
+    1/0
+}
+catch [DivideByZeroException]
+{
+    Write-Error 'DivideByZeroException'
+}
+
+try
+{
+    1/0
+}
+catch [DivideByZeroException]
+{
+    throw 'DivideByZeroException'
+}
+```
diff --git a/docs/Rules/AvoidUsingInvokeExpression.md b/docs/Rules/AvoidUsingInvokeExpression.md
new file mode 100644
index 000000000..7779008ec
--- /dev/null
+++ b/docs/Rules/AvoidUsingInvokeExpression.md
@@ -0,0 +1,35 @@
+---
+description: Avoid Using Invoke-Expression
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingInvokeExpression
+---
+# AvoidUsingInvokeExpression
+
+**Severity Level: Warning**
+
+## Description
+
+Care must be taken when using the `Invoke-Expression` command. The `Invoke-Expression` executes the
+specified string and returns the results.
+
+Code injection into your application or script can occur if the expression passed as a string
+includes any data provided from the user.
+
+## How
+
+Remove the use of `Invoke-Expression`.
+
+## Example
+
+### Wrong
+
+```powershell
+Invoke-Expression 'Get-Process'
+```
+
+### Correct
+
+```powershell
+Get-Process
+```
diff --git a/RuleDocumentation/AvoidUsingPlainTextForPassword.md b/docs/Rules/AvoidUsingPlainTextForPassword.md
similarity index 57%
rename from RuleDocumentation/AvoidUsingPlainTextForPassword.md
rename to docs/Rules/AvoidUsingPlainTextForPassword.md
index b9e4bffb8..c25123ec1 100644
--- a/RuleDocumentation/AvoidUsingPlainTextForPassword.md
+++ b/docs/Rules/AvoidUsingPlainTextForPassword.md
@@ -1,31 +1,39 @@
+---
+description: Avoid Using Plain Text For Password Parameter
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingPlainTextForPassword
+---
 # AvoidUsingPlainTextForPassword
 
 **Severity Level: Warning**
 
 ## Description
 
-Password parameters that take in plaintext will expose passwords and compromise the security of your system. Passwords should be stored in the
-```SecureString``` type.
+Password parameters that take in plaintext will expose passwords and compromise the security of your
+system. Passwords should be stored in the **SecureString** type.
 
 The following parameters are considered password parameters (this is not case sensitive):
-* Password
-* Pass
-* Passwords
-* Passphrase
-* Passphrases
-* PasswordParam
 
-If a parameter is defined with a name in the above list, it should be declared with type ```SecureString```
+- Password
+- Pass
+- Passwords
+- Passphrase
+- Passphrases
+- PasswordParam
+
+If a parameter is defined with a name in the above list, it should be declared with type
+**SecureString**.
 
 ## How
 
-Change the type to ```SecureString```.
+Change the type to **SecureString**.
 
 ## Example
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Test-Script
 {
     [CmdletBinding()]
@@ -40,7 +48,7 @@ function Test-Script
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Test-Script
 {
     [CmdletBinding()]
diff --git a/docs/Rules/AvoidUsingPositionalParameters.md b/docs/Rules/AvoidUsingPositionalParameters.md
new file mode 100644
index 000000000..1a1b77d01
--- /dev/null
+++ b/docs/Rules/AvoidUsingPositionalParameters.md
@@ -0,0 +1,59 @@
+---
+description: Avoid Using Positional Parameters
+ms.date: 02/13/2024
+ms.topic: reference
+title: AvoidUsingPositionalParameters
+---
+# AvoidUsingPositionalParameters
+
+** Severity Level: Information **
+
+## Description
+
+Using positional parameters reduces the readability of code and can introduce errors. It is possible
+that a future version of the cmdlet could change in a way that would break existing scripts if calls
+to the cmdlet rely on the position of the parameters.
+
+For simple cmdlets with only a few positional parameters, the risk is much smaller. To prevent this
+rule from being too noisy, this rule gets only triggered when there are 3 or more parameters
+supplied. A simple example where the risk of using positional parameters is negligible, is
+`Test-Path $Path`.
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSAvoidUsingPositionalParameters = @{
+        CommandAllowList = 'Join-Path', 'MyCmdletOrScript'
+        Enable           = $true
+    }
+}
+```
+
+### Parameters
+
+#### CommandAllowList: string[] (Default value is @()')
+
+Commands or scripts to be excluded from this rule.
+
+#### Enable: bool (Default value is `$true`)
+
+Enable or disable the rule during ScriptAnalyzer invocation.
+
+## How
+
+Use full parameter names when calling commands.
+
+## Example
+
+### Wrong
+
+```powershell
+Get-Command ChildItem Microsoft.PowerShell.Management
+```
+
+### Correct
+
+```powershell
+Get-Command -Noun ChildItem -Module Microsoft.PowerShell.Management
+```
diff --git a/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md b/docs/Rules/AvoidUsingUsernameAndPasswordParams.md
similarity index 59%
rename from RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md
rename to docs/Rules/AvoidUsingUsernameAndPasswordParams.md
index 747cf2ca5..32fbac3c7 100644
--- a/RuleDocumentation/AvoidUsingUsernameAndPasswordParams.md
+++ b/docs/Rules/AvoidUsingUsernameAndPasswordParams.md
@@ -1,20 +1,27 @@
+---
+description: Avoid Using Username and Password Parameters
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingUsernameAndPasswordParams
+---
 # AvoidUsingUsernameAndPasswordParams
 
 **Severity Level: Error**
 
 ## Description
 
-To standardize command parameters, credentials should be accepted as objects of type ```PSCredential```. Functions should not make use of username or password parameters.
+To standardize command parameters, credentials should be accepted as objects of type
+**PSCredential**. Functions should not make use of username or password parameters.
 
 ## How
 
-Change the parameter to type ```PSCredential```.
+Change the parameter to type **PSCredential**.
 
 ## Example
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Test-Script
 {
     [CmdletBinding()]
@@ -31,7 +38,7 @@ function Test-Script
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Test-Script
 {
     [CmdletBinding()]
diff --git a/docs/Rules/AvoidUsingWMICmdlet.md b/docs/Rules/AvoidUsingWMICmdlet.md
new file mode 100644
index 000000000..96e716718
--- /dev/null
+++ b/docs/Rules/AvoidUsingWMICmdlet.md
@@ -0,0 +1,58 @@
+---
+description: Avoid Using Get-WMIObject, Remove-WMIObject, Invoke-WmiMethod, Register-WmiEvent, Set-WmiInstance
+ms.date: 06/28/2023
+ms.topic: reference
+title: AvoidUsingWMICmdlet
+---
+# AvoidUsingWMICmdlet
+
+**Severity Level: Warning**
+
+## Description
+
+As of PowerShell 3.0, the CIM cmdlets should be used over the WMI cmdlets.
+
+The following cmdlets should not be used:
+
+- `Get-WmiObject`
+- `Remove-WmiObject`
+- `Invoke-WmiMethod`
+- `Register-WmiEvent`
+- `Set-WmiInstance`
+
+Use the following cmdlets instead:
+
+- `Get-CimInstance`
+- `Remove-CimInstance`
+- `Invoke-CimMethod`
+- `Register-CimIndicationEvent`
+- `Set-CimInstance`
+
+The CIM cmdlets comply with WS-Management (WSMan) standards and with the Common Information Model
+(CIM) standard, allowing for the management of Windows and non-Windows operating systems.
+
+## How
+
+Change to the equivalent CIM based cmdlet.
+
+- `Get-WmiObject` -> `Get-CimInstance`
+- `Remove-WmiObject` -> `Remove-CimInstance`
+- `Invoke-WmiMethod` -> `Invoke-CimMethod`
+- `Register-WmiEvent` -> `Register-CimIndicationEvent`
+- `Set-WmiInstance` -> `Set-CimInstance`
+
+## Example
+
+### Wrong
+
+```powershell
+Get-WmiObject -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-WmiObject
+Invoke-WmiMethod -Class Win32_Process -Name 'Create' -ArgumentList @{ CommandLine = 'notepad.exe' }
+```
+
+### Correct
+
+```powershell
+Get-CimInstance -Query 'Select * from Win32_Process where name LIKE "myprocess%"' | Remove-CIMInstance
+Invoke-CimMethod -ClassName Win32_Process -MethodName 'Create' -Arguments @{ CommandLine = 'notepad.exe' }
+```
diff --git a/docs/Rules/AvoidUsingWriteHost.md b/docs/Rules/AvoidUsingWriteHost.md
new file mode 100644
index 000000000..a02571c79
--- /dev/null
+++ b/docs/Rules/AvoidUsingWriteHost.md
@@ -0,0 +1,62 @@
+---
+description: Avoid Using Write-Host
+ms.date: 12/05/2024
+ms.topic: reference
+title: AvoidUsingWriteHost
+---
+# AvoidUsingWriteHost
+
+**Severity Level: Warning**
+
+## Description
+
+The primary purpose of the `Write-Host` cmdlet is to produce display-only output in the host. For
+example: printing colored text or prompting the user for input when combined with `Read-Host`.
+`Write-Host` uses the `ToString()` method to write the output. The particular result depends on the
+program that's hosting PowerShell. The output from `Write-Host` isn't sent to the pipeline. To
+output data to the pipeline, use `Write-Output` or implicit output.
+
+The use of `Write-Host` in a function is discouraged unless the function uses the `Show` verb. The
+`Show` verb explicitly means _display information to the user_. This rule doesn't apply to functions
+with the `Show` verb.
+
+## How
+
+Replace `Write-Host` with `Write-Output` or `Write-Verbose` depending on whether the intention is
+logging or returning one or more objects.
+
+## Example
+
+### Wrong
+
+```powershell
+function Get-MeaningOfLife
+{
+    Write-Host 'Computing the answer to the ultimate question of life, the universe and everything'
+    Write-Host 42
+}
+```
+
+### Correct
+
+Use `Write-Verbose` for informational messages. The user can decide whether to see the message by
+providing the **Verbose** parameter.
+
+```powershell
+function Get-MeaningOfLife
+{
+    [CmdletBinding()]Param() # makes it possible to support Verbose output
+
+    Write-Verbose 'Computing the answer to the ultimate question of life, the universe and everything'
+    Write-Output 42
+}
+
+function Show-Something
+{
+    Write-Host 'show something on screen'
+}
+```
+
+## More information
+
+[Write-Host](xref:Microsoft.PowerShell.Utility.Write-Host)
diff --git a/docs/Rules/DSCDscExamplesPresent.md b/docs/Rules/DSCDscExamplesPresent.md
new file mode 100644
index 000000000..b2b1cf608
--- /dev/null
+++ b/docs/Rules/DSCDscExamplesPresent.md
@@ -0,0 +1,63 @@
+---
+description: DSC examples are present
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCDscExamplesPresent
+---
+# DscExamplesPresent
+
+**Severity Level: Information**
+
+## Description
+
+Checks that DSC examples for given resource are present.
+
+## How
+
+To fix a violation of this rule, please make sure `Examples` directory is present:
+
+- For non-class based resources it should exist at the same folder level as `DSCResources` folder.
+- For class based resources it should be present at the same folder level as resource `.psm1` file.
+
+The `Examples` folder should contain a sample configuration for given resource. The filename should
+contain the resource's name.
+
+## Example
+
+### Non-class based resource
+
+Let's assume we have non-class based resource with a following file structure:
+
+- xAzure
+  - DSCResources
+    - MSFT_xAzureSubscription
+      - MSFT_xAzureSubscription.psm1
+      - MSFT_xAzureSubscription.schema.mof
+
+In this case, to fix this warning, we should add examples in a following way:
+
+- xAzure
+  - DSCResources
+    - MSFT_xAzureSubscription
+      - MSFT_xAzureSubscription.psm1
+      - MSFT_xAzureSubscription.schema.mof
+  - Examples
+    - MSFT_xAzureSubscription_AddSubscriptionExample.ps1
+    - MSFT_xAzureSubscription_RemoveSubscriptionExample.ps1
+
+### Class based resource
+
+Let's assume we have class based resource with a following file structure:
+
+- MyDscResource
+  - MyDscResource.psm1
+  - MyDscResource.psd1
+
+In this case, to fix this warning, we should add examples in a following way:
+
+- MyDscResource
+  - MyDscResource.psm1
+  - MyDscResource.psd1
+  - Examples
+    - MyDscResource_Example1.ps1
+    - MyDscResource_Example2.ps1
diff --git a/docs/Rules/DSCDscTestsPresent.md b/docs/Rules/DSCDscTestsPresent.md
new file mode 100644
index 000000000..f8fe31983
--- /dev/null
+++ b/docs/Rules/DSCDscTestsPresent.md
@@ -0,0 +1,61 @@
+---
+description: Dsc tests are present
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCDscTestsPresent
+---
+# DscTestsPresent
+
+**Severity Level: Information**
+
+## Description
+
+Checks that DSC tests for given resource are present.
+
+## How
+
+To fix a violation of this rule, please make sure `Tests` directory is present:
+
+- For non-class based resources it should exist at the same folder level as `DSCResources` folder.
+- For class based resources it should be present at the same folder level as resource `.psm1` file.
+
+The `Tests` folder should contain test script for given resource. The filename should contain the
+resource's name.
+
+## Example
+
+### Non-class based resource
+
+Let's assume we have non-class based resource with a following file structure:
+
+- xAzure
+  - DSCResources
+    - MSFT_xAzureSubscription
+      - MSFT_xAzureSubscription.psm1
+      - MSFT_xAzureSubscription.schema.mof
+
+In this case, to fix this warning, we should add tests in a following way:
+
+- xAzure
+  - DSCResources
+    - MSFT_xAzureSubscription
+      - MSFT_xAzureSubscription.psm1
+      - MSFT_xAzureSubscription.schema.mof
+  - Tests
+    - MSFT_xAzureSubscription_Tests.ps1
+
+### Class based resource
+
+Let's assume we have class based resource with a following file structure:
+
+- MyDscResource
+  - MyDscResource.psm1
+  - MyDscResource.psd1
+
+In this case, to fix this warning, we should add tests in a following way:
+
+- MyDscResource
+  - MyDscResource.psm1
+  - MyDscResource.psd1
+  - Tests
+    - MyDscResource_Tests.ps1
diff --git a/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md b/docs/Rules/DSCReturnCorrectTypesForDSCFunctions.md
similarity index 76%
rename from RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md
rename to docs/Rules/DSCReturnCorrectTypesForDSCFunctions.md
index f41e242e8..168185280 100644
--- a/RuleDocumentation/DSCReturnCorrectTypesForDSCFunctions.md
+++ b/docs/Rules/DSCReturnCorrectTypesForDSCFunctions.md
@@ -1,3 +1,9 @@
+---
+description: Return Correct Types For DSC Functions
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCReturnCorrectTypesForDSCFunctions
+---
 # ReturnCorrectTypesForDSCFunctions
 
 **Severity Level: Information**
@@ -7,24 +13,26 @@
 The functions in DSC resources have specific return objects.
 
 For non-class based resources:
-* `Set-TargetResource` must not return any value.
-* `Test-TargetResource` must return a boolean.
-* `Get-TargetResource` must return a hash table.
+
+- `Set-TargetResource` must not return any value.
+- `Test-TargetResource` must return a boolean.
+- `Get-TargetResource` must return a hash table.
 
 For class based resources:
-* `Set` must not return any value.
-* `Test` must return a boolean.
-* `Get` must return an instance of the DSC class.
+
+- `Set` must not return any value.
+- `Test` must return a boolean.
+- `Get` must return an instance of the DSC class.
 
 ## How
 
 Ensure that each function returns the correct type.
 
-## Example
+## Example 1
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     param
@@ -61,7 +69,7 @@ function Test-TargetResource
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [OutputType([Hashtable])]
@@ -98,11 +106,11 @@ function Test-TargetResource
 }
 ```
 
-## Example
+## Example 2
 
 ### Wrong
 
-``` PowerShell
+```powershell
 [DscResource()]
 class MyDSCResource
 {
@@ -128,7 +136,7 @@ class MyDSCResource
 
 ### Correct
 
-``` PowerShell
+```powershell
 [DscResource()]
 class MyDSCResource
 {
diff --git a/RuleDocumentation/DSCStandardDSCFunctionsInResource.md b/docs/Rules/DSCStandardDSCFunctionsInResource.md
similarity index 80%
rename from RuleDocumentation/DSCStandardDSCFunctionsInResource.md
rename to docs/Rules/DSCStandardDSCFunctionsInResource.md
index ad37f69c8..f455d7437 100644
--- a/RuleDocumentation/DSCStandardDSCFunctionsInResource.md
+++ b/docs/Rules/DSCStandardDSCFunctionsInResource.md
@@ -1,3 +1,9 @@
+---
+description: Use Standard Get/Set/Test TargetResource functions in DSC Resource
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCStandardDSCFunctionsInResource
+---
 # StandardDSCFunctionsInResource
 
 **Severity Level: Error**
@@ -7,24 +13,26 @@
 All DSC resources are required to implement the correct functions.
 
 For non-class based resources:
-* `Set-TargetResource`
-* `Test-TargetResource`
-* `Get-TargetResource`
+
+- `Set-TargetResource`
+- `Test-TargetResource`
+- `Get-TargetResource`
 
 For class based resources:
-* `Set`
-* `Test`
-* `Get`
+
+- `Set`
+- `Test`
+- `Get`
 
 ## How
 
 Add the missing functions to the resource.
 
-## Example
+## Example 1
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [OutputType([Hashtable])]
@@ -48,9 +56,10 @@ function Set-TargetResource
     ...
 }
 ```
+
 ### Correct
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [OutputType([Hashtable])]
@@ -87,11 +96,11 @@ function Test-TargetResource
 }
 ```
 
-## Example
+## Example 2
 
 ### Wrong
 
-``` PowerShell
+```powershell
 [DscResource()]
 class MyDSCResource
 {
@@ -111,7 +120,7 @@ class MyDSCResource
 
 ### Correct
 
-``` PowerShell
+```powershell
 [DscResource()]
 class MyDSCResource
 {
diff --git a/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md b/docs/Rules/DSCUseIdenticalMandatoryParametersForDSC.md
similarity index 81%
rename from RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md
rename to docs/Rules/DSCUseIdenticalMandatoryParametersForDSC.md
index 053925f16..dc8e9e918 100644
--- a/RuleDocumentation/DSCUseIdenticalMandatoryParametersForDSC.md
+++ b/docs/Rules/DSCUseIdenticalMandatoryParametersForDSC.md
@@ -1,14 +1,23 @@
+---
+description: Use identical mandatory parameters for DSC Get/Test/Set TargetResource functions
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCUseIdenticalMandatoryParametersForDSC
+---
 # UseIdenticalMandatoryParametersForDSC
 
 **Severity Level: Error**
 
 ## Description
 
-For script based DSC resources, if a property is declared with attributes `Key` of `Required` in a mof file, then is should be present as a mandatory parameter in the corresponding `Get-TargetResource`, `Set-TargetResource` and `Test-TargetResource` functions.
+For script based DSC resources, if a property is declared with attributes `Key` of `Required` in a
+mof file, then is should be present as a mandatory parameter in the corresponding
+`Get-TargetResource`, `Set-TargetResource` and `Test-TargetResource` functions.
 
 ## How
 
-Make sure all the properties with `Key` and `Required` attributes have equivalent mandatory parameters in the `Get/Set/Test` functions.
+Make sure all the properties with `Key` and `Required` attributes have equivalent mandatory
+parameters in the `Get/Set/Test` functions.
 
 ## Example
 
@@ -27,7 +36,7 @@ class WaitForAny : OMI_BaseResource
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [CmdletBinding()]
@@ -77,7 +86,7 @@ function Test-TargetResource
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [CmdletBinding()]
diff --git a/RuleDocumentation/DSCUseIdenticalParametersForDSC.md b/docs/Rules/DSCUseIdenticalParametersForDSC.md
similarity index 84%
rename from RuleDocumentation/DSCUseIdenticalParametersForDSC.md
rename to docs/Rules/DSCUseIdenticalParametersForDSC.md
index 8d595db93..8f8e98e55 100644
--- a/RuleDocumentation/DSCUseIdenticalParametersForDSC.md
+++ b/docs/Rules/DSCUseIdenticalParametersForDSC.md
@@ -1,10 +1,17 @@
+---
+description: Use Identical Parameters For DSC Test and Set Functions
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCUseIdenticalParametersForDSC
+---
 # UseIdenticalParametersForDSC
 
 **Severity Level: Error**
 
 ## Description
 
-The `Get-TargetResource`, `Test-TargetResource` and `Set-TargetResource` functions of DSC Resource must have the same parameters.
+The `Get-TargetResource`, `Test-TargetResource` and `Set-TargetResource` functions of DSC Resource
+must have the same parameters.
 
 ## How
 
@@ -14,7 +21,7 @@ Correct the parameters for the functions in DSC resource.
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [OutputType([Hashtable])]
@@ -56,7 +63,7 @@ function Test-TargetResource
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Get-TargetResource
 {
     [OutputType([Hashtable])]
diff --git a/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md b/docs/Rules/DSCUseVerboseMessageInDSCResource.md
similarity index 58%
rename from RuleDocumentation/DSCUseVerboseMessageInDSCResource.md
rename to docs/Rules/DSCUseVerboseMessageInDSCResource.md
index d96a4c28a..bb5abacef 100644
--- a/RuleDocumentation/DSCUseVerboseMessageInDSCResource.md
+++ b/docs/Rules/DSCUseVerboseMessageInDSCResource.md
@@ -1,10 +1,17 @@
+---
+description: Use verbose message in DSC resource
+ms.date: 06/28/2023
+ms.topic: reference
+title: DSCUseVerboseMessageInDSCResource
+---
 # UseVerboseMessageInDSCResource
 
 **Severity Level: Information**
 
 ## Description
 
-Best practice recommends that additional user information is provided within commands, functions and scripts using `Write-Verbose`.
+Best practice recommends that additional user information is provided within commands, functions and
+scripts using `Write-Verbose`.
 
 ## How
 
@@ -14,7 +21,7 @@ Make use of the `Write-Verbose` command.
 
 ### Wrong
 
-``` PowerShell
+```powershell
 Function Test-Function
 {
     [CmdletBinding()]
@@ -25,12 +32,12 @@ Function Test-Function
 
 ### Correct
 
-``` PowerShell
+```powershell
 Function Test-Function
 {
     [CmdletBinding()]
     Param()
-    Write-Verbose "Verbose output"
+    Write-Verbose 'Verbose output'
     ...
 }
 ```
diff --git a/RuleDocumentation/MisleadingBacktick.md b/docs/Rules/MisleadingBacktick.md
similarity index 54%
rename from RuleDocumentation/MisleadingBacktick.md
rename to docs/Rules/MisleadingBacktick.md
index a5b581601..e140b8e9d 100644
--- a/RuleDocumentation/MisleadingBacktick.md
+++ b/docs/Rules/MisleadingBacktick.md
@@ -1,7 +1,13 @@
+---
+description: Misleading Backtick
+ms.date: 06/28/2023
+ms.topic: reference
+title: MisleadingBacktick
+---
 # MisleadingBacktick
 
 **Severity Level: Warning**
 
 ## Description
 
-Checks that lines don't end with a backtick followed by whitespace.
\ No newline at end of file
+Checks that lines don't end with a backtick followed by whitespace.
diff --git a/RuleDocumentation/MissingModuleManifestField.md b/docs/Rules/MissingModuleManifestField.md
similarity index 71%
rename from RuleDocumentation/MissingModuleManifestField.md
rename to docs/Rules/MissingModuleManifestField.md
index e5eec77b8..c19d53454 100644
--- a/RuleDocumentation/MissingModuleManifestField.md
+++ b/docs/Rules/MissingModuleManifestField.md
@@ -1,14 +1,22 @@
+---
+description: Module Manifest Fields
+ms.date: 06/28/2023
+ms.topic: reference
+title: MissingModuleManifestField
+---
 # MissingModuleManifestField
 
 **Severity Level: Warning**
 
 ## Description
 
-A module manifest is a `.psd1` file that contains a hash table. The keys and values in the hash table describe the contents and attributes of the module, define the
-prerequisites, and determine how the components are processed.
+A module manifest is a `.psd1` file that contains a hash table. The keys and values in the hash
+table describe the contents and attributes of the module, define the prerequisites, and determine
+how the components are processed.
 
 Module manifests must contain the following keys (and a corresponding value) to be considered valid:
-* `ModuleVersion`
+
+- `ModuleVersion`
 
 All other keys are optional. The order of the entries is not important.
 
@@ -20,7 +28,7 @@ Please consider adding the missing fields to the manifest.
 
 ### Wrong
 
-``` PowerShell
+```powershell
 @{
     Author              = 'PowerShell Author'
     NestedModules       = @('.\mymodule.psm1')
@@ -32,7 +40,7 @@ Please consider adding the missing fields to the manifest.
 
 ### Correct
 
-``` PowerShell
+```powershell
 @{
     ModuleVersion       = '1.0'
     Author              = 'PowerShell Author'
diff --git a/RuleDocumentation/PlaceCloseBrace.md b/docs/Rules/PlaceCloseBrace.md
similarity index 53%
rename from RuleDocumentation/PlaceCloseBrace.md
rename to docs/Rules/PlaceCloseBrace.md
index e8feb4884..6e14acc74 100644
--- a/RuleDocumentation/PlaceCloseBrace.md
+++ b/docs/Rules/PlaceCloseBrace.md
@@ -1,24 +1,31 @@
+---
+description: Place close braces
+ms.date: 06/28/2023
+ms.topic: reference
+title: PlaceCloseBrace
+---
 # PlaceCloseBrace
 
 **Severity Level: Warning**
 
 ## Description
 
-Close brace placement should follow a consistent style. It should be on a new line by itself and should not be followed by an empty line.
+Close brace placement should follow a consistent style. It should be on a new line by itself and
+should not be followed by an empty line.
 
 **Note**: This rule is not enabled by default. The user needs to enable it through settings.
 
 ## Configuration
 
 ```powershell
-    Rules = @{
-        PSPlaceCloseBrace = @{
-            Enable = $true
-            NoEmptyLineBefore = $false
-            IgnoreOneLineBlock = $true
-            NewLineAfter = $true
-        }
+Rules = @{
+    PSPlaceCloseBrace = @{
+        Enable = $true
+        NoEmptyLineBefore = $false
+        IgnoreOneLineBlock = $true
+        NewLineAfter = $true
     }
+}
 ```
 
 ### Parameters
@@ -33,10 +40,11 @@ Create violation if there is an empty line before a close brace.
 
 #### IgnoreOneLineBlock: bool (Default value is `$true`)
 
-Indicates if close braces in a one line block should be ignored or not.
-E.g. $x = if ($true) { "blah" } else { "blah blah" }
-In the above example, if the property is set to true then the rule will not fire a violation.
+Indicates if closed brace pairs in a one line block should be ignored or not. For example,
+`$x = if ($true) { 'blah' } else { 'blah blah' }`, if the property is set to true then the rule
+doesn't fire a violation.
 
 #### NewLineAfter: bool (Default value is `$true`)
 
-Indicates if a new line should follow a close brace. If set to true a close brace should be followed by a new line.
+Indicates if a new line should follow a close brace. If set to true a close brace should be followed
+by a new line.
diff --git a/RuleDocumentation/PlaceOpenBrace.md b/docs/Rules/PlaceOpenBrace.md
similarity index 61%
rename from RuleDocumentation/PlaceOpenBrace.md
rename to docs/Rules/PlaceOpenBrace.md
index 31949901c..a523ec4e8 100644
--- a/RuleDocumentation/PlaceOpenBrace.md
+++ b/docs/Rules/PlaceOpenBrace.md
@@ -1,24 +1,31 @@
+---
+description: Place open braces consistently
+ms.date: 06/28/2023
+ms.topic: reference
+title: PlaceOpenBrace
+---
 # PlaceOpenBrace
 
 **Severity Level: Warning**
 
 ## Description
 
-Open brace placement should follow a consistent style. It can either follow KR style (on same line) or the Allman style (not on same line).
+Open brace placement should follow a consistent style. It can either follow K&R style (on same line)
+or the Allman style (not on same line).
 
 **Note**: This rule is not enabled by default. The user needs to enable it through settings.
 
 ## Configuration
 
 ```powershell
-    Rules = @{
-        PSPlaceOpenBrace = @{
-            Enable = $true
-            OnSameLine = $true
-            NewLineAfter = $true
-            IgnoreOneLineBlock = $true
-        }
+Rules = @{
+    PSPlaceOpenBrace = @{
+        Enable = $true
+        OnSameLine = $true
+        NewLineAfter = $true
+        IgnoreOneLineBlock = $true
     }
+}
 ```
 
 ### Parameters
@@ -37,6 +44,6 @@ Enforce a new line character after an open brace. The default value is true.
 
 #### IgnoreOneLineBlock: bool (Default value is `$true`)
 
-Indicates if open braces in a one line block should be ignored or not.
-E.g. $x = if ($true) { "blah" } else { "blah blah" }
-In the above example, if the property is set to true then the rule will not fire a violation.
+Indicates if open braces in a one line block should be ignored or not. For example,
+`$x = if ($true) { 'blah' } else { 'blah blah' }`, if the property is set to true then the rule
+doesn't fire a violation.
diff --git a/docs/Rules/PossibleIncorrectComparisonWithNull.md b/docs/Rules/PossibleIncorrectComparisonWithNull.md
new file mode 100644
index 000000000..9a28646f4
--- /dev/null
+++ b/docs/Rules/PossibleIncorrectComparisonWithNull.md
@@ -0,0 +1,80 @@
+---
+description: Null Comparison
+ms.date: 12/03/2024
+ms.topic: reference
+title: PossibleIncorrectComparisonWithNull
+---
+# PossibleIncorrectComparisonWithNull
+
+**Severity Level: Warning**
+
+## Description
+
+To ensure that PowerShell performs comparisons correctly, the `$null` element should be on the left
+side of the operator.
+
+There are multiple reasons why this occurs:
+
+- `$null` is a scalar value. When the value on the left side of an operator is a scalar, comparison
+  operators return a **Boolean** value. When the value is a collection, the comparison operators
+  return any matching values or an empty array if there are no matches in the collection.
+- PowerShell performs type casting on the right-hand operand, resulting in incorrect comparisons
+  when `$null` is cast to other scalar types.
+
+The only way to reliably check if a value is `$null` is to place `$null` on the left side of the
+operator so that a scalar comparison is performed.
+
+## How
+
+Move `$null` to the left side of the comparison.
+
+## Example
+
+### Wrong
+
+```powershell
+function Test-CompareWithNull
+{
+    if ($DebugPreference -eq $null)
+    {
+    }
+}
+```
+
+### Correct
+
+```powershell
+function Test-CompareWithNull
+{
+    if ($null -eq $DebugPreference)
+    {
+    }
+}
+```
+
+## Try it Yourself
+
+```powershell
+# This example returns 'false' because the comparison does not return any objects from the array
+if (@() -eq $null) { 'true' } else { 'false' }
+# This example returns 'true' because the array is empty
+if ($null -ne @()) { 'true' } else { 'false' }
+```
+
+This is how the comparison operator works by-design. But, as demonstrated, this can lead
+to non-intuitive behavior, especially when the intent is simple test for null.
+
+The following example demonstrates the designed behavior of the comparison operator when the
+left-hand side is a collection. Each element in the collection is compared to the right-hand side
+value. When true, that element of the collection is returned.
+
+```powershell
+PS> 1,2,3,1,2 -eq $null
+PS> 1,2,3,1,2 -eq 1
+1
+1
+PS> (1,2,3,1,2 -eq $null).count
+0
+PS> (1,2,$null,3,$null,1,2 -eq $null).count
+2
+```
diff --git a/docs/Rules/PossibleIncorrectUsageOfAssignmentOperator.md b/docs/Rules/PossibleIncorrectUsageOfAssignmentOperator.md
new file mode 100644
index 000000000..11c5d23f1
--- /dev/null
+++ b/docs/Rules/PossibleIncorrectUsageOfAssignmentOperator.md
@@ -0,0 +1,67 @@
+---
+description: Equal sign is not an assignment operator. Did you mean the equality operator \'-eq\'?
+ms.date: 06/28/2023
+ms.topic: reference
+title: PossibleIncorrectUsageOfAssignmentOperator
+---
+# PossibleIncorrectUsageOfAssignmentOperator
+
+**Severity Level: Information**
+
+## Description
+
+In many programming languages, the equality operator is denoted as `==` or `=`, but `PowerShell`
+uses `-eq`. Therefore, it can easily happen that the wrong operator is used unintentionally. This
+rule catches a few special cases where the likelihood of that is quite high.
+
+The rule looks for usages of `==` and `=` operators inside `if`, `else if`, `while` and `do-while`
+statements but it does not warn if any kind of command or expression is used at the right hand side
+as this is probably by design.
+
+## Example
+
+### Wrong
+
+```powershell
+if ($a = $b)
+{
+    ...
+}
+```
+
+```powershell
+if ($a == $b)
+{
+
+}
+```
+
+### Correct
+
+```powershell
+if ($a -eq $b) # Compare $a with $b
+{
+    ...
+}
+```
+
+```powershell
+if ($a = Get-Something) # Only execute action if command returns something and assign result to variable
+{
+    Do-SomethingWith $a
+}
+```
+
+## Implicit suppression using Clang style
+
+There are some rare cases where assignment of variable inside an `if` statement is by design.
+Instead of suppressing the rule, one can also signal that assignment was intentional by wrapping the
+expression in extra parenthesis. An exception for this is when `$null` is used on the LHS because
+there is no use case for this.
+
+```powershell
+if (($shortVariableName = $SuperLongVariableName['SpecialItem']['AnotherItem']))
+{
+    ...
+}
+```
diff --git a/docs/Rules/PossibleIncorrectUsageOfRedirectionOperator.md b/docs/Rules/PossibleIncorrectUsageOfRedirectionOperator.md
new file mode 100644
index 000000000..871d1340f
--- /dev/null
+++ b/docs/Rules/PossibleIncorrectUsageOfRedirectionOperator.md
@@ -0,0 +1,39 @@
+---
+description: \'>\' is not a comparison operator. Use \'-gt\' (greater than) or \'-ge\' (greater or equal).
+ms.date: 06/28/2023
+ms.topic: reference
+title: PossibleIncorrectUsageOfRedirectionOperator
+---
+# PossibleIncorrectUsageOfRedirectionOperator
+
+**Severity Level: Information**
+
+## Description
+
+In many programming languages, the comparison operator for 'greater than' is `>` but `PowerShell`
+uses `-gt` for it and `-ge` (greater or equal) for `>=`. Therefore, it can easily happen that the
+wrong operator is used unintentionally. This rule catches a few special cases where the likelihood
+of that is quite high.
+
+The rule looks for usages of `>` or `>=` operators inside `if`, `elseif`, `while` and `do-while`
+statements because this is likely going to be unintentional usage.
+
+## Example
+
+### Wrong
+
+```powershell
+if ($a > $b)
+{
+    ...
+}
+```
+
+### Correct
+
+```powershell
+if ($a -gt $b)
+{
+    ...
+}
+```
diff --git a/docs/Rules/ProvideCommentHelp.md b/docs/Rules/ProvideCommentHelp.md
new file mode 100644
index 000000000..19e83681a
--- /dev/null
+++ b/docs/Rules/ProvideCommentHelp.md
@@ -0,0 +1,124 @@
+---
+description: Basic Comment Help
+ms.date: 06/28/2023
+ms.topic: reference
+title: ProvideCommentHelp
+---
+# ProvideCommentHelp
+
+**Severity Level: Info**
+
+## Description
+
+Comment based help should be provided for all PowerShell commands. This test only checks for the
+presence of comment based help and not on the validity or format.
+
+For assistance on comment based help, use the command `Get-Help about_comment_based_help` or the
+following articles:
+
+- [Writing Comment-based Help][01]
+- [Writing Help for PowerShell Cmdlets][02]
+- [Create XML-based help using PlatyPS][03]
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSProvideCommentHelp = @{
+        Enable = $true
+        ExportedOnly = $false
+        BlockComment = $true
+        VSCodeSnippetCorrection = $false
+        Placement = 'before'
+    }
+}
+```
+
+### Parameters
+
+- `Enable`: **bool** (Default value is `$true`)
+
+  Enable or disable the rule during ScriptAnalyzer invocation.
+
+- `ExportedOnly`: **bool** (Default value is `$true`)
+
+  If enabled, throw violation only on functions/cmdlets that are exported using the
+  `Export-ModuleMember` cmdlet.
+
+- `BlockComment`: **bool** (Default value is `$true`)
+
+  If enabled, returns comment help in block comment style (`<#...#>`). Otherwise returns
+  comment help in line comment style where each comment line starts with `#`.
+
+- `VSCodeSnippetCorrection`: **bool** (Default value is `$false`)
+
+  If enabled, returns comment help in vscode snippet format.
+
+- `Placement`: **string** (Default value is `before`)
+
+  Represents the position of comment help with respect to the function definition.
+
+  Possible values are:
+
+  - `before`: means the help is placed before the function definition
+  - `begin` means the help is placed at the beginning of the function definition body
+  - `end` means the help is places the end of the function definition body
+
+  If any invalid value is given, the property defaults to `before`.
+
+## Example
+
+### Wrong
+
+```powershell
+function Get-File
+{
+    [CmdletBinding()]
+    Param
+    (
+        ...
+    )
+
+}
+```
+
+### Correct
+
+```powershell
+<#
+.Synopsis
+    Short description
+.DESCRIPTION
+    Long description
+.EXAMPLE
+    Example of how to use this cmdlet
+.EXAMPLE
+    Another example of how to use this cmdlet
+.INPUTS
+    Inputs to this cmdlet (if any)
+.OUTPUTS
+    Output from this cmdlet (if any)
+.NOTES
+    General notes
+.COMPONENT
+    The component this cmdlet belongs to
+.ROLE
+    The role this cmdlet belongs to
+.FUNCTIONALITY
+    The functionality that best describes this cmdlet
+#>
+
+function Get-File
+{
+    [CmdletBinding()]
+    Param
+    (
+        ...
+    )
+
+}
+```
+<!-- link references -->
+[01]: https://learn.microsoft.com/powershell/scripting/developer/help/writing-comment-based-help-topics
+[02]: https://learn.microsoft.com/powershell/scripting/developer/help/writing-help-for-windows-powershell-cmdlets
+[03]: https://learn.microsoft.com/powershell/utility-modules/platyps/create-help-using-platyps
diff --git a/docs/Rules/README.md b/docs/Rules/README.md
new file mode 100644
index 000000000..06f27d2da
--- /dev/null
+++ b/docs/Rules/README.md
@@ -0,0 +1,87 @@
+---
+description: List of PSScriptAnalyzer rules
+ms.date: 03/27/2024
+ms.topic: reference
+title: List of PSScriptAnalyzer rules
+---
+# PSScriptAnalyzer Rules
+
+The PSScriptAnalyzer contains the following rule definitions.
+
+|                                               Rule                                                |  Severity   | Enabled by default |  Configurable   |
+| ------------------------------------------------------------------------------------------------- | ----------- | :----------------: | :-------------: |
+| [AlignAssignmentStatement](./AlignAssignmentStatement.md)                                         | Warning     |         No         |       Yes       |
+| [AvoidAssignmentToAutomaticVariable](./AvoidAssignmentToAutomaticVariable.md)                     | Warning     |        Yes         |                 |
+| [AvoidDefaultValueForMandatoryParameter](./AvoidDefaultValueForMandatoryParameter.md)             | Warning     |        Yes         |                 |
+| [AvoidDefaultValueSwitchParameter](./AvoidDefaultValueSwitchParameter.md)                         | Warning     |        Yes         |                 |
+| [AvoidExclaimOperator](./AvoidExclaimOperator.md)                                                 | Warning     |         No         |                 |
+| [AvoidGlobalAliases<sup>1</sup>](./AvoidGlobalAliases.md)                                         | Warning     |        Yes         |                 |
+| [AvoidGlobalFunctions](./AvoidGlobalFunctions.md)                                                 | Warning     |        Yes         |                 |
+| [AvoidGlobalVars](./AvoidGlobalVars.md)                                                           | Warning     |        Yes         |                 |
+| [AvoidInvokingEmptyMembers](./AvoidInvokingEmptyMembers.md)                                       | Warning     |        Yes         |                 |
+| [AvoidLongLines](./AvoidLongLines.md)                                                             | Warning     |         No         |       Yes       |
+| [AvoidMultipleTypeAttributes<sup>1</sup>](./AvoidMultipleTypeAttributes.md)                       | Warning     |        Yes         |                 |
+| [AvoidNullOrEmptyHelpMessageAttribute](./AvoidNullOrEmptyHelpMessageAttribute.md)                 | Warning     |        Yes         |                 |
+| [AvoidOverwritingBuiltInCmdlets](./AvoidOverwritingBuiltInCmdlets.md)                             | Warning     |        Yes         |       Yes       |
+| [AvoidSemicolonsAsLineTerminators](./AvoidSemicolonsAsLineTerminators.md)                         | Warning     |         No         |                 |
+| [AvoidShouldContinueWithoutForce](./AvoidShouldContinueWithoutForce.md)                           | Warning     |        Yes         |                 |
+| [AvoidTrailingWhitespace](./AvoidTrailingWhitespace.md)                                           | Warning     |        Yes         |                 |
+| [AvoidUsingAllowUnencryptedAuthentication](./AvoidUsingAllowUnencryptedAuthentication.md)         | Warning     |        Yes         |                 |
+| [AvoidUsingBrokenHashAlgorithms](./AvoidUsingBrokenHashAlgorithms.md)                             | Warning     |        Yes         |                 |
+| [AvoidUsingCmdletAliases](./AvoidUsingCmdletAliases.md)                                           | Warning     |        Yes         | Yes<sup>2</sup> |
+| [AvoidUsingComputerNameHardcoded](./AvoidUsingComputerNameHardcoded.md)                           | Error       |        Yes         |                 |
+| [AvoidUsingConvertToSecureStringWithPlainText](./AvoidUsingConvertToSecureStringWithPlainText.md) | Error       |        Yes         |                 |
+| [AvoidUsingDeprecatedManifestFields](./AvoidUsingDeprecatedManifestFields.md)                     | Warning     |        Yes         |                 |
+| [AvoidUsingDoubleQuotesForConstantString](./AvoidUsingDoubleQuotesForConstantString.md)           | Information |         No         |                 |
+| [AvoidUsingEmptyCatchBlock](./AvoidUsingEmptyCatchBlock.md)                                       | Warning     |        Yes         |                 |
+| [AvoidUsingInvokeExpression](./AvoidUsingInvokeExpression.md)                                     | Warning     |        Yes         |                 |
+| [AvoidUsingPlainTextForPassword](./AvoidUsingPlainTextForPassword.md)                             | Warning     |        Yes         |                 |
+| [AvoidUsingPositionalParameters](./AvoidUsingPositionalParameters.md)                             | Warning     |        Yes         |                 |
+| [AvoidUsingUsernameAndPasswordParams](./AvoidUsingUsernameAndPasswordParams.md)                   | Error       |        Yes         |                 |
+| [AvoidUsingWMICmdlet](./AvoidUsingWMICmdlet.md)                                                   | Warning     |        Yes         |                 |
+| [AvoidUsingWriteHost](./AvoidUsingWriteHost.md)                                                   | Warning     |        Yes         |                 |
+| [DSCDscExamplesPresent](./DSCDscExamplesPresent.md)                                               | Information |        Yes         |                 |
+| [DSCDscTestsPresent](./DSCDscTestsPresent.md)                                                     | Information |        Yes         |                 |
+| [DSCReturnCorrectTypesForDSCFunctions](./DSCReturnCorrectTypesForDSCFunctions.md)                 | Information |        Yes         |                 |
+| [DSCStandardDSCFunctionsInResource](./DSCStandardDSCFunctionsInResource.md)                       | Error       |        Yes         |                 |
+| [DSCUseIdenticalMandatoryParametersForDSC](./DSCUseIdenticalMandatoryParametersForDSC.md)         | Error       |        Yes         |                 |
+| [DSCUseIdenticalParametersForDSC](./DSCUseIdenticalParametersForDSC.md)                           | Error       |        Yes         |                 |
+| [DSCUseVerboseMessageInDSCResource](./DSCUseVerboseMessageInDSCResource.md)                       | Error       |        Yes         |                 |
+| [MisleadingBacktick](./MisleadingBacktick.md)                                                     | Warning     |        Yes         |                 |
+| [MissingModuleManifestField](./MissingModuleManifestField.md)                                     | Warning     |        Yes         |                 |
+| [PlaceCloseBrace](./PlaceCloseBrace.md)                                                           | Warning     |         No         |       Yes       |
+| [PlaceOpenBrace](./PlaceOpenBrace.md)                                                             | Warning     |         No         |       Yes       |
+| [PossibleIncorrectComparisonWithNull](./PossibleIncorrectComparisonWithNull.md)                   | Warning     |        Yes         |                 |
+| [PossibleIncorrectUsageOfAssignmentOperator](./PossibleIncorrectUsageOfAssignmentOperator.md)     | Warning     |        Yes         |                 |
+| [PossibleIncorrectUsageOfRedirectionOperator](./PossibleIncorrectUsageOfRedirectionOperator.md)   | Warning     |        Yes         |                 |
+| [ProvideCommentHelp](./ProvideCommentHelp.md)                                                     | Information |        Yes         |       Yes       |
+| [ReservedCmdletChar](./ReservedCmdletChar.md)                                                     | Error       |        Yes         |                 |
+| [ReservedParams](./ReservedParams.md)                                                             | Error       |        Yes         |                 |
+| [ReviewUnusedParameter](./ReviewUnusedParameter.md)                                               | Warning     |        Yes         | Yes<sup>2</sup> |
+| [ShouldProcess](./ShouldProcess.md)                                                               | Warning     |        Yes         |                 |
+| [UseApprovedVerbs](./UseApprovedVerbs.md)                                                         | Warning     |        Yes         |                 |
+| [UseBOMForUnicodeEncodedFile](./UseBOMForUnicodeEncodedFile.md)                                   | Warning     |        Yes         |                 |
+| [UseCmdletCorrectly](./UseCmdletCorrectly.md)                                                     | Warning     |        Yes         |                 |
+| [UseCompatibleCmdlets](./UseCompatibleCmdlets.md)                                                 | Warning     |        Yes         | Yes<sup>2</sup> |
+| [UseCompatibleCommands](./UseCompatibleCommands.md)                                               | Warning     |         No         |       Yes       |
+| [UseCompatibleSyntax](./UseCompatibleSyntax.md)                                                   | Warning     |         No         |       Yes       |
+| [UseCompatibleTypes](./UseCompatibleTypes.md)                                                     | Warning     |         No         |       Yes       |
+| [UseConsistentIndentation](./UseConsistentIndentation.md)                                         | Warning     |         No         |       Yes       |
+| [UseConsistentWhitespace](./UseConsistentWhitespace.md)                                           | Warning     |         No         |       Yes       |
+| [UseCorrectCasing](./UseCorrectCasing.md)                                                         | Information |         No         |       Yes       |
+| [UseDeclaredVarsMoreThanAssignments](./UseDeclaredVarsMoreThanAssignments.md)                     | Warning     |        Yes         |                 |
+| [UseLiteralInitializerForHashtable](./UseLiteralInitializerForHashtable.md)                       | Warning     |        Yes         |                 |
+| [UseOutputTypeCorrectly](./UseOutputTypeCorrectly.md)                                             | Information |        Yes         |                 |
+| [UseProcessBlockForPipelineCommand](./UseProcessBlockForPipelineCommand.md)                       | Warning     |        Yes         |                 |
+| [UsePSCredentialType](./UsePSCredentialType.md)                                                   | Warning     |        Yes         |                 |
+| [UseShouldProcessForStateChangingFunctions](./UseShouldProcessForStateChangingFunctions.md)       | Warning     |        Yes         |                 |
+| [UseSingularNouns](./UseSingularNouns.md)                                                         | Warning     |        Yes         |       Yes       |
+| [UseSupportsShouldProcess](./UseSupportsShouldProcess.md)                                         | Warning     |        Yes         |                 |
+| [UseToExportFieldsInManifest](./UseToExportFieldsInManifest.md)                                   | Warning     |        Yes         |                 |
+| [UseUsingScopeModifierInNewRunspaces](./UseUsingScopeModifierInNewRunspaces.md)                   | Warning     |        Yes         |                 |
+| [UseUTF8EncodingForHelpFile](./UseUTF8EncodingForHelpFile.md)                                     | Warning     |        Yes         |                 |
+
+- <sup>1</sup> Rule is not available on all PowerShell versions, editions, or OS platforms. See the
+  rule's documentation for details.
+- <sup>2</sup> The rule has a configurable property, but the rule can't be disabled like other
+  configurable rules.
diff --git a/RuleDocumentation/ReservedCmdletChar.md b/docs/Rules/ReservedCmdletChar.md
similarity index 52%
rename from RuleDocumentation/ReservedCmdletChar.md
rename to docs/Rules/ReservedCmdletChar.md
index 5443ae010..55acfc707 100644
--- a/RuleDocumentation/ReservedCmdletChar.md
+++ b/docs/Rules/ReservedCmdletChar.md
@@ -1,12 +1,19 @@
+---
+description: Reserved Cmdlet Chars
+ms.date: 06/28/2023
+ms.topic: reference
+title: ReservedCmdletChar
+---
 # ReservedCmdletChar
 
 **Severity Level: Error**
 
 ## Description
 
-You cannot use following reserved characters in a function or cmdlet name as these can cause parsing or runtime errors.
+You cannot use following reserved characters in a function or cmdlet name as these can cause parsing
+or runtime errors.
 
-Reserved Characters include: `#,(){}[]&/\\$^;:\"'<>|?@`*%+=~`
+Reserved Characters include: ``#,(){}[]&/\\$^;:\"'<>|?@`*%+=~``
 
 ## How
 
@@ -16,14 +23,14 @@ Remove reserved characters from names.
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function MyFunction[1]
 {...}
 ```
 
 ### Correct
 
-``` PowerShell
+```powershell
 function MyFunction
 {...}
 ```
diff --git a/docs/Rules/ReservedParams.md b/docs/Rules/ReservedParams.md
new file mode 100644
index 000000000..0e433e0e4
--- /dev/null
+++ b/docs/Rules/ReservedParams.md
@@ -0,0 +1,51 @@
+---
+description: Reserved Parameters
+ms.date: 03/06/2024
+ms.topic: reference
+title: ReservedParams
+---
+# ReservedParams
+
+**Severity Level: Error**
+
+## Description
+
+You can't redefine [common parameters][01] in an advanced function. Using the `CmdletBinding` or
+`Parameter` attributes creates an advanced function. The common parameters are are automatically
+available in advanced functions, so you can't redefine them.
+
+## How
+
+Change the name of the parameter.
+
+## Example
+
+### Wrong
+
+```powershell
+function Test
+{
+    [CmdletBinding()]
+    Param
+    (
+        $ErrorVariable,
+        $Parameter2
+    )
+}
+```
+
+### Correct
+
+```powershell
+function Test
+{
+    [CmdletBinding()]
+    Param
+    (
+        $Err,
+        $Parameter2
+    )
+}
+```
+
+[01]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_commonparameters
diff --git a/docs/Rules/ReviewUnusedParameter.md b/docs/Rules/ReviewUnusedParameter.md
new file mode 100644
index 000000000..4732b8aba
--- /dev/null
+++ b/docs/Rules/ReviewUnusedParameter.md
@@ -0,0 +1,70 @@
+---
+description: ReviewUnusedParameter
+ms.date: 03/26/2024
+ms.topic: reference
+title: ReviewUnusedParameter
+---
+# ReviewUnusedParameter
+
+**Severity Level: Warning**
+
+## Description
+
+This rule identifies parameters declared in a script, scriptblock, or function scope that have not
+been used in that scope.
+
+## Configuration settings
+
+By default, this rule doesn't consider child scopes other than scriptblocks provided to
+`Where-Object` or `ForEach-Object`. The `CommandsToTraverse` setting is an string array allows you
+to add additional commands that accept scriptblocks that this rule should examine.
+
+```powershell
+@{
+    Rules = @{
+        PSReviewUnusedParameter = @{
+            CommandsToTraverse = @(
+                'Invoke-PSFProtectedCommand'
+            )
+        }
+    }
+}
+```
+
+## How
+
+Consider removing the unused parameter.
+
+## Example
+
+### Wrong
+
+```powershell
+function Test-Parameter
+{
+    Param (
+        $Parameter1,
+
+        # this parameter is never called in the function
+        $Parameter2
+    )
+
+    Get-Something $Parameter1
+}
+```
+
+### Correct
+
+```powershell
+function Test-Parameter
+{
+    Param (
+        $Parameter1,
+
+        # now this parameter is being called in the same scope
+        $Parameter2
+    )
+
+    Get-Something $Parameter1 $Parameter2
+}
+```
diff --git a/docs/Rules/ShouldProcess.md b/docs/Rules/ShouldProcess.md
new file mode 100644
index 000000000..40dcedec4
--- /dev/null
+++ b/docs/Rules/ShouldProcess.md
@@ -0,0 +1,78 @@
+---
+description: Should Process
+ms.date: 06/28/2023
+ms.topic: reference
+title: ShouldProcess
+---
+# ShouldProcess
+
+**Severity Level: Warning**
+
+## Description
+
+If a cmdlet declares the `SupportsShouldProcess` attribute, then it should also call
+`ShouldProcess`. A violation is any function which either declares `SupportsShouldProcess` attribute
+but makes no calls to `ShouldProcess` or it calls `ShouldProcess` but does not declare
+`SupportsShouldProcess`.
+
+For more information, see the following articles:
+
+- [about_Functions_Advanced_Methods][01]
+- [about_Functions_CmdletBindingAttribute][02]
+- [Everything you wanted to know about ShouldProcess][03]
+
+## How
+
+To fix a violation of this rule, please call `ShouldProcess` method when a cmdlet declares
+`SupportsShouldProcess` attribute. Or please add `SupportsShouldProcess` attribute argument when
+calling `ShouldProcess`.
+
+## Example
+
+### Wrong
+
+```powershell
+function Set-File
+{
+    [CmdletBinding(SupportsShouldProcess=$true)]
+    Param
+    (
+        # Path to file
+        [Parameter(Mandatory=$true)]
+        $Path
+    )
+    'String' | Out-File -FilePath $Path
+}
+```
+
+### Correct
+
+```powershell
+function Set-File
+{
+    [CmdletBinding(SupportsShouldProcess=$true)]
+    Param
+    (
+        # Path to file
+        [Parameter(Mandatory=$true)]
+        $Path,
+
+        [Parameter(Mandatory=$true)]
+        [string]$Content
+    )
+
+    if ($PSCmdlet.ShouldProcess($Path, ("Setting content to '{0}'" -f $Content)))
+    {
+        $Content | Out-File -FilePath $Path
+    }
+    else
+    {
+        # Code that should be processed if doing a WhatIf operation
+        # Must NOT change anything outside of the function / script
+    }
+}
+```
+<!-- link references -->
+[01]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_functions_advanced_methods
+[02]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_Functions_CmdletBindingAttribute
+[03]: https://learn.microsoft.com/powershell/scripting/learn/deep-dives/everything-about-shouldprocess
diff --git a/docs/Rules/UseApprovedVerbs.md b/docs/Rules/UseApprovedVerbs.md
new file mode 100644
index 000000000..c1bcaa0c7
--- /dev/null
+++ b/docs/Rules/UseApprovedVerbs.md
@@ -0,0 +1,47 @@
+---
+description: Cmdlet Verbs
+ms.date: 03/26/2024
+ms.topic: reference
+title: UseApprovedVerbs
+---
+# UseApprovedVerbs
+
+**Severity Level: Warning**
+
+## Description
+
+All cmdlets must used approved verbs.
+
+Approved verbs can be found by running the command `Get-Verb`.
+
+For a more information about approved verbs, see [Approved Verbs for PowerShell Commands][01]. Some
+unapproved verbs are documented on the approved verbs page and point to approved alternatives. Try
+searching for the verb you used to find its approved form. For example, searching for `Read`,
+`Open`, or `Search` leads you to `Get`.
+
+## How
+
+Change the verb in the cmdlet's name to an approved verb.
+
+## Example
+
+### Wrong
+
+```powershell
+function Change-Item
+{
+    ...
+}
+```
+
+### Correct
+
+```powershell
+function Update-Item
+{
+    ...
+}
+```
+
+<!-- link references -->
+[01]: /powershell/scripting/developer/cmdlet/approved-verbs-for-windows-powershell-commands
diff --git a/docs/Rules/UseBOMForUnicodeEncodedFile.md b/docs/Rules/UseBOMForUnicodeEncodedFile.md
new file mode 100644
index 000000000..e0a46b1e2
--- /dev/null
+++ b/docs/Rules/UseBOMForUnicodeEncodedFile.md
@@ -0,0 +1,42 @@
+---
+description: Use BOM encoding for non-ASCII files
+ms.date: 01/07/2025
+ms.topic: reference
+title: UseBOMForUnicodeEncodedFile
+---
+# UseBOMForUnicodeEncodedFile
+
+**Severity Level: Warning**
+
+## Description
+
+For a file encoded with a format other than ASCII, ensure Byte Order Mark (BOM) is present to ensure
+that any application consuming this file can interpret it correctly.
+
+You can use this rule to test any arbitrary text file, but the intent is to ensure that PowerShell
+scripts are saved with a BOM when using a Unicode encoding.
+
+## How
+
+For PowerShell commands that write to files, ensure that you set the encoding parameter to a value
+that produces a BOM. In PowerShell 7 and higher, the following values of the **Encoding** parameter
+produce a BOM:
+
+- `bigendianunicode`
+- `bigendianutf32`
+- `oem`
+- `unicode`
+- `utf32`
+- `utf8BOM`
+
+When you create a script file using a text editor, ensure that the editor is configured to save the
+file with a BOM. Consult the documentation for your text editor for instructions on how to save
+files with a BOM.
+
+## Further reading
+
+For more information, see the following articles:
+
+- [about_Character_Encoding](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_character_encoding)
+- [Set-Content](https://learn.microsoft.com/powershell/module/microsoft.powershell.management/set-content)
+- [Understanding file encoding in VS Code and PowerShell](https://learn.microsoft.com/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding)
diff --git a/RuleDocumentation/UseCmdletCorrectly.md b/docs/Rules/UseCmdletCorrectly.md
similarity index 54%
rename from RuleDocumentation/UseCmdletCorrectly.md
rename to docs/Rules/UseCmdletCorrectly.md
index 9405a6381..81ec42e4e 100644
--- a/RuleDocumentation/UseCmdletCorrectly.md
+++ b/docs/Rules/UseCmdletCorrectly.md
@@ -1,10 +1,17 @@
+---
+description: Use Cmdlet Correctly
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseCmdletCorrectly
+---
 # UseCmdletCorrectly
 
 **Severity Level: Warning**
 
 ## Description
 
-Whenever we call a command, care should be taken that it is invoked with the correct syntax and parameters.
+Whenever we call a command, care should be taken that it is invoked with the correct syntax and
+parameters.
 
 ## How
 
@@ -14,21 +21,21 @@ Specify all mandatory parameters when calling commands.
 
 ### Wrong
 
-``` PowerShell
+```powershell
 Function Set-TodaysDate ()
 {
-	Set-Date
-	...
+    Set-Date
+    ...
 }
 ```
 
 ### Correct
 
-``` PowerShell
+```powershell
 Function Set-TodaysDate ()
 {
-	$date = Get-Date
-	Set-Date -Date $date
-	...
+    $date = Get-Date
+    Set-Date -Date $date
+    ...
 }
 ```
diff --git a/docs/Rules/UseCompatibleCmdlets.md b/docs/Rules/UseCompatibleCmdlets.md
new file mode 100644
index 000000000..4cd52340e
--- /dev/null
+++ b/docs/Rules/UseCompatibleCmdlets.md
@@ -0,0 +1,50 @@
+---
+description: Use compatible cmdlets
+ms.date: 12/12/2024
+ms.topic: reference
+title: UseCompatibleCmdlets
+---
+# UseCompatibleCmdlets
+
+**Severity Level: Warning**
+
+## Description
+
+This rule flags cmdlets that aren't available in a given Edition and Version of PowerShell on a
+given Operating System. It works by comparing a cmdlet against a set of allowlists which ship with
+PSScriptAnalyzer. They can be found at `/path/to/PSScriptAnalyzerModule/Settings`. These files are
+of the form, `<psedition>-<psversion>-<os>.json` where `<psedition>` can be either `Core` or
+`Desktop`, `<os>` can be either `Windows`, `Linux` or `MacOS`, and `<psversion>` is the PowerShell
+version. To enable the rule to check if your script is compatible on PowerShell Core on windows, put
+the following your settings file:
+
+```powershell
+@{
+    'Rules' = @{
+        'PSUseCompatibleCmdlets' = @{
+            'compatibility' = @('core-6.1.0-windows')
+        }
+    }
+}
+```
+
+The parameter `compatibility` is a list that contain any of the following
+
+- desktop-2.0-windows
+- desktop-3.0-windows
+- desktop-4.0-windows (taken from Windows Server 2012R2)
+- desktop-5.1.14393.206-windows
+- core-6.1.0-windows (taken from Windows 10 - 1803)
+- core-6.1.0-linux (taken from Ubuntu 18.04)
+- core-6.1.0-linux-arm (taken from Raspbian)
+- core-6.1.0-macos
+
+Usually, patched versions of PowerShell have the same cmdlet data, therefore only settings of major
+and minor versions of PowerShell are supplied. You can also create a custom settings file with the
+[New-CommandDataFile.ps1][01] script. Place the created `.json` file in the `Settings` folder of the
+`PSScriptAnalyzer` module folder. Then the `compatibility` parameter values is just the filename.
+Note that the `core-6.0.2-*` files were removed in PSScriptAnalyzer 1.18 since PowerShell 6.0
+reached it's end of life.
+
+<!-- link references -->
+[01]: https://github.com/PowerShell/PSScriptAnalyzer/blob/main/Utils/New-CommandDataFile.ps1
diff --git a/docs/Rules/UseCompatibleCommands.md b/docs/Rules/UseCompatibleCommands.md
new file mode 100644
index 000000000..ae74862ba
--- /dev/null
+++ b/docs/Rules/UseCompatibleCommands.md
@@ -0,0 +1,145 @@
+---
+description: Use compatible commands
+ms.date: 12/12/2024
+ms.topic: reference
+title: UseCompatibleCommands
+---
+# UseCompatibleCommands
+
+**Severity Level: Warning**
+
+## Description
+
+This rule identifies commands that are not available on a targeted PowerShell platform.
+
+A PowerShell platform is identified by a name in the following format:
+
+```
+<os-name>_<os-arch>_<os-version>_<ps-version>_<ps-arch>_<dotnet-version>_<dotnet-edition>
+```
+
+Where:
+
+- `<os-name>`: The name of the operating system PowerShell is running on.
+    On Windows, this includes the SKU number.
+    On Linux, this is the name of the distribution.
+- `<os-arch>`: The machine architecture the operating system is running on (this is usually `x64`).
+- `<os-version>`: The self-reported version of the operating system (on Linux, this is the
+  distribution version).
+- `<ps-version>`: The PowerShell version (from `$PSVersionTable.PSVersion`).
+- `<ps-arch>`: The machine architecture of the PowerShell process.
+- `<dotnet-version>`: The reported version of the .NET runtime PowerShell is running on (from
+  `System.Environment.Version`).
+- `<dotnet-edition>`: The .NET runtime flavor PowerShell is running on (currently `framework` or
+  `core`).
+
+For example:
+
+- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on
+  Windows 10 Enterprise (build 18312) for x64.
+- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same
+  operating system.
+- `ubuntu_x64_18.04_6.2.0_x64_4.0.30319.42000_core` is PowerShell 6.2.0 running on Ubuntu 18.04.
+
+Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in
+your configuration.
+
+Platforms bundled by default are:
+
+| PowerShell Version |    Operating System    |                                  ID                                   |
+| :----------------: | ---------------------- | --------------------------------------------------------------------- |
+|        3.0         | Windows Server 2012    | `win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework`              |
+|        4.0         | Windows Server 2012 R2 | `win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework`              |
+|        5.1         | Windows Server 2016    | `win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework` |
+|        5.1         | Windows Server 2019    | `win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework`  |
+|        5.1         | Windows 10 Pro         | `win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework` |
+|        6.2         | Ubuntu 18.04 LTS       | `ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core`                     |
+|        6.2         | Windows 10.0.14393     | `win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core`               |
+|        6.2         | Windows 10.0.17763     | `win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core`               |
+|        6.2         | Windows 10.0.18362     | `win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core`               |
+|        7.0         | Ubuntu 18.04 LTS       | `ubuntu_x64_18.04_7.0.0_x64_3.1.2_core`                               |
+|        7.0         | Windows 10.0.14393     | `win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core`                         |
+|        7.0         | Windows 10.0.17763     | `win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core`                         |
+|        7.0         | Windows 10.0.18362     | `win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core`                         |
+
+Other profiles can be found in the [GitHub repo][02].
+
+You can also generate your own platform profile using the [PSCompatibilityCollector module][01].
+
+The compatibility profile settings takes a list of platforms to target under `TargetProfiles`. A
+platform can be specified as:
+
+- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json`
+  added to the end and is searched for in the default profile directory.
+- A filename (like `my_custom_platform.json`), which will be searched for the in the default profile
+  directory.
+- An absolute path to a file (like `D:\PowerShellProfiles\TargetMachine.json`).
+
+The default profile directory is under the PSScriptAnalzyer module at
+`$PSScriptRoot/compatibility_profiles` (where `$PSScriptRoot` here refers to the directory
+containing `PSScriptAnalyzer.psd1`).
+
+The compatibility analysis compares a command used to both a target profile and a 'union' profile
+(containing all commands available in _any_ profile in the profile dir). If a command is not present
+in the union profile, it is assumed to be locally created and ignored. Otherwise, if a command is
+present in the union profile but not present in a target, it is deemed to be incompatible with that
+target.
+
+## Configuration settings
+
+| Configuration key |                                     Meaning                                      |                                     Accepted values                                     |                                   Mandatory                                   |                                                            Example                                                            |
+| ----------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
+| `Enable`          | Activates the rule                                                               | bool (`$true`/`$false`)                                                                 | No (default: `$false`)                                                        | `$true`                                                                                                                       |
+| `TargetProfiles`  | The list of PowerShell profiles to target                                        | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`)                                                           | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` |
+| `ProfileDirPath`  | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir                                                | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles`                                                                                    |
+| `IgnoreCommands`  | Commands to ignore compatibility of in scripts                                   | string[]: names of commands to ignore                                                   | No (default: `@()`)                                                           | `@('Get-ChildItem','Import-Module')`                                                                                          |
+
+An example configuration might look like:
+
+```powershell
+@{
+    Rules = @{
+        PSUseCompatibleCommands = @{
+            Enable = $true
+            TargetProfiles = @(
+                'ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core'
+                'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+                'MyProfile'
+                'another_custom_profile_in_the_profiles_directory.json'
+                'D:\My Profiles\profile1.json'
+            )
+            # You can specify commands to not check like this, which also will ignore its parameters:
+            IgnoreCommands = @(
+                'Install-Module'
+            )
+        }
+    }
+}
+```
+
+## Suppression
+
+Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a
+scriptblock as with other rules.
+
+```powershell
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands', '')]
+```
+
+The rule can also be suppressed only for particular commands:
+
+```powershell
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands',
+    'Start-Service')]
+```
+
+And also suppressed only for parameters:
+
+```powershell
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands',
+    'Import-Module/FullyQualifiedName')]
+```
+
+<!-- link references -->
+[01]: https://github.com/PowerShell/PSScriptAnalyzer/tree/main/PSCompatibilityCollector
+[02]: https://github.com/PowerShell/PSScriptAnalyzer/tree/main/PSCompatibilityCollector/optional_profiles
diff --git a/RuleDocumentation/UseCompatibleSyntax.md b/docs/Rules/UseCompatibleSyntax.md
similarity index 55%
rename from RuleDocumentation/UseCompatibleSyntax.md
rename to docs/Rules/UseCompatibleSyntax.md
index 4c51e9b97..a2adbbbb6 100644
--- a/RuleDocumentation/UseCompatibleSyntax.md
+++ b/docs/Rules/UseCompatibleSyntax.md
@@ -1,25 +1,31 @@
-# UseCompatibleSyntax
-
-**Severity Level: Warning**
-
-## Description
-
-This rule identifies syntax elements that are incompatible with targeted PowerShell versions.
-
-It cannot identify syntax elements incompatible with PowerShell 3/4 from PowerShell 3/4
-due to those PowerShell versions not being able to parse the incompatible syntaxes.
-
-```PowerShell
-@{
-    Rules = @{
-        PSUseCompatibleSyntax = @{
-            Enable = $true
-            TargetVersions = @(
-                "6.0",
-                "5.1",
-                "4.0"
-            )
-        }
-    }
-}
-```
+---
+description: Use compatible syntax
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseCompatibleSyntax
+---
+# UseCompatibleSyntax
+
+**Severity Level: Warning**
+
+## Description
+
+This rule identifies syntax elements that are incompatible with targeted PowerShell versions.
+
+It cannot identify syntax elements incompatible with PowerShell 3 or 4 when run from those
+PowerShell versions because they aren't able to parse the incompatible syntaxes.
+
+```powershell
+@{
+    Rules = @{
+        PSUseCompatibleSyntax = @{
+            Enable = $true
+            TargetVersions = @(
+                '6.0',
+                '5.1',
+                '4.0'
+            )
+        }
+    }
+}
+```
diff --git a/docs/Rules/UseCompatibleTypes.md b/docs/Rules/UseCompatibleTypes.md
new file mode 100644
index 000000000..9bff5fa76
--- /dev/null
+++ b/docs/Rules/UseCompatibleTypes.md
@@ -0,0 +1,165 @@
+---
+description: Use compatible types
+ms.date: 12/12/2024
+ms.topic: reference
+title: UseCompatibleTypes
+---
+# UseCompatibleTypes
+
+**Severity Level: Warning**
+
+## Description
+
+This rule identifies types that are not available (loaded by default) in targeted PowerShell
+platforms.
+
+A PowerShell platform is identified by a name in the following format:
+
+```
+<os-name>_<os-arch>_<os-version>_<ps-version>_<ps-arch>_<dotnet-version>_<dotnet-edition>
+```
+
+Where:
+
+- `<os-name>`: The name of the operating system PowerShell is running on.
+    On Windows, this includes the SKU number.
+    On Linux, this is the name of the distribution.
+- `<os-arch>`: The machine architecture the operating system is running on (this is usually `x64`).
+- `<os-version>`: The self-reported version of the operating system (on Linux, this is the
+  distribution version).
+- `<ps-version>`: The PowerShell version (from `$PSVersionTable.PSVersion`).
+- `<ps-arch>`: The machine architecture of the PowerShell process.
+- `<dotnet-version>`: The reported version of the .NET runtime PowerShell is running on (from
+  `System.Environment.Version`).
+- `<dotnet-edition>`: The .NET runtime flavor PowerShell is running on (currently `framework` or
+  `core`).
+
+For example:
+
+- `win-4_x64_10.0.18312.0_5.1.18312.1000_x64_4.0.30319.42000_framework` is PowerShell 5.1 running on
+  Windows 10 Enterprise (build 18312) for x64.
+- `win-4_x64_10.0.18312.0_6.1.2_x64_4.0.30319.42000_core` is PowerShell 6.1.2 running on the same
+  operating system.
+- `ubuntu_x64_18.04_6.2.0_x64_4.0.30319.42000_core` is PowerShell 6.2.0 running on Ubuntu 18.04.
+
+Some platforms come bundled with PSScriptAnalyzer as JSON files, named in this way for targeting in
+your configuration.
+
+Platforms bundled by default are:
+
+| PowerShell Version |    Operating System    |                                  ID                                   |
+| :----------------: | ---------------------- | --------------------------------------------------------------------- |
+|        3.0         | Windows Server 2012    | `win-8_x64_6.2.9200.0_3.0_x64_4.0.30319.42000_framework`              |
+|        4.0         | Windows Server 2012 R2 | `win-8_x64_6.3.9600.0_4.0_x64_4.0.30319.42000_framework`              |
+|        5.1         | Windows Server 2016    | `win-8_x64_10.0.14393.0_5.1.14393.2791_x64_4.0.30319.42000_framework` |
+|        5.1         | Windows Server 2019    | `win-8_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework`  |
+|        5.1         | Windows 10 Pro         | `win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework` |
+|        6.2         | Ubuntu 18.04 LTS       | `ubuntu_x64_18.04_6.2.4_x64_4.0.30319.42000_core`                     |
+|        6.2         | Windows 10.0.14393     | `win-8_x64_10.0.14393.0_6.2.4_x64_4.0.30319.42000_core`               |
+|        6.2         | Windows 10.0.17763     | `win-8_x64_10.0.17763.0_6.2.4_x64_4.0.30319.42000_core`               |
+|        6.2         | Windows 10.0.18362     | `win-4_x64_10.0.18362.0_6.2.4_x64_4.0.30319.42000_core`               |
+|        7.0         | Ubuntu 18.04 LTS       | `ubuntu_x64_18.04_7.0.0_x64_3.1.2_core`                               |
+|        7.0         | Windows 10.0.14393     | `win-8_x64_10.0.14393.0_7.0.0_x64_3.1.2_core`                         |
+|        7.0         | Windows 10.0.17763     | `win-8_x64_10.0.17763.0_7.0.0_x64_3.1.2_core`                         |
+|        7.0         | Windows 10.0.18362     | `win-4_x64_10.0.18362.0_7.0.0_x64_3.1.2_core`                         |
+
+Other profiles can be found in the [GitHub repo][02].
+
+You can also generate your own platform profile using the [PSCompatibilityCollector module][01].
+
+The compatibility profile settings takes a list of platforms to target under `TargetProfiles`. A
+platform can be specified as:
+
+- A platform name (like `ubuntu_x64_18.04_6.1.1_x64_4.0.30319.42000_core`), which will have `.json`
+  added to the end and is searched for in the default profile directory.
+- A filename (like `my_custom_platform.json`), which will be searched for the in the default profile
+  directory.
+- An absolute path to a file (like `D:\PowerShellProfiles\TargetMachine.json`).
+
+The default profile directory is under the PSScriptAnalzyer module at
+`$PSScriptRoot/PSCompatibilityCollector/profiles` (where `$PSScriptRoot` here refers to the
+directory containing `PSScriptAnalyzer.psd1`).
+
+The compatibility analysis compares a type used to both a target profile and a 'union' profile
+(containing all types available in _any_ profile in the profile dir). If a type is not present in
+the union profile, it is assumed to be locally created and ignored. Otherwise, if a type is present
+in the union profile but not present in a target, it is deemed to be incompatible with that target.
+
+## Configuration settings
+
+| Configuration key |                                     Meaning                                      |                                     Accepted values                                     |                                   Mandatory                                   |                                                            Example                                                            |
+| ----------------- | -------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- |
+| `Enable`          | Activates the rule                                                               | bool (`$true`/`$false`)                                                                 | No (default: `$false`)                                                        | `$true`                                                                                                                       |
+| `TargetProfiles`  | The list of PowerShell profiles to target                                        | string[]: absolute paths to profile files or names of profiles in the profile directory | No (default: `@()`)                                                           | `@('ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core', 'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')` |
+| `ProfileDirPath`  | The location to search for profiles by name and use for union profile generation | string: absolute path to new profile dir                                                | No (defaults to `compatibility_profiles` directory in PSScriptAnalyzer module | `C:\Users\me\Documents\pssaCompatProfiles`                                                                                    |
+| `IgnoreTypes`     | Full names of types or type accelerators to ignore compatibility of in scripts   | string[]: names of types to ignore                                                      | No (default: `@()`)                                                           | `@('System.Collections.ArrayList','string')`                                                                                  |
+
+An example configuration might look like:
+
+```powershell
+@{
+    Rules = @{
+        PSUseCompatibleTypes = @{
+            Enable = $true
+            TargetProfiles = @(
+                'ubuntu_x64_18.04_6.1.3_x64_4.0.30319.42000_core'
+                'win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework'
+                'MyProfile'
+                'another_custom_profile_in_the_profiles_directory.json'
+                'D:\My Profiles\profile1.json'
+            )
+            # You can specify types to not check like this, which will also ignore methods and members on it:
+            IgnoreTypes = @(
+                'System.IO.Compression.ZipFile'
+            )
+        }
+    }
+}
+```
+
+Alternatively, you could provide a settings object as follows:
+
+```powershell
+PS> $settings = @{
+      Rules = @{
+        PSUseCompatibleTypes = @{
+          Enable = $true
+          TargetProfiles = @('win-48_x64_10.0.17763.0_5.1.17763.316_x64_4.0.30319.42000_framework')
+        }
+      }
+}
+PS> Invoke-ScriptAnalyzer -Settings $settings -ScriptDefinition "[System.Management.Automation.SemanticVersion]'1.18.0-rc1'"
+
+RuleName                Severity     ScriptName Line  Message
+--------                --------     ---------- ----  -------
+PSUseCompatibleTypes    Warning                 1     The type 'System.Management.Automation.SemanticVersion' is
+                                                      not available by default in PowerShell version
+                                                      '5.1.17763.316' on platform 'Microsoft Windows 10 Pro'
+```
+
+## Suppression
+
+Command compatibility diagnostics can be suppressed with an attribute on the `param` block of a
+scriptblock as with other rules.
+
+```powershell
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleTypes', '')]
+```
+
+The rule can also be suppressed only for particular types:
+
+```powershell
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleTypes',
+    'System.Management.Automation.Security.SystemPolicy')]
+```
+
+And also suppressed only for type members:
+
+```powershell
+[System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseCompatibleCommands',
+    'System.Management.Automation.LanguagePrimitives/ConvertTypeNameToPSTypeName')]
+```
+
+<!-- link references -->
+[01]: https://github.com/PowerShell/PSScriptAnalyzer/tree/main/PSCompatibilityCollector
+[02]: https://github.com/PowerShell/PSScriptAnalyzer/tree/main/PSCompatibilityCollector/optional_profiles
diff --git a/RuleDocumentation/UseConsistentIndentation.md b/docs/Rules/UseConsistentIndentation.md
similarity index 70%
rename from RuleDocumentation/UseConsistentIndentation.md
rename to docs/Rules/UseConsistentIndentation.md
index 81ff32ca8..f084d5ac4 100644
--- a/RuleDocumentation/UseConsistentIndentation.md
+++ b/docs/Rules/UseConsistentIndentation.md
@@ -1,3 +1,9 @@
+---
+description: Use consistent indentation
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseConsistentIndentation
+---
 # UseConsistentIndentation
 
 **Severity Level: Warning**
@@ -35,29 +41,38 @@ Indentation size in the number of space characters.
 
 Whether to increase indentation after a pipeline for multi-line statements. The settings are:
 
-- IncreaseIndentationForFirstPipeline (default): Indent once after the first pipeline and keep this indentation. Example:
-```powershell
-foo |
-    bar |
-    baz
-```
-- IncreaseIndentationAfterEveryPipeline: Indent more after the first pipeline and keep this indentation. Example:
-```powershell
-foo |
-    bar |
-        baz
-```
+- IncreaseIndentationForFirstPipeline (default): Indent once after the first pipeline and keep this
+  indentation. Example:
+
+  ```powershell
+  foo |
+      bar |
+      baz
+  ```
+
+- IncreaseIndentationAfterEveryPipeline: Indent more after the first pipeline and keep this
+  indentation. Example:
+
+  ```powershell
+  foo |
+      bar |
+          baz
+  ```
+
 - NoIndentation: Do not increase indentation. Example:
-```powershell
-foo |
-bar |
-baz
-```
+
+  ```powershell
+  foo |
+  bar |
+  baz
+  ```
+
 - None: Do not change any existing pipeline indentation.
 
 #### Kind: string (Default value is `space`)
 
-Represents the kind of indentation to be used. Possible values are: `space`, `tab`. If any invalid value is given, the property defaults to `space`.
+Represents the kind of indentation to be used. Possible values are: `space`, `tab`. If any invalid
+value is given, the property defaults to `space`.
 
-`space` means `IndentationSize` number of `space` characters are used to provide one level of indentation.
-`tab` means a tab character, `\t`.
+`space` means `IndentationSize` number of `space` characters are used to provide one level of
+indentation. `tab` means a tab character, `\t`.
diff --git a/docs/Rules/UseConsistentWhitespace.md b/docs/Rules/UseConsistentWhitespace.md
new file mode 100644
index 000000000..e36c42783
--- /dev/null
+++ b/docs/Rules/UseConsistentWhitespace.md
@@ -0,0 +1,85 @@
+---
+description: Use whitespaces
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseConsistentWhitespace
+---
+# UseConsistentWhitespace
+
+**Severity Level: Warning**
+
+## Description
+
+This rule is not enabled by default. The user needs to enable it through settings.
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSUseConsistentWhitespace  = @{
+        Enable                          = $true
+        CheckInnerBrace                 = $true
+        CheckOpenBrace                  = $true
+        CheckOpenParen                  = $true
+        CheckOperator                   = $true
+        CheckPipe                       = $true
+        CheckPipeForRedundantWhitespace = $false
+        CheckSeparator                  = $true
+        CheckParameter                  = $false
+        IgnoreAssignmentOperatorInsideHashTable = $false
+    }
+}
+```
+
+### Enable: bool (Default value is `$false`)
+
+Enable or disable the rule during ScriptAnalyzer invocation.
+
+### CheckInnerBrace: bool (Default value is `$true`)
+
+Checks if there is a space after the opening brace and a space before the closing brace. E.g.
+`if ($true) { foo }` instead of `if ($true) {bar}`.
+
+### CheckOpenBrace: bool (Default value is `$true`)
+
+Checks if there is a space between a keyword and its corresponding open brace. E.g. `foo { }`
+instead of `foo{ }`. If an open brace is preceded by an open parenthesis, then no space is required.
+
+### CheckOpenParen: bool (Default value is `$true`)
+
+Checks if there is space between a keyword and its corresponding open parenthesis. E.g. `if (true)`
+instead of `if(true)`.
+
+### CheckOperator: bool (Default value is `$true`)
+
+Checks if a binary or unary operator is surrounded on both sides by a space. E.g. `$x = 1` instead
+of `$x=1`.
+
+### CheckSeparator: bool (Default value is `$true`)
+
+Checks if a comma or a semicolon is followed by a space. E.g. `@(1, 2, 3)` or `@{a = 1; b = 2}`
+instead of `@(1,2,3)` or `@{a = 1;b = 2}`.
+
+### CheckPipe: bool (Default value is `$true`)
+
+Checks if a pipe is surrounded on both sides by a space but ignores redundant whitespace. E.g.
+`foo | bar` instead of `foo|bar`.
+
+### CheckPipeForRedundantWhitespace : bool (Default value is `$false`)
+
+Checks if a pipe is surrounded by redundant whitespace (i.e. more than 1 whitespace). E.g.
+`foo | bar` instead of `foo    |    bar`.
+
+### CheckParameter: bool (Default value is `$false` at the moment due to the setting being new)
+
+Checks if there is more than one space between parameters and values. E.g. `foo -bar $baz -bat`
+instead of `foo   -bar   $baz   -bat`. This eliminates redundant whitespace that was probably added
+unintentionally. The rule does not check for whitespace between parameter and value when the colon
+syntax `-ParameterName:$ParameterValue` is used as some users prefer either 0 or 1 whitespace in
+this case.
+
+### IgnoreAssignmentOperatorInsideHashTable: bool (Default value is `$false`)
+
+When `CheckOperator` is set, ignore whitespace around assignment operators within multi-line hash
+tables. Set this option to use the `AlignAssignmentStatement` rule and still check whitespace around
+operators everywhere else.
diff --git a/docs/Rules/UseCorrectCasing.md b/docs/Rules/UseCorrectCasing.md
new file mode 100644
index 000000000..1874a7a84
--- /dev/null
+++ b/docs/Rules/UseCorrectCasing.md
@@ -0,0 +1,75 @@
+---
+description: Use exact casing of cmdlet/function/parameter name.
+ms.date: 03/19/2025
+ms.topic: reference
+title: UseCorrectCasing
+---
+# UseCorrectCasing
+
+**Severity Level: Information**
+
+## Description
+
+This is a style/formatting rule. PowerShell is case insensitive wherever possible, so the casing of
+cmdlet names, parameters, keywords and operators does not matter. This rule nonetheless ensures
+consistent casing for clarity and readability. Using lowercase keywords helps distinguish them from
+commands. Using lowercase operators helps distinguish them from parameters.
+
+## How
+
+- Use exact casing for type names.
+- Use exact casing of the cmdlet and its parameters.
+- Use lowercase for language keywords and operators.
+
+## Configuration
+
+```powershell
+Rules = @{
+    PS UseCorrectCasing = @{
+        Enable        = $true
+        CheckCommands = $true
+        CheckKeyword  = $true
+        CheckOperator = $true
+    }
+}
+```
+
+### Parameters
+
+#### Enable: bool (Default value is `$false`)
+
+Enable or disable the rule during ScriptAnalyzer invocation.
+
+#### CheckCommands: bool (Default value is `$true`)
+
+If true, require the case of all operators to be lowercase.
+
+#### CheckKeyword: bool (Default value is `$true`)
+
+If true, require the case of all keywords to be lowercase.
+
+#### CheckOperator: bool (Default value is `$true`)
+
+If true, require the case of all commands to match their actual casing.
+
+## Examples
+
+### Wrong way
+
+```powershell
+ForEach ($file in Get-childitem -Recurse) {
+    $file.Extension -eq '.txt'
+}
+
+invoke-command { 'foo' } -runasadministrator
+```
+
+### Correct way
+
+```powershell
+foreach ($file in Get-ChildItem -Recurse) {
+    $file.Extension -eq '.txt'
+}
+
+Invoke-Command { 'foo' } -RunAsAdministrator
+```
diff --git a/docs/Rules/UseDeclaredVarsMoreThanAssignments.md b/docs/Rules/UseDeclaredVarsMoreThanAssignments.md
new file mode 100644
index 000000000..e316dbf85
--- /dev/null
+++ b/docs/Rules/UseDeclaredVarsMoreThanAssignments.md
@@ -0,0 +1,72 @@
+---
+description: Extra Variables
+ms.date: 03/06/2024
+ms.topic: reference
+title: UseDeclaredVarsMoreThanAssignments
+---
+# UseDeclaredVarsMoreThanAssignments
+
+**Severity Level: Warning**
+
+## Description
+
+Variables that are assigned but not used are not needed.
+
+> [!NOTE]
+> For this rule, the variable must be used within the same scriptblock that it was declared or it
+> won't be considered to be 'used'.
+
+## How
+
+Remove the variables that are declared but not used.
+
+## Example
+
+### Wrong
+
+```powershell
+function Test
+{
+    $declaredVar = 'Declared just for fun'
+    $declaredVar2 = 'Not used'
+    Write-Output $declaredVar
+}
+```
+
+### Correct
+
+```powershell
+function Test
+{
+    $declaredVar = 'Declared just for fun'
+    Write-Output $declaredVar
+}
+```
+
+### Special cases
+
+The following examples trigger the **PSUseDeclaredVarsMoreThanAssignments** warning. This behavior
+is a limitation of the rule. There is no way to avoid these false positive warnings.
+
+In this case, the warning is triggered because `$bar` is not used within the scriptblock where it
+was defined.
+
+```powershell
+$foo | ForEach-Object {
+    if ($_ -eq $false) {
+        $bar = $true
+    }
+}
+
+if($bar){
+    Write-Host 'Collection contained a false case.'
+}
+```
+
+In the next example, the warning is triggered because `$errResult` isn't recognized as being used in
+the `Write-Host` command.
+
+```powershell
+$errResult = $null
+Write-Host 'Ugh:' -ErrorVariable errResult
+```
diff --git a/docs/Rules/UseLiteralInitializerForHashtable.md b/docs/Rules/UseLiteralInitializerForHashtable.md
new file mode 100644
index 000000000..16f9a2f9b
--- /dev/null
+++ b/docs/Rules/UseLiteralInitializerForHashtable.md
@@ -0,0 +1,43 @@
+---
+description: Create hashtables with literal initializers
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseLiteralInitializerForHashtable
+---
+# UseLiteralInitializerForHashtable
+
+**Severity Level: Warning**
+
+## Description
+
+Creating a hashtable using `[hashtable]::new()` or `New-Object -TypeName hashtable` without passing
+a `IEqualityComparer` object to the constructor creates a hashtable where the keys are looked-up in
+a case-sensitive manner. However, PowerShell is case-insensitive in nature and it is best to create
+hashtables with case-insensitive key look-up.
+
+This rule is intended to warn the author of the case-sensitive nature of the hashtable when created
+using the `new` method or the `New-Object` cmdlet.
+
+## How to Fix
+
+Create the hashtable using a literal hashtable expression.
+
+## Example
+
+### Wrong
+
+```powershell
+$hashtable = [hashtable]::new()
+```
+
+### Wrong
+
+```powershell
+$hashtable = New-Object -TypeName hashtable
+```
+
+### Correct
+
+```powershell
+$hashtable = @{}
+```
diff --git a/RuleDocumentation/UseOutputTypeCorrectly.md b/docs/Rules/UseOutputTypeCorrectly.md
similarity index 73%
rename from RuleDocumentation/UseOutputTypeCorrectly.md
rename to docs/Rules/UseOutputTypeCorrectly.md
index c4c0d1892..733425fdd 100644
--- a/RuleDocumentation/UseOutputTypeCorrectly.md
+++ b/docs/Rules/UseOutputTypeCorrectly.md
@@ -1,3 +1,9 @@
+---
+description: Use OutputType Correctly
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseOutputTypeCorrectly
+---
 # UseOutputTypeCorrectly
 
 **Severity Level: Information**
@@ -6,7 +12,8 @@
 
 A command should return the same type as declared in `OutputType`.
 
-You can get more details by running `Get-Help about_Functions_OutputTypeAttribute` command in Windows PowerShell.
+You can get more details by running `Get-Help about_Functions_OutputTypeAttribute` command in
+PowerShell.
 
 ## How
 
@@ -16,7 +23,7 @@ Specify that the OutputType attribute lists and the types returned in the cmdlet
 
 ### Wrong
 
-``` PowerShell
+```powershell
 function Get-Foo
 {
         [CmdletBinding()]
@@ -29,7 +36,7 @@ function Get-Foo
 
 ### Correct
 
-``` PowerShell
+```powershell
 function Get-Foo
 {
         [CmdletBinding()]
@@ -37,6 +44,6 @@ function Get-Foo
         Param(
         )
 
-        return "four"
+        return 'four'
 }
 ```
diff --git a/docs/Rules/UsePSCredentialType.md b/docs/Rules/UsePSCredentialType.md
new file mode 100644
index 000000000..c962762ed
--- /dev/null
+++ b/docs/Rules/UsePSCredentialType.md
@@ -0,0 +1,38 @@
+---
+description: Use PSCredential type.
+ms.date: 06/28/2023
+ms.topic: reference
+title: UsePSCredentialType
+---
+# UsePSCredentialType
+
+**Severity Level: Warning**
+
+## Description
+
+If the cmdlet or function has a **Credential** parameter, the parameter must accept the
+**PSCredential** type.
+
+## How
+
+Change the **Credential** parameter's type to be **PSCredential**.
+
+## Example
+
+### Wrong
+
+```powershell
+function Credential([String]$Credential)
+{
+    ...
+}
+```
+
+### Correct
+
+```powershell
+function Credential([PSCredential]$Credential)
+{
+    ...
+}
+```
diff --git a/docs/Rules/UseProcessBlockForPipelineCommand.md b/docs/Rules/UseProcessBlockForPipelineCommand.md
new file mode 100644
index 000000000..2e5630880
--- /dev/null
+++ b/docs/Rules/UseProcessBlockForPipelineCommand.md
@@ -0,0 +1,70 @@
+---
+description: Use process block for command that accepts input from pipeline.
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseProcessBlockForPipelineCommand
+---
+# UseProcessBlockForPipelineCommand
+
+**Severity Level: Warning**
+
+## Description
+
+Functions that support pipeline input should always handle parameter input in a process block.
+Unexpected behavior can result if input is handled directly in the body of a function where
+parameters declare pipeline support.
+
+## Example
+
+### Wrong
+
+```powershell
+Function Get-Number
+{
+    [CmdletBinding()]
+    Param(
+        [Parameter(ValueFromPipeline)]
+        [int]
+        $Number
+    )
+
+    $Number
+}
+```
+
+#### Result
+
+```
+PS C:\> 1..5 | Get-Number
+5
+```
+
+### Correct
+
+```powershell
+Function Get-Number
+{
+    [CmdletBinding()]
+    Param(
+        [Parameter(ValueFromPipeline)]
+        [int]
+        $Number
+    )
+
+    process
+    {
+        $Number
+    }
+}
+```
+
+#### Result
+
+```
+PS C:\> 1..5 | Get-Number
+1
+2
+3
+4
+5
+```
diff --git a/docs/Rules/UseShouldProcessForStateChangingFunctions.md b/docs/Rules/UseShouldProcessForStateChangingFunctions.md
new file mode 100644
index 000000000..97bb97767
--- /dev/null
+++ b/docs/Rules/UseShouldProcessForStateChangingFunctions.md
@@ -0,0 +1,78 @@
+---
+description: Use ShouldProcess For State Changing Functions
+ms.date: 12/05/2024
+ms.topic: reference
+title: UseShouldProcessForStateChangingFunctions
+---
+# UseShouldProcessForStateChangingFunctions
+
+**Severity Level: Warning**
+
+## Description
+
+Functions whose verbs change system state should support `ShouldProcess`. To enable the
+`ShouldProcess` feature, set the `SupportsShouldProcess` argument in the `CmdletBinding` attribute.
+The `SupportsShouldProcess` argument adds **Confirm** and **WhatIf** parameters to the function. The
+**Confirm** parameter prompts the user before it runs the command on each object in the pipeline.
+The **WhatIf** parameter lists the changes that the command would make, instead of running the
+command.
+
+Verbs that should support `ShouldProcess`:
+
+- `New`
+- `Set`
+- `Remove`
+- `Start`
+- `Stop`
+- `Restart`
+- `Reset`
+- `Update`
+
+## How
+
+Include the `SupportsShouldProcess` argument in the `CmdletBinding` attribute.
+
+## Example
+
+### Wrong
+
+```powershell
+function Set-ServiceObject
+{
+    [CmdletBinding()]
+    param
+    (
+        [string]
+        $Parameter1
+    )
+    ...
+}
+```
+
+### Correct
+
+```powershell
+function Set-ServiceObject
+{
+    [CmdletBinding(SupportsShouldProcess = $true)]
+    param
+    (
+        [string]
+        $Parameter1
+    )
+    ...
+}
+```
+
+## More information
+
+- [about_Functions_CmdletBindingAttribute][01]
+- [Everything you wanted to know about ShouldProcess][04]
+- [Required Development Guidelines][03]
+- [Requesting Confirmation from Cmdlets][02]
+
+<!-- link references -->
+[01]: https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_functions_cmdletbindingattribute
+[02]: https://learn.microsoft.com/powershell/scripting/developer/cmdlet/requesting-confirmation-from-cmdlets
+[03]: https://learn.microsoft.com/powershell/scripting/developer/cmdlet/required-development-guidelines#support-confirmation-requests-rd04
+[04]: https://learn.microsoft.com/powershell/scripting/learn/deep-dives/everything-about-shouldprocess
diff --git a/docs/Rules/UseSingularNouns.md b/docs/Rules/UseSingularNouns.md
new file mode 100644
index 000000000..3997c069a
--- /dev/null
+++ b/docs/Rules/UseSingularNouns.md
@@ -0,0 +1,67 @@
+---
+description: Cmdlet Singular Noun
+ms.date: 03/27/2024
+ms.topic: reference
+title: UseSingularNouns
+---
+# UseSingularNouns
+
+**Severity Level: Warning**
+
+## Description
+
+PowerShell team best practices state cmdlets should use singular nouns and not plurals. Suppression
+allows you to suppress the rule for specific function names. For example:
+
+```
+function Get-Elements {
+    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute('PSUseSingularNouns', 'Get-Elements')]
+    Param()
+}
+```
+
+## Configuration
+
+```powershell
+Rules = @{
+    PSUseSingularNouns = @{
+        Enable           = $true
+        NounAllowList    = 'Data', 'Windows', 'Foos'
+    }
+}
+```
+
+### Parameters
+
+- `Enable`: `bool` (Default value is `$true`)
+
+  Enable or disable the rule during ScriptAnalyzer invocation.
+
+- `NounAllowList`: `string[]` (Default value is `{'Data', 'Windows'}`)
+
+  Commands to be excluded from this rule. `Data` and `Windows` are common false positives and are
+  excluded by default.
+
+## How
+
+Change plurals to singular.
+
+## Example
+
+### Wrong
+
+```powershell
+function Get-Files
+{
+    ...
+}
+```
+
+### Correct
+
+```powershell
+function Get-File
+{
+    ...
+}
+```
diff --git a/docs/Rules/UseSupportsShouldProcess.md b/docs/Rules/UseSupportsShouldProcess.md
new file mode 100644
index 000000000..904ad0773
--- /dev/null
+++ b/docs/Rules/UseSupportsShouldProcess.md
@@ -0,0 +1,42 @@
+---
+description: Use SupportsShouldProcess
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseSupportsShouldProcess
+---
+# UseSupportsShouldProcess
+
+**Severity Level: Warning**
+
+## Description
+
+This rule discourages manual declaration of `WhatIf` and `Confirm` parameters in a function/cmdlet.
+These parameters are, however, provided automatically when a function declares a `CmdletBinding`
+attribute with `SupportsShouldProcess` as its named argument. Using `SupportsShouldProcess` not only
+provides these parameters but also some generic functionality that allows the function/cmdlet
+authors to provide the desired interactive experience while using the cmdlet.
+
+## Example
+
+### Wrong
+
+```powershell
+function foo {
+    param(
+        $param1,
+        $Confirm,
+        $WhatIf
+    )
+}
+```
+
+### Correct
+
+```powershell
+function foo {
+    [CmdletBinding(SupportsShouldProcess)]
+    param(
+        $param1
+    )
+}
+```
diff --git a/docs/Rules/UseToExportFieldsInManifest.md b/docs/Rules/UseToExportFieldsInManifest.md
new file mode 100644
index 000000000..5faaf9d1b
--- /dev/null
+++ b/docs/Rules/UseToExportFieldsInManifest.md
@@ -0,0 +1,59 @@
+---
+description: Use the *ToExport module manifest fields.
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseToExportFieldsInManifest
+---
+# UseToExportFieldsInManifest
+
+**Severity Level: Warning**
+
+## Description
+
+To improve the performance of module auto-discovery, module manifests should not use wildcards
+(`'*'`) or null (`$null`) in the following entries:
+
+- `AliasesToExport`
+- `CmdletsToExport`
+- `FunctionsToExport`
+- `VariablesToExport`
+
+Using wildcards or null has causes PowerShell to perform expensive work to analyze a module during
+module auto-discovery.
+
+## How
+
+Use an explicit list in the entries.
+
+## Example 1
+
+Suppose there are no functions in your module to export. Then,
+
+### Wrong
+
+```powershell
+FunctionsToExport = $null
+```
+
+### Correct
+
+```powershell
+FunctionToExport = @()
+```
+
+## Example 2
+
+Suppose there are only two functions in your module, `Get-Foo` and `Set-Foo` that you want to
+export. Then,
+
+### Wrong
+
+```powershell
+FunctionsToExport = '*'
+```
+
+### Correct
+
+```powershell
+FunctionToExport = @(Get-Foo, Set-Foo)
+```
diff --git a/docs/Rules/UseUTF8EncodingForHelpFile.md b/docs/Rules/UseUTF8EncodingForHelpFile.md
new file mode 100644
index 000000000..6d8e0f3c2
--- /dev/null
+++ b/docs/Rules/UseUTF8EncodingForHelpFile.md
@@ -0,0 +1,33 @@
+---
+description: Use UTF8 Encoding For Help File
+ms.date: 01/07/2025
+ms.topic: reference
+title: UseUTF8EncodingForHelpFile
+---
+# UseUTF8EncodingForHelpFile
+
+**Severity Level: Warning**
+
+## Description
+
+Check that an `about_` help file uses UTF-8 encoding. The filename must start with `about_` and end
+with `.help.txt`. The rule uses the **CurrentEncoding** property of the **StreamReader** class to
+determine the encoding of the file.
+
+## How
+
+For PowerShell commands that write to files, ensure that you set the encoding parameter to `utf8`,
+`utf8BOM`, or `utf8NoBOM`.
+
+When you create a help file using a text editor, ensure that the editor is configured to save the
+file in a UTF8 format. Consult the documentation for your text editor for instructions on how to
+save files with a specific encoding.
+
+## Further reading
+
+For more information, see the following articles:
+
+- [System.IO.StreamReader](https://learn.microsoft.com/dotnet/api/system.io.streamreader.currentencoding)
+- [about_Character_Encoding](https://learn.microsoft.com/powershell/module/microsoft.powershell.core/about/about_character_encoding)
+- [Set-Content](https://learn.microsoft.com/powershell/module/microsoft.powershell.management/set-content)
+- [Understanding file encoding in VS Code and PowerShell](https://learn.microsoft.com/powershell/scripting/dev-cross-plat/vscode/understanding-file-encoding)
diff --git a/docs/Rules/UseUsingScopeModifierInNewRunspaces.md b/docs/Rules/UseUsingScopeModifierInNewRunspaces.md
new file mode 100644
index 000000000..bde0f667d
--- /dev/null
+++ b/docs/Rules/UseUsingScopeModifierInNewRunspaces.md
@@ -0,0 +1,70 @@
+---
+description: Use 'Using:' scope modifier in RunSpace ScriptBlocks
+ms.date: 06/28/2023
+ms.topic: reference
+title: UseUsingScopeModifierInNewRunspaces
+---
+# UseUsingScopeModifierInNewRunspaces
+
+**Severity Level: Warning**
+
+## Description
+
+If a scriptblock is intended to be run in a new runspace, variables inside it should use the
+`$using:` scope modifier, or be initialized within the scriptblock. This applies to:
+
+- `Invoke-Command`- Only with the **ComputerName** or **Session** parameter.
+- `Workflow { InlineScript {} }`
+- `Foreach-Object` - Only with the **Parallel** parameter
+- `Start-Job`
+- `Start-ThreadJob`
+- The `Script` resource in DSC configurations, specifically for the `GetScript`, `TestScript` and
+  `SetScript` properties.
+
+## How to Fix
+
+Within the ScriptBlock, instead of just using a variable from the parent scope, you have to add the
+`using:` scope modifier to it.
+
+## Example
+
+### Wrong
+
+```powershell
+$var = 'foo'
+1..2 | ForEach-Object -Parallel { $var }
+```
+
+### Correct
+
+```powershell
+$var = 'foo'
+1..2 | ForEach-Object -Parallel { $using:var }
+```
+
+## More correct examples
+
+```powershell
+$bar = 'bar'
+Invoke-Command -ComputerName 'foo' -ScriptBlock { $using:bar }
+```
+
+```powershell
+$bar = 'bar'
+$s = New-PSSession -ComputerName 'foo'
+Invoke-Command -Session $s -ScriptBlock { $using:bar }
+```
+
+```powershell
+# Remark: Workflow is supported on Windows PowerShell only
+Workflow {
+    $foo = 'foo'
+    InlineScript { $using:foo }
+}
+```
+
+```powershell
+$foo = 'foo'
+Start-ThreadJob -ScriptBlock { $using:foo }
+Start-Job -ScriptBlock {$using:foo }
+```
diff --git a/docs/markdown/Get-ScriptAnalyzerRule.md b/docs/markdown/Get-ScriptAnalyzerRule.md
deleted file mode 100644
index 285529e73..000000000
--- a/docs/markdown/Get-ScriptAnalyzerRule.md
+++ /dev/null
@@ -1,168 +0,0 @@
----
-external help file: Microsoft.Windows.PowerShell.ScriptAnalyzer.dll-Help.xml
-schema: 2.0.0
----
-
-# Get-ScriptAnalyzerRule
-## SYNOPSIS
-Gets the script analyzer rules on the local computer.
-
-## SYNTAX
-
-```
-Get-ScriptAnalyzerRule [-CustomRulePath <String>] [-RecurseCustomRulePath] [-Name <String[]>]
- [-Severity <String[]>]
-```
-
-## DESCRIPTION
-Gets the script analyzer rules on the local computer.
-You can select rules by Name, Severity, Source, or SourceType, or even particular words in the rule description.
-
-Use this cmdlet to create collections of rules to include and exclude when running the Invoke-ScriptAnalyzer cmdlet.
-
-To get information about the rules, see the value of the Description property of each rule.
-
-The PSScriptAnalyzer module tests the Windows PowerShell code in a script, module, or DSC resource to determine whether, and to what extent, it fulfils best practice standards.
-
-PSScriptAnalyzer is an open-source project.
-For more information about PSScriptAnalyzer, to contribute or file an issue, see GitHub.com\PowerShell\PSScriptAnalyzer.
-
-## EXAMPLES
-
-### -------------------------- EXAMPLE 1 --------------------------
-```
-Get-ScriptAnalyzerRule
-```
-
-This command gets all Script Analyzer rules on the local computer.
-
-### -------------------------- EXAMPLE 2 --------------------------
-```
-Get-ScriptAnalyzerRule -Severity Error
-```
-
-This command gets only rules with the Error severity.
-
-### -------------------------- EXAMPLE 3 --------------------------
-```
-$DSCError = Get-ScriptAnalyzerRule -Severity Error | Where SourceName -eq PSDSC
-
-PS C:\>$Path = "$home\Documents\WindowsPowerShell\Modules\MyDSCModule\*"
-
-PS C:\> Invoke-ScriptAnalyzerRule -Path $Path -IncludeRule $DSCError -Recurse
-```
-
-This example runs only the DSC rules with the Error severity on the files in the MyDSCModule module.
-
-Using the IncludeRule parameter of Invoke-ScriptAnalyzerRule is much more efficient than using its Severity parameter, which is applied only after using all rules to analyze all module files.
-
-### -------------------------- EXAMPLE 4 --------------------------
-```
-$TestParameters = Get-ScriptAnalyzerRule -Severity Error, Warning -Name *Parameter*, *Alias*
-```
-
-This command gets rules with "Parameter" or "Alias" in the name that generate an Error or Warning.
-Use this set of rules to test the parameters of your script or module.
-
-### -------------------------- EXAMPLE 5 --------------------------
-```
-Get-ScriptAnalyzerRule -CustomRulePath $home\Documents\WindowsPowerShell\Modules\*StrictRules -RecurseCustomRulePath
-```
-
-This command gets the standard rules and the rules in the VeryStrictRules and ExtremelyStrictRules modules.
-The command uses the RecurseCustomRulePath parameter to get rules defined in subdirectories of the matching paths.
-
-## PARAMETERS
-
-### -CustomRulePath
-Gets the Script Analyzer rules in the specified path in addition to the standard Script Analyzer rules.
-By default, PSScriptAnalyzer gets only the standard rules specified in the Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll file in the module.
-
-Enter the path to a .NET assembly or module that contains Script Analyzer rules.
-You can enter only one value, but wildcards are supported.
-To get rules in subdirectories of the path, use the RecurseCustomRulePath parameter.
-
-You can create custom rules by using a custom .NET assembly or a Windows PowerShell module, such as the Community Analyzer Rules in
-https://github.com/PowerShell/PSScriptAnalyzer/blob/development/Tests/Engine/CommunityAnalyzerRules/CommunityAnalyzerRules.psm1.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases: CustomizedRulePath
-
-Required: False
-Position: Named
-Default value: The rules in Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll.
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -RecurseCustomRulePath
-Searches the CustomRulePath location recursively to add rules defined in files in subdirectories of the path.
-By default, Get-ScriptAnalyzerRule adds only the custom rules in the specified path.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Name
-Gets only rules with the specified names or name patterns.
-Wildcards are supported.
-If you list multiple names or patterns, it gets rules that match any of the name patterns, as though the name patterns were joined by an OR.
-
-By default, Get-ScriptAnalyzerRule gets all rules.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: All rules
-Accept pipeline input: False
-Accept wildcard characters: True
-```
-
-### -Severity
-Gets only rules with the specified severity values.
-Valid values are Information, Warning, and Error.
-By default, Get-ScriptAnalyzerRule gets all rules.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: All rules
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-## INPUTS
-
-### None
-You cannot pipe input to this cmdlet.
-
-## OUTPUTS
-
-### Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.RuleInfo
-The RuleInfo object is a custom object created especially for Script Analyzer. It is not documented on MSDN.
-
-## NOTES
-
-## RELATED LINKS
-
-[Invoke-ScriptAnalyzer]()
-
-[PSScriptAnalyzer on GitHub](https://github.com/PowerShell/PSScriptAnalyzer)
diff --git a/docs/markdown/Invoke-Formatter.md b/docs/markdown/Invoke-Formatter.md
deleted file mode 100644
index acbacc091..000000000
--- a/docs/markdown/Invoke-Formatter.md
+++ /dev/null
@@ -1,118 +0,0 @@
----
-external help file: Microsoft.Windows.PowerShell.ScriptAnalyzer.dll-Help.xml
-schema: 2.0.0
----
-
-# Invoke-Formatter
-## SYNOPSIS
-Formats a script text based on the input settings or default settings.
-
-## SYNTAX
-
-```
-Invoke-Formatter [-ScriptDefinition] <String> [-Settings <object>] [-Range <int[]>]
-```
-
-## DESCRIPTION
-
-The Invoke-Formatter cmdlet takes a string parameter named ScriptDefinition and formats it according to the input settings parameter Settings. If no Settings parameter is provided, the cmdlet assumes the default code formatting settings as defined in Settings/CodeFormatting.psd1.
-
-## EXAMPLES
-
-### -------------------------- EXAMPLE 1 --------------------------
-```
-$scriptDefinition = @'
-function foo {
-"hello"
-  }
-'@
-
-Invoke-Formatter -ScriptDefinition $scriptDefinition
-```
-
-This command formats the input script text using the default settings.
-
-### -------------------------- EXAMPLE 2 --------------------------
-```
-$scriptDefinition = @'
-function foo {
-"hello"
-}
-'@
-
-$settings = @{
-    IncludeRules = @("PSPlaceOpenBrace", "PSUseConsistentIndentation")
-    Rules = @{
-        PSPlaceOpenBrace = @{
-            Enable = $true
-            OnSameLine = $false
-        }
-        PSUseConsistentIndentation = @{
-            Enable = $true
-        }
-    }
-}
-
-Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings $settings
-```
-
-This command formats the input script text using the settings defined in the $settings hashtable.
-
-### -------------------------- EXAMPLE 3 --------------------------
-```
-Invoke-Formatter -ScriptDefinition $scriptDefinition -Settings /path/to/settings.psd1
-```
-
-This command formats the input script text using the settings defined in the settings.psd1 file.
-
-## PARAMETERS
-
-### -ScriptDefinition
-The script text to be formated.
-
-*NOTE*: Unlike ScriptBlock parameter, the ScriptDefinition parameter require a string value.
-
-```yaml
-Type: String
-Parameter Sets: (All)
-Aliases:
-
-Required: True
-Position: 1
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Settings
-A settings hashtable or a path to a PowerShell data file (.psd1) file that contains the settings.
-
-```yaml
-Type: Object
-Parameter Sets: (All)
-
-Required: False
-Position: 2
-Default value: CodeFormatting
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Range
-The range within which formatting should take place. The parameter is an array of integers of length 4 such that the first, second, third and last elements correspond to the start line number, start column number, end line number and end column number. These numbers must be greater than 0.
-
-```yaml
-Type: Int32[]
-Parameter Sets: (All)
-
-Required: False
-Position: 3
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-## OUTPUTS
-
-### System.String
-The formatted string result.
diff --git a/docs/markdown/Invoke-ScriptAnalyzer.md b/docs/markdown/Invoke-ScriptAnalyzer.md
deleted file mode 100644
index 4150da099..000000000
--- a/docs/markdown/Invoke-ScriptAnalyzer.md
+++ /dev/null
@@ -1,539 +0,0 @@
----
-external help file: Microsoft.Windows.PowerShell.ScriptAnalyzer.dll-Help.xml
-schema: 2.0.0
----
-
-# Invoke-ScriptAnalyzer
-## SYNOPSIS
-Evaluates a script or module based on selected best practice rules
-
-## SYNTAX
-
-### UNNAMED_PARAMETER_SET_1
-```
-Invoke-ScriptAnalyzer [-Path] <String> [-CustomRulePath <String>] [-RecurseCustomRulePath]
- [-ExcludeRule <String[]>] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-Fix] [-EnableExit] [-ReportSummary]
- [-Settings <String>]
-```
-
-### UNNAMED_PARAMETER_SET_2
-```
-Invoke-ScriptAnalyzer [-ScriptDefinition] <String> [-CustomRulePath <String>] [-RecurseCustomRulePath]
- [-ExcludeRule <String[]>] [-IncludeRule <String[]>] [-Severity <String[]>] [-Recurse] [-SuppressedOnly] [-EnableExit] [-ReportSummary]
- [-Settings <String>]
-```
-
-## DESCRIPTION
-Invoke-ScriptAnalyzer evaluates a script or module files (.ps1, .psm1 and .psd1 files) based on a collection of best practice rules and returns objects
-that represent rule violations. It also includes special rules to analyze DSC resources.
-
-In each evaluation, you can run either all rules or just a specific set using the -IncludeRule parameter and also exclude rules using the -ExcludeRule parameter.
-Invoke-ScriptAnalyzer comes with a set of built-in rules, but you can also use customized rules that you write in
-Windows PowerShell scripts, or compile in assemblies by using C#. This is possible by using the -CustomRulePath parameter and it will then only run those custom rules, if the built-in rules should still be run, then also specify the -IncludeDefaultRules parameter. Custom rules are also supported together with the -IncludeRule and -ExcludeRule parameters. To include multiple custom rules, the -RecurseCustomRulePath parameter can be used.
-
-To analyze your script or module, begin by using the Get-ScriptAnalyzerRule cmdlet to examine and select the rules you
-want to include and/or exclude from the evaluation.
-
-You can also include a rule in the analysis, but suppress the output of that rule for selected functions or scripts.
-This feature should be used only when absolutely necessary.
-To get rules that were suppressed, run Invoke-ScriptAnalyzer with the -SuppressedOnly parameter.
-For instructions on suppressing a rule, see the description of the SuppressedOnly parameter.
-
-For usage in CI systems, the -EnableExit exits the shell with an exit code equal to  the number of error records.
-
-PSScriptAnalyzer is an open-source project.
-For more information about PSScriptAnalyzer, to contribute or file an issue, see GitHub.com\PowerShell\PSScriptAnalyzer.
-
-## EXAMPLES
-
-### -------------------------- EXAMPLE 1 --------------------------
-```
-Invoke-ScriptAnalyzer -Path C:\Scripts\Get-LogData.ps1
-```
-
-This command runs all Script Analyzer rules on the Get-LogData.ps1 script.
-
-### -------------------------- EXAMPLE 2 --------------------------
-```
-Invoke-ScriptAnalyzer -Path $home\Documents\WindowsPowerShell\Modules -Recurse
-```
-
-This command runs all Script Analyzer rules on all .ps1 and .psm1 files in the Modules directory and its
-subdirectories.
-
-### -------------------------- EXAMPLE 3 --------------------------
-```
-Invoke-ScriptAnalyzer -Path C:\Windows\System32\WindowsPowerShell\v1.0\Modules\PSDiagnostics -IncludeRule PSAvoidUsingPositionalParameters
-```
-
-This command runs only the PSAvoidUsingPositionalParameters rule on the files in the PSDiagnostics module.
-You might use a command like this to find all instances of a particular rule violation while working to eliminate it.
-
-### -------------------------- EXAMPLE 4 --------------------------
-```
-Invoke-ScriptAnalyzer -Path C:\ps-test\MyModule -Recurse -ExcludeRule PSAvoidUsingCmdletAliases, PSAvoidUsingInternalURLs
-```
-
-This command runs Script Analyzer on the .ps1 and .psm1 files in the MyModules directory, including the scripts in its subdirectories, with all rules except for PSAvoidUsingCmdletAliases and PSAvoidUsingInternalURLs.
-
-### -------------------------- EXAMPLE 5 --------------------------
-```
-Invoke-ScriptAnalyzer -Path D:\test_scripts\Test-Script.ps1 -CustomRulePath C:\CommunityAnalyzerRules
-```
-
-This command runs Script Analyzer on Test-Script.ps1 with the standard rules and rules in the C:\CommunityAnalyzerRules path.
-
-### -------------------------- EXAMPLE 6 --------------------------
-```
-$DSCError = Get-ScriptAnalyzerRule -Severity Error | Where SourceName -eq PSDSC
-
-PS C:\>$Path = "$home\Documents\WindowsPowerShell\Modules\MyDSCModule"
-
-PS C:\> Invoke-ScriptAnalyzerRule -Path $Path -IncludeRule $DSCError -Recurse
-```
-
-This example runs only the rules that are Error severity and have the PSDSC source name.
-
-### -------------------------- EXAMPLE 7 --------------------------
-```
-function Get-Widgets
-{
-    [CmdletBinding()]
-    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSUseSingularNouns", "")]
-    [System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSAvoidUsingCmdletAliases", "", Justification="Resolution in progress.")]
-    Param()
-
-    dir $pshome
-    ...
-}
-
-PS C:\> Invoke-ScriptAnalyzer -Path .\Get-Widgets.ps1
-
-RuleName                            Severity     FileName   Line  Message
---------                            --------     --------   ----  -------
-PSProvideCommentHelp                Information  ManageProf 14    The cmdlet 'Get-Widget' does not have a help comment.
-                                                 iles.psm1
-
-PS C:\> Invoke-ScriptAnalyzer -Path .\Get-Widgets.ps1 -SuppressedOnly
-
-Rule Name                           Severity     File Name  Line  Justification
----------                           --------     ---------  ----  -------------
-PSAvoidUsingCmdletAliases           Warning      ManageProf 21    Resolution in progress.
-                                                 iles.psm1
-PSUseSingularNouns                  Warning      ManageProf 14
-                                                 iles.psm1
-```
-
-This example shows how to suppress the reporting of rule violations in a function and how to discover rule violations
-that are suppressed.
-
-The example uses the SuppressMessageAttribute attribute to suppress the PSUseSingularNouns and
-PSAvoidUsingCmdletAliases rules for the Get-Widgets function in the Get-Widgets.ps1 script.
-You can use this attribute
-to suppress a rule for a module, script, class, function, parameter, or line.
-
-The first command runs Script Analyzer on the script that contains the Get-Widgets function.
-The output reports a rule
-violation, but neither of the suppressed rules is listed, even though they are violated.
-
-The second command uses the SuppressedOnly parameter to discover the rules that are supressed in the Get-Widgets.ps1
-file.
-The output reports the suppressed rules.
-
-### -------------------------- EXAMPLE 8 --------------------------
-```
-# In .\ScriptAnalyzerProfile.txt
-@{
-    Severity = @('Error', 'Warning')
-    IncludeRules = 'PSAvoid*'
-    ExcludeRules = '*WriteHost'
-}
-
-PS C:\> Invoke-ScriptAnalyzer -Path $pshome\Modules\BitLocker -Profile .\ScriptAnalyzerProfile.txt
-```
-
-In this example, we create a Script Analyzer profile and save it in the ScriptAnalyzerProfile.txt file in the local
-directory.
-
-Next, we run Invoke-ScriptAnalyzer on the BitLocker module files.
-The value of the Profile parameter is the path to the
-Script Analyzer profile.
-
-If you include a conflicting parameter in the Invoke-ScriptAnalyzer command, such as '-Severity Error',
-Invoke-ScriptAnalyzer uses the profile value and ignores the parameter.
-
-### -------------------------- EXAMPLE 9 --------------------------
-```
-Invoke-ScriptAnalyzer -ScriptDefinition "function Get-Widgets {Write-Host 'Hello'}"
-
-RuleName                            Severity     FileName   Line  Message
---------                            --------     --------   ----  -------
-PSAvoidUsingWriteHost               Warning                 1     Script
-                                                                  because
-                                                                  there i
-                                                                  suppres
-                                                                  Write-O
-PSUseSingularNouns                  Warning                 1     The cmd
-                                                                  noun sh
-```
-
-This command uses the ScriptDefinition parameter to analyze a function at the command line.
-The function string is enclosed in quotation marks.
-
-When you use the ScriptDefinition parameter, the FileName property of the DiagnosticRecord object is $null.
-
-## PARAMETERS
-
-### -Path
-Specifies the path to the scripts or module to be analyzed.
-Wildcard characters are supported.
-
-Enter the path to a script (.ps1) or module file (.psm1) or to a directory that contains scripts or modules.
-If the directory contains other types of files, they are ignored.
-
-To analyze files that are not in the root directory of the specified path, use a wildcard character
-(C:\Modules\MyModule\*) or the Recurse parameter.
-
-```yaml
-Type: String
-Parameter Sets: UNNAMED_PARAMETER_SET_1
-Aliases: PSPath
-
-Required: True
-Position: 0
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -CustomRulePath
-Uses only the custom rules defined in the specified paths to the analysis. To still use the built-in rules, add the -IncludeDefaultRules switch.
-
-Enter the path to a file that defines rules or a directory that contains files that define rules.
-Wildcard characters are supported.
-To add rules defined in subdirectories of the path, use the RecurseCustomRulePath parameter.
-
-By default, Invoke-ScriptAnalyzer uses only rules defined in the Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll file in the PSScriptAnalyzer module.
-
-If Invoke-ScriptAnalyzer cannot find rules in the CustomRulePath, it runs the standard rules without notice.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases: CustomizedRulePath
-
-Required: False
-Position: Named
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -RecurseCustomRulePath
-Adds rules defined in subdirectories of the CustomRulePath location.
-By default, Invoke-ScriptAnalyzer uses only the custom rules defined in the specified file or directory.
-To still use the built-in rules, additionally use the -IncludeDefaultRules switch.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -ExcludeRule
-Omits the specified rules from the Script Analyzer test.
-Wildcard characters are supported.
-
-Enter a comma-separated list of rule names, a variable that contains rule names, or a command that gets rule names.
-You can also specify a list of excluded rules in a Script Analyzer profile file.
-You can exclude standard rules and rules in a custom rule path.
-
-When you exclude a rule, the rule does not run on any of the files in the path.
-To exclude a rule on a particular line, parameter, function, script, or class, adjust the Path parameter or suppress the rule.
-For information about suppressing a rule, see the examples.
-
-If a rule is specified in both the ExcludeRule and IncludeRule collections, the rule is excluded.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: All rules are included.
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -IncludeDefaultRules
-Invoke default rules along with Custom rules
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -IncludeRule
-Runs only the specified rules in the Script Analyzer test.
-By default, PSScriptAnalyzer runs all rules.
-
-Enter a comma-separated list of rule names, a variable that contains rule names, or a command that gets rule names.
-Wildcard characters are supported.
-You can also specify rule names in a Script Analyzer profile file.
-
-When you use the CustomizedRulePath parameter, you can use this parameter to include standard rules and rules in the
-custom rule paths.
-
-If a rule is specified in both the ExcludeRule and IncludeRule collections, the rule is excluded.
-
-Also, Severity takes precedence over IncludeRule.
-For example, if Severity is Error, you cannot use IncludeRule to include a Warning rule.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: All rules are included.
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Severity
-After running Script Analyzer with all rules, this parameter selects rule violations with the specified severity.
-
-Valid values are: Error, Warning, and Information.
-You can specify one ore more severity values.
-
-Because this parameter filters the rules only after running with all rules, it is not an efficient filter.
-To filter rules efficiently, use Get-ScriptAnalyzer rule to get the rules you want to run or exclude and
-then use the ExcludeRule or IncludeRule parameters.
-
-Also, Severity takes precedence over IncludeRule.
-For example, if Severity is Error, you cannot use IncludeRule to include a Warning rule.
-
-```yaml
-Type: String[]
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: All rule violations
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Recurse
-Runs Script Analyzer on the files in the Path directory and all subdirectories recursively.
-
-Recurse applies only to the Path parameter value.
-To search the CustomRulePath recursively, use the RecurseCustomRulePath parameter.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -SuppressedOnly
-Returns rules that are suppressed, instead of analyzing the files in the path.
-
-When you used SuppressedOnly, Invoke-ScriptAnalyzer returns a SuppressedRecord object
-(Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.SuppressedRecord).
-
-To suppress a rule, use the SuppressMessageAttribute.
-For help, see the examples.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Fix
-Fixes certain warnings which contain a fix in their DiagnosticRecord.
-
-When you used Fix, Invoke-ScriptAnalyzer runs as usual but will apply the fixes before running the analysis.
-Please make sure that you have a backup of your files when using this switch.
-It tries to preserve the file encoding but there are still some cases where the encoding can change.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: UNNAMED_PARAMETER_SET_1
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -EnableExit
-Exits PowerShell and returns an exit code equal to the number of error records. This can be useful in CI systems.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -ReportSummary
-Writes a report summary of the found warnings to the host.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -Settings
-File path that contains user profile or hash table for ScriptAnalyzer
-
-Runs Invoke-ScriptAnalyzer with the parameters and values specified in a Script Analyzer profile file or hash table
-
-If the path, the file's or hashtable's content are invalid, it is ignored.
-The parameters and values in the profile take precedence over the same parameter and values specified at the command line.
-
-A Script Analyzer profile file is a text file that contains a hash table with one or more of the following keys:
-
--- CustomRulePath
--- ExcludeRules
--- IncludeDefaultRules
--- IncludeRules
--- RecurseCustomRulePath
--- Rules
--- Severity
-
-The keys and values in the profile are interpreted as if they were standard parameters and parameter values of Invoke-ScriptAnalyzer.
-
-To specify a single value, enclose the value in quotation marks.
-For example:
-
-    @{ Severity = 'Error'}
-
-To specify multiple values, enclose the values in an array.
-For example:
-
-    @{ Severity = 'Error', 'Warning'}
-
-A more sophisticated example is:
-
-    @{
-        CustomRulePath='path\to\CustomRuleModule.psm1'
-        IncludeDefaultRules=$true
-        ExcludeRules = @(
-            'PSAvoidUsingWriteHost',
-            'MyCustomRuleName'
-        )
-    }
-
-```yaml
-Type: Object
-Parameter Sets: (All)
-Aliases: Profile
-
-Required: False
-Position: Named
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -ScriptDefinition
-Runs Invoke-ScriptAnalyzer on commands, functions, or expressions in a string.
-You can use this feature to analyze statements, expressions, and functions, independent of their script context.
-
-Unlike ScriptBlock parameters, the ScriptDefinition parameter requires a string value.
-
-```yaml
-Type: String
-Parameter Sets: UNNAMED_PARAMETER_SET_2
-Aliases:
-
-Required: True
-Position: 0
-Default value:
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-### -SaveDscDependency
-Resolve DSC resource dependency
-
-Whenever Invoke-ScriptAnalyzer is run on a script having the dynamic keyword "Import-DSCResource -ModuleName <somemodule>", if <somemodule> is not present in any of the PSModulePath, Invoke-ScriptAnalyzer gives parse error. This error is caused by the powershell parser not being able to find the symbol for <somemodule>. If Invoke-ScriptAnalyzer finds the module in the PowerShell Gallery (www.powershellgallery.com) then it downloads the missing module to a temp path. The temp path is then added to PSModulePath only for duration of the scan. The temp location can be found in $LOCALAPPDATA/PSScriptAnalyzer/TempModuleDir.
-
-```yaml
-Type: SwitchParameter
-Parameter Sets: (All)
-Aliases:
-
-Required: False
-Position: Named
-Default value: False
-Accept pipeline input: False
-Accept wildcard characters: False
-```
-
-
-## INPUTS
-
-### None
-You cannot pipe input to this cmdlet.
-
-## OUTPUTS
-
-### Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.DiagnosticRecord
-By default, Invoke-ScriptAnalyzer returns one DiagnosticRecord object to report a rule violation.
-
-### Microsoft.Windows.PowerShell.ScriptAnalyzer.Generic.SuppressedRecord
-If you use the SuppressedOnly parameter, Invoke-ScriptAnalyzer instead returns a SuppressedRecord object.
-
-## NOTES
-
-## RELATED LINKS
-
-[Get-ScriptAnalyzerRule]()
-
-[PSScriptAnalyzer on GitHub](https://github.com/PowerShell/PSScriptAnalyzer)
diff --git a/global.json b/global.json
index 775c52f92..37239305b 100644
--- a/global.json
+++ b/global.json
@@ -1,5 +1,6 @@
 {
     "sdk": {
-        "version": "3.1.101"
+        "version": "8.0.406",
+        "rollForward": "latestFeature"
     }
 }
diff --git a/tools/appveyor.psm1 b/tools/appveyor.psm1
deleted file mode 100644
index 3997cedfb..000000000
--- a/tools/appveyor.psm1
+++ /dev/null
@@ -1,145 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-
-$ErrorActionPreference = 'Stop'
-
-function Install-Pester {
-    $requiredPesterVersion = '4.10.1'
-    $pester = Get-Module Pester -ListAvailable | Where-Object { $_.Version -eq $requiredPesterVersion }
-    if ($null -eq $pester) {
-        if ($null -eq (Get-Module -ListAvailable PowershellGet)) {
-            # WMF 4 image build
-            Write-Verbose -Verbose "Installing Pester via nuget"
-            nuget install Pester -Version $requiredPesterVersion -source https://www.powershellgallery.com/api/v2 -outputDirectory "$env:ProgramFiles\WindowsPowerShell\Modules\." -ExcludeVersion
-        }
-        else {
-            # Visual Studio 2017 build (has already Pester v3, therefore a different installation mechanism is needed to make it also use the new version 4)
-            Write-Verbose -Verbose "Installing Pester via Install-Module"
-            Install-Module -Name Pester -MaximumVersion 4.99 -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
-        Write-Verbose -Verbose "Installing platyPS via nuget"
-        nuget install platyPS -source https://www.powershellgallery.com/api/v2 -outputDirectory "$Env:ProgramFiles\WindowsPowerShell\Modules\." -ExcludeVersion
-    }
-    else {
-        Write-Verbose -Verbose "Installing platyPS via Install-Module"
-        Install-Module -Name platyPS -Force -Scope CurrentUser -Repository PSGallery
-    }
-
-    # Do not use 'build.ps1 -bootstrap' option for bootstraping the .Net SDK as it does not work well in CI with the AppVeyor Ubuntu image
-    Write-Verbose -Verbose "Installing required .Net CORE SDK"
-    # the legacy WMF4 image only has the old preview SDKs of dotnet
-    $globalDotJson = Get-Content (Join-Path $PSScriptRoot '..\global.json') -Raw | ConvertFrom-Json
-    $requiredDotNetCoreSDKVersion = $globalDotJson.sdk.version
-    if ($PSVersionTable.PSVersion.Major -gt 4) {
-        $requiredDotNetCoreSDKVersionPresent = (dotnet --list-sdks) -match $requiredDotNetCoreSDKVersion
-    }
-    else {
-        # WMF 4 image has old SDK that does not have --list-sdks parameter
-        $requiredDotNetCoreSDKVersionPresent = (dotnet --version).StartsWith($requiredDotNetCoreSDKVersion)
-    }
-    if (-not $requiredDotNetCoreSDKVersionPresent) {
-        Write-Verbose -Verbose "Installing required .Net CORE SDK $requiredDotNetCoreSDKVersion"
-        $originalSecurityProtocol = [Net.ServicePointManager]::SecurityProtocol
-        try {
-            [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12
-            if ($IsLinux -or $isMacOS) {
-                Invoke-WebRequest 'https://dot.net/v1/dotnet-install.sh' -OutFile dotnet-install.sh
-                bash dotnet-install.sh --version $requiredDotNetCoreSDKVersion
-                [System.Environment]::SetEnvironmentVariable('PATH', "/home/appveyor/.dotnet$([System.IO.Path]::PathSeparator)$PATH")
-            }
-            else {
-                Invoke-WebRequest 'https://dot.net/v1/dotnet-install.ps1' -OutFile dotnet-install.ps1
-                .\dotnet-install.ps1 -Version $requiredDotNetCoreSDKVersion
-            }
-        }
-        finally {
-            [Net.ServicePointManager]::SecurityProtocol = $originalSecurityProtocol
-            Remove-Item .\dotnet-install.*
-        }
-    }
-}
-
-# Implements AppVeyor 'test_script' step
-function Invoke-AppveyorTest {
-    Param(
-        [Parameter(Mandatory)]
-        [ValidateScript( {Test-Path $_})]
-        $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)
-    Write-Verbose -Verbose "Language set to '${env:LANG}'"
-
-    # set up env:PSModulePath to the build location, don't copy it to the "normal place"
-    $analyzerVersion = ([xml](Get-Content "${CheckoutPath}\Engine\Engine.csproj")).SelectSingleNode(".//VersionPrefix")."#text".Trim()
-    $majorVersion = ([System.Version]$analyzerVersion).Major
-    $psMajorVersion = $PSVersionTable.PSVersion.Major
-
-    if ( $psMajorVersion -lt 5 ) {
-        $versionModuleDir = "${CheckoutPath}\out\PSScriptAnalyzer\${analyzerVersion}"
-        $renameTarget = "${CheckoutPath}\out\PSScriptAnalyzer\PSScriptAnalyzer"
-        Rename-Item "${versionModuleDir}" "${renameTarget}"
-        $moduleDir = "${CheckoutPath}\out\PSScriptAnalyzer"
-    }
-    else{
-        $moduleDir = "${CheckoutPath}\out"
-    }
-
-    $env:PSModulePath = "${moduleDir}","${env:PSModulePath}" -join [System.IO.Path]::PathSeparator
-    Write-Verbose -Verbose "module path: ${env:PSModulePath}"
-
-    # Set up testing assets
-    $testResultsPath = Join-Path ${CheckoutPath} TestResults.xml
-    $testScripts = "${CheckoutPath}\Tests\Engine","${CheckoutPath}\Tests\Rules","${CheckoutPath}\Tests\Documentation","${CheckoutPath}\PSCompatibilityCollector\Tests"
-
-    # Change culture to Turkish to test that PSSA works well with different locales
-    [System.Threading.Thread]::CurrentThread.CurrentCulture = [cultureinfo]::CreateSpecificCulture('tr-TR')
-    [System.Threading.Thread]::CurrentThread.CurrentUICulture = [cultureinfo]::CreateSpecificCulture('tr-TR')
-
-    # Run all tests
-    $testResults = Invoke-Pester -Script $testScripts -OutputFormat NUnitXml -OutputFile $testResultsPath -PassThru
-
-    # Upload the test results
-    if ($env:APPVEYOR) {
-        $uploadUrl = "https://ci.appveyor.com/api/testresults/nunit/${env:APPVEYOR_JOB_ID}"
-        Write-Verbose -Verbose "Uploading test results '$testResultsPath' to '${uploadUrl}'"
-        [byte[]]$response = (New-Object 'System.Net.WebClient').UploadFile("$uploadUrl" , $testResultsPath)
-    }
-
-    # Throw an error if any tests failed
-    if ($testResults.FailedCount -gt 0) {
-        throw "$($testResults.FailedCount) tests failed."
-    }
-}
-
-# Implements AppVeyor 'on_finish' step
-function Invoke-AppveyorFinish {
-    $stagingDirectory = (Resolve-Path ..).Path
-    $zipFile = Join-Path $stagingDirectory "$(Split-Path $pwd -Leaf).zip"
-    Add-Type -AssemblyName 'System.IO.Compression.FileSystem'
-    [System.IO.Compression.ZipFile]::CreateFromDirectory((Join-Path $pwd 'out'), $zipFile)
-    @(
-        # add test results as an artifact
-        (Get-ChildItem TestResults.xml)
-        # You can add other artifacts here
-        (Get-ChildItem $zipFile)
-    ) | ForEach-Object { Push-AppveyorArtifact $_.FullName }
-}
diff --git a/tools/docker/ubuntu16/Dockerfile b/tools/docker/ubuntu16/Dockerfile
deleted file mode 100644
index 7bb23eb74..000000000
--- a/tools/docker/ubuntu16/Dockerfile
+++ /dev/null
@@ -1,12 +0,0 @@
-FROM mcr.microsoft.com/powershell:ubuntu-16.04
-
-ENV __InContainer 1
-
-RUN apt update -qq && apt install -q -y wget git apt-transport-https
-RUN wget -q https://packages.microsoft.com/config/ubuntu/16.04/packages-microsoft-prod.deb && dpkg -i packages-microsoft-prod.deb
-
-RUN apt update -qq && \
-    cd / && \
-    git clone https://github.com/PowerShell/PSScriptAnalyzer
-
-RUN pwsh -c 'save-module -name platyps,pester -path $PSHOME/Modules'
diff --git a/tools/installPSResources.ps1 b/tools/installPSResources.ps1
new file mode 100644
index 000000000..48ab81bdd
--- /dev/null
+++ b/tools/installPSResources.ps1
@@ -0,0 +1,24 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+param(
+    [ValidateSet("PSGallery", "CFS")]
+    [string]$PSRepository = "PSGallery"
+)
+
+if ($PSRepository -eq "CFS" -and -not (Get-PSResourceRepository -Name CFS -ErrorAction SilentlyContinue)) {
+    Register-PSResourceRepository -Name CFS -Uri "https://pkgs.dev.azure.com/powershell/PowerShell/_packaging/PowerShellGalleryMirror/nuget/v3/index.json"
+}
+
+# NOTE: Due to a bug in Install-PSResource with upstream feeds, we have to
+# request an exact version. Otherwise, if a newer version is available in the
+# upstream feed, it will fail to install any version at all.
+Install-PSResource -Verbose -TrustRepository -RequiredResource  @{
+    platyPS = @{
+        version = "0.14.2"
+        repository = $PSRepository
+    }
+    Pester = @{
+        version = "5.7.1"
+        repository = $PSRepository
+    }
+}
diff --git a/tools/releaseBuild/AssemblySignConfig.xml b/tools/releaseBuild/AssemblySignConfig.xml
deleted file mode 100644
index 2d2738804..000000000
--- a/tools/releaseBuild/AssemblySignConfig.xml
+++ /dev/null
@@ -1,43 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<SignConfigXML>
-  <!-- ****Begin**** BothDual - Dual (Sha256 and Sha1) AuthicodeDual) and should be StrongName, but we will add this in 6.1.0 ******** -->
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Microsoft.PowerShell.CrossCompatibility.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Microsoft.PowerShell.CrossCompatibility.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psm1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psm1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.format.ps1xml" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.format.ps1xml" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.types.ps1xml" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.types.ps1xml" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CmdletDesign.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CmdletDesign.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormatting.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormatting.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingAllman.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingAllman.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingOTBS.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingOTBS.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingStroustrup.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingStroustrup.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\DSC.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\DSC.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\PSGallery.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\PSGallery.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\ScriptFunctions.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\ScriptFunctions.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\ScriptingStyle.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\ScriptingStyle.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\ScriptSecurity.psd1" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\ScriptSecurity.psd1" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv6" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.PowerShell.CrossCompatibility.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv7" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.PowerShell.CrossCompatibility.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv4" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.PowerShell.CrossCompatibility.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv3" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.PowerShell.CrossCompatibility.dll" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
-</SignConfigXML>
diff --git a/tools/releaseBuild/CatalogSignConfig.xml b/tools/releaseBuild/CatalogSignConfig.xml
deleted file mode 100644
index 73091961b..000000000
--- a/tools/releaseBuild/CatalogSignConfig.xml
+++ /dev/null
@@ -1,6 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<SignConfigXML>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer File Catalog" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.cat" signType="400" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.cat" />
- </job>
-</SignConfigXML>
diff --git a/tools/releaseBuild/CredScan.Suppressions.json b/tools/releaseBuild/CredScan.Suppressions.json
deleted file mode 100644
index 53b49888f..000000000
--- a/tools/releaseBuild/CredScan.Suppressions.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-    "tool": "Credential Scanner",
-    "suppressions": [
-        { "file": "\\Engine\\Settings\\desktop-4.0-windows.json",
-            "_justification": "The file contains the list of all parameters of a cmdlet but no passwords are actually present." },
-        { "file": "\\Engine\\Settings\\desktop-3.0-windows.json",
-            "_justification": "The file contains the list of all parameters of a cmdlet but no passwords are actually present." },
-        { "file": "\\Engine\\Settings\\desktop-5.1.14393.206-windows.json",
-            "_justification": "The file contains the list of all parameters of a cmdlet but no passwords are actually present." },
-        { "file": "\\Tests\\Engine\\RuleSuppression.tests.ps1",
-            "_justification": "The parameter password is used in function declaration for test but is not called and no password is present." }
-     ]
-}
-
-
diff --git a/tools/releaseBuild/FileCatalogSigning.xml b/tools/releaseBuild/FileCatalogSigning.xml
deleted file mode 100644
index 6fc649112..000000000
--- a/tools/releaseBuild/FileCatalogSigning.xml
+++ /dev/null
@@ -1,10 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<SignConfigXML>
-  <!-- ****Begin**** BothDual - Dual (Sha256 and Sha1) AuthenticodeDual) and should be StrongName, but we will add this in 6.1.0 ******** -->
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer File Catalog" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.cat" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.cat" />
- </job>
-<!-- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Compatibility Analyzer File Catalog" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\PSCompatibilityCollector\PSCompatibilityCollector.cat" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\PSCompatibilityAnalzyer.cat" />
- </job> -->
-</SignConfigXML>
diff --git a/tools/releaseBuild/Image/DockerFile b/tools/releaseBuild/Image/DockerFile
deleted file mode 100644
index 771b8c9fb..000000000
--- a/tools/releaseBuild/Image/DockerFile
+++ /dev/null
@@ -1,28 +0,0 @@
-# escape=`
-#0.3.6 (no powershell 6)
-# FROM microsoft/windowsservercore
-FROM mcr.microsoft.com/dotnet/framework/sdk:4.8
-LABEL maintainer='PowerShell Team <powershellteam@hotmail.com>'
-LABEL description="This Dockerfile for Windows Server Core with git installed via chocolatey."
-
-SHELL ["C:\\windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "-command"]
-# Install Git, and platyPS
-# Git installs to C:\Program Files\Git
-# nuget installs to C:\ProgramData\chocolatey\bin\NuGet.exe
-COPY dockerInstall.psm1 containerFiles/dockerInstall.psm1
-
-RUN Import-Module PackageManagement; `
-    Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force; `
-    Import-Module ./containerFiles/dockerInstall.psm1; `
-    [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor [System.Net.SecurityProtocolType]::Tls12; `
-    Install-ChocolateyPackage -PackageName git -Executable git.exe; `
-    Install-ChocolateyPackage -PackageName nuget.commandline -Executable nuget.exe -Cleanup; `
-    Install-Module -Force -Name platyPS -Repository PSGallery; `
-    Invoke-WebRequest -Uri https://raw.githubusercontent.com/dotnet/cli/master/scripts/obtain/dotnet-install.ps1 -outfile C:/dotnet-install.ps1; `
-    C:/dotnet-install.ps1 -Channel Release -Version 2.1.4; `
-    Add-Path C:/Users/ContainerAdministrator/AppData/Local/Microsoft/dotnet;
-
-COPY buildPSSA.ps1 containerFiles/buildPSSA.ps1
-
-ENTRYPOINT ["C:\\windows\\System32\\WindowsPowerShell\\v1.0\\powershell.exe", "-command"]
-
diff --git a/tools/releaseBuild/Image/buildPSSA.ps1 b/tools/releaseBuild/Image/buildPSSA.ps1
deleted file mode 100644
index bb60eb2b5..000000000
--- a/tools/releaseBuild/Image/buildPSSA.ps1
+++ /dev/null
@@ -1,4 +0,0 @@
-push-location C:/PSScriptAnalyzer
-import-module C:/PSScriptAnalyzer/Utils/ReleaseMaker.psm1
-New-ReleaseBuild
-Copy-Item -Recurse C:/PSScriptAnalyzer/out C:/
diff --git a/tools/releaseBuild/Image/dockerInstall.psm1 b/tools/releaseBuild/Image/dockerInstall.psm1
deleted file mode 100644
index 24d1235d6..000000000
--- a/tools/releaseBuild/Image/dockerInstall.psm1
+++ /dev/null
@@ -1,114 +0,0 @@
-function Install-ChocolateyPackage
-{
-    param(
-        [Parameter(Mandatory=$true)]
-        [string]
-        $PackageName,
-
-        [Parameter(Mandatory=$false)]
-        [string]
-        $Executable,
-
-        [string[]]
-        $ArgumentList,
-
-        [switch]
-        $Cleanup,
-
-        [int]
-        $ExecutionTimeout = 2700,
-
-        [string]
-        $Version
-    )
-
-    if(-not(Get-Command -name Choco -ErrorAction SilentlyContinue))
-    {
-        Write-Verbose "Installing Chocolatey provider..." -Verbose
-        Invoke-WebRequest https://chocolatey.org/install.ps1 -UseBasicParsing | Invoke-Expression
-    }
-
-    Write-Verbose "Installing $PackageName..." -Verbose
-    $extraCommand = @()
-    if($Version)
-    {
-        $extraCommand += '--version', $version
-    }
-    choco install -y $PackageName --no-progress --execution-timeout=$ExecutionTimeout $ArgumentList $extraCommands
-
-    if($executable)
-    {
-        Write-Verbose "Verifing $Executable is in path..." -Verbose
-        $exeSource = $null
-        $exeSource = Get-ChildItem -path "$env:ProgramFiles\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName
-        if(!$exeSource)
-        {
-            Write-Verbose "Falling back to x86 program files..." -Verbose
-            $exeSource = Get-ChildItem -path "${env:ProgramFiles(x86)}\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName
-        }
-
-        # Don't search the chocolatey program data until more official locations have been searched
-        if(!$exeSource)
-        {
-            Write-Verbose "Falling back to chocolatey..." -Verbose
-            $exeSource = Get-ChildItem -path "$env:ProgramData\chocolatey\$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName
-        }
-
-        # all obvious locations are exhausted, use brute force and search from the root of the filesystem
-        if(!$exeSource)
-        {
-            Write-Verbose "Falling back to the root of the drive..." -Verbose
-            $exeSource = Get-ChildItem -path "/$Executable" -Recurse -ErrorAction SilentlyContinue | Select-Object -First 1 -ExpandProperty FullName
-        }
-
-        if(!$exeSource)
-        {
-            throw "$Executable not found"
-        }
-
-        $exePath = Split-Path -Path $exeSource
-        Add-Path -path $exePath
-    }
-
-    if($Cleanup.IsPresent)
-    {
-        Remove-Folder -Folder "$env:temp\chocolatey"
-    }
-}
-
-function Add-Path
-{
-    param
-    (
-        $path
-    )
-    $machinePathString = [System.Environment]::GetEnvironmentVariable('path',[System.EnvironmentVariableTarget]::Machine)
-    $machinePath = $machinePathString -split ';'
-
-    if($machinePath -inotcontains $path)
-    {
-        $newPath = "$machinePathString;$path"
-        Write-Verbose "Adding $path to path..." -Verbose
-        [System.Environment]::SetEnvironmentVariable('path',$newPath,[System.EnvironmentVariableTarget]::Machine)
-        Write-Verbose "Added $path to path." -Verbose
-        $env:Path += ";$newPath"
-    }
-    else
-    {
-        Write-Verbose "$path already in path." -Verbose
-    }
-}
-
-function Remove-Folder
-{
-    param(
-        [string]
-        $Folder
-    )
-
-    Write-Verbose "Cleaning up $Folder..." -Verbose
-    $filter = Join-Path -Path $Folder -ChildPath *
-    [int]$measuredCleanupMB = (Get-ChildItem $filter -Recurse | Measure-Object -Property Length -Sum).Sum / 1MB
-    Remove-Item -recurse -force $filter -ErrorAction SilentlyContinue
-    Write-Verbose "Cleaned up $measuredCleanupMB MB from $Folder" -Verbose
-}
diff --git a/tools/releaseBuild/build.json b/tools/releaseBuild/build.json
deleted file mode 100644
index 8d46f2e33..000000000
--- a/tools/releaseBuild/build.json
+++ /dev/null
@@ -1,15 +0,0 @@
-{
-  "Windows": {
-        "Name": "win7-x64",
-        "RepoDestinationPath": "C:\\PSScriptAnalyzer",
-        "BuildCommand": "C:\\containerFiles\\buildPSSA.ps1",
-        "DockerFile": ".\\tools\\releaseBuild\\Image\\DockerFile",
-        "DockerImageName": "pssa",
-        "BinaryBucket": "release",
-        "PublishAsFolder": true,
-        "AdditionalContextFiles" : [
-            ".\\tools\\releaseBuild\\Image\\buildPSSA.ps1",
-            ".\\tools\\releaseBuild\\Image\\dockerInstall.psm1"
-        ]
-    }
-}
diff --git a/tools/releaseBuild/signing.xml b/tools/releaseBuild/signing.xml
deleted file mode 100644
index 642d20bf2..000000000
--- a/tools/releaseBuild/signing.xml
+++ /dev/null
@@ -1,55 +0,0 @@
-<?xml version="1.0" encoding="utf-8" ?>
-<SignConfigXML>
-  <!-- ****Begin**** BothDual - Dual (Sha256 and Sha1) AuthicodeDual) and should be StrongName, but we will add this in 6.1.0 ******** -->
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Microsoft.PowerShell.CrossCompatibility.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psm1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSScriptAnalyzer.psm1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.format.ps1xml" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.format.ps1xml" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.types.ps1xml" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\ScriptAnalyzer.types.ps1xml" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CmdletDesign.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CmdletDesign.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormatting.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormatting.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingAllman.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingAllman.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingOTBS.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingOTBS.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingStroustrup.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\CodeFormattingStroustrup.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\DSC.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\DSC.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\PSGallery.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\PSGallery.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\ScriptFunctions.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\ScriptFunctions.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\ScriptingStyle.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\ScriptingStyle.psd1" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\Settings\ScriptSecurity.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\Settings\ScriptSecurity.psd1" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv6" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv6\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv7" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv7\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv3" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv3\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Script Analyzer PSv4" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.BuiltinRules.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.Windows.PowerShell.ScriptAnalyzer.dll" />
-    <file src="__INPATHROOT__\out\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSScriptAnalyzer\1.19.0\PSv4\Microsoft.PowerShell.CrossCompatibility.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Compatibility Analyzer" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSCompatibilityCollector\PSCompatibilityCollector.psd1" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\PSCompatibilityCollector.psd1" />
-    <file src="__INPATHROOT__\out\PSCompatibilityCollector\PSCompatibilityCollector.psm1" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\PSCompatibilityCollector.psm1" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Compatibility Analyzer netstandard2.0 DLLs" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSCompatibilityCollector\netstandard2.0\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\netstandard2.0\Microsoft.PowerShell.CrossCompatibility.dll" />
-    <file src="__INPATHROOT__\out\PSCompatibilityCollector\netstandard2.0\Newtonsoft.Json.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\netstandard2.0\Newtonsoft.Json.dll" />
- </job>
- <job platform="" configuration="" dest="__OUTPATHROOT__\signed" jobname="PowerShell Compatibility Analyzer net452 DLLs" approvers="vigarg;gstolt">
-    <file src="__INPATHROOT__\out\PSCompatibilityCollector\net452\Microsoft.PowerShell.CrossCompatibility.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\net452\Microsoft.PowerShell.CrossCompatibility.dll" />
-    <file src="__INPATHROOT__\out\PSCompatibilityCollector\net452\Newtonsoft.Json.dll" signType="Authenticode" dest="__OUTPATHROOT__\PSCompatibilityCollector\net452\Newtonsoft.Json.dll" />
- </job>
-</SignConfigXML>
diff --git a/tools/releaseBuild/updateSigning.ps1 b/tools/releaseBuild/updateSigning.ps1
deleted file mode 100644
index d3973fb44..000000000
--- a/tools/releaseBuild/updateSigning.ps1
+++ /dev/null
@@ -1,39 +0,0 @@
-# Copyright (c) Microsoft Corporation. All rights reserved.
-# Licensed under the MIT License.
-param(
-    [string] $SigningXmlPath = (Join-Path -Path $PSScriptRoot  -ChildPath 'signing.xml')
-)
-# Script for use in VSTS to update signing.xml
-
-$ErrorActionPreference = 'Stop'
-
-# Parse the signing xml
-$signingXml = [xml](Get-Content $signingXmlPath)
-
-# Get any variables to updating 'signType' in the XML
-# Define a varabile named `<signTypeInXml>SignType' in VSTS to updating that signing type
-# Example:  $env:AuthenticodeSignType='newvalue'
-#      will cause all files with the 'Authenticode' signtype to be updated with the 'newvalue' signtype
-$signTypes = @{}
-Get-ChildItem -Path env:/*SignType | ForEach-Object -Process {
-    $signType = $_.Name.ToUpperInvariant().Replace('SIGNTYPE','')
-    Write-Host "Found SigningType $signType with value $($_.value)"
-    $signTypes[$signType] = $_.Value
-}
-
-# examine each job in the xml
-$signingXml.SignConfigXML.job | ForEach-Object -Process {
-    # examine each file in the job
-    $_.file | ForEach-Object -Process {
-        # if the sign type is one of the variables we found, update it to the new value
-        $signType = $_.SignType.ToUpperInvariant()
-        if($signTypes.ContainsKey($signType))
-        {
-            $newSignType = $signTypes[$signType]
-            Write-Host "Updating $($_.src) to $newSignType"
-            $_.signType = $newSignType
-        }
-    }
-}
-
-$signingXml.Save($signingXmlPath)
diff --git a/tools/releaseBuild/vstsbuild.ps1 b/tools/releaseBuild/vstsbuild.ps1
deleted file mode 100644
index 9faeedfa0..000000000
--- a/tools/releaseBuild/vstsbuild.ps1
+++ /dev/null
@@ -1,70 +0,0 @@
-[cmdletbinding()]
-param ( )
-
-Begin
-{
-    $ErrorActionPreference = 'Stop'
-
-    $gitBinFullPath = (Get-Command -Name git -CommandType Application).Path | Select-Object -First 1
-    if ( ! $gitBinFullPath )
-    {
-        throw "Git is missing! Install from 'https://git-scm.com/download/win'"
-    }
-
-    # clone the release tools
-    $releaseToolsDirName = "PSRelease"
-    $releaseToolsLocation = Join-Path -Path $PSScriptRoot -ChildPath PSRelease
-    if ( Test-Path $releaseToolsLocation )
-    {
-        Remove-Item -Force -Recurse -Path $releaseToolsLocation
-    }
-    & $gitBinFullPath clone -b master --quiet https://github.com/PowerShell/${releaseToolsDirName}.git $releaseToolsLocation
-    Import-Module "$releaseToolsLocation/vstsBuild" -Force
-    Import-Module "$releaseToolsLocation/dockerBasedBuild" -Force
-}
-
-End {
-
-    $AdditionalFiles = .{
-        Join-Path $PSScriptRoot -child "Image/buildPSSA.ps1"
-        Join-Path $PSScriptRoot -child "Image/dockerInstall.psm1"
-        }
-    $buildPackageName = $null
-
-    # defined if building in VSTS
-    if($env:BUILD_STAGINGDIRECTORY)
-    {
-        # Use artifact staging if running in VSTS
-        $destFolder = $env:BUILD_STAGINGDIRECTORY
-    }
-    else
-    {
-        # Use temp as destination if not running in VSTS
-        $destFolder = $env:temp
-    }
-
-    $resolvedRepoRoot = (Resolve-Path (Join-Path -Path $PSScriptRoot -ChildPath "../../")).Path
-
-    try
-    {
-        Write-Verbose "Starting build at $resolvedRepoRoot  ..." -Verbose
-        Clear-VstsTaskState
-
-        $buildArgs = @{
-            RepoPath = $resolvedRepoRoot
-            BuildJsonPath = './tools/releaseBuild/build.json'
-            Parameters = @{ ReleaseTag = "unused" } # not needed for PSSA
-            AdditionalFiles = $AdditionalFiles
-            Name = "win7-x64"
-        }
-        Invoke-Build @buildArgs
-    }
-    catch
-    {
-        Write-VstsError -Error $_
-    }
-    finally{
-        Write-VstsTaskState
-        exit 0
-    }
-}
diff --git a/tools/updateVersion.ps1 b/tools/updateVersion.ps1
new file mode 100644
index 000000000..7e9d1a47d
--- /dev/null
+++ b/tools/updateVersion.ps1
@@ -0,0 +1,29 @@
+# Copyright (c) Microsoft Corporation.
+# Licensed under the MIT License.
+
+param(
+    [Parameter(Mandatory)]
+    [semver]$Version,
+
+    [Parameter(Mandatory)]
+    [string]$Changes
+)
+
+git diff --staged --quiet --exit-code
+if ($LASTEXITCODE -ne 0) {
+    throw "There are staged changes in the repository. Please commit or reset them before running this script."
+}
+
+$Path = "Directory.Build.props"
+$f = Get-Content -Path $Path
+$f = $f -replace '^(?<prefix>\s+<ModuleVersion>)(.+)(?<suffix></ModuleVersion>)$', "`${prefix}${Version}`${suffix}"
+$f | Set-Content -Path $Path
+git add $Path
+
+$Path = "docs/Cmdlets/PSScriptAnalyzer.md"
+$f = Get-Content -Path $Path
+$f = $f -replace '^(?<prefix>Help Version: )(.+)$', "`${prefix}${Version}"
+$f | Set-Content -Path $Path
+git add $Path
+
+git commit --edit --message "v${Version}: $Changes"
