[CmdletBinding()] Param( [Parameter(Mandatory=$True,Position=1)] [string]$path ) $noticeFile = Get-Content -Raw "NOTICE.md" Write-Host $noticeFile Write-Host "Verifying NuGet packages" $projFiles = Get-ChildItem $path -Filter *.csproj -force -Recurse $projFiles.Count Write-Host "Going through all csproj files" $totalList = $projFiles | ForEach-Object -Parallel { $csproj = $_ $nugetTemp = @(); #Workaround for preventing exit code from dotnet process from reflecting exit code in PowerShell $procInfo = New-Object System.Diagnostics.ProcessStartInfo -Property @{ FileName = "dotnet.exe"; Arguments = "list $csproj package"; RedirectStandardOutput = $true; RedirectStandardError = $true; } $proc = [System.Diagnostics.Process]::Start($procInfo); while (!$proc.StandardOutput.EndOfStream) { $nugetTemp += $proc.StandardOutput.ReadLine(); } $proc = $null; $procInfo = $null; if($nugetTemp -is [array] -and $nugetTemp.count -gt 3) { # Need to debug this script? Uncomment this line. # Write-Host $csproj "`r`n" $nugetTemp "`r`n" $temp = New-Object System.Collections.ArrayList $temp.AddRange($nugetTemp) $temp.RemoveRange(0, 3) foreach($p in $temp) { # ignore "Auto-referenced" string in the output if ($p -match "Auto-referenced") { continue } # breaking item down to usable array and getting 1 and 2, see below of a sample output # > PACKAGE VERSION VERSION # if a package is Auto-referenced, "(A)" will appear in position 1 instead of a version number. $p = -split $p $p = $p[1, 2] $tempString = $p[0] if([string]::IsNullOrWhiteSpace($tempString)) { Continue } if($tempString.StartsWith("Microsoft.") -Or $tempString.StartsWith("System.")) { Continue } echo "- $tempString" } $csproj = $null; } } -ThrottleLimit 4 | Sort-Object $returnList = [System.Collections.Generic.HashSet[string]]($totalList) -join "`r`n" Write-Host $returnList # Extract the current package list from NOTICE.md $noticePattern = "## NuGet Packages used by PowerToys\s*((?:\r?\n- .+)+)" $noticeMatch = [regex]::Match($noticeFile, $noticePattern) if ($noticeMatch.Success) { $currentNoticePackageList = $noticeMatch.Groups[1].Value.Trim() } else { Write-Warning "Warning: Could not find 'NuGet Packages used by PowerToys' section in NOTICE.md" $currentNoticePackageList = "" } # Test-only packages that are allowed to be in NOTICE.md but not in the build # (e.g., when BuildTests=false, these packages won't appear in the NuGet list) $allowedExtraPackages = @( "- Moq", "- MSTest" ) if (!$noticeFile.Trim().EndsWith($returnList.Trim())) { Write-Host -ForegroundColor Yellow "Notice.md does not exactly match NuGet list. Analyzing differences..." # Show detailed differences $generatedPackages = $returnList -split "`r`n|`n" | Where-Object { $_.Trim() -ne "" } | Sort-Object $noticePackages = $currentNoticePackageList -split "`r`n|`n" | Where-Object { $_.Trim() -ne "" } | ForEach-Object { $_.Trim() } | Sort-Object Write-Host "" Write-Host -ForegroundColor Cyan "=== DETAILED DIFFERENCE ANALYSIS ===" Write-Host "" # Find packages in proj file list but not in NOTICE.md $missingFromNotice = $generatedPackages | Where-Object { $noticePackages -notcontains $_ } if ($missingFromNotice.Count -gt 0) { Write-Host -ForegroundColor Red "MissingFromNotice (ERROR - these must be added to NOTICE.md):" foreach ($pkg in $missingFromNotice) { Write-Host -ForegroundColor Red " $pkg" } Write-Host "" } # Find packages in NOTICE.md but not in proj file list $extraInNotice = $noticePackages | Where-Object { $generatedPackages -notcontains $_ } # Filter out allowed extra packages (test-only dependencies) $unexpectedExtra = $extraInNotice | Where-Object { $allowedExtraPackages -notcontains $_ } $allowedExtra = $extraInNotice | Where-Object { $allowedExtraPackages -contains $_ } if ($allowedExtra.Count -gt 0) { Write-Host -ForegroundColor Green "ExtraInNotice (OK - allowed test-only packages):" foreach ($pkg in $allowedExtra) { Write-Host -ForegroundColor Green " $pkg" } Write-Host "" } if ($unexpectedExtra.Count -gt 0) { Write-Host -ForegroundColor Red "ExtraInNotice (ERROR - unexpected packages in NOTICE.md):" foreach ($pkg in $unexpectedExtra) { Write-Host -ForegroundColor Red " $pkg" } Write-Host "" } # Show counts for summary Write-Host -ForegroundColor Cyan "Summary:" Write-Host " Proj file list has $($generatedPackages.Count) packages" Write-Host " NOTICE.md has $($noticePackages.Count) packages" Write-Host " MissingFromNotice: $($missingFromNotice.Count) packages" Write-Host " ExtraInNotice (allowed): $($allowedExtra.Count) packages" Write-Host " ExtraInNotice (unexpected): $($unexpectedExtra.Count) packages" Write-Host "" # Fail if there are missing packages OR unexpected extra packages if ($missingFromNotice.Count -gt 0 -or $unexpectedExtra.Count -gt 0) { Write-Host -ForegroundColor Red "FAILED: NOTICE.md mismatch detected." exit 1 } else { Write-Host -ForegroundColor Green "PASSED: NOTICE.md matches (with allowed test-only packages)." } } exit 0