From 0045cbd078fc7e0df816ebe3895d39b90dac3507 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Thu, 27 Feb 2025 13:08:42 -0800
Subject: [PATCH 1/7] New powershell script

---
 release-notes/RunApiDiff2.md  |  25 ++
 release-notes/RunApiDiff2.ps1 | 646 ++++++++++++++++++++++++++++++++++
 2 files changed, 671 insertions(+)
 create mode 100644 release-notes/RunApiDiff2.md
 create mode 100644 release-notes/RunApiDiff2.ps1

diff --git a/release-notes/RunApiDiff2.md b/release-notes/RunApiDiff2.md
new file mode 100644
index 0000000000..800eddaab1
--- /dev/null
+++ b/release-notes/RunApiDiff2.md
@@ -0,0 +1,25 @@
+# RunApiDiff2 Script
+
+The [`RunApiDiff2.ps1`](./RunApiDiff2.ps1) script can automatically generate an API comparison report for two specified .NET previews, in the format expected for publishing in the dotnet/core repo.
+
+## Instructions
+
+1. Clone the dotnet/sdk repo. Let's assume you clone it into `D:\sdk`.
+2. Clone the dotnet/core repo. Let's assume you clone it into `D:\core`.
+3. Create a temporary directory. Let's assume you create it in `D:\tmp`.
+4. Run the command. Execution example:
+
+```powershell
+.\RunApiDiff2.ps1 `
+   -PreviousDotNetVersion 10.0 `
+   -PreviousPreviewOrRC preview `
+   -PreviousPreviewNumberVersion 1 `
+   -CurrentDotNetVersion 10.0 `
+   -CurrentPreviewOrRC preview `
+   -CurrentPreviewNumberVersion 2 `
+   -CoreRepo D:\core\ `
+   -SdkRepo D:\sdk\ `
+   -TmpFolder D:\tmp\
+```
+
+Example of what this script generates: [API diff between .NET 10.0 Preview1 and .NET 10 Preview2](https://github.com/dotnet/core/pull/9771)
diff --git a/release-notes/RunApiDiff2.ps1 b/release-notes/RunApiDiff2.ps1
new file mode 100644
index 0000000000..4a553f2174
--- /dev/null
+++ b/release-notes/RunApiDiff2.ps1
@@ -0,0 +1,646 @@
+# This script allows running API-diff to generate the dotnet/core report that compares the APIs introduced between two previews, in the format expected for publishing in the dotnet/core repo.
+
+# Usage:
+
+# RunApiDiff2.ps1
+# -PreviousDotNetVersion        : The 'before' .NET version: '6.0', '7.0', '8.0', etc.
+# -PreviousPreviewOrRC          : An optional word that indicates if the 'before' version is a Preview, an RC, or GA. Accepted values: "preview", "rc" or "ga".
+# -PreviousPreviewNumberVersion : The optional preview or RC number of the 'before' version: '1', '2', '3', etc. For GA, this number is the 3rd one in the released version (7.0.0, 7.0.1, 7.0.2, ...).
+# -CurrentDotNetVersion         : The 'after' .NET version: '6.0', '7.0', '8.0', etc.
+# -CurrentPreviewOrRC           : An optional word that indicates if the 'after' version is a Preview, an RC, or GA. Accepted values: "preview", "rc" or "ga".
+# -CurrentPreviewNumberVersion  : The optional preview or RC number of the 'before' version: '1', '2', '3', etc. For GA, this number is the 3rd one in the released version (7.0.0, 7.0.1, 7.0.2, ...).
+# -CoreRepo                     : The full path to your local clone of the dotnet/core repo.
+# -SdkRepo                      : The full path to your local clone of the dotnet/sdk repo.
+# -TmpFolder                    : The full path to the folder where the assets will be downloaded, extracted and compared.
+# -AttributesToExcludeFilePath  : The full path to the file containing the attributes to exclude from the report. By default, it is "ApiDiffAttributesToExclude.txt" in the same folder as this script.
+# -UseNuGet                     : By default, the feed used is https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json , but if this is set to true, the feed used is https://api.nuget.org/v3/index.json
+
+# Example:
+# .\RunApiDiff2.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo C:\Users\calope\source\repos\core\ -SdkRepo C:\Users\calope\source\repos\sdk\ -TmpFolder C:\Users\calope\source\repos\tmp\
+
+# TODO: SDK Repo argument should go away, the tool will be available in the dotnet10 feed after the PR gets merged.
+
+Param (
+    [Parameter(Mandatory=$true)]
+    [ValidatePattern("\d+\.\d")]
+    [string]
+    $PreviousDotNetVersion # 7.0, 8.0, 9.0, ...
+,
+    [Parameter(Mandatory=$true)]
+    [string]
+    [ValidateSet("preview", "rc", "ga")]
+    $PreviousPreviewOrRC
+,
+    [Parameter(Mandatory=$true)]
+    [ValidatePattern("(\d+)?")]
+    [string]
+    $PreviousPreviewNumberVersion # 0, 1, 2, 3, ...
+,
+    [Parameter(Mandatory=$true)]
+    [ValidatePattern("\d+\.\d")]
+    [string]
+    $CurrentDotNetVersion # 7.0, 8.0, 9.0, ...
+,
+    [Parameter(Mandatory=$true)]
+    [string]
+    [ValidateSet("preview", "rc", "ga")]
+    $CurrentPreviewOrRC
+,
+    [Parameter(Mandatory=$true)]
+    [ValidatePattern("(\d+)?")]
+    [string]
+    $CurrentPreviewNumberVersion # 0, 1, 2, 3, ...
+,
+    [Parameter(Mandatory=$true)]
+    [ValidateNotNullOrEmpty()]
+    [string]
+    $CoreRepo #"D:\\core"
+,
+    [Parameter(Mandatory=$true)]
+    [ValidateNotNullOrEmpty()]
+    [string]
+    $SdkRepo #"D:\\sdk" # TODO: DELETE AFTER MERGING PR, REPLACE WITH DOWNLOADING TOOL FROM dotnet10 FEED
+,
+    [Parameter(Mandatory=$true)]
+    [ValidateNotNullOrEmpty()]
+    [string]
+    $TmpFolder #"D:\tmp"
+,
+    [Parameter(Mandatory=$false)]
+    [ValidateNotNullOrEmpty()]
+    [string]
+    $AttributesToExcludeFilePath = "ApiDiffAttributesToExclude.txt"
+,
+    [Parameter(Mandatory=$false)]
+    [bool]
+    $UseNuGet = $false
+)
+
+### Functions ###
+
+Function Write-Color
+{
+    Param (
+        [ValidateNotNullOrEmpty()]
+        [string] $newColor
+    )
+
+    $oldColor = $host.UI.RawUI.ForegroundColor
+    $host.UI.RawUI.ForegroundColor = $newColor
+
+    If ($args)
+    {
+        Write-Output $args
+    }
+    Else
+    {
+        $input | Write-Output
+    }
+
+    $host.UI.RawUI.ForegroundColor = $oldColor
+}
+
+Function VerifyPathOrExit
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $path
+    )
+
+    If (-Not (Test-Path -Path $path))
+    {
+        Write-Error "The path '$path' does not exist." -ErrorAction Stop
+    }
+}
+
+Function RemoveFolderIfExists
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $path
+    )
+
+    If (Test-Path -Path $path)
+    {
+        Write-Color yellow "Removing existing folder: $path"
+        Remove-Item -Recurse -Path $path
+    }
+}
+
+Function RecreateFolder
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $path
+    )
+
+    RemoveFolderIfExists $path
+
+    Write-Color cyan "Creating new folder: $path"
+    New-Item -ItemType Directory -Path $path
+}
+
+Function VerifyCountDlls
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $path
+    )
+
+    VerifyPathOrExit $path
+
+    $count=(Get-ChildItem -Path $path -Filter "*.dll" | Measure-Object).Count
+    If ($count -eq 0)
+    {
+        Write-Error "There are no DLL files inside the folder." -ErrorAction Stop
+    }
+}
+
+Function RunCommand
+{
+    Param (
+        [Parameter(Mandatory=$True)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $command
+    )
+
+    Write-Color yellow $command
+    Invoke-Expression "$command"
+}
+
+Function GetDotNetFullName
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [bool]
+        $IsComparingReleases
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("\d+\.\d")]
+        [string]
+        $dotNetVersion # 7.0, 8.0, 9.0, ...
+    ,
+        [Parameter(Mandatory=$true)]
+        [string]
+        [ValidateSet("preview", "rc", "ga")]
+        $previewOrRC
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("(\d+)?")]
+        [string]
+        $previewNumberVersion # 0, 1, 2, 3, ...
+    )
+
+    If ($IsComparingReleases)
+    {
+        Return "$dotNetVersion.$previewNumberVersion"
+    }
+
+    If ($previewOrRC -eq "ga")
+    {
+        If ($previewNumberVersion -eq "0")
+        {
+            # Example: Don't return "7.0-ga0", instead just return "7.0-ga"
+            Return "$dotNetVersion-$previewOrRC"
+        }
+
+        # Examples: Don't include "ga", instead just return "7.0.1", "7.0.2"
+        Return "$dotNetVersion.$previewNumberVersion"
+    }
+
+    # Examples: "7.0-preview5", "7.0-rc2", "7.0-ga"
+    Return "$dotNetVersion-$previewOrRC$previewNumberVersion"
+}
+
+Function GetDotNetFriendlyName
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("\d+\.\d")]
+        [string]
+        $DotNetVersion # 7.0, 8.0, 9.0, ...
+    ,
+        [Parameter(Mandatory=$true)]
+        [string]
+        [ValidateSet("preview", "rc", "ga")]
+        $PreviewOrRC
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("(\d+)?")]
+        [string]
+        $PreviewNumberVersion # 0, 1, 2, 3, ...
+    )
+
+    $friendlyPreview = ""
+    If ($PreviewOrRC -eq "preview")
+    {
+        $friendlyPreview = "Preview"
+    }
+    ElseIf ($PreviewOrRC -eq "rc")
+    {
+        $friendlyPreview = "RC"
+    }
+    ElseIf ($PreviewOrRC -eq "ga")
+    {
+        $friendlyPreview = "GA"
+        If ($PreviewNumberVersion -eq 0)
+        {
+            # Example: Don't return "7.0 GA 0", instead just return "7.0 GA"
+            Return ".NET $DotNetVersion $friendlyPreview"
+        }
+
+        # Examples: Don't include "ga", instead just return "7.0.1", "7.0.2"
+        Return ".NET $DotNetVersion.$PreviewNumberVersion"
+    }
+
+    # Examples: "7.0 Preview 5", "7.0 RC 2"
+    Return ".NET $DotNetVersion $friendlyPreview $PreviewNumberVersion"
+}
+
+Function GetPreviewOrRCFolderName
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("\d+\.\d")]
+        [string]
+        $dotNetVersion # 7.0, 8.0, 9.0, ...
+    ,
+        [Parameter(Mandatory=$true)]
+        [string]
+        [ValidateSet("preview", "rc", "ga")]
+        $previewOrRC
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("(\d+)?")]
+        [string]
+        $previewNumberVersion # 0, 1, 2, 3, ...
+    )
+
+    If ($previewOrRC -eq "ga")
+    {
+        If ($previewNumberVersion -eq "0")
+        {
+            # return "ga", not "ga0"
+            Return $previewOrRC
+        }
+
+        # return "7.0.1", "7.0.2", not "ga1, ga2"
+        Return "$dotNetVersion$previewNumberVersion"
+    }
+
+    Return "$previewOrRC$previewNumberVersion"
+}
+
+Function GetPreviewFolderPath
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $rootFolder #"D:\\core"
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("\d+\.\d")]
+        [string]
+        $dotNetVersion # 7.0, 8.0, 9.0, ...
+    ,
+        [Parameter(Mandatory=$true)]
+        [string]
+        [ValidateSet("preview", "rc", "ga")]
+        $previewOrRC
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("(\d+)?")]
+        [string]
+        $previewNumberVersion # 0, 1, 2, 3, ...
+    ,
+        [Parameter(Mandatory=$true)]
+        [bool]
+        $IsComparingReleases # True when comparing 8.0 GA with 9.0 GA
+    )
+
+    $prefixFolder = [IO.Path]::Combine($rootFolder, "release-notes", $dotNetVersion)
+    $apiDiffFolderName = "api-diff"
+
+    If ($IsComparingReleases)
+    {
+        Return [IO.Path]::Combine($prefixFolder, "$dotNetVersion.$previewNumberVersion", $apiDiffFolderName)
+    }
+
+    $previewOrRCFolderName = GetPreviewOrRCFolderName $dotNetVersion $previewOrRC $previewNumberVersion
+    Return [IO.Path]::Combine($prefixFolder, "preview", $previewOrRCFolderName, $apiDiffFolderName)
+}
+
+Function RunApiDiff2
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $apiDiffExe
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $outputFolder
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $beforeFolder
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $afterFolder
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $tableOfContentsFileNamePrefix
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $attributesToExclude
+    )
+
+    VerifyPathOrExit $apiDiffExe
+    VerifyPathOrExit $beforeFolder
+    VerifyPathOrExit $afterFolder
+
+    # All arguments:
+    # "https://github.com/dotnet/sdk/tree/main/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs"
+
+    RunCommand "$apiDiffExe -b $beforeFolder -a $afterFolder -o $outputFolder -tc $tableOfContentsFileNamePrefix -eattrs '$attributesToExclude'"
+}
+
+Function CreateReadme
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $previewFolderPath
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $dotNetFriendlyName
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $dotNetFullName
+    )
+
+    $readmePath=[IO.Path]::Combine($previewFolderPath, "README.md")
+    If (Test-Path -Path $readmePath)
+    {
+        Remove-Item -Path $readmePath
+    }
+    New-Item -ItemType File $readmePath
+
+    Add-Content $readmePath "# $dotNetFriendlyName API Changes"
+    Add-Content $readmePath ""
+    Add-Content $readmePath "The following API changes were made in $($dotNetFriendlyName):"
+    Add-Content $readmePath ""
+    Add-Content $readmePath "- [Microsoft.NETCore.App](./Microsoft.NETCore.App/$dotNetFullName.md)"
+    Add-Content $readmePath "- [Microsoft.AspNetCore.App](./Microsoft.AspNetCore.App/$dotNetFullName.md)"
+    Add-Content $readmePath "- [Microsoft.WindowsDesktop.App](./Microsoft.WindowsDesktop.App/$dotNetFullName.md)"
+}
+
+Function RebuildIfExeNotFound
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $exePath
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $projectPath
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $artifactsPath
+    )
+
+    VerifyPathOrExit $projectPath
+
+    If (-Not (Test-Path -Path $exePath))
+    {
+        # Building the project
+
+        Write-Color cyan "Building project '$projectPath'"
+        RunCommand "$SdkRepo/.dotnet/dotnet build -c release $projectPath"
+
+        # Verifying expected output from building
+        VerifyPathOrExit $artifactsPath
+        VerifyPathOrExit $exePath
+    }
+}
+
+Function DownloadPackage
+{
+    Param
+    (
+        [Parameter(Mandatory=$true)]
+        [bool]
+        $useNuget
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateSet("NETCore", "AspNetCore", "WindowsDesktop")]
+        [string]
+        $sdkName
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateSet("Before", "After")]
+        [string]
+        $beforeOrAfter
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("\d+\.\d")]
+        [string]
+        $dotNetVersion
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidateSet("preview", "rc", "ga")]
+        [string]
+        $previewOrRC
+    ,
+        [Parameter(Mandatory=$true)]
+        [ValidatePattern("(\d+)?")]
+        [string]
+        $previewNumberVersion
+    ,
+        [ref]
+        $resultingPath
+    )
+
+    $fullSdkName = "Microsoft.$sdkName.App"
+    $destinationFolder = [IO.Path]::Combine($TmpFolder, "$fullSdkName.$beforeOrAfter")
+    RecreateFolder $destinationFolder
+
+    $refPackageName = "$fullSdkName.Ref"
+
+    $nugetSource = $useNuget ? "https://api.nuget.org/v3/index.json" : "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json"
+
+    $searchTerm = ""
+    If ($previewOrRC -eq "ga")
+    {
+        $searchTerm = "$dotNetversion.$previewNumberVersion"
+    }
+    ElseIf (-Not ([System.String]::IsNullOrWhiteSpace($previewOrRC)) -And -Not ([System.String]::IsNullOrWhiteSpace($previewNumberVersion)))
+    {
+        $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*"
+    }
+
+    $results = Find-Package -AllVersions -Source $nugetSource -Name $refPackageName -AllowPrereleaseVersions | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending
+
+    If ($results.Count -eq 0)
+    {
+        Write-Error "No NuGet packages found with search term '$searchTerm'." -ErrorAction Stop
+    }
+
+    $version = $results[0].Version
+    $nupkgFile = [IO.Path]::Combine($TmpFolder, "$refPackageName.$version.nupkg")
+
+    If (-Not(Test-Path -Path $nupkgFile))
+    {
+        $href = $results[0].Links | Where-Object -Property Relationship -Eq "icon" | Select-Object -ExpandProperty HRef
+        $link = $href.AbsoluteUri.Replace("?extract=Icon.png", "")
+
+        $nupkgUrl = $useNuget ? "https://www.nuget.org/api/v2/package/$refPackageName/$version" : $link
+
+        Write-Color yellow "Downloading '$nupkgUrl' to '$nupkgFile'..."
+        Invoke-WebRequest -Uri $nupkgUrl -OutFile $nupkgFile
+        VerifyPathOrExit $nupkgFile
+    }
+    Else
+    {
+        Write-Color green "File '$nupkgFile' already exists locally. Skipping re-download."
+    }
+
+    Expand-Archive -Path $nupkgFile -DestinationPath $destinationFolder -ErrorAction Stop
+
+    $dllPath = [IO.Path]::Combine($destinationFolder, "ref", "net$dotNetVersion")
+    VerifyPathOrExit $dllPath
+    VerifyCountDlls $dllPath
+    $resultingPath.value = $dllPath
+}
+
+Function GetAttributesToExclude
+{
+    Param (
+        [Parameter(Mandatory=$true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $filePath
+    )
+
+    VerifyPathOrExit $filePath
+
+    $attributesToExclude = (Get-Content -Path $filePath) -join ","
+    Return $attributesToExclude
+}
+
+### Execution ###
+
+## Generate strings with no whitespace
+
+# True when comparing 8.0 GA with 9.0 GA
+$IsComparingReleases = ($PreviousDotNetVersion -Ne $CurrentDotNetVersion) -And ($PreviousPreviewOrRC -Eq "ga") -And ($CurrentPreviewOrRC -eq "ga")
+
+$currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
+
+
+## Check folders passed as parameters exist
+
+VerifyPathOrExit $CoreRepo
+VerifyPathOrExit $SdkRepo
+VerifyPathOrExit $TmpFolder
+
+
+## Download the NuGet packages
+
+# NETCore
+$netCoreBeforeDllFolder = ""
+DownloadPackage $UseNuget "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$netCoreBeforeDllFolder)
+VerifyPathOrExit $netCoreBeforeDllFolder
+
+$netCoreAfterDllFolder = ""
+DownloadPackage $UseNuget "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$netCoreAfterDllFolder)
+VerifyPathOrExit $netCoreAfterDllFolder
+
+# AspNetCore
+$aspNetCoreBeforeDllFolder = ""
+DownloadPackage $UseNuget "AspNetCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$aspNetCoreBeforeDllFolder)
+VerifyPathOrExit $aspNetCoreBeforeDllFolder
+
+$aspNetCoreAfterDllFolder = ""
+DownloadPackage $UseNuget "AspNetCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$aspNetCoreAfterDllFolder)
+VerifyPathOrExit $aspNetCoreAfterDllFolder
+
+# WindowsDesktop
+$windowsDesktopBeforeDllFolder = ""
+DownloadPackage $UseNuget "WindowsDesktop" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$windowsDesktopBeforeDllFolder)
+VerifyPathOrExit $windowsDesktopBeforeDllFolder
+
+$windowsDesktopAfterDllFolder = ""
+DownloadPackage $UseNuget "WindowsDesktop" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$windowsDesktopAfterDllFolder)
+VerifyPathOrExit $windowsDesktopAfterDllFolder
+
+
+## Ensure ApiDiff artifacts exist
+
+$apiDiffProjectPath = [IO.Path]::Combine($SdkRepo, "src", "Compatibility", "ApiDiff", "Microsoft.DotNet.ApiDiff.Tool", "Microsoft.DotNet.ApiDiff.Tool.csproj")
+$apiDiffArtifactsPath = [IO.Path]::Combine($SdkRepo , "artifacts", "bin", "Microsoft.DotNet.ApiDiff.Tool")
+$apiDiffExe = [IO.Path]::Combine($apiDiffArtifactsPath, "Release", "net8.0", "Microsoft.DotNet.ApiDiff.Tool.exe")
+ReBuildIfExeNotFound $apiDiffExe $apiDiffProjectPath $apiDiffArtifactsPath
+
+## Recreate api-diff folder in core repo folder
+
+$previewFolderPath = GetPreviewFolderPath $CoreRepo $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $IsComparingReleases
+Write-Color cyan "Checking existing diff folder: $previewFolderPath"
+RecreateFolder $previewFolderPath
+
+
+## Create subfolders
+
+# NETCore
+$netCoreTargetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.NETCore.App")
+RecreateFolder $netCoreTargetFolder
+
+#AspNetCore
+$aspNetCoreTargetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.AspNetCore.App")
+RecreateFolder $aspNetCoreTargetFolder
+
+# WindowsDesktop
+$windowsDesktopTargetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.WindowsDesktop.App")
+RecreateFolder $windowsDesktopTargetFolder
+
+
+## Run the ApiDiff commands
+
+$attributesToExclude = GetAttributesToExclude $AttributesToExcludeFilePath
+
+RunApiDiff2 $apiDiffExe $netCoreTargetFolder $netCoreBeforeDllFolder $netCoreAfterDllFolder $currentDotNetFullName $attributesToExclude
+RunApiDiff2 $apiDiffExe $aspNetCoreTargetFolder $aspNetCoreBeforeDllFolder $aspNetCoreAfterDllFolder $currentDotNetFullName $attributesToExclude
+RunApiDiff2 $apiDiffExe $windowsDesktopTargetFolder $windowsDesktopBeforeDllFolder $windowsDesktopAfterDllFolder $currentDotNetFullName $attributesToExclude
+
+$currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
+
+CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName

From 4d6b085ba40e77a79e6dd39a239c47a8dfe0b659 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Thu, 27 Feb 2025 13:09:04 -0800
Subject: [PATCH 2/7] Text file with attribute APIs to exclude by default

---
 release-notes/ApiDiffAttributesToExclude.txt | 6 ++++++
 1 file changed, 6 insertions(+)
 create mode 100644 release-notes/ApiDiffAttributesToExclude.txt

diff --git a/release-notes/ApiDiffAttributesToExclude.txt b/release-notes/ApiDiffAttributesToExclude.txt
new file mode 100644
index 0000000000..3ed785dc8d
--- /dev/null
+++ b/release-notes/ApiDiffAttributesToExclude.txt
@@ -0,0 +1,6 @@
+T:System.AttributeUsageAttribute
+T:System.ComponentModel.EditorBrowsableAttribute
+T:System.Diagnostics.CodeAnalysis.RequiresDynamicCodeAttribute
+T:System.Diagnostics.CodeAnalysis.RequiresUnreferencedCodeAttribute
+T:System.Windows.Markup.ContentWrapperAttribute
+T:System.Windows.TemplatePartAttribute
\ No newline at end of file

From 9b19f887eff9822194d28a81613029bf80fa52a0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Thu, 27 Feb 2025 16:41:00 -0800
Subject: [PATCH 3/7] Add beforeFriendlyName and afterFriendlyName arguments.
 Pass the correct strings to the api diff tool. Add better logic to determine
 root of failure when packages are not found.

---
 release-notes/RunApiDiff2.ps1 | 40 +++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 9 deletions(-)

diff --git a/release-notes/RunApiDiff2.ps1 b/release-notes/RunApiDiff2.ps1
index 4a553f2174..cdfe636aed 100644
--- a/release-notes/RunApiDiff2.ps1
+++ b/release-notes/RunApiDiff2.ps1
@@ -372,6 +372,16 @@ Function RunApiDiff2
         [ValidateNotNullOrEmpty()]
         [string]
         $attributesToExclude
+        ,
+        [Parameter(Mandatory = $true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $beforeFriendlyName
+        ,
+        [Parameter(Mandatory = $true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $afterFriendlyName
     )
 
     VerifyPathOrExit $apiDiffExe
@@ -381,7 +391,7 @@ Function RunApiDiff2
     # All arguments:
     # "https://github.com/dotnet/sdk/tree/main/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs"
 
-    RunCommand "$apiDiffExe -b $beforeFolder -a $afterFolder -o $outputFolder -tc $tableOfContentsFileNamePrefix -eattrs '$attributesToExclude'"
+    RunCommand "$apiDiffExe -b '$beforeFolder' -a '$afterFolder' -o '$outputFolder' -tc '$tableOfContentsFileNamePrefix' -eattrs '$attributesToExclude' -bfn '$beforeFriendlyName' -afn '$afterFriendlyName'"
 }
 
 Function CreateReadme
@@ -496,7 +506,7 @@ Function DownloadPackage
 
     $refPackageName = "$fullSdkName.Ref"
 
-    $nugetSource = $useNuget ? "https://api.nuget.org/v3/index.json" : "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json"
+    $feed = $useNuget ? "https://api.nuget.org/v3/index.json" : "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json"
 
     $searchTerm = ""
     If ($previewOrRC -eq "ga")
@@ -508,7 +518,16 @@ Function DownloadPackage
         $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*"
     }
 
-    $results = Find-Package -AllVersions -Source $nugetSource -Name $refPackageName -AllowPrereleaseVersions | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending
+    $foundPackages = Find-Package -AllVersions -Source $feed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue
+
+    If ($foundPackages.Count -eq 0)
+    {
+        Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$feed'"
+        Get-PackageSource -Name $refPackageName | Format-Table -Property Name, SourceUri
+        Write-Error "Exiting" -ErrorAction Stop
+    }
+
+    $results = $foundPackages | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending
 
     If ($results.Count -eq 0)
     {
@@ -564,9 +583,6 @@ Function GetAttributesToExclude
 # True when comparing 8.0 GA with 9.0 GA
 $IsComparingReleases = ($PreviousDotNetVersion -Ne $CurrentDotNetVersion) -And ($PreviousPreviewOrRC -Eq "ga") -And ($CurrentPreviewOrRC -eq "ga")
 
-$currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
-
-
 ## Check folders passed as parameters exist
 
 VerifyPathOrExit $CoreRepo
@@ -635,12 +651,18 @@ RecreateFolder $windowsDesktopTargetFolder
 
 ## Run the ApiDiff commands
 
+# Comma separated docIDs of attribute types
 $attributesToExclude = GetAttributesToExclude $AttributesToExcludeFilePath
 
-RunApiDiff2 $apiDiffExe $netCoreTargetFolder $netCoreBeforeDllFolder $netCoreAfterDllFolder $currentDotNetFullName $attributesToExclude
-RunApiDiff2 $apiDiffExe $aspNetCoreTargetFolder $aspNetCoreBeforeDllFolder $aspNetCoreAfterDllFolder $currentDotNetFullName $attributesToExclude
-RunApiDiff2 $apiDiffExe $windowsDesktopTargetFolder $windowsDesktopBeforeDllFolder $windowsDesktopAfterDllFolder $currentDotNetFullName $attributesToExclude
+# Example: "10.0-preview2"
+$currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
 
+# Examples: ".NET 10 Preview 1" and ".NET 10 Preview 2"
+$previousDotNetFriendlyName = GetDotNetFriendlyName $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion
 $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
 
+RunApiDiff2 $apiDiffExe $netCoreTargetFolder $netCoreBeforeDllFolder $netCoreAfterDllFolder $currentDotNetFullName $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+RunApiDiff2 $apiDiffExe $aspNetCoreTargetFolder $aspNetCoreBeforeDllFolder $aspNetCoreAfterDllFolder $currentDotNetFullName $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+RunApiDiff2 $apiDiffExe $windowsDesktopTargetFolder $windowsDesktopBeforeDllFolder $windowsDesktopAfterDllFolder $currentDotNetFullName $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+
 CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName

From 4d0c79f7c76b63b08de76da05224777701243dbd Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Fri, 7 Mar 2025 15:45:29 -0800
Subject: [PATCH 4/7] Add assemblies to exclude

---
 release-notes/ApiDiffAssembliesToExclude.txt |  2 ++
 release-notes/RunApiDiff2.ps1                | 37 ++++++++++++++------
 2 files changed, 28 insertions(+), 11 deletions(-)
 create mode 100644 release-notes/ApiDiffAssembliesToExclude.txt

diff --git a/release-notes/ApiDiffAssembliesToExclude.txt b/release-notes/ApiDiffAssembliesToExclude.txt
new file mode 100644
index 0000000000..079acb739f
--- /dev/null
+++ b/release-notes/ApiDiffAssembliesToExclude.txt
@@ -0,0 +1,2 @@
+netstandard.dll
+mscorlib.dll
\ No newline at end of file
diff --git a/release-notes/RunApiDiff2.ps1 b/release-notes/RunApiDiff2.ps1
index cdfe636aed..60f1797462 100644
--- a/release-notes/RunApiDiff2.ps1
+++ b/release-notes/RunApiDiff2.ps1
@@ -13,6 +13,7 @@
 # -SdkRepo                      : The full path to your local clone of the dotnet/sdk repo.
 # -TmpFolder                    : The full path to the folder where the assets will be downloaded, extracted and compared.
 # -AttributesToExcludeFilePath  : The full path to the file containing the attributes to exclude from the report. By default, it is "ApiDiffAttributesToExclude.txt" in the same folder as this script.
+# -AssembliesToExcludeFilePath  : The full path to the file containing the assemblies to exclude from the report. By default, it is "ApiDiffAssembliesToExclude.txt" in the same folder as this script.
 # -UseNuGet                     : By default, the feed used is https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json , but if this is set to true, the feed used is https://api.nuget.org/v3/index.json
 
 # Example:
@@ -70,7 +71,13 @@ Param (
     [ValidateNotNullOrEmpty()]
     [string]
     $AttributesToExcludeFilePath = "ApiDiffAttributesToExclude.txt"
-,
+    ,
+    [Parameter(Mandatory = $false)]
+    [ValidateNotNullOrEmpty()]
+    [string]
+    $AssembliesToExcludeFilePath = "ApiDiffAssembliesToExclude.txt"
+    ,
+
     [Parameter(Mandatory=$false)]
     [bool]
     $UseNuGet = $false
@@ -367,7 +374,12 @@ Function RunApiDiff2
         [ValidateNotNullOrEmpty()]
         [string]
         $tableOfContentsFileNamePrefix
-    ,
+        ,
+        [Parameter(Mandatory = $true)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $assembliesToExclude
+        ,
         [Parameter(Mandatory=$true)]
         [ValidateNotNullOrEmpty()]
         [string]
@@ -391,7 +403,7 @@ Function RunApiDiff2
     # All arguments:
     # "https://github.com/dotnet/sdk/tree/main/src/Compatibility/ApiDiff/Microsoft.DotNet.ApiDiff.Tool/Program.cs"
 
-    RunCommand "$apiDiffExe -b '$beforeFolder' -a '$afterFolder' -o '$outputFolder' -tc '$tableOfContentsFileNamePrefix' -eattrs '$attributesToExclude' -bfn '$beforeFriendlyName' -afn '$afterFriendlyName'"
+    RunCommand "$apiDiffExe -b '$beforeFolder' -a '$afterFolder' -o '$outputFolder' -tc '$tableOfContentsFileNamePrefix' -eas '$assembliesToExclude' -eattrs '$attributesToExclude' -bfn '$beforeFriendlyName' -afn '$afterFriendlyName'"
 }
 
 Function CreateReadme
@@ -561,7 +573,7 @@ Function DownloadPackage
     $resultingPath.value = $dllPath
 }
 
-Function GetAttributesToExclude
+Function GetFileLinesAsCommaSeparaterList
 {
     Param (
         [Parameter(Mandatory=$true)]
@@ -572,8 +584,8 @@ Function GetAttributesToExclude
 
     VerifyPathOrExit $filePath
 
-    $attributesToExclude = (Get-Content -Path $filePath) -join ","
-    Return $attributesToExclude
+    $lines = (Get-Content -Path $filePath) -join ","
+    Return $lines
 }
 
 ### Execution ###
@@ -651,8 +663,11 @@ RecreateFolder $windowsDesktopTargetFolder
 
 ## Run the ApiDiff commands
 
-# Comma separated docIDs of attribute types
-$attributesToExclude = GetAttributesToExclude $AttributesToExcludeFilePath
+# Comma separated docIDs of attribute types to exclude
+$attributesToExclude = GetFileLinesAsCommaSeparaterList $AttributesToExcludeFilePath
+
+# Comma separated list of assembly names to exclude
+$assembliesToExclude = GetFileLinesAsCommaSeparaterList $AssembliesToExcludeFilePath
 
 # Example: "10.0-preview2"
 $currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
@@ -661,8 +676,8 @@ $currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVe
 $previousDotNetFriendlyName = GetDotNetFriendlyName $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion
 $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
 
-RunApiDiff2 $apiDiffExe $netCoreTargetFolder $netCoreBeforeDllFolder $netCoreAfterDllFolder $currentDotNetFullName $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
-RunApiDiff2 $apiDiffExe $aspNetCoreTargetFolder $aspNetCoreBeforeDllFolder $aspNetCoreAfterDllFolder $currentDotNetFullName $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
-RunApiDiff2 $apiDiffExe $windowsDesktopTargetFolder $windowsDesktopBeforeDllFolder $windowsDesktopAfterDllFolder $currentDotNetFullName $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+RunApiDiff2 $apiDiffExe $netCoreTargetFolder $netCoreBeforeDllFolder $netCoreAfterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+RunApiDiff2 $apiDiffExe $aspNetCoreTargetFolder $aspNetCoreBeforeDllFolder $aspNetCoreAfterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+RunApiDiff2 $apiDiffExe $windowsDesktopTargetFolder $windowsDesktopBeforeDllFolder $windowsDesktopAfterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
 
 CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName

From 55028d0e8116ac0f0c86b32eb2a0fe6937226337 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Thu, 27 Mar 2025 22:30:21 -0700
Subject: [PATCH 5/7] Remove extensions from assemblies to exclude

---
 release-notes/ApiDiffAssembliesToExclude.txt | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/release-notes/ApiDiffAssembliesToExclude.txt b/release-notes/ApiDiffAssembliesToExclude.txt
index 079acb739f..4ec161b762 100644
--- a/release-notes/ApiDiffAssembliesToExclude.txt
+++ b/release-notes/ApiDiffAssembliesToExclude.txt
@@ -1,2 +1,2 @@
-netstandard.dll
-mscorlib.dll
\ No newline at end of file
+netstandard
+mscorlib
\ No newline at end of file

From cc9ff4429b55d1b972d840d63e4cfbc477240cb5 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Thu, 27 Mar 2025 22:30:35 -0700
Subject: [PATCH 6/7] Add options to exclude a particular sdk

---
 release-notes/RunApiDiff2.ps1 | 441 +++++++++++++++++-----------------
 1 file changed, 227 insertions(+), 214 deletions(-)

diff --git a/release-notes/RunApiDiff2.ps1 b/release-notes/RunApiDiff2.ps1
index 60f1797462..3884dbbcb9 100644
--- a/release-notes/RunApiDiff2.ps1
+++ b/release-notes/RunApiDiff2.ps1
@@ -15,6 +15,9 @@
 # -AttributesToExcludeFilePath  : The full path to the file containing the attributes to exclude from the report. By default, it is "ApiDiffAttributesToExclude.txt" in the same folder as this script.
 # -AssembliesToExcludeFilePath  : The full path to the file containing the assemblies to exclude from the report. By default, it is "ApiDiffAssembliesToExclude.txt" in the same folder as this script.
 # -UseNuGet                     : By default, the feed used is https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json , but if this is set to true, the feed used is https://api.nuget.org/v3/index.json
+# -ExcludeNetCore               : Optional boolean to exclude the NETCore comparison. Default is false.
+# -ExcludeAspNetCore            : Optional boolean to exclude the AspNetCore comparison. Default is false.
+# -ExcludeWindowsDesktop        : Optional boolean to exclude the WindowsDesktop comparison. Default is false.
 
 # Example:
 # .\RunApiDiff2.ps1 -PreviousDotNetVersion 9.0 -PreviousPreviewOrRC preview -PreviousPreviewNumberVersion 7 -CurrentDotNetVersion 9.0 -CurrentPreviewOrRC rc -CurrentPreviewNumberVersion 1 -CoreRepo C:\Users\calope\source\repos\core\ -SdkRepo C:\Users\calope\source\repos\sdk\ -TmpFolder C:\Users\calope\source\repos\tmp\
@@ -22,52 +25,52 @@
 # TODO: SDK Repo argument should go away, the tool will be available in the dotnet10 feed after the PR gets merged.
 
 Param (
-    [Parameter(Mandatory=$true)]
+    [Parameter(Mandatory = $true)]
     [ValidatePattern("\d+\.\d")]
     [string]
     $PreviousDotNetVersion # 7.0, 8.0, 9.0, ...
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [string]
     [ValidateSet("preview", "rc", "ga")]
     $PreviousPreviewOrRC
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [ValidatePattern("(\d+)?")]
     [string]
     $PreviousPreviewNumberVersion # 0, 1, 2, 3, ...
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [ValidatePattern("\d+\.\d")]
     [string]
     $CurrentDotNetVersion # 7.0, 8.0, 9.0, ...
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [string]
     [ValidateSet("preview", "rc", "ga")]
     $CurrentPreviewOrRC
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [ValidatePattern("(\d+)?")]
     [string]
     $CurrentPreviewNumberVersion # 0, 1, 2, 3, ...
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [ValidateNotNullOrEmpty()]
     [string]
     $CoreRepo #"D:\\core"
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [ValidateNotNullOrEmpty()]
     [string]
     $SdkRepo #"D:\\sdk" # TODO: DELETE AFTER MERGING PR, REPLACE WITH DOWNLOADING TOOL FROM dotnet10 FEED
-,
-    [Parameter(Mandatory=$true)]
+    ,
+    [Parameter(Mandatory = $true)]
     [ValidateNotNullOrEmpty()]
     [string]
     $TmpFolder #"D:\tmp"
-,
-    [Parameter(Mandatory=$false)]
+    ,
+    [Parameter(Mandatory = $false)]
     [ValidateNotNullOrEmpty()]
     [string]
     $AttributesToExcludeFilePath = "ApiDiffAttributesToExclude.txt"
@@ -77,16 +80,28 @@ Param (
     [string]
     $AssembliesToExcludeFilePath = "ApiDiffAssembliesToExclude.txt"
     ,
-
-    [Parameter(Mandatory=$false)]
+    [Parameter(Mandatory = $false)]
     [bool]
     $UseNuGet = $false
+    ,
+    [Parameter(Mandatory = $false)]
+    [bool]
+    $ExcludeNetCore = $false
+    ,
+    [Parameter(Mandatory = $false)]
+    [bool]
+    $ExcludeAspNetCore = $false
+    ,
+    [Parameter(Mandatory = $false)]
+    [bool]
+    $ExcludeWindowsDesktop = $false
 )
 
-### Functions ###
+#######################
+### Start Functions ###
+#######################
 
-Function Write-Color
-{
+Function Write-Color {
     Param (
         [ValidateNotNullOrEmpty()]
         [string] $newColor
@@ -95,53 +110,46 @@ Function Write-Color
     $oldColor = $host.UI.RawUI.ForegroundColor
     $host.UI.RawUI.ForegroundColor = $newColor
 
-    If ($args)
-    {
+    If ($args) {
         Write-Output $args
     }
-    Else
-    {
+    Else {
         $input | Write-Output
     }
 
     $host.UI.RawUI.ForegroundColor = $oldColor
 }
 
-Function VerifyPathOrExit
-{
+Function VerifyPathOrExit {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $path
     )
 
-    If (-Not (Test-Path -Path $path))
-    {
+    If (-Not (Test-Path -Path $path)) {
         Write-Error "The path '$path' does not exist." -ErrorAction Stop
     }
 }
 
-Function RemoveFolderIfExists
-{
+Function RemoveFolderIfExists {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $path
     )
 
-    If (Test-Path -Path $path)
-    {
+    If (Test-Path -Path $path) {
         Write-Color yellow "Removing existing folder: $path"
         Remove-Item -Recurse -Path $path
     }
 }
 
-Function RecreateFolder
-{
+Function RecreateFolder {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $path
@@ -153,10 +161,9 @@ Function RecreateFolder
     New-Item -ItemType Directory -Path $path
 }
 
-Function VerifyCountDlls
-{
+Function VerifyCountDlls {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $path
@@ -164,17 +171,15 @@ Function VerifyCountDlls
 
     VerifyPathOrExit $path
 
-    $count=(Get-ChildItem -Path $path -Filter "*.dll" | Measure-Object).Count
-    If ($count -eq 0)
-    {
+    $count = (Get-ChildItem -Path $path -Filter "*.dll" | Measure-Object).Count
+    If ($count -eq 0) {
         Write-Error "There are no DLL files inside the folder." -ErrorAction Stop
     }
 }
 
-Function RunCommand
-{
+Function RunCommand {
     Param (
-        [Parameter(Mandatory=$True)]
+        [Parameter(Mandatory = $True)]
         [ValidateNotNullOrEmpty()]
         [string]
         $command
@@ -184,38 +189,34 @@ Function RunCommand
     Invoke-Expression "$command"
 }
 
-Function GetDotNetFullName
-{
+Function GetDotNetFullName {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [bool]
         $IsComparingReleases
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("\d+\.\d")]
         [string]
         $dotNetVersion # 7.0, 8.0, 9.0, ...
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [string]
         [ValidateSet("preview", "rc", "ga")]
         $previewOrRC
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("(\d+)?")]
         [string]
         $previewNumberVersion # 0, 1, 2, 3, ...
     )
 
-    If ($IsComparingReleases)
-    {
+    If ($IsComparingReleases) {
         Return "$dotNetVersion.$previewNumberVersion"
     }
 
-    If ($previewOrRC -eq "ga")
-    {
-        If ($previewNumberVersion -eq "0")
-        {
+    If ($previewOrRC -eq "ga") {
+        If ($previewNumberVersion -eq "0") {
             # Example: Don't return "7.0-ga0", instead just return "7.0-ga"
             Return "$dotNetVersion-$previewOrRC"
         }
@@ -228,39 +229,34 @@ Function GetDotNetFullName
     Return "$dotNetVersion-$previewOrRC$previewNumberVersion"
 }
 
-Function GetDotNetFriendlyName
-{
+Function GetDotNetFriendlyName {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("\d+\.\d")]
         [string]
         $DotNetVersion # 7.0, 8.0, 9.0, ...
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [string]
         [ValidateSet("preview", "rc", "ga")]
         $PreviewOrRC
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("(\d+)?")]
         [string]
         $PreviewNumberVersion # 0, 1, 2, 3, ...
     )
 
     $friendlyPreview = ""
-    If ($PreviewOrRC -eq "preview")
-    {
+    If ($PreviewOrRC -eq "preview") {
         $friendlyPreview = "Preview"
     }
-    ElseIf ($PreviewOrRC -eq "rc")
-    {
+    ElseIf ($PreviewOrRC -eq "rc") {
         $friendlyPreview = "RC"
     }
-    ElseIf ($PreviewOrRC -eq "ga")
-    {
+    ElseIf ($PreviewOrRC -eq "ga") {
         $friendlyPreview = "GA"
-        If ($PreviewNumberVersion -eq 0)
-        {
+        If ($PreviewNumberVersion -eq 0) {
             # Example: Don't return "7.0 GA 0", instead just return "7.0 GA"
             Return ".NET $DotNetVersion $friendlyPreview"
         }
@@ -273,29 +269,26 @@ Function GetDotNetFriendlyName
     Return ".NET $DotNetVersion $friendlyPreview $PreviewNumberVersion"
 }
 
-Function GetPreviewOrRCFolderName
-{
+Function GetPreviewOrRCFolderName {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("\d+\.\d")]
         [string]
         $dotNetVersion # 7.0, 8.0, 9.0, ...
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [string]
         [ValidateSet("preview", "rc", "ga")]
         $previewOrRC
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("(\d+)?")]
         [string]
         $previewNumberVersion # 0, 1, 2, 3, ...
     )
 
-    If ($previewOrRC -eq "ga")
-    {
-        If ($previewNumberVersion -eq "0")
-        {
+    If ($previewOrRC -eq "ga") {
+        If ($previewNumberVersion -eq "0") {
             # return "ga", not "ga0"
             Return $previewOrRC
         }
@@ -307,30 +300,29 @@ Function GetPreviewOrRCFolderName
     Return "$previewOrRC$previewNumberVersion"
 }
 
-Function GetPreviewFolderPath
-{
+Function GetPreviewFolderPath {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $rootFolder #"D:\\core"
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("\d+\.\d")]
         [string]
         $dotNetVersion # 7.0, 8.0, 9.0, ...
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [string]
         [ValidateSet("preview", "rc", "ga")]
         $previewOrRC
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("(\d+)?")]
         [string]
         $previewNumberVersion # 0, 1, 2, 3, ...
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [bool]
         $IsComparingReleases # True when comparing 8.0 GA with 9.0 GA
     )
@@ -338,8 +330,7 @@ Function GetPreviewFolderPath
     $prefixFolder = [IO.Path]::Combine($rootFolder, "release-notes", $dotNetVersion)
     $apiDiffFolderName = "api-diff"
 
-    If ($IsComparingReleases)
-    {
+    If ($IsComparingReleases) {
         Return [IO.Path]::Combine($prefixFolder, "$dotNetVersion.$previewNumberVersion", $apiDiffFolderName)
     }
 
@@ -347,30 +338,29 @@ Function GetPreviewFolderPath
     Return [IO.Path]::Combine($prefixFolder, "preview", $previewOrRCFolderName, $apiDiffFolderName)
 }
 
-Function RunApiDiff2
-{
+Function RunApiDiff2 {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $apiDiffExe
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $outputFolder
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $beforeFolder
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $afterFolder
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $tableOfContentsFileNamePrefix
@@ -380,7 +370,7 @@ Function RunApiDiff2
         [string]
         $assembliesToExclude
         ,
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $attributesToExclude
@@ -406,28 +396,26 @@ Function RunApiDiff2
     RunCommand "$apiDiffExe -b '$beforeFolder' -a '$afterFolder' -o '$outputFolder' -tc '$tableOfContentsFileNamePrefix' -eas '$assembliesToExclude' -eattrs '$attributesToExclude' -bfn '$beforeFriendlyName' -afn '$afterFriendlyName'"
 }
 
-Function CreateReadme
-{
+Function CreateReadme {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $previewFolderPath
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $dotNetFriendlyName
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $dotNetFullName
     )
 
-    $readmePath=[IO.Path]::Combine($previewFolderPath, "README.md")
-    If (Test-Path -Path $readmePath)
-    {
+    $readmePath = [IO.Path]::Combine($previewFolderPath, "README.md")
+    If (Test-Path -Path $readmePath) {
         Remove-Item -Path $readmePath
     }
     New-Item -ItemType File $readmePath
@@ -441,20 +429,19 @@ Function CreateReadme
     Add-Content $readmePath "- [Microsoft.WindowsDesktop.App](./Microsoft.WindowsDesktop.App/$dotNetFullName.md)"
 }
 
-Function RebuildIfExeNotFound
-{
+Function RebuildIfExeNotFound {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $exePath
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $projectPath
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $artifactsPath
@@ -462,8 +449,7 @@ Function RebuildIfExeNotFound
 
     VerifyPathOrExit $projectPath
 
-    If (-Not (Test-Path -Path $exePath))
-    {
+    If (-Not (Test-Path -Path $exePath)) {
         # Building the project
 
         Write-Color cyan "Building project '$projectPath'"
@@ -475,39 +461,38 @@ Function RebuildIfExeNotFound
     }
 }
 
-Function DownloadPackage
-{
+Function DownloadPackage {
     Param
     (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [bool]
         $useNuget
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateSet("NETCore", "AspNetCore", "WindowsDesktop")]
         [string]
         $sdkName
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateSet("Before", "After")]
         [string]
         $beforeOrAfter
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("\d+\.\d")]
         [string]
         $dotNetVersion
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidateSet("preview", "rc", "ga")]
         [string]
         $previewOrRC
-    ,
-        [Parameter(Mandatory=$true)]
+        ,
+        [Parameter(Mandatory = $true)]
         [ValidatePattern("(\d+)?")]
         [string]
         $previewNumberVersion
-    ,
+        ,
         [ref]
         $resultingPath
     )
@@ -521,19 +506,16 @@ Function DownloadPackage
     $feed = $useNuget ? "https://api.nuget.org/v3/index.json" : "https://dnceng.pkgs.visualstudio.com/public/_packaging/dotnet10/nuget/v3/index.json"
 
     $searchTerm = ""
-    If ($previewOrRC -eq "ga")
-    {
+    If ($previewOrRC -eq "ga") {
         $searchTerm = "$dotNetversion.$previewNumberVersion"
     }
-    ElseIf (-Not ([System.String]::IsNullOrWhiteSpace($previewOrRC)) -And -Not ([System.String]::IsNullOrWhiteSpace($previewNumberVersion)))
-    {
+    ElseIf (-Not ([System.String]::IsNullOrWhiteSpace($previewOrRC)) -And -Not ([System.String]::IsNullOrWhiteSpace($previewNumberVersion))) {
         $searchTerm = "$dotNetversion.*-$previewOrRC.$previewNumberVersion*"
     }
 
     $foundPackages = Find-Package -AllVersions -Source $feed -Name $refPackageName -AllowPrereleaseVersions -ErrorAction Continue
 
-    If ($foundPackages.Count -eq 0)
-    {
+    If ($foundPackages.Count -eq 0) {
         Write-Error "No NuGet packages found with ref package name '$refPackageName' in feed '$feed'"
         Get-PackageSource -Name $refPackageName | Format-Table -Property Name, SourceUri
         Write-Error "Exiting" -ErrorAction Stop
@@ -541,16 +523,14 @@ Function DownloadPackage
 
     $results = $foundPackages | Where-Object -Property Version -Like $searchTerm | Sort-Object Version -Descending
 
-    If ($results.Count -eq 0)
-    {
+    If ($results.Count -eq 0) {
         Write-Error "No NuGet packages found with search term '$searchTerm'." -ErrorAction Stop
     }
 
     $version = $results[0].Version
     $nupkgFile = [IO.Path]::Combine($TmpFolder, "$refPackageName.$version.nupkg")
 
-    If (-Not(Test-Path -Path $nupkgFile))
-    {
+    If (-Not(Test-Path -Path $nupkgFile)) {
         $href = $results[0].Links | Where-Object -Property Relationship -Eq "icon" | Select-Object -ExpandProperty HRef
         $link = $href.AbsoluteUri.Replace("?extract=Icon.png", "")
 
@@ -560,8 +540,7 @@ Function DownloadPackage
         Invoke-WebRequest -Uri $nupkgUrl -OutFile $nupkgFile
         VerifyPathOrExit $nupkgFile
     }
-    Else
-    {
+    Else {
         Write-Color green "File '$nupkgFile' already exists locally. Skipping re-download."
     }
 
@@ -573,10 +552,9 @@ Function DownloadPackage
     $resultingPath.value = $dllPath
 }
 
-Function GetFileLinesAsCommaSeparaterList
-{
+Function GetFileLinesAsCommaSeparaterList {
     Param (
-        [Parameter(Mandatory=$true)]
+        [Parameter(Mandatory = $true)]
         [ValidateNotNullOrEmpty()]
         [string]
         $filePath
@@ -588,48 +566,79 @@ Function GetFileLinesAsCommaSeparaterList
     Return $lines
 }
 
-### Execution ###
+Function ProcessSdk
+{
+    Param(
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $sdkName
+    ,
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $apiDiffExe
+    ,
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $currentDotNetFullName
+    ,
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $assembliesToExclude
+    ,
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $attributesToExclude
+    ,
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $previousDotNetFriendlyName
+    ,
+        [Parameter(Mandatory = $false)]
+        [ValidateNotNullOrEmpty()]
+        [string]
+        $currentDotNetFriendlyName
+    )
 
-## Generate strings with no whitespace
+    $beforeDllFolder = ""
+    DownloadPackage $UseNuget $sdkName "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$beforeDllFolder)
+    VerifyPathOrExit $beforeDllFolder
 
-# True when comparing 8.0 GA with 9.0 GA
-$IsComparingReleases = ($PreviousDotNetVersion -Ne $CurrentDotNetVersion) -And ($PreviousPreviewOrRC -Eq "ga") -And ($CurrentPreviewOrRC -eq "ga")
+    $afterDllFolder = ""
+    DownloadPackage $UseNuget $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$afterDllFolder)
+    VerifyPathOrExit $afterDllFolder
 
-## Check folders passed as parameters exist
+    $targetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.$adkName.App")
+    RecreateFolder $targetFolder
 
-VerifyPathOrExit $CoreRepo
-VerifyPathOrExit $SdkRepo
-VerifyPathOrExit $TmpFolder
+    RunApiDiff2 $apiDiffExe $targetFolder $beforeDllFolder $afterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+}
 
+#####################
+### End Functions ###
+#####################
 
-## Download the NuGet packages
+#######################
+### Start Execution ###
+#######################
 
-# NETCore
-$netCoreBeforeDllFolder = ""
-DownloadPackage $UseNuget "NETCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$netCoreBeforeDllFolder)
-VerifyPathOrExit $netCoreBeforeDllFolder
 
-$netCoreAfterDllFolder = ""
-DownloadPackage $UseNuget "NETCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$netCoreAfterDllFolder)
-VerifyPathOrExit $netCoreAfterDllFolder
+## Generate strings with no whitespace
 
-# AspNetCore
-$aspNetCoreBeforeDllFolder = ""
-DownloadPackage $UseNuget "AspNetCore" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$aspNetCoreBeforeDllFolder)
-VerifyPathOrExit $aspNetCoreBeforeDllFolder
+# True when comparing 8.0 GA with 9.0 GA
+$IsComparingReleases = ($PreviousDotNetVersion -Ne $CurrentDotNetVersion) -And ($PreviousPreviewOrRC -Eq "ga") -And ($CurrentPreviewOrRC -eq "ga")
 
-$aspNetCoreAfterDllFolder = ""
-DownloadPackage $UseNuget "AspNetCore" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$aspNetCoreAfterDllFolder)
-VerifyPathOrExit $aspNetCoreAfterDllFolder
 
-# WindowsDesktop
-$windowsDesktopBeforeDllFolder = ""
-DownloadPackage $UseNuget "WindowsDesktop" "Before" $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion ([ref]$windowsDesktopBeforeDllFolder)
-VerifyPathOrExit $windowsDesktopBeforeDllFolder
+## Check folders passed as parameters exist
 
-$windowsDesktopAfterDllFolder = ""
-DownloadPackage $UseNuget "WindowsDesktop" "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$windowsDesktopAfterDllFolder)
-VerifyPathOrExit $windowsDesktopAfterDllFolder
+VerifyPathOrExit $CoreRepo
+VerifyPathOrExit $SdkRepo
+VerifyPathOrExit $TmpFolder
 
 
 ## Ensure ApiDiff artifacts exist
@@ -639,26 +648,15 @@ $apiDiffArtifactsPath = [IO.Path]::Combine($SdkRepo , "artifacts", "bin", "Micro
 $apiDiffExe = [IO.Path]::Combine($apiDiffArtifactsPath, "Release", "net8.0", "Microsoft.DotNet.ApiDiff.Tool.exe")
 ReBuildIfExeNotFound $apiDiffExe $apiDiffProjectPath $apiDiffArtifactsPath
 
+
 ## Recreate api-diff folder in core repo folder
 
 $previewFolderPath = GetPreviewFolderPath $CoreRepo $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion $IsComparingReleases
-Write-Color cyan "Checking existing diff folder: $previewFolderPath"
-RecreateFolder $previewFolderPath
-
-
-## Create subfolders
-
-# NETCore
-$netCoreTargetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.NETCore.App")
-RecreateFolder $netCoreTargetFolder
-
-#AspNetCore
-$aspNetCoreTargetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.AspNetCore.App")
-RecreateFolder $aspNetCoreTargetFolder
-
-# WindowsDesktop
-$windowsDesktopTargetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.WindowsDesktop.App")
-RecreateFolder $windowsDesktopTargetFolder
+If (-Not (Test-Path -Path $previewFolderPath))
+{
+    Write-Color white "Creating new diff folder: $previewFolderPath"
+    New-Item -ItemType Directory -Path $previewFolderPath
+}
 
 
 ## Run the ApiDiff commands
@@ -676,8 +674,23 @@ $currentDotNetFullName = GetDotNetFullName $IsComparingReleases $CurrentDotNetVe
 $previousDotNetFriendlyName = GetDotNetFriendlyName $PreviousDotNetVersion $PreviousPreviewOrRC $PreviousPreviewNumberVersion
 $currentDotNetFriendlyName = GetDotNetFriendlyName $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion
 
-RunApiDiff2 $apiDiffExe $netCoreTargetFolder $netCoreBeforeDllFolder $netCoreAfterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
-RunApiDiff2 $apiDiffExe $aspNetCoreTargetFolder $aspNetCoreBeforeDllFolder $aspNetCoreAfterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
-RunApiDiff2 $apiDiffExe $windowsDesktopTargetFolder $windowsDesktopBeforeDllFolder $windowsDesktopAfterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+If (-Not $ExcludeNetCore)
+{
+    ProcessSdk "NETCore" $apiDiffExe $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+}
+
+If (-Not $ExcludeAspNetCore)
+{
+    ProcessSdk "AspNetCore" $apiDiffExe $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+}
+
+If (-Not $ExcludeWindowsDesktop)
+{
+    ProcessSdk "WindowsDesktop" $apiDiffExe $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName
+}
 
 CreateReadme $previewFolderPath $currentDotNetFriendlyName $currentDotNetFullName
+
+#####################
+### End Execution ###
+#####################
\ No newline at end of file

From f4414dce86bc4f4650214f0fb92ab1bfd37049a8 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Carlos=20S=C3=A1nchez=20L=C3=B3pez?=
 <1175054+carlossanlop@users.noreply.github.com>
Date: Thu, 27 Mar 2025 22:45:28 -0700
Subject: [PATCH 7/7] typo

---
 release-notes/RunApiDiff2.ps1 | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/release-notes/RunApiDiff2.ps1 b/release-notes/RunApiDiff2.ps1
index 3884dbbcb9..40daf32827 100644
--- a/release-notes/RunApiDiff2.ps1
+++ b/release-notes/RunApiDiff2.ps1
@@ -613,7 +613,7 @@ Function ProcessSdk
     DownloadPackage $UseNuget $sdkName "After" $CurrentDotNetVersion $CurrentPreviewOrRC $CurrentPreviewNumberVersion ([ref]$afterDllFolder)
     VerifyPathOrExit $afterDllFolder
 
-    $targetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.$adkName.App")
+    $targetFolder = [IO.Path]::Combine($previewFolderPath, "Microsoft.$sdkName.App")
     RecreateFolder $targetFolder
 
     RunApiDiff2 $apiDiffExe $targetFolder $beforeDllFolder $afterDllFolder $currentDotNetFullName $assembliesToExclude $attributesToExclude $previousDotNetFriendlyName $currentDotNetFriendlyName