You've already forked winget-pkgs
mirror of
https://github.com/TermoraDev/winget-pkgs.git
synced 2026-04-22 15:31:19 -07:00
5694 lines
178 KiB
PowerShell
5694 lines
178 KiB
PowerShell
#Copyright 2022-2025 Microsoft Corporation
|
|
#Author: Stephen Gillie
|
|
#Title: Manual Validation Pipeline v3.90.0
|
|
#Created: 10/19/2022
|
|
#Updated: 3/3/2025
|
|
#Notes: Utilities to streamline evaluating 3rd party PRs.
|
|
|
|
|
|
$build = 1085
|
|
$appName = "ManualValidationPipeline"
|
|
Write-Host "$appName build: $build"
|
|
$MainFolder = "C:\ManVal"
|
|
$Owner = "microsoft"
|
|
$Repo = "winget-pkgs"
|
|
$ReposFolder = "C:\repos\$Repo"
|
|
#Share this folder with Windows File Sharing, then access it from within the VM across the network, as \\LaptopIPAddress\SharedFolder. For LaptopIPAddress use Ethernet adapter vEthernet (Default Switch) IPv4 Address.
|
|
Set-Location $MainFolder
|
|
|
|
$ipconfig = (ipconfig)
|
|
$remoteIP = ([ipaddress](($ipconfig[($ipconfig | Select-String "vEthernet").LineNumber..$ipconfig.length] | Select-String "IPv4 Address") -split ": ")[1]).IPAddressToString
|
|
$RemoteMainFolder = "//$remoteIP/"
|
|
$SharedFolder = "$RemoteMainFolder/write"
|
|
|
|
$imagesFolder = "$MainFolder\Images" #VM Images folder
|
|
$logsFolder = "$MainFolder\logs" #VM Logs folder
|
|
$runPath = "$MainFolder\vm\" #VM working folder
|
|
$writeFolder = "$MainFolder\write" #Folder with write permissions
|
|
$vmCounter = "$MainFolder\vmcounter.txt"
|
|
$VMversion = "$MainFolder\VMversion.txt"
|
|
$StatusFile = "$writeFolder\status.csv"
|
|
$TrackerModeFile = "$logsFolder\trackermode.txt"
|
|
$RemoteTrackerModeFile = "$RemoteMainFolder\ManVal\logs\trackermode.txt"
|
|
$LogFile = "$MainFolder\misc\ApprovedPRs.txt"
|
|
$PeriodicRunLog = "$MainFolder\misc\PeriodicRunLog.txt"
|
|
$SharedErrorFile = "$writeFolder\err.txt"
|
|
$DataFileName = "$ReposFolder\Tools\ManualValidationPipeline.csv"
|
|
|
|
$LabelActionFile = "$ReposFolder\Tools\LabelActions.csv"
|
|
$ExitCodeFile = "$ReposFolder\Tools\ExitCodes.csv"
|
|
$MsiErrorCodeFile = "$ReposFolder\Tools\MsiErrorCodes.csv"
|
|
$AutowaiverFile = "$ReposFolder\Tools\Autowaiver.csv"
|
|
$PRStateDataFile = "$ReposFolder\Tools\PRStateFromComments.csv"
|
|
$PRQueueFile = "C:\manval\misc\PRQueue.txt"
|
|
$PRExcludeFile = "C:\manval\misc\PRExclude.txt"
|
|
|
|
$Win10Folder = "$imagesFolder\Win10-Created053025-Original"
|
|
$Win11Folder = "$imagesFolder\Win11-Created061225-Original"
|
|
|
|
$GitHubBaseUrl = "https://github.com/$Owner/$Repo"
|
|
$GitHubContentBaseUrl = "https://raw.githubusercontent.com//$Owner/$Repo"
|
|
$GitHubApiBaseUrl = "https://api.github.com/repos/$Owner/$Repo"
|
|
$ADOMSBaseUrl = "https://dev.azure.com/shine-oss"
|
|
$ADOMSGUID = "8b78618a-7973-49d8-9174-4360829d979b"
|
|
|
|
$CheckpointName = "Validation"
|
|
$VMUserName = "user" #Set to the internal username you're using in your VMs.
|
|
$GitHubUserName = "stephengillie"
|
|
$SystemRAM = (Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb
|
|
$Host.UI.RawUI.WindowTitle = "Utility"
|
|
$GitHubRateLimitDelay = 0.2 #seconds
|
|
|
|
$PRRegex = "[0-9]{5,6}"
|
|
$hashPRRegex = "[#]"+$PRRegex
|
|
$hashPRRegexEnd = $hashPRRegex+"$"
|
|
$colonPRRegex = $PRRegex+"[:]"
|
|
#"Manual Validation results for $PackageIdentifier version $PackageVersion on $Date"
|
|
|
|
<#
|
|
$package = "clang-uml"
|
|
$a = Get-ARPTable |where {$_.DisplayName -match $package}
|
|
$a.displayversion
|
|
$b = &"C:\Program Files\clang-uml\bin\clang-uml.exe" "--version"
|
|
$a.DisplayVersion -match $b
|
|
$a.DisplayVersion -match $b -join " "
|
|
$b -match $a.DisplayVersion
|
|
#>
|
|
|
|
#region Data
|
|
[array]$DisplayVersionExceptionList = "Netbird.Netbird",
|
|
"ppy.osu"
|
|
|
|
#$MagicStrings = @{}
|
|
[array]$MagicStrings = "Installer Verification Analysis Context Information:", #0
|
|
"[error] One or more errors occurred.", #1
|
|
"[error] Manifest Error:", #2
|
|
"BlockingDetectionFound", #3
|
|
"Processing manifest", #4
|
|
"SQL error or missing database", #5
|
|
"Error occurred while downloading installer", #6
|
|
"Specified hash doesn't match", #7
|
|
"[error] Manifest is invalid", #8
|
|
"Result: Failed", #9
|
|
"[error] Manifest Warning:",#10
|
|
"[error] Manifest:",#11
|
|
"Exception Message",#12
|
|
"[error] "#13
|
|
|
|
$Actions = @{}
|
|
$Actions.Approved = "Approved"
|
|
$Actions.Blocking = "Blocking"
|
|
$Actions.Feedback = "Feedback"
|
|
$Actions.Retry = "Retry"
|
|
$Actions.Manual = "Manual"
|
|
$Actions.Closed = "Closed"
|
|
$Actions.Project = "Project"
|
|
$Actions.Squash = "Squash"
|
|
$Actions.Waiver = "Waiver"
|
|
|
|
$Labels = @{}
|
|
|
|
$Labels.403 = "Validation-Forbidden-URL-Error"
|
|
$Labels.404 = "Validation-404-Error"
|
|
$Labels.AGR = "Agreements"
|
|
$Labels.ANA = "Author-Not-Authorized"
|
|
$Labels.ANF = "Manifest-AppsAndFeaturesVersion-Error"
|
|
$Labels.APP = "Azure-Pipeline-Passed"
|
|
$Labels.BI = "Blocking-Issue"
|
|
$Labels.BMM = "Bulk-Modify-Metadata"
|
|
$Labels.BVE = "Binary-Validation-Error"
|
|
$Labels.CLA = "Needs-CLA"
|
|
$Labels.CR = "Changes-Requested"
|
|
$Labels.DI = "DriverInstall"
|
|
$Labels.EAT = "Error-Analysis-Timeout"
|
|
$Labels.EHM = "Error-Hash-Mismatch"
|
|
$Labels.EIA = "Error-Installer-Availability"
|
|
$Labels.HVF = "Validation-Hash-Verification-Failed"
|
|
$Labels.HVL = "Highest-Version-Remaining"
|
|
$Labels.HVR = "Highest-Version-Removal"
|
|
$Labels.HW = "Hardware"
|
|
$Labels.IE = "Internal-Error"
|
|
$Labels.IEDS = "Internal-Error-Dynamic-Scan"
|
|
$Labels.IEM = "Internal-Error-Manifest"
|
|
$Labels.IEU = "Internal-Error-URL"
|
|
$Labels.IOD = "Interactive-Only-Download"
|
|
$Labels.IOI = "3AInteractive-Only-Installer"
|
|
$Labels.LBI = "License-Blocks-Install"
|
|
$Labels.LVR = "Last-Version-Removal"
|
|
$Labels.MA = "Moderator-Approved"
|
|
$Labels.MIVE = "Manifest-Installer-Validation-Error"
|
|
$Labels.MMC = "Manifest-Metadata-Consistency"
|
|
$Labels.MV = "Manually-Validated"
|
|
$Labels.MVE = "Manifest-Validation-Error"
|
|
$Labels.NA = "Needs-Attention"
|
|
$Labels.NAF = "Needs-Author-Feedback"
|
|
$Labels.NB = "Network-Blocker"
|
|
$Labels.NM = "New-Manifest"
|
|
$Labels.NMM = "Needs-Manual-Merge"
|
|
$Labels.NP = "New-Package"
|
|
$Labels.NR = "Needs-Review"
|
|
$Labels.NRA = "No-Recent-Activity"
|
|
$Labels.NSA = "Internal-Error-NoSupportedArchitectures"
|
|
$Labels.OUF = "Validation-Open-Url-Failed"
|
|
$Labels.PD = "Possible-Duplicate"
|
|
$Labels.PF = "Project-File"
|
|
$Labels.PRE = "PullRequest-Error"
|
|
$Labels.PT12 = "Policy-Test-1.2"
|
|
$Labels.PT23 = "Policy-Test-2.3"
|
|
$Labels.PT27 = "Policy-Test-2.7"
|
|
$Labels.RB = "Reboot"
|
|
$Labels.RET = "Retry-1"
|
|
$Labels.SA = "Scripted-Application"
|
|
$Labels.UF = "Unexpected-File"
|
|
$Labels.UVE = "URL-Validation-Error"
|
|
$Labels.VC = "Validation-Completed"
|
|
$Labels.VCR = "Validation-Certificate-Root"
|
|
$Labels.VD = "Validation-Domain"
|
|
$Labels.VDE = "Validation-Defender-Error"
|
|
$Labels.VEE = "Validation-Executable-Error"
|
|
$Labels.VER = "Manifest-Version-Error"
|
|
$Labels.VHE = "Validation-HTTP-Error"
|
|
$Labels.VIE = "Validation-Installation-Error"
|
|
$Labels.VMC = "Validation-Merge-Conflict"
|
|
$Labels.VMD = "Validation-Missing-Dependency"
|
|
$Labels.VNE = "Validation-No-Executables"
|
|
$Labels.VR = "Validation-Retry"
|
|
$Labels.VSA = "Validation-Skip-Automations"
|
|
$Labels.VSE = "Validation-Shell-Execute"
|
|
$Labels.VSS = "Validation-SmartScreen-Error"
|
|
$Labels.VUF = "Validation-Unattended-Failed"
|
|
$Labels.VUU = "Validation-Unapproved-URL"
|
|
|
|
|
|
$PushMePRWho = "Author,MatchString`nspectopo,Mozilla.Firefox`ntrenly,Standardize formatting`nSpecterShell,Mozilla.Thunderbird" | ConvertFrom-Csv
|
|
|
|
$QueueInputs = "No suitable installer found for manifest", #0
|
|
"Caught std::exception: bad allocation", #1
|
|
"exit code: -1073741515",#2
|
|
"exit code: -1978335216"#3
|
|
|
|
#endregion
|
|
|
|
#First tab
|
|
Function Get-TrackerVMRunTracker {
|
|
param(
|
|
[switch]$RunLatch
|
|
)
|
|
$HourLatch = $False
|
|
while ($True) {
|
|
$Host.UI.RawUI.WindowTitle = "Orchestration"
|
|
#Run once an hour at ~20 after.
|
|
if (([int](get-date -f mm) -eq 20) -OR ([int](get-date -f mm) -eq 50)) {
|
|
$HourLatch = $True
|
|
}
|
|
if ($RunLatch -eq $False) {
|
|
$HourLatch = $False
|
|
}
|
|
if ($HourLatch) {#Hourly Run functionality
|
|
Get-ScheduledRun
|
|
$HourLatch = $False
|
|
}
|
|
|
|
Clear-Host
|
|
$GetStatus = Get-Status
|
|
$GetStatus | Format-Table;
|
|
$VMRAM = Get-ArraySum $GetStatus.RAM
|
|
$ramColor = "green"
|
|
$valMode = Get-TrackerMode
|
|
|
|
(Get-Status).vm | %{$path = "C:\ManVal\vm\$_\manifest\Package.yaml";(gc $path) -replace "ManifestVersion: 1..0$","ManifestVersion: 1.10.0" | out-file $path}
|
|
|
|
if ($VMRAM -gt ($SystemRAM*0.5)) {
|
|
$ramColor = "red"
|
|
} elseif ($VMRAM -gt ($SystemRAM*.25)) {
|
|
$ramColor = "yellow"
|
|
}
|
|
Write-Host "VM RAM Total: " -nonewline
|
|
Write-Host -f $ramColor $VMRAM
|
|
$timeClockColor = "red"
|
|
if (Get-TimeRunning) {
|
|
$timeClockColor = "green"
|
|
}
|
|
$PRQueueCount = Get-PRQueueCount
|
|
Write-Host -nonewline "Build: $build - Hours worked: "
|
|
Write-Host -nonewline -f $timeClockColor (Get-HoursWorkedToday)
|
|
Write-Host " - PRs in queue: $PRQueueCount - Hourly Run: $RunLatch"
|
|
(Get-VM) | ForEach-Object {
|
|
if(($_.MemoryDemand / $_.MemoryMaximum) -ge 0.9){
|
|
Set-VM -VMName $_.name -MemoryMaximumBytes "$(($_.MemoryMaximum / 1073741824)+2)GB"
|
|
}
|
|
}
|
|
$status = Get-Status
|
|
$status | ForEach-Object {$_.RAM = [math]::Round((Get-VM -Name ("vm"+$_.vm)).MemoryAssigned/1024/1024/1024,2)}
|
|
Write-Status $status
|
|
Get-TrackerVMCycle;
|
|
Get-TrackerVMWindowArrange
|
|
|
|
if ($valMode -eq "IEDS") {
|
|
if ((Get-ArraySum (Get-Status).RAM) -lt ($SystemRAM*.42)) {
|
|
Write-Output $valMode
|
|
Get-RandomIEDS
|
|
}
|
|
}
|
|
|
|
if ($PRQueueCount -gt 0) {
|
|
if ((Get-ArraySum (Get-Status).RAM) -lt ($SystemRAM*.42)) {
|
|
$PR = Get-PopPRQueue
|
|
if ($null -ne $PR) {
|
|
Write-Output "Running $PR from queue."
|
|
Get-RandomIEDS -PR $PR
|
|
}
|
|
}
|
|
}
|
|
|
|
$clip = (Get-Clipboard)
|
|
If ($clip -match $ADOMSBaseUrl) {
|
|
#Write-Output "Gathering Automated Validation Logs"
|
|
#Get-AutoValLog
|
|
} elseIf ($clip -match "Skip to content") {
|
|
if ($valMode -eq "Validating") {
|
|
Write-Output $valMode
|
|
Get-TrackerVMValidate;
|
|
$valMode | clip
|
|
}
|
|
} elseIf ($clip -match " Windows Package Manager") {#Package Manager Dashboard
|
|
#Write-Output "Gathering PR Headings"
|
|
#Get-PRNumber
|
|
} elseIf ($clip -match "^manifests`/") {
|
|
Write-Output "Opening manifest file"
|
|
$ManifestUrl = "$GitHubBaseUrl/tree/master/"+$clip
|
|
$ManifestUrl | clip
|
|
start-process ($ManifestUrl)
|
|
}
|
|
# $MozillaThunderbird = (Get-Status | ? {$_.Package -match "Mozilla.Thunderbird"} ).vm
|
|
# if ($null -ne $MozillaThunderbird) {
|
|
# $MozillaThunderbird | %{Get-TrackerVMSetStatus -Status Complete -VM $_}
|
|
# }
|
|
if (Get-ConnectedVM) {
|
|
#Get-TrackerVMResetStatus
|
|
} else {
|
|
Get-TrackerVMRotate
|
|
}
|
|
Write-Output "End of cycle."
|
|
Start-Sleep 5;
|
|
}
|
|
#Write-Progress -Completed
|
|
}
|
|
|
|
#Second tab
|
|
Function Get-PRWatch {
|
|
[CmdletBinding()]
|
|
param(
|
|
[switch]$noNew,
|
|
[ValidateSet("Default","Warm","Cool","Random","Afghanistan","Albania","Algeria","American Samoa","Andorra","Angola","Anguilla","Antigua And Barbuda","Argentina","Armenia","Aruba","Australia","Austria","Azerbaijan","Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belgium","Belize","Benin","Bermuda","Bhutan","Bolivia","Bosnia And Herzegovina","Botswana","Bouvet Island","Brazil","Brunei Darussalam","Bulgaria","Burkina Faso","Burundi","Cabo Verde","Cambodia","Cameroon","Canada","Central African Republic","Chad","Chile","China","Colombia","Comoros","Cook Islands","Costa Rica","Croatia","Cuba","Curacao","Cyprus","Czechia","Cöte D'Ivoire","Democratic Republic Of The Congo","Denmark","Djibouti","Dominica","Dominican Republic","Ecuador","Egypt","El Salvador","Equatorial Guinea","Eritrea","Estonia","Eswatini","Ethiopia","Fiji","Finland","France","French Polynesia","Gabon","Gambia","Georgia","Germany","Ghana","Greece","Grenada","Guatemala","Guinea","Guinea-Bissau","Guyana","Haiti","Holy See (Vatican City State)","Honduras","Hungary","Iceland","India","Indonesia","Iran","Iraq","Ireland","Israel","Italy","Jamaica","Japan","Jordan","Kazakhstan","Kenya","Kiribati","Kuwait","Kyrgyzstan","Laos","Latvia","Lebanon","Lesotho","Liberia","Libya","Liechtenstein","Lithuania","Luxembourg","Madagascar","Malawi","Malaysia","Maldives","Mali","Malta","Marshall Islands","Mauritania","Mauritius","Mexico","Micronesia","Moldova","Monaco","Mongolia","Montenegro","Morocco","Mozambique","Myanmar","Namibia","Nauru","Nepal","Netherlands","New Zealand","Nicaragua","Niger","Nigeria","Niue","Norfolk Island","North Korea","North Macedonia","Norway","Oman","Pakistan","Palau","Palestine","Panama","Papua New Guinea","Paraguay","Peru","Philippines","Pitcairn Islands","Poland","Portugal","Qatar","Republic Of The Congo","Romania","Russian Federation","Rwanda","Saint Kitts And Nevis","Saint Lucia","Saint Vincent And The Grenadines","Samoa","San Marino","Sao Tome And Principe","Saudi Arabia","Senegal","Serbia","Seychelles","Sierra Leone","Singapore","Slovakia","Slovenia","Solomon Islands","Somalia","South Africa","South Korea","South Sudan","Spain","Sri Lanka","Sudan","Suriname","Sweden","Switzerland","Syrian Arab Republic","Tajikistan","Tanzania, United Republic Of","Thailand","Togo","Tonga","Trinidad And Tobago","Tunisia","Turkey","Turkmenistan","Tuvalu","Uganda","Ukraine","United Arab Emirates","United Kingdom","United States","Uruguay","Uzbekistan","Vanuatu","Venezuela","Vietnam","Yemen","Zambia","Zimbabwe","Åland Islands")]$Chromatic = "Default",
|
|
$LogFile = ".\PR.txt",
|
|
$ReviewFile = ".\Review.csv",
|
|
$oldclip = "",
|
|
$PrePipeline = $false,
|
|
$AuthList = (Get-ValidationData -Property authStrictness),
|
|
$AgreementsList = (Get-ValidationData -Property AgreementUrl),
|
|
$ReviewList = (Get-LoadFileIfExists $ReviewFile),
|
|
$clip = (Get-Clipboard),
|
|
[switch]$WhatIf
|
|
)
|
|
$Host.UI.RawUI.WindowTitle = "PR Watcher"#I'm a PR Watcher, watchin PRs go by.
|
|
#if ((Get-Command Get-TrackerVMSetMode).name) {Get-TrackerVMSetMode "Approving"}
|
|
|
|
Write-Host " | Timestmp | $(Get-PadRight PR# 6) | $(Get-PadRight PackageIdentifier) | $(Get-PadRight prVersion 15) | A | R | G | W | F | I | D | V | $(Get-PadRight ManifestVer 14) | OK |"
|
|
Write-Host " | -------- | ----- | ------------------------------- | -------------- | - | - | - | - | - | - | - | - | ------------- | -- |"
|
|
|
|
while($True -gt 0){
|
|
$clip = (Get-Clipboard)
|
|
$PRtitle = $clip | Select-String ($hashPRRegexEnd);
|
|
$PR = ($PRtitle -split "#")[1]
|
|
if ($PRtitle) {
|
|
if (Compare-Object $PRtitle $oldclip) {
|
|
# if ((Get-Command Get-Status).name) {
|
|
# (Get-Status | Where-Object {$_.status -eq "ValidationCompleted"} | Format-Table)
|
|
# }
|
|
$validColor = "green"
|
|
$invalidColor = "red"
|
|
$cautionColor = "yellow"
|
|
|
|
Switch ($Chromatic) {
|
|
#Color schemes, to accomodate needs and also add variety.
|
|
"Default" {
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Warm" {
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Cool" {
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Random" {
|
|
$Chromatic = ($CountrySet | get-random)
|
|
Write-Host "Using CountrySet $Chromatic" -f green
|
|
}
|
|
#https://www.flagpictures.com/countries/flag-colors/
|
|
"Afghanistan"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Albania"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Algeria"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"American Samoa"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Andorra"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Angola"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Anguilla"{
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Antigua And Barbuda"{
|
|
$invalidColor = "Red"
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Blue"
|
|
$validColor = "White"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Argentina"{
|
|
$validColor = "White"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Armenia"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Aruba"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Australia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Austria"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Azerbaijan"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Bahamas"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Cyan"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Bahrain"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Bangladesh"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Barbados"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Belarus"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Belgium"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Belize"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Benin"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Bermuda"{
|
|
$invalidColor = "Red"
|
|
}
|
|
"Bhutan"{
|
|
$validColor = "DarkRed"
|
|
$invalidColor = "DarkYellow"
|
|
$cautionColor = "White"
|
|
}
|
|
"Bolivia"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Bosnia And Herzegovina"{
|
|
$invalidColor = "Blue"
|
|
$validColor = "White"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Botswana"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "White"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Bouvet Island"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Brazil"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Brunei Darussalam"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$validColor = "White"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Bulgaria"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Burkina Faso"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Burundi"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Cabo Verde"{
|
|
$validColor = "White"
|
|
$invalidColor = "DarkYellow"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Cambodia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Cameroon"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Canada"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Central African Republic"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Chad"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Chile"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"China"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Colombia"{
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Comoros"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Cook Islands"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Costa Rica"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Croatia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Cuba"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Curaçao"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Cyprus"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Czechia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Côte D'Ivoire"{
|
|
$validColor = "Green"
|
|
$invalidColor = "DarkYellow"
|
|
$cautionColor = "White"
|
|
}
|
|
"Democratic Republic Of The Congo"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Denmark"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Djibouti"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Dominica"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Dominican Republic"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Ecuador"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Egypt"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "DarkYellow"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"El Salvador"{
|
|
$validColor = "White"
|
|
$invalidColor = "DarkYellow"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Equatorial Guinea"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Eritrea"{
|
|
$validColor = "Green"
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Estonia"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Eswatini"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Ethiopia"{
|
|
$validColor = "Green"
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Fiji"{
|
|
$validColor = "White"
|
|
$validColor = "DarkBlue"
|
|
$invalidColor = "DarkYellow"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Finland"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"France"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"French Polynesia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Gabon"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Gambia"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Georgia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Germany"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Ghana"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Greece"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Grenada"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Guatemala"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Guinea"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Guinea-Bissau"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Guyana"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Haiti"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Holy See (Vatican City State)"{
|
|
$validColor = "White"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Honduras"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Hong Kong" {
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Hungary"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Iceland"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"India"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Indonesia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Iran"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Iraq"{
|
|
$invalidColor = "Red"
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Ireland"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Israel"{
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Italy"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Jamaica"{
|
|
$validColor = "Green"
|
|
$invalidColor = "DarkGray"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Japan"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Jordan"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Kazakhstan"{
|
|
$cautionColor = "Yellow"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Kenya"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Kiribati"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Kuwait"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Kyrgyzstan"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Laos"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Latvia"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Lebanon"{
|
|
$invalidColor = "Red"
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Lesotho"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Liberia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Libya"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Liechtenstein"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Lithuania"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Luxembourg"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Macao" {
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Madagascar"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Malawi"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkGray"
|
|
}
|
|
"Malaysia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "DarkBlue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Maldives"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Mali"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Malta"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Marshall Islands"{
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "DarkYellow"
|
|
$cautionColor = "White"
|
|
}
|
|
"Mauritania"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Mauritius"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Mexico"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Micronesia"{
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Moldova"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "DarkYellow"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Monaco"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Mongolia"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Montenegro"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Morocco"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Mozambique"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Myanmar"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
$cautionColor = "White"
|
|
}
|
|
"Namibia"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Nauru"{
|
|
$invalidColor = "Blue"
|
|
$validColor = "White"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Nepal"{
|
|
$validColor = "DarkRed"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Netherlands"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"New Zealand"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Nicaragua"{
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Niger"{
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Nigeria"{
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Niue"{
|
|
$validColor = "DarkYellow"
|
|
}
|
|
"Norfolk Island"{
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"North Korea"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"North Macedonia"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Norway"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Oman"{
|
|
$invalidColor = "Red"
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Pakistan"{
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Palau"{
|
|
$cautionColor = "Yellow"
|
|
$invalidColor = "Blue"
|
|
}
|
|
"Palestine"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Panama"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Papua New Guinea"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Paraguay"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Peru"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Philippines"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Pitcairn Islands"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Brown"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Poland"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
}
|
|
"Portugal"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Qatar"{
|
|
$validColor = "DarkRed"
|
|
$cautionColor = "White"
|
|
}
|
|
"Republic Of The Congo"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Romania"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Russian Federation"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Rwanda"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Cyan"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Saint Kitts And Nevis"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Saint Lucia"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "White"
|
|
$invalidColor = "Cyan"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Saint Vincent And The Grenadines"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Samoa"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"San Marino"{
|
|
$validColor = "White"
|
|
$cautionColor = "Cyan"
|
|
}
|
|
"Sao Tome And Principe"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Saudi Arabia"{
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Senegal"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Serbia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Seychelles"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Sierra Leone"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Singapore"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Slovakia"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Slovenia"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "DarkYellow"
|
|
$cautionColor = "White"
|
|
}
|
|
"Solomon Islands"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Somalia"{
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"South Africa"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "DarkYellow"
|
|
$cautionColor = "White"
|
|
}
|
|
"South Korea"{
|
|
$validColor = "White"
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"South Sudan"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Spain"{
|
|
$invalidColor = "Red"
|
|
$invalidColor = "DarkYellow"
|
|
}
|
|
"Sri Lanka"{
|
|
$validColor = "Green"
|
|
$invalidColor = "DarkRed"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Sudan"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Suriname"{
|
|
$validColor = "DarkYellow"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Sweden"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "DarkYellow"
|
|
}
|
|
"Switzerland"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Syrian Arab Republic"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Tajikistan"{
|
|
$validColor = "DarkYellow"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Tanzania, United Republic Of"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Thailand"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Togo"{
|
|
$validColor = "Green"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Tonga"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Trinidad And Tobago"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Tunisia"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Turkey"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Turkmenistan"{
|
|
$validColor = "Green"
|
|
$cautionColor = "White"
|
|
}
|
|
"Tuvalu"{
|
|
$validColor = "DarkBlue"
|
|
$invalidColor = "DarkYellow"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Cyan"
|
|
$cautionColor = "White"
|
|
}
|
|
"Uganda"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Ukraine"{
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "DarkYellow"
|
|
}
|
|
"United Arab Emirates"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"United Kingdom"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"United States"{
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Blue"
|
|
}
|
|
"Uruguay"{
|
|
$invalidColor = "Blue"
|
|
$cautionColor = "White"
|
|
}
|
|
"Uzbekistan"{
|
|
$validColor = "Green"
|
|
$invalidColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Vanuatu"{
|
|
$validColor = "DarkGray"
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Venezuela"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Vietnam"{
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Yemen"{
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "White"
|
|
}
|
|
"Zambia"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
"Zimbabwe"{
|
|
$validColor = "Green"
|
|
$validColor = "DarkGray"
|
|
$validColor = "White"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
"Ã…land Islands"{
|
|
$validColor = "Blue"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "DarkYellow"
|
|
}
|
|
Default {
|
|
$validColor = "Green"
|
|
$invalidColor = "Red"
|
|
$cautionColor = "Yellow"
|
|
}
|
|
}; #end Switch Chromatic
|
|
|
|
$noRecord = $False
|
|
$title = $PRtitle -split ": "
|
|
if ($title[1]) {
|
|
$title = $title[1] -split " "
|
|
} else {
|
|
$title = $title -split " "
|
|
}
|
|
$Submitter = (($clip | Select-String "wants to merge") -split " ")[0]
|
|
$InstallerType = Get-YamlValue InstallerType
|
|
|
|
#Split the title by spaces. Try extracting the version location as the next item after the word "version", and if that fails, use the 2nd to the last item, then 3rd to last, and 4th to last. For some reason almost everyone puts the version number as the last item, and GitHub appends the PR number.
|
|
$prVerLoc =($title | Select-String "version").linenumber
|
|
#Version is on the line before the line number, and this set indexes with 1 - but the following array indexes with 0, so the value is automatically transformed by the index mismatch.
|
|
try {
|
|
[System.Version]$prVersion = Get-YamlValue PackageVersion $clip -replace "'","" -replace '"',''
|
|
} catch {
|
|
try {
|
|
$prVersion = Get-YamlValue PackageVersion $clip -replace "'","" -replace '"',''
|
|
} catch {
|
|
try {
|
|
[System.Version]$prVersion = Get-YamlValue PackageVersion $clip
|
|
} catch {
|
|
if ($null -ne $PRVerLoc) {
|
|
try {
|
|
[System.Version]$prVersion = $title[$prVerLoc]
|
|
} catch {
|
|
[string]$prVersion = $title[$prVerLoc]
|
|
}
|
|
} else {
|
|
#Otherwise we have to go hunting for the version number.
|
|
try {
|
|
[System.Version]$prVersion = $title[-1]
|
|
} catch {
|
|
try {
|
|
[System.Version]$prVersion = $title[-2]
|
|
} catch {
|
|
try {
|
|
[System.Version]$prVersion = $title[-3]
|
|
} catch {
|
|
try {
|
|
[System.Version]$prVersion = $title[-4]
|
|
} catch {
|
|
#If it's not a semantic version, guess that it's the 2nd to last, based on the above logic.
|
|
[string]$prVersion = $title[-2]
|
|
}
|
|
}
|
|
}
|
|
}; #end try
|
|
}; #end try
|
|
}; #end if null
|
|
}; #end try
|
|
}; #end try
|
|
|
|
#Get the PackageIdentifier and alert if it matches the auth list.
|
|
$PackageIdentifier = ""
|
|
try {
|
|
$PackageIdentifier = Get-YamlValue PackageIdentifier $clip -replace '"',""
|
|
} catch {
|
|
$PackageIdentifier = (Get-CleanClip $PRtitle); -replace '"',""
|
|
}
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
Write-Host -nonewline -f $matchColor " | $(Get-Date -Format T) | $PR | $(Get-PadRight $PackageIdentifier) | "
|
|
|
|
#Variable effervescence
|
|
$prAuth = "+"
|
|
$Auth = "A"
|
|
$Review = "R"
|
|
$WordFilter = "W"
|
|
$AgreementAccept = "G"
|
|
$AnF = "F"
|
|
$InstVer = "I"
|
|
$ListingDiff = "D"
|
|
$NumVersions = 99
|
|
$PRvMan = "P"
|
|
$Approve = "+"
|
|
|
|
$WinGetOutput = Find-WinGetPackage $PackageIdentifier | where {$_.id -eq $PackageIdentifier}
|
|
$ManifestVersion = $WinGetOutput.version
|
|
$ManifestVersionParams = ($ManifestVersion -split "[.]").count
|
|
$prVersionParams = ($prVersion -split "[.]").count
|
|
|
|
|
|
$AuthMatch = $AuthList | Where-Object {$_.PackageIdentifier -eq $PackageIdentifier}
|
|
|
|
if ($AuthMatch) {
|
|
$AuthAccount = $AuthMatch.GitHubUserName | Sort-Object -Unique
|
|
}
|
|
|
|
if ($null -eq $WinGetOutput) {
|
|
$PRvMan = "N"
|
|
$matchColor = $invalidColor
|
|
$Approve = "-!"
|
|
if ($noNew) {
|
|
$noRecord = $True
|
|
} else {
|
|
Add-PRToQueue -PR $PR
|
|
# if ($title[-1] -match $hashPRRegex) {
|
|
# if ((Get-Command Get-TrackerVMValidate).name) {
|
|
#Add-PRToQueue -PR $PR
|
|
# Get-TrackerVMValidate -Silent -InspectNew
|
|
# } else {
|
|
# Get-Sandbox ($title[-1] -replace"#","")
|
|
# }; #end if Get-Command
|
|
# }; #end if title
|
|
}; #end if noNew
|
|
}
|
|
Write-Host -nonewline -f $matchColor "$(Get-PadRight $PRVersion.toString() 14) | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
if ($AuthMatch) {
|
|
$strictness = $AuthMatch.authStrictness | Sort-Object -Unique
|
|
$matchVar = ""
|
|
$matchColor = $cautionColor
|
|
$AuthAccount -split "/" | where {$_ -notmatch "Microsoft"} | %{
|
|
#write-host "This $_ Submitter $Submitter"
|
|
if ($_ -eq $Submitter) {
|
|
$matchVar = "matches"
|
|
$Auth = "+"
|
|
$matchColor = $validColor
|
|
}
|
|
foreach ($User in ((Invoke-GitHubPRRequest -PR $PR -Type reviews -Output Content).user.login | select -Unique)) {
|
|
if ($Submitter -match $User) {
|
|
$matchVar = "preapproved"
|
|
$Auth = "+"
|
|
$matchColor = $validColor
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
if ($matchVar -eq "") {
|
|
$matchVar = "does not match"
|
|
$Auth = "-"
|
|
$matchColor = $invalidColor
|
|
}
|
|
if ($strictness -eq "must") {
|
|
$Auth += "!"
|
|
}
|
|
}
|
|
if ($Auth -eq "-!") {
|
|
if (!$WhatIf) {
|
|
Get-PRApproval -PR $PR -PackageIdentifier $PackageIdentifier
|
|
}
|
|
}
|
|
Write-Host -nonewline -f $matchColor "$Auth | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
$ReviewMatch = $ReviewList | Where-Object {$_.PackageIdentifier -match $PackageIdentifier }
|
|
if ($ReviewMatch) {
|
|
$Review = $ReviewMatch.Reason | Sort-Object -Unique
|
|
$matchColor = $cautionColor
|
|
}
|
|
|
|
Write-Host -nonewline -f $matchColor "$Review | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
#In list, matches PR - explicit pass
|
|
#In list, PR has no Installer.yaml - implicit pass
|
|
#In list, missing from PR - block
|
|
#In list, mismatch from PR - block
|
|
#Not in list or PR - pass
|
|
#Not in list, in PR - alert and pass?
|
|
#Check previous version for omission - depend on wingetbot for now.
|
|
$AgreementUrlFromList = ($AgreementsList | where {$_.PackageIdentifier -eq $PackageIdentifier}).AgreementUrl
|
|
if ($AgreementUrlFromList) {
|
|
$AgreementUrlFromClip = Get-YamlValue AgreementUrl $clip -replace '"',""
|
|
if ($AgreementUrlFromClip -eq $AgreementUrlFromList) {
|
|
#Explicit Approve - URL is present and matches.
|
|
$AgreementAccept = "+!"
|
|
} else {
|
|
#Explicit mismatch - URL is present and does not match, or URL is missing.
|
|
$AgreementAccept = "-!"
|
|
if (!$WhatIf) {
|
|
Reply-ToPR -PR $PR -CannedMessage AgreementMismatch -UserInput $AgreementUrlFromList -Silent
|
|
}
|
|
}
|
|
} else {
|
|
$AgreementAccept = "+"
|
|
#Implicit Approve - your AgreementsUrl is in another file. Can't modify what isn't there.
|
|
}
|
|
Write-Host -nonewline -f $matchColor "$AgreementAccept | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (($PRtitle -notmatch "Automatic deletion") -AND
|
|
($PRtitle -notmatch "Delete") -AND
|
|
($PRtitle -notmatch "Remove") -AND
|
|
($AgreementAccept -notmatch "[+]")) {
|
|
|
|
$WordFilterMatch = $WordFilterList | ForEach-Object {($Clip -match $_) -notmatch "Url" -notmatch "Agreement"}
|
|
|
|
if ($WordFilterMatch) {
|
|
$WordFilter = "-!"
|
|
$Approve = "-!"
|
|
$matchColor = $invalidColor
|
|
if (!$WhatIf) {
|
|
Reply-ToPR -PR $PR -CannedMessage WordFilter -UserInput $WordFilterMatch -Silent
|
|
}
|
|
}
|
|
}
|
|
Write-Host -nonewline -f $matchColor "$WordFilter | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if ($null -ne $WinGetOutput) {
|
|
if (($PRvMan -ne "N") -AND
|
|
($PRtitle -notmatch (($DisplayVersionExceptionList) -join " ")) -AND
|
|
($PRtitle -notmatch "Automatic deletion") -AND
|
|
($PRtitle -notmatch "Delete") -AND
|
|
($PRtitle -notmatch "Remove")) {
|
|
$DisplayVersion = Get-YamlValue DisplayVersion -clip $clip
|
|
$DeveloperIsAuthor = (((Get-YamlValue PackageIdentifier -clip $clip) -split ".") -eq $Submitter)
|
|
$InstallerMatch = ($InstallerUrl -split "/") -match $Submitter
|
|
|
|
if ($DisplayVersion) {
|
|
if ($DisplayVersion -eq $prVersion) {
|
|
$matchColor = $invalidColor
|
|
$AnF = "-"
|
|
if (!$WhatIf) {
|
|
Reply-ToPR -PR $PR -CannedMessage AppsAndFeaturesMatch -UserInput $Submitter -Policy $Labels.NAF -Silent
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback -Title $PRtitle
|
|
}
|
|
}
|
|
}
|
|
|
|
# if (!($DeveloperIsAuthor)) {
|
|
# if ($InstallerMatch) {
|
|
# $matchColor = $invalidColor
|
|
# $AnF = "-"
|
|
# Reply-ToPR -PR $PR -CannedMessage InstallerMatchesSubmitter -UserInput $Submitter -Policy $Labels.NAF -Silent
|
|
# Add-PRToRecord -PR $PR -Action $Actions.Feedback -Title $PRtitle
|
|
# }
|
|
# }
|
|
}
|
|
}
|
|
<#
|
|
#>
|
|
Write-Host -nonewline -f $matchColor "$AnF | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
if (($PRvMan -ne "N") -AND
|
|
($PRtitle -notmatch "Automatic deletion") -AND
|
|
($PRtitle -notmatch "Delete") -AND
|
|
($PRtitle -notmatch "Remove")) {
|
|
try {
|
|
if ([bool]($clip -match "InstallerUrl")) {
|
|
$InstallerUrl = Get-YamlValue InstallerUrl -clip $clip
|
|
#write-host "InstallerUrl: $InstallerUrl $installerMatches prVersion: -PR $PRVersion" -f "blue"
|
|
$installerMatches = [bool]($InstallerUrl | Select-String $PRVersion)
|
|
if (!($installerMatches)) {
|
|
#Matches when the dots are removed from semantec versions in the URL.
|
|
$installerMatches2 = [bool]($InstallerUrl | Select-String ($prVersion -replace "[.]",""))
|
|
if (!($installerMatches2)) {
|
|
$matchColor = $invalidColor
|
|
$InstVer = "-"
|
|
}
|
|
}
|
|
}
|
|
} catch {
|
|
$matchColor = $invalidColor
|
|
$InstVer = "-"
|
|
}; #end try
|
|
}; #end if PRvMan
|
|
|
|
try {
|
|
if (($prVersion = Get-YamlValue PackageVersion $clip) -match " ") {
|
|
$matchColor = $invalidColor
|
|
$InstVer = "-!"
|
|
}
|
|
}catch{
|
|
$null = (Get-Process) #This section intentionally left blank.
|
|
}
|
|
|
|
Write-Host -nonewline -f $matchColor "$InstVer | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
if (($PRvMan -ne "N") -AND
|
|
(($PRtitle -match "Automatic deletion") -OR
|
|
($PRtitle -match "Delete") -OR
|
|
($PRtitle -match "Remove"))) {#Removal PR
|
|
#$Versions =
|
|
$NumVersions = ($WinGetOutput.AvailableVersions | sort).count
|
|
if (($prVersion -eq $ManifestVersion) -OR ($NumVersions -eq 1)) {
|
|
$matchColor = $invalidColor
|
|
if (!$WhatIf) {
|
|
Reply-ToPR -PR $PR -CannedMessage VersionCount -UserInput $Submitter -Silent -Policy "[Policy] $($Labels.NAF)`n[Policy] $($Labels.HVL)" -Output Silent
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback -Title $PRtitle
|
|
$NumVersions = "L"
|
|
}
|
|
}
|
|
} else {#Addition PR
|
|
$GLD = (Get-ListingDiff $clip | Where-Object {$_.SideIndicator -eq "<="}).installer.yaml #Ignores when a PR adds files that didn't exist before.
|
|
if ($null -ne $GLD) {
|
|
if ($GLD -eq "Error") {
|
|
$ListingDiff = "E"
|
|
$matchColor = $invalidColor
|
|
} else {
|
|
$ListingDiff = "-!"
|
|
$matchColor = $cautionColor
|
|
if (!$WhatIf) {
|
|
Reply-ToPR -PR $PR -CannedMessage ListingDiff -UserInput $GLD -Silent
|
|
Invoke-GitHubPRRequest -PR $PR -Method POST -Type comments -Data "[Policy] $Labels.NAF" -Output Silent
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback -Title $PRtitle
|
|
}#if Whatif
|
|
}#end if GLD
|
|
}#end if null
|
|
}#end if PRvMan
|
|
Write-Host -nonewline -f $matchColor "$ListingDiff | "
|
|
Write-Host -nonewline -f $matchColor "$NumVersions | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
if ($PRvMan -ne "N") {
|
|
if ($null -eq $PRVersion -or "" -eq $PRVersion) {
|
|
$noRecord = $True
|
|
$PRvMan = "Error:prVersion"
|
|
$matchColor = $invalidColor
|
|
} elseif ($ManifestVersion -eq "Unknown") {
|
|
$noRecord = $True
|
|
$PRvMan = "Error:ManifestVersion"
|
|
$matchColor = $invalidColor
|
|
} elseif ($null -eq $ManifestVersion) {
|
|
$noRecord = $True
|
|
$PRvMan = $WinGetOutput
|
|
$matchColor = $invalidColor
|
|
} elseif ($prVersion -gt $ManifestVersion) {
|
|
$PRvMan = $ManifestVersion.toString()
|
|
} elseif ($prVersion -lt $ManifestVersion) {
|
|
$PRvMan = $ManifestVersion.toString()
|
|
$matchColor = $cautionColor
|
|
} elseif ($prVersion -eq $ManifestVersion) {
|
|
$PRvMan = "="
|
|
} else {
|
|
$noRecord = $True
|
|
$PRvMan = $WinGetOutput
|
|
};
|
|
};
|
|
|
|
|
|
if (($Approve -eq "-!") -or
|
|
($Auth -eq "-!") -or
|
|
($AnF -eq "-") -or
|
|
($InstVer -eq "-!") -or
|
|
($prAuth -eq "-!") -or
|
|
($Review -ne "R") -or
|
|
($ListingDiff -eq "-!") -or
|
|
($NumVersions -eq 1) -or
|
|
($NumVersions -eq "L") -or
|
|
($WordFilter -eq "-!") -or
|
|
($AgreementAccept -eq "-!") -or
|
|
($PRvMan -eq "N")) {
|
|
#-or ($PRvMan -match "^Error")
|
|
$matchColor = $cautionColor
|
|
$Approve = "-!"
|
|
$noRecord = $True
|
|
}
|
|
if ($WhatIf) {
|
|
$Approve += "W"
|
|
}
|
|
|
|
$PRvMan = Get-PadRight $PRvMan 14
|
|
Write-Host -nonewline -f $matchColor "$PRvMan | "
|
|
$matchColor = $validColor
|
|
|
|
|
|
|
|
|
|
|
|
if ($PrePipeline -eq $false) {
|
|
if ($Approve -eq "+") {
|
|
if (!$WhatIf) {
|
|
$Approve = Approve-PR -PR $PR
|
|
Add-PRToRecord -PR $PR -Action $Actions.Approved -Title $PRtitle
|
|
}
|
|
}
|
|
}
|
|
|
|
Write-Host -nonewline -f $matchColor "$Approve | "
|
|
Write-Host -f $matchColor ""
|
|
|
|
$oldclip = $PRtitle
|
|
}; #end if Compare-Object
|
|
}; #end if PRtitle
|
|
Start-Sleep 1
|
|
}; #end while Count
|
|
$Count--
|
|
}; #end function
|
|
|
|
Function Get-RunPRWatchAutomation {
|
|
param(
|
|
$SleepDuration = 5,
|
|
$Preset = "Approval2",
|
|
$Results = (Get-SearchGitHub -Preset $Preset).number
|
|
)
|
|
Write-Output "$(Get-Date -Format T) Starting $Preset with $($Results.length) Results"
|
|
$Results | %{
|
|
write-output "$(Get-Date): $_";
|
|
Get-PRManifest -PR $_ | clip;
|
|
sleep $SleepDuration
|
|
}
|
|
Write-Output "$(Get-Date -Format T) Completing $Preset with $($Results.length) Results"
|
|
}
|
|
|
|
#Third tab
|
|
Function Get-WorkSearch {
|
|
param(
|
|
$PresetList = @("ToWork"),#Approval","
|
|
$Days = 7
|
|
)
|
|
Foreach ($Preset in $PresetList) {
|
|
$Page = 1
|
|
While ($true) {
|
|
$line = 0
|
|
$PRs = (Get-SearchGitHub -Preset $Preset -Page $Page -NoLabels -nBMM)
|
|
Write-Output "$(Get-Date -f T) $Preset Page $Page beginning with $Count Results"
|
|
$PRs = $PRs | where {$_.labels} | where {$_.number -notin (Get-Status).pr}
|
|
|
|
Foreach ($FullPR in $PRs) {
|
|
$PR = $FullPR.number
|
|
Get-TrackerProgress -PR $PR $MyInvocation.MyCommand $line $PRs.length
|
|
$line++
|
|
if ($Labels.HVL -notin $FullPR.labels.name) {
|
|
if (($FullPR.title -match "Remove") -OR
|
|
($FullPR.title -match "Delete") -OR
|
|
($FullPR.title -match "Automatic deletion")){
|
|
Get-GitHubPreset CheckInstaller -PR $PR
|
|
}
|
|
}
|
|
$Comments = (Invoke-GitHubPRRequest -PR $PR -Type comments -Output content)
|
|
if ($Preset -eq "Approval"){
|
|
if (Get-NonstandardPRComments -PR $PR -comments $Comments.body){
|
|
Open-PRInBrowser -PR $PR
|
|
} else {
|
|
Open-PRInBrowser -PR $PR -FIles
|
|
}
|
|
} elseif ($Preset -eq "Defender"){
|
|
Get-GitHubPreset -Preset LabelAction -PR $PR
|
|
} else {#ToWork etc
|
|
$Comments = ($Comments | select created_at,@{n="UserName";e={$_.user.login -replace "\[bot\]"}},body)
|
|
$State = (Get-PRStateFromComments -PR $PR -Comments $Comments)
|
|
$LastState = $State[-1]
|
|
if ($LastState.event -eq "DefenderFail") {
|
|
Get-PRLabelAction -PR $PR
|
|
} elseif ($LastState.event -eq "LabelAction") {
|
|
Get-GitHubPreset -Preset LabelAction -PR $PR
|
|
Open-PRInBrowser -PR $PR
|
|
} else {
|
|
if ($Comments[-1].UserName -ne $GitHubUserName) {
|
|
if ($LastState.event -eq "PreValidation") {
|
|
Get-GitHubPreset -Preset LabelAction -PR $PR
|
|
}
|
|
Open-PRInBrowser -PR $PR
|
|
}
|
|
}#end if LastCommenter
|
|
}#end if Preset
|
|
}#end foreach FullPR
|
|
Read-Host "$(Get-Date -f T) $Preset Page $Page complete with $Count Results - press ENTER to continue..."
|
|
$Page++
|
|
}#end While Count
|
|
}#end Foreach Preset
|
|
Write-Progress -Activity $MyInvocation.MyCommand -Completed
|
|
}#end Get-WorkSearch
|
|
|
|
#Automation tools
|
|
Function Get-GitHubPreset {
|
|
param(
|
|
[ValidateSet("Approved","AutomationBlock","BadPR","Blocking","CheckInstaller","Closed","Completed","DefenderFail","DriverInstall","Duplicate","Feedback","IdleMode","IEDSMode","InstallerNotSilent","InstallerMissing","LabelAction","ManuallyValidated","MergeConflicts","NetworkBlocker","NoInstallerChange","OneManifestPerPR","PRNoYamlFiles","PackageUrl","Paths","PossibleDuplicate","Project","RestrictedSubmitter","ResetApproval","Retry","Squash","Timeclock","Validating","VedantResetPR","WorkSearch","Waiver")][string]$Preset,
|
|
$PR = (Get-Clipboard),
|
|
$CannedMessage = $Preset,
|
|
$UserInput,
|
|
[Switch]$Force,
|
|
$out = ""
|
|
)
|
|
if (($Preset -eq "GitHubStatus") -OR
|
|
($Preset -eq "IdleMode") -OR
|
|
($Preset -eq "IEDSMode") -OR
|
|
($Preset -eq "Timeclock") -OR
|
|
($Preset -eq "Validating") -OR
|
|
($Preset -eq "WorkSearch")) {
|
|
$Force = $True
|
|
$out += $Preset;
|
|
}
|
|
|
|
if (($PR.ToString().length -eq 6) -OR $Force) {
|
|
Switch ($Preset) {
|
|
$Actions.Approved {
|
|
$out += Approve-PR -PR $PR;
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
}
|
|
"AutomationBlock" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Blocking
|
|
$out += Reply-ToPR -PR $PR -CannedMessage AutomationBlock -Policy $Labels.NB
|
|
}
|
|
$Actions.Blocking {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Blocking
|
|
$out += Invoke-GitHubPRRequest -PR $PR -Method POST -Type comments -Data "[Policy] $($Labels.NB)"
|
|
}
|
|
"CheckInstaller" {
|
|
$Pull = (Invoke-GitHubPRRequest -PR $PR -Type files -Output content -JSON)
|
|
$PullInstallerContents = (Get-DecodeGitHubFile ((Invoke-GitHubRequest -Uri $Pull.contents_url[0] -JSON).content))
|
|
$Url = (Get-YamlValue -StringName InstallerUrl -clip $PullInstallerContents)
|
|
$out = ""
|
|
try {
|
|
$InstallerStatus = Check-PRInstallerStatusInnerWrapper $Url
|
|
$out = "Status Code: $InstallerStatus"
|
|
}catch{
|
|
$out = $error[0].Exception.Message
|
|
}
|
|
$Body = "URL: $Url `n"+$out + "`n`n(Automated message - build $build)"
|
|
#If ($Body -match "Response status code does not indicate success") {
|
|
#$out += Get-GitHubPreset InstallerMissing -PR $PR
|
|
#} #Need this to only take action on new PRs, not removal PRs.
|
|
$out = $out += Invoke-GitHubPRRequest -PR $PR -Method Post -Type comments -Data $Body -Output StatusDescription
|
|
}
|
|
"Completed" {
|
|
$out += Reply-ToPR -PR $PR -Body "This package installs and launches normally in a Windows 10 VM." -Policy $Labels.MV
|
|
}
|
|
$Actions.Closed {
|
|
if ($UserInput) {
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
$out += Invoke-GitHubPRRequest -PR $PR -Type comments -Output StatusDescription -Method POST -Data "Close with reason: $UserInput;"
|
|
} else {
|
|
Write-Output "-UserInput needed to use preset $preset"
|
|
}
|
|
}
|
|
"DefenderFail" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Blocking
|
|
$out += Get-CannedMessage -Response DefenderFail -NoClip -NotAutomated
|
|
#$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy "Needs-Attention`n[Policy] $($Labels.VDE)"
|
|
}
|
|
"DriverInstall" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Blocking
|
|
$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Labels.DI
|
|
}
|
|
"Duplicate" {
|
|
if ($UserInput -match "[0-9]{5,6}") {
|
|
Get-GitHubPreset -Preset Closed -PR $PR -UserInput "Duplicate of #$UserInput"
|
|
} else {
|
|
Write-Output "-UserInput PRNumber needed to close as duplicate."
|
|
}
|
|
}
|
|
$Actions.Feedback {
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
if ($UserInput) {
|
|
$out += Reply-ToPR -PR $PR -Body $UserInput -Policy $Labels.NAF
|
|
} else {
|
|
Write-Output "-UserInput needed to use preset $preset"
|
|
}
|
|
}
|
|
"GitHubStatus" {
|
|
return (Invoke-GitHubRequest -Uri https://www.githubstatus.com/api/v2/summary.json -JSON) | Select-Object @{n="Status";e={$_.incidents[0].status}},@{n="Message";e={$_.incidents[0].name+" ("+$_.incidents.count+")"}}
|
|
#$out += $Preset;
|
|
}
|
|
"IEDSMode" {
|
|
Get-TrackerVMSetMode IEDS
|
|
}
|
|
"IdleMode" {
|
|
Get-TrackerVMSetMode Idle
|
|
}
|
|
"InstallerNotSilent" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback
|
|
$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Labels.NAF
|
|
}
|
|
"InstallerMissing" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback
|
|
$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Labels.NAF
|
|
}
|
|
"LabelAction" {
|
|
Get-PRLabelAction -PR $PR
|
|
}
|
|
"ManuallyValidated" {
|
|
$out += Reply-ToPR -PR $PR -Body "Completing validation." -Policy $Labels.MV
|
|
}
|
|
"MergeConflicts" {
|
|
Get-GitHubPreset -Preset Closed -PR $PR -UserInput "Merge Conflicts"
|
|
}
|
|
"NetworkBlocker" {
|
|
Write-Output "Use AutomationBlock instead."
|
|
}
|
|
"NoInstallerChange" {
|
|
$out += Reply-ToPR -PR $PR -Body "This PR doesn't modify any of the `InstallerUrl` nor `InstallerSha256` fields." -Policy $Labels.MV
|
|
}
|
|
"OneManifestPerPR" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback
|
|
$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Labels.NAF
|
|
Get-AddPRLabel -PR $PR -Label $Labels.BI
|
|
}
|
|
"PRNoYamlFiles" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback
|
|
$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Labels.NAF
|
|
Get-GitHubPreset -Preset MergeConflicts -PR $PR
|
|
}
|
|
"PackageUrl" {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Feedback
|
|
$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Labels.NAF
|
|
}
|
|
"PossibleDuplicate" {
|
|
$Pull = (Invoke-GitHubPRRequest -PR $PR -Type files -Output content -JSON)
|
|
$PullInstallerContents = (Get-DecodeGitHubFile ((Invoke-GitHubRequest -Uri $Pull.contents_url[0] -JSON).content))
|
|
$Url = (Get-YamlValue -StringName InstallerUrl -clip $PullInstallerContents)
|
|
$PackageIdentifier = (Get-YamlValue -StringName PackageIdentifier -clip $PullInstallerContents)
|
|
$Version = (Find-WinGetPackage $PackageIdentifier | where {$_.ID -eq $PackageIdentifier}).Version
|
|
$out = ($PullInstallerContents -match $Version)
|
|
$UserInput = $out | where {$_ -match "http"} | where {$_ -notmatch "json"}
|
|
if ($UserInput) {
|
|
$UserInput = "InstallerUrl contains Manifest version instead of PR version:`n"+$UserInput + "`n`n(Automated message - build $build)"
|
|
$out += Reply-ToPR -PR $PR -Body $UserInput -Policy $Labels.NAF
|
|
Add-PRToRecord -PR $PR -Action Feedback
|
|
}
|
|
}
|
|
"Project" {
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
}
|
|
"RestrictedSubmitter" {
|
|
Get-GitHubPreset -Preset Closed -PR $PR -UserInput "Restricted Submitter"
|
|
}
|
|
"ResetApproval" {
|
|
$out += Reply-ToPR -PR $PR -Body "Reset approval workflow." -Policy "Reset Feedback `n[Policy] $($Labels.VC) `n[Policy] $($Actions.Approved)"
|
|
}
|
|
"Retry" {
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
$out += Get-RetryPR -PR $PR
|
|
}
|
|
"Squash" {
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
}
|
|
"Timeclock" {
|
|
Get-TimeclockSet
|
|
}
|
|
"Validating" {
|
|
Get-TrackerVMSetMode Validating
|
|
$PR = ""
|
|
}
|
|
"Waiver" {
|
|
Add-PRToRecord -PR $PR -Action $Preset
|
|
$out += Add-Waiver -PR $PR;
|
|
}
|
|
"WorkSearch" {
|
|
Get-WorkSearch
|
|
}
|
|
}
|
|
} else {
|
|
$out += "Error: $($PR[0..10])"
|
|
}
|
|
Write-Output "PR $($PR): $out"
|
|
}
|
|
|
|
Function Get-PRLabelAction { #Soothing label action.
|
|
param(
|
|
[int]$PR,
|
|
$PRLabels = ((Invoke-GitHubPRRequest -PR $PR -Type labels -Output content -JSON).name),
|
|
$PRLabelActions = (Get-Content $LabelActionFile | ConvertFrom-Csv)
|
|
)
|
|
Write-Output "PR $PR has labels $PRLabels"
|
|
if ($PRLabels -contains $Labels.VDE) {
|
|
$PRState = Get-PRStateFromComments $PR
|
|
if (($PRState | where {$_.event -eq "PreValidation"})[-1].created_at -lt (Get-Date).AddHours(-8)) {# -AND #Last Prevalidation was 8 hours ago.
|
|
#($PRState | where {$_.event -eq "AutoValEnd"})[-1].created_at -lt (Get-Date).AddHours(-12)) { #Last Run was 18 hours ago.
|
|
Get-GitHubPreset Retry -PR $PR
|
|
}
|
|
} else {
|
|
|
|
Foreach ($Label in ($PRLabels -split " ")) {
|
|
$Logset = ($PRLabelActions | ? {$_.Label -match $Label}).Logset -split "\|"
|
|
$StringSet = ($PRLabelActions | ? {$_.Label -match $Label}).StringSet -split "\|"
|
|
$LengthSet = ($PRLabelActions | ? {$_.Label -match $Label}).LengthSet -split "\|"
|
|
Switch -wildcard ($Label) {
|
|
$Labels.403 {
|
|
$UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
$Labels.ANF {
|
|
$UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet
|
|
if ($null -ne $UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.BVE {
|
|
$UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -length 5
|
|
if ($null -ne $UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
if ($UserInput -match $MagicStrings[3]) {
|
|
#Get-GitHubPreset -PR $PR -Preset AutomationBlock
|
|
}
|
|
}
|
|
$Labels.EAT {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 36 -SearchString $MagicStrings[0] -length 4
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
if ($UserInput -match $MagicStrings[3]) {
|
|
Get-GitHubPreset -PR $PR -Preset AutomationBlock
|
|
}
|
|
}
|
|
$Labels.EHM {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 44 -SearchString $MagicStrings[7] -length 3
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
} # write-host "a"
|
|
# $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -Length $LengthSet
|
|
# write-host "b"
|
|
# if ($null -ne $UserInput) {
|
|
# write-host "c"
|
|
# Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
# write-host "d"
|
|
# Get-UpdateHashInPR2 -PR $PR -Clip $UserInput
|
|
# write-host "e"
|
|
# }
|
|
# write-host "f"
|
|
}
|
|
$Labels.EIA {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 53 -SearchString $MagicStrings[6] -length 5
|
|
if ($null -eq $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $MagicStrings[0] -Length 10
|
|
}
|
|
if ($null -eq $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 57 -SearchString $MagicStrings[0] -Length 10
|
|
}
|
|
if ($null -eq $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $MagicStrings[0] -Length 10
|
|
}
|
|
if ($UserInput) {
|
|
$UserInput = Get-AutomatedErrorAnalysis $UserInput
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
Get-GitHubPreset -PR $PR -Preset CheckInstaller
|
|
}
|
|
}
|
|
$Labels.HVF {
|
|
Get-AutoValLog -PR $PR
|
|
}
|
|
$Labels.HVL {
|
|
Approve-PR -PR $PR
|
|
}
|
|
$Labels.HVR {
|
|
Approve-PR -PR $PR
|
|
}
|
|
$Labels.IE {
|
|
$UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet
|
|
if ($UserInput) {
|
|
if (($MagicStrings[5] -in $UserInput) -OR ("Server Unavailable" -in $UserInput)) {
|
|
Get-GitHubPreset -PR $PR Retry
|
|
}
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.IEDS {
|
|
Get-AutoValLog -PR $PR
|
|
Add-PRToQueue -PR $PR
|
|
}
|
|
$Labels.IEM {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 15 -SearchString $MagicStrings[1]
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 30 -SearchString $MagicStrings[13]
|
|
}
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $MagicStrings[4] -length 7
|
|
}
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 39 -SearchString $MagicStrings[4] -length 7
|
|
}
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $MagicStrings[9] -MatchOffset -3 -Length 4
|
|
}
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 46 -SearchString $MagicStrings[9] -MatchOffset -3 -Length 4
|
|
}
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 47 -SearchString $MagicStrings[9] -MatchOffset -3 -Length 4
|
|
}
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
if ($UserInput -match "Sequence contains no elements") {#Reindex fixes this.
|
|
Reply-ToPR -PR $PR -CannedMessage SequenceNoElements
|
|
$PRtitle = ((Invoke-GitHubPRRequest -PR $PR -Type "" -Output content -JSON).title)
|
|
if (($PRtitle -match "Automatic deletion") -OR ($PRtitle -match "Remove")) {
|
|
Get-GitHubPreset -Preset Completed -PR $PR
|
|
}
|
|
}
|
|
}
|
|
}
|
|
$Labels.IEU {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $MagicStrings[1]
|
|
if ($UserInput) {
|
|
if ($MagicStrings[5] -in $UserInput) {
|
|
Get-GitHubPreset -PR $PR Retry
|
|
}
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.LVR {
|
|
Approve-PR -PR $PR
|
|
}
|
|
$Labels.MIVE {
|
|
$UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet
|
|
if ($null -ne $UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.MMC {
|
|
Get-VerifyMMC -PR $PR
|
|
}
|
|
$Labels.MVE {#One of these is VER.
|
|
$UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet
|
|
if ($null -ne $UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.MVE {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $MagicStrings[2]
|
|
if ($null -eq $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $MagicStrings[1]
|
|
}
|
|
if ($null -ne $UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.NMM {
|
|
Approve-PR -PR $PR
|
|
Get-MergePR -PR $PR
|
|
}
|
|
$Labels.NP {
|
|
if ((($PRLabels -join " ") -notmatch $Labels.MA)) {
|
|
Add-PRToQueue -PR $PR
|
|
}
|
|
}
|
|
$Labels.PD {
|
|
Get-DuplicateCheck -PR $PR
|
|
}
|
|
$Labels.PRE {
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 47 -SearchString $MagicStrings[12] -Length 2
|
|
}
|
|
if ($null -match $UserInput) {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 33 -SearchString $MagicStrings[12] -Length 2
|
|
}
|
|
$UserInput += Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet
|
|
|
|
if ($UserInput -match "The pull request contains more than one manifest") {
|
|
Get-GitHubPreset -Preset OneManifestPerPR -PR $PR
|
|
}
|
|
if ($UserInput -match "The pull request doesn't include any manifest files yaml") {
|
|
Get-GitHubPreset -Preset PRNoYamlFiles -PR $PR
|
|
}
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.UVE {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 32 -SearchString "Validation result: Failed"
|
|
Get-GitHubPreset -PR $PR -Preset CheckInstaller
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
$Labels.VC {
|
|
}
|
|
$Labels.VD {
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
$Labels.VEE {
|
|
Get-AutoValLog -PR $PR
|
|
Add-PRToQueue -PR $PR
|
|
}
|
|
$Labels.VIE {
|
|
Get-AutoValLog -PR $PR
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
$Labels.VMD {
|
|
$UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $MagicStrings[1]
|
|
if ($UserInput) {
|
|
Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
$Labels.VMC {
|
|
}
|
|
$Labels.VNE {
|
|
Get-Autowaiver -PR $PR
|
|
<#
|
|
$Title = ((Invoke-GitHubPRRequest -PR $PR -Type "" -Output content -JSON).title);
|
|
foreach ($Waiver in (Get-ValidationData -Property AutoWaiverLabel)) {
|
|
if ($Title -match $Waiver.PackageIdentifier) {
|
|
Get-GitHubPreset -PR $PR Waiver
|
|
}
|
|
}
|
|
#>
|
|
}
|
|
$Labels.VSE {
|
|
Get-AutoValLog -PR $PR
|
|
Add-PRToQueue -PR $PR
|
|
}
|
|
$Labels.VUF {
|
|
Get-AutoValLog -PR $PR
|
|
Add-PRToQueue -PR $PR
|
|
}
|
|
$Labels.VUE {
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
$Labels.VUU {
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
"Policy-Test-*" {
|
|
Get-Autowaiver -PR $PR
|
|
}
|
|
}#end Switch Label
|
|
}#end Foreach Label
|
|
}#end if PRLabels
|
|
}
|
|
|
|
Function Get-ScheduledRun {
|
|
[console]::beep(500,250);[console]::beep(500,250);[console]::beep(500,250) #Beep 3x to alert the PC user.
|
|
$Host.UI.RawUI.WindowTitle = "Periodic Run"
|
|
|
|
#Check for yesterday's report and create if missing.
|
|
$Month = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month)
|
|
md "C:\ManVal\logs\$Month" -ErrorAction SilentlyContinue
|
|
$Yesterday = (get-date).AddDays(-1)
|
|
$YesterdayFormatted = (get-date $Yesterday -f MMddyy)
|
|
$ReportName = "$logsFolder\$Month\$YesterdayFormatted-Report.txt"
|
|
if (Get-Content $ReportName -ErrorAction SilentlyContinue) {
|
|
Write-Host "Report for $YesterdayFormatted found."
|
|
} else {
|
|
Write-Host "Report for $YesterdayFormatted not found."
|
|
Get-PRFullReport -Today $YesterdayFormatted
|
|
}
|
|
|
|
Get-StaleVMCheck
|
|
|
|
$PresetList = ("Defender","Domain","Duplicate","HVR","IEDS","LVR","MMC","NMM","ToWork3","Approval","Approval2","VCMA")
|
|
foreach ($Preset in $PresetList) {
|
|
$Results = (Get-SearchGitHub -Preset $Preset -nBMM).number
|
|
Write-Output "$(Get-Date -Format T) Starting $Preset with $($Results.length) Results"
|
|
if ($Results) {
|
|
switch ($Preset) {
|
|
"Approval" {
|
|
$Results = (Get-SearchGitHub Approval -NewPackages).number
|
|
$Results | %{Add-PRToQueue -PR $_}
|
|
}
|
|
"Approval2" {
|
|
$Results | %{
|
|
write-output "$(get-date): $_";
|
|
Get-PRManifest -pr $_ | clip;
|
|
sleep 5
|
|
}
|
|
}
|
|
"IEDS" {
|
|
$Results | %{Add-PRToQueue -PR $_}
|
|
}
|
|
"VCMA" {
|
|
$GitHubResults = Get-SearchGitHub VCMA
|
|
$AnHourAgo = (get-date).AddHours(-1)
|
|
$Results = ($GitHubResults | where {[TimeZone]::CurrentTimeZone.ToLocalTime($_.updated_at) -lt $AnHourAgo}).number
|
|
#Time, as a number, is always increasing. So the past is always less than the present, which is always less than the future.
|
|
$Results | %{Approve-PR -PR $_;Get-MergePR -PR $_}
|
|
}
|
|
Default {
|
|
$Results | %{Get-PRLabelAction -PR $_ }
|
|
}
|
|
}#end switch Preset
|
|
}#end if Results12
|
|
Write-Output "$(Get-Date -Format T) Completing $Preset with $($Results.length) Results"
|
|
}#End for preset
|
|
|
|
|
|
Write-Output "$(Get-Date -Format T) Starting PushMePRYou with $($PushMePRWho.count) Results"
|
|
$PushMePRWho | %{write-host $_.Author;Get-PushMePRYou -Author $_.Author -MatchString $_.MatchString}
|
|
Write-Output "$(Get-Date -Format T) Completing PushMePRYou with $($PushMePRWho.count) Results"
|
|
if (([int](get-date -f mm) -eq 20) -OR ([int](get-date -f mm) -eq 50)) {
|
|
sleep (60-(get-date -f ss))#Sleep out the minute.
|
|
}
|
|
}
|
|
|
|
Function Get-StaleVMCheck {
|
|
$VMStatus = gc $statusFile | convertfrom-csv
|
|
$CheckVMStatus = ($VMStatus | where {$_.status -ne "Ready"})
|
|
Write-Output "$(Get-Date -Format T) Starting stale VM check with $($CheckVMStatus.count) Results"
|
|
foreach ($vm in $CheckVMStatus) {
|
|
$PRState = Invoke-GitHubPRRequest -PR $VM.pr -Type "" -Output Content;
|
|
$PRLabels = ((Invoke-GitHubPRRequest -PR $PR -Type "labels" -Output content -JSON).name)
|
|
if (($PRState.state -ne "open") -OR
|
|
(($PRLabels -join " ") -match $Labels.CR)){
|
|
Get-TrackerVMSetStatus -Status Complete -VM $VM.vm
|
|
}
|
|
}
|
|
Write-Output "$(Get-Date -Format T) Completing stale VM check with $($CheckVMStatus.count) Results"
|
|
}
|
|
|
|
Function Get-LogFromCommitFile {
|
|
param(
|
|
$PR,
|
|
$LogNumbers,
|
|
$StringNumbers,
|
|
$Length,
|
|
[switch]$WhatIf
|
|
)
|
|
Foreach ($Log in $LogNumbers) {
|
|
$n = 0;
|
|
if ($WhatIf) {
|
|
write-host $log
|
|
}
|
|
while ($n -le ($StringNumbers.Count -1)) {
|
|
if ($WhatIf) {
|
|
write-host "n $n - string $($MagicStrings[($StringNumbers[$n])]) - UserInput $UserInput"
|
|
}
|
|
try {
|
|
if ($WhatIf) {
|
|
write-host "Get-LineFromBuildResult -PR $PR -LogNumber $Log -SearchString $($MagicStrings[$StringNumbers[$n]]) -Length $Length"
|
|
} else {
|
|
$UserInput += Get-LineFromBuildResult -PR $PR -LogNumber $Log -SearchString $MagicStrings[$StringNumbers[$n]] -Length $Length
|
|
}
|
|
} catch {}
|
|
$n++
|
|
}
|
|
}
|
|
|
|
if ($WhatIf) {
|
|
write-host "return $UserInput"
|
|
} else {
|
|
return $UserInput
|
|
}
|
|
}
|
|
|
|
Function Add-Waiver {
|
|
param(
|
|
$PR,
|
|
$Labels = ((Invoke-GitHubPRRequest -PR $PR -Type "labels" -Output content -JSON).name)
|
|
)
|
|
#$actions = "Manual","Waiver","Approved"
|
|
$actions = "Manual","Manual","Approved"
|
|
Foreach ($Label in $Labels) {
|
|
$Waiver = ""
|
|
Switch ($Label) {
|
|
$Labels.EAT {
|
|
Get-GitHubPreset -Preset Completed -PR $PR
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.PT27 {
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.PT12 {
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.PT23 {
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VC {
|
|
Get-GitHubPreset -Preset Approved -PR $PR
|
|
Add-PRToRecord -PR $PR -Action $actions[2]
|
|
}
|
|
$Labels.VD {
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VEE {
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.403 {
|
|
Add-PRToRecord -PR $PR -Action $actions[1]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VIE {
|
|
Add-PRToRecord -PR $PR -Action $actions[1]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VNE {
|
|
Add-PRToRecord -PR $PR -Action $actions[1]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VSE {
|
|
Add-PRToRecord -PR $PR -Action $actions[1]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VUF {
|
|
Add-PRToRecord -PR $PR -Action $actions[1]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VUE {
|
|
Add-PRToRecord -PR $PR -Action $actions[1]
|
|
$Waiver = $Label
|
|
}
|
|
$Labels.VR {
|
|
Get-GitHubPreset -Preset Completed -PR $PR
|
|
#Invoke-GitHubPRRequest -PR $PR -Method POST -Type labels -Data "Retry-1"
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
}
|
|
$Labels.IEDS {
|
|
Get-GitHubPreset -Preset Completed -PR $PR
|
|
#Invoke-GitHubPRRequest -PR $PR -Method POST -Type labels -Data "Retry-1"
|
|
Add-PRToRecord -PR $PR -Action $actions[0]
|
|
}
|
|
}
|
|
if ($Waiver -ne "") {
|
|
$out = Get-CompletePR -PR $PR
|
|
Write-Output $out
|
|
}; #end if Waiver
|
|
}; #end Foreach Label
|
|
}; #end Add-Waiver
|
|
|
|
Function Get-SearchGitHub {
|
|
param(
|
|
[ValidateSet("Approval","Approval2","Autowaiver","Blocking","Defender","Domain","Duplicate","HVR","IEDS","LVR","MMC","NMM","None","ToWork","ToWork2","ToWork3","VCMA")][string]$Preset = "Approval",
|
|
[Switch]$Browser,
|
|
$Url = "https://api.github.com/search/issues?page=$Page&q=",
|
|
$Author, #wingetbot
|
|
$Commenter, #wingetbot
|
|
$Title,
|
|
$ExcludeTitle,
|
|
[string]$Label,
|
|
$Page = 1,
|
|
[int]$Days,
|
|
[Switch]$BMM,
|
|
[Switch]$NewPackages,
|
|
[Switch]$nBMM,
|
|
[Switch]$IEDS,
|
|
[Switch]$NotWorked,
|
|
[Switch]$NoLabels,
|
|
[Switch]$AllowClosedPRs
|
|
)
|
|
if ($Browser) {
|
|
$Url = "$GitHubBaseUrl/pulls?page=$Page&q="
|
|
}
|
|
#Base settings
|
|
$Base = "repo:$Owner/$Repo+"
|
|
$Base = $Base + "is:pr+"
|
|
if (!($AllowClosedPRs)) {
|
|
$Base += "is:open+"
|
|
}
|
|
$Base += "draft:false+"
|
|
$Base += "sort:created-asc+"
|
|
|
|
#Smaller blocks
|
|
$date = Get-Date (Get-Date).AddDays(-$Days) -Format "yyyy-MM-dd"
|
|
$Defender = "label:$($Labels.VDE)+"
|
|
$HaventWorked = "-commenter:$($GitHubUserName)+"
|
|
$HVR = "label:$($Labels.HVR)+"
|
|
$IEDSLabel = "label:$($Labels.IEDS)+"
|
|
$IEM = "label:$($Labels.IEM)+"
|
|
$LVR = "label:$($Labels.LVR)+"
|
|
$MA = "label:$($Labels.MA)+"
|
|
$MMC = "label:$($Labels.MMC)+"
|
|
$NA = "label:$($Labels.NA)+"
|
|
$NAF = "label:$($Labels.NAF)+"
|
|
$nBI = "-label:Blocking-Issue+"
|
|
$nHW = "-label:Hardware+"
|
|
$nIEDS = "-"+$IEDSLabel
|
|
$nMA = "-"+$MA
|
|
$NMM = "label:$($Labels.NMM)+"
|
|
$nMMC = "-"+$MMC
|
|
$nNA = "-"+$NA
|
|
$nNP = "-label:$($Labels.NP)+"
|
|
$nNRA = "-label:$($Labels.IOD)+"
|
|
$nNRA = "-label:$($Labels.IOI)+"
|
|
$nNRA = "-label:$($Labels.NRA)+"
|
|
$nNSA = "-label:$($Labels.NSA)+"
|
|
$NotPass = "-label:$($Labels.APP)+"#Hasn't psased pipelines
|
|
$nVC = "-"+$VC #Not Completed
|
|
$Recent = "updated:>$($date)+"
|
|
$VC = "label:$($Labels.VC)+"#Completed
|
|
$VD = "label:$($Labels.VD)+"
|
|
$VSA = "label:$($Labels.VSA)+"
|
|
|
|
|
|
#Building block settings
|
|
$Blocking = $nHW
|
|
$Blocking += $nNSA
|
|
$Blocking += "-label:$($Labels.AGR)+"
|
|
$Blocking += "-label:$($Labels.DI)+"
|
|
$Blocking += "-label:$($Labels.LBI)+"
|
|
$Blocking += "-label:$($Labels.NB)+"
|
|
$Blocking += "-label:$($Labels.PF)+"
|
|
$Blocking += "-label:$($Labels.RB)+"
|
|
$Blocking += "-label:$($Labels.SA)+"
|
|
|
|
$Common = $nBI
|
|
$Common = $Common + "-"+$IEM
|
|
$Common = $Common + "-"+$Defender
|
|
|
|
$Cna = $VC
|
|
$Cna = $Cna+ $nMA
|
|
|
|
$Review1 = "-label:$($Labels.CR)+"
|
|
$Review1 += "-label:$($Labels.CLA)+"
|
|
$Review1 += $nNRA
|
|
|
|
$Review2 = "-"+$NA
|
|
$Review2 = $Review2 + "-"+$NAF
|
|
$Review2 = $Review2 + "-label:$($Labels.NR)+"
|
|
|
|
$Approvable = "-label:$($Labels.VMC)+"
|
|
$Approvable += "-label:$($Labels.VER)+"
|
|
$Approvable += "-label:$($Labels.MIVE)+"
|
|
$Approvable += "-label:$($Labels.PD)+"
|
|
$Approvable += "-label:$($Labels.UF)+"
|
|
|
|
$Workable += "-label:$($Labels.LVR)+"
|
|
$Workable += "-label:$($Labels.HVR)+"
|
|
$Workable += "-label:$($Labels.VMC)+"
|
|
$Workable += "-label:$($Labels.BVE)+"
|
|
$Workable += "-label:$($Labels.UF)+"
|
|
$Workable += "-label:$($Labels.VCR)+"
|
|
$Workable += "-label:$($Labels.VSS)+"
|
|
|
|
$PolicyTests = "-label:Policy-Test-1.1+";
|
|
$PolicyTests += "-label:$($Labels.PT12)+"
|
|
$PolicyTests += "-label:Policy-Test-1.3+";
|
|
$PolicyTests += "-label:Policy-Test-1.4+";
|
|
$PolicyTests += "-label:Policy-Test-1.5+";
|
|
$PolicyTests += "-label:Policy-Test-1.6+";
|
|
$PolicyTests += "-label:Policy-Test-1.7+";
|
|
$PolicyTests += "-label:Policy-Test-1.8+";
|
|
$PolicyTests += "-label:Policy-Test-1.9+";
|
|
$PolicyTests += "-label:Policy-Test-1.10+";
|
|
$PolicyTests += "-label:Policy-Test-2.1+";
|
|
$PolicyTests += "-label:Policy-Test-2.2+";
|
|
$PolicyTests += "-label:$($Labels.PT23)+"
|
|
$PolicyTests += "-label:Policy-Test-2.4+";
|
|
$PolicyTests += "-label:Policy-Test-2.5+";
|
|
$PolicyTests += "-label:Policy-Test-2.6+";
|
|
$PolicyTests += "-label:$($Labels.PT27)+"
|
|
$PolicyTests += "-label:Policy-Test-2.8+";
|
|
$PolicyTests += "-label:Policy-Test-2.9+";
|
|
$PolicyTests += "-label:Policy-Test-2.10+";
|
|
$PolicyTests += "-label:Policy-Test-2.11+";
|
|
$PolicyTests += "-label:Policy-Test-2.12+";
|
|
|
|
$Automatable = "-label:WSL+";
|
|
$Automatable = "-label:$($Labels.UVE)+"
|
|
$Automatable = "-label:$($Labels.VUE)+"
|
|
$Automatable = "-label:$($Labels.OUF)+"
|
|
$Automatable = "-label:$($Labels.VHE)+"
|
|
$Automatable = "-label:$($Labels.403)+"
|
|
$Automatable = "-label:$($Labels.404)+"
|
|
$Automatable = "-label:$($Labels.ANA)+"
|
|
$Automatable = "-label:$($Labels.HW)+"
|
|
$Automatable = "-label:$($Labels.PRE)+"
|
|
$Automatable = "-label:$($Labels.MVE)+"
|
|
$Automatable = "-label:$($Labels.EHM)+"
|
|
$Automatable = "-label:$($Labels.ANF)+"
|
|
$Automatable = "-label:$($Labels.EIA)+"
|
|
$Automatable = "-label:$($Labels.VC)+"
|
|
$Automatable += "-"+$VD;
|
|
|
|
#Composite settings
|
|
$Set1 = $Blocking + $Common + $Review1
|
|
$Set2 = $Set1 + $Review2
|
|
$Url += $Base
|
|
if ($Author) {
|
|
$Url += "author:$($Author)+"
|
|
}
|
|
if ($Commenter) {
|
|
$Url += "commenter:$($Commenter)+"
|
|
}
|
|
if ($Days) {
|
|
$Url += $Recent
|
|
}
|
|
if ($IEDS) {
|
|
$Url += $nIEDS
|
|
}
|
|
if ($Label) {
|
|
$Url += "label:$($Label)+"
|
|
}
|
|
if ($NotWorked) {
|
|
$Url += $HaventWorked
|
|
}
|
|
if ($NewPackages) {
|
|
$Url += "label:New-Package+"
|
|
}
|
|
if ($Title) {
|
|
$Url += "$Title in:title+"
|
|
}
|
|
if ($BMM) {
|
|
$Url += "label:$($Labels.BMM)+"
|
|
}
|
|
if ($nBMM) {
|
|
$Url += "-label:$($Labels.BMM)+"
|
|
}
|
|
switch ($Preset) {
|
|
"Approval"{
|
|
$Url += $Cna
|
|
$Url += $Set2 #Blocking + Common + Review1 + Review2
|
|
$Url += $Approvable
|
|
$Url += $Workable;
|
|
$Url += $nMMC;
|
|
}
|
|
"Approval2"{
|
|
$Url += $Cna
|
|
$Url += $nNP
|
|
$Url += $Set2 #Blocking + Common + Review1 + Review2
|
|
$Url += $Approvable
|
|
$Url += $Workable;
|
|
$Url += $nMMC;
|
|
}
|
|
"Defender"{
|
|
$Url += $Defender
|
|
}
|
|
"Domain"{
|
|
$Url += "label:$($Labels.VD)+"
|
|
}
|
|
"Duplicate"{
|
|
$Url += "label:"+$Labels.PD+"+";#dupe
|
|
$Url += $nNRA
|
|
}
|
|
"Autowaiver"{
|
|
$Url += $Set1
|
|
$Url += $Workable
|
|
$Url += $nIEDS
|
|
$Url += $nVC
|
|
$Url += "label:$($Labels.EHM)+"
|
|
$Url += "label:$($Labels.MIVE)+"
|
|
$Url += "label:$($Labels.MVE)+"
|
|
$Url += "label:$($Labels.VEE)+"
|
|
$Url += "label:$($Labels.VNE)+"
|
|
$Url += "label:$($Labels.VIE)+"
|
|
$Url += "label:$($Labels.VSE)+"
|
|
$Url += "label:$($Labels.VUF)+"
|
|
$Url += "label:$($Labels.ANF)+"
|
|
$Url += $nBI
|
|
$Url += $nIOD
|
|
$Url += $nIOI
|
|
}
|
|
"IEDS" {
|
|
$Url += $IEDSLabel
|
|
$Url += $nBI
|
|
$Url += $Blocking
|
|
$Url += $NotPass
|
|
$Url += $nVC
|
|
}
|
|
"HVR"{
|
|
$date = Get-Date (Get-Date).AddDays(-7) -Format "yyyy-MM-dd"
|
|
$createdDate = "created:<$($date)+"
|
|
$Url += $createdDate;
|
|
$Url += $HVR;
|
|
}
|
|
"LVR"{
|
|
$date = Get-Date (Get-Date).AddDays(-7) -Format "yyyy-MM-dd"
|
|
$createdDate = "created:<$($date)+"
|
|
$Url += $createdDate;
|
|
$Url += $LVR;
|
|
}
|
|
"MMC"{
|
|
$Url += $MMC;
|
|
}
|
|
"NMM"{
|
|
$Url += $NMM;
|
|
}
|
|
"None"{
|
|
}
|
|
"ToWork"{
|
|
$Url += $Set1 #Blocking + Common + Review1
|
|
$Url += $Workable;
|
|
#$Url += $Workable
|
|
}
|
|
"ToWork2"{
|
|
$Url += $HaventWorked
|
|
$Url += "-"+$Defender
|
|
$Url += $Set1 #Blocking + Common + Review1
|
|
$Url += $nVC
|
|
}
|
|
"ToWork3"{
|
|
$Url += $HaventWorked
|
|
$Url += "-"+$Defender
|
|
$Url += $Set1 #Blocking + Common + Review1
|
|
$Url += $nVC
|
|
$Url += $nMA
|
|
$Url += $nNA
|
|
}
|
|
"VCMA"{
|
|
#$date = Get-Date (Get-Date).AddHours(-1) -Format "yyyy-MM-dd"
|
|
#$createdDate = "created:<$($date)+"
|
|
$Url += $createdDate;
|
|
$Url += $MA
|
|
$Url += $VC
|
|
$Url += $Set2 #Blocking + Common + Review1 + Review2
|
|
$Url += $Approvable
|
|
$Url += $Workable;
|
|
$Url += $nMMC;
|
|
}
|
|
}
|
|
|
|
if ($Browser) {
|
|
Start-Process $Url
|
|
} else {
|
|
$Response = Invoke-GitHubRequest $Url
|
|
$Response = ($Response.Content | ConvertFrom-Json).items
|
|
#$Response = $Response | ? {!(($_.labels.name -match $Labels.MA) -AND ($_.labels.name -match "Needs-Attention"))}
|
|
if ($ExcludeTitle) {
|
|
$Response = $Response | ? {$_.title -notmatch $ExcludeTitle}
|
|
}
|
|
if (!($NoLabels)) {
|
|
$Response = $Response | where {$_.labels}
|
|
}
|
|
return $Response
|
|
}
|
|
}
|
|
|
|
Function Get-CannedMessage {
|
|
param(
|
|
[ValidateSet("AgreementMismatch","AppFail","Approve","AutomationBlock","AutoValEnd","AppsAndFeaturesNew","AppsAndFeaturesMissing","AppsAndFeaturesMatch","DriverInstall","DefenderFail","HashFailRegen","InstallerFail","InstallerMatchesSubmitter","InstallerMissing","InstallerNotSilent","NormalInstall","InstallerUrlBad","ListingDiff","ManValEnd","ManifestVersion","MergeFail","NoCause","NoExe","NoRecentActivity","NotGoodFit","OneManifestPerPR","Only64bit","PackageFail","PackageUrl","Paths","PendingAttendedInstaller","PolicyWrapper","PRNoYamlFiles","RemoveAsk","SequenceNoElements","Unattended","Unavailable","UrlBad","VersionCount","WhatIsIEDS","WordFilter")]
|
|
[string]$Response,
|
|
$UserInput=(Get-Clipboard),
|
|
[switch]$NoClip,
|
|
[switch]$NotAutomated
|
|
)
|
|
[string]$Username = "@"+$UserInput.replace(" ","")+","
|
|
switch ($Response) {
|
|
"AgreementMismatch" {
|
|
$out = "Hi $Username`n`nThis package uses Agreements, but this manifest's AgreementsUrl doesn't match the AgreementsUrl on file."
|
|
}
|
|
"AppsAndFeaturesNew" {
|
|
$out = "Hi $Username`n`nThis manifest adds a `DisplayVersion` to the `AppsAndFeaturesEntries` that isn't present in previous manifest versions. This entry should be added to the previous versions, or removed from this version."
|
|
}
|
|
"AppsAndFeaturesMissing" {
|
|
$out = "Hi $Username`n`nThis manifest removes the `DisplayVersion` from the `AppsAndFeaturesEntries`, which is present in previous manifest versions. This entry should be added to this version, to maintain version matching, and prevent the 'upgrade always available' situation with this package."
|
|
}
|
|
"AppsAndFeaturesMatch" {
|
|
$out = "Hi $Username`n`nThis manifest uses the same values for `DisplayVersion` and `PackageVersion`. This is not recommended, and the `DisplayVersion` should be removed."
|
|
}
|
|
"AppFail" {
|
|
$out = "Hi $Username`n`nThe application installed normally, but gave an error instead of launching:`n"
|
|
}
|
|
"Approve" {
|
|
$out = "Hi $Username`n`nDo you approve of these changes?"
|
|
}
|
|
"AutomationBlock" {
|
|
$out = "This might be due to a network block of data centers, to prevent automated downloads."
|
|
}
|
|
"UserAgentBlock" {
|
|
$out = "This might be due to user-agent throttling."
|
|
}
|
|
"AutoValEnd" {
|
|
$UserInput = $UserInput -join "`n"
|
|
$UserInput = "Automatic Validation ended with:`n```````n $UserInput`n```````n"
|
|
$out = Get-AutomatedErrorAnalysis $UserInput
|
|
}
|
|
"DriverInstall" {
|
|
$out = "Hi $Username`n`nThe installation is unattended, but installs a driver which isn't unattended:`nUnfortunately, installer switches are not usually provided for this situation. Are you aware of an installer switch to have the driver silently install as well?"
|
|
}
|
|
"DefenderFail" {
|
|
$out = "The package didn't pass a Defender or similar security scan. This might be a false positive and we can rescan tomorrow.."
|
|
}
|
|
"HashFailRegen" {
|
|
$out = "Closing to regenerate with correct hash."
|
|
}
|
|
"InstallerFail" {
|
|
$out = "Hi $Username`n`nThe installer did not complete:`n"
|
|
}
|
|
"InstallerMatchesSubmitter" {
|
|
$out = "Submitter username detected in InstallerUrl, but not in PackageIdentifier. Verify not a forked repository."
|
|
}
|
|
"InstallerMissing" {
|
|
$out = "Hi $Username`n`nHas the installer been removed?"
|
|
}
|
|
"InstallerNotSilent" {
|
|
$out = "Hi $Username`n`nThe installation isn't unattended. Is there an installer switch to have the package install silently?"
|
|
}
|
|
"ListingDiff" {
|
|
$out = "This PR omits these files that are present in the current manifest:`n> $UserInput"
|
|
}
|
|
"ManifestVersion" {
|
|
$out = "Hi $Username`n`nWe don't often see the `1.0.0` manifest version anymore. Would it be possible to upgrade this to the [1.5.0]($GitHubBaseUrl/tree/master/doc/manifest/schema/1.5.0) version, possibly through a tool such as [WinGetCreate](https://learn.microsoft.com/en-us/windows/package-manager/package/manifest?tabs=minschema%2Cversion-example), [YAMLCreate]($GitHubBaseUrl/blob/master/Tools/YamlCreate.ps1), or [Komac](https://github.com/russellbanks/Komac)? "
|
|
}
|
|
"ManValEnd" {
|
|
$UserInput = $UserInput -join "`n"
|
|
$UserInput = "Manual Validation ended with:`n```````n$UserInput`n```````n"
|
|
$out = Get-AutomatedErrorAnalysis $UserInput
|
|
}
|
|
"MergeFail" {
|
|
$out = "Merging failed with:`n> $UserInput"
|
|
}
|
|
"NoCause" {
|
|
$out = "I'm not able to find the cause for this error. It installs and runs normally on a Windows 10 VM."
|
|
}
|
|
"NoExe" {
|
|
$out = "Hi $Username`n`nThe installer doesn't appear to install any executables, only supporting files:`n`nIs this expected?"
|
|
}
|
|
"NoRecentActivity" {
|
|
$out = "No recent activity."
|
|
}
|
|
"NotGoodFit" {
|
|
$out = "Hi $Username`n`nUnfortunately, this package might not be a good fit for inclusion into the WinGet public manifests. Please consider using a local manifest (`WinGet install --manifest C:\path\to\manifest\files\`) for local installations. "
|
|
}
|
|
"NormalInstall" {
|
|
$out = "This package installs and launches normally in a Windows 10 VM."
|
|
}
|
|
"OneManifestPerPR" {
|
|
$out = "Hi $Username`n`nWe have a limit of 1 manifest change, addition, or removal per PR. This PR modifies more than one PR. Can these changes be spread across multiple PRs?"
|
|
}
|
|
"Only64bit" {
|
|
$out = "Hi $Username`n`nValidation failed on the x86 package, and x86 packages are validated on 32-bit OSes. So this might be a 64-bit package."
|
|
}
|
|
"PackageFail" {
|
|
$out = "Hi $Username`n`nThe package installs normally, but fails to run:`n"
|
|
}
|
|
"PackageUrl" {
|
|
$out = "Hi $Username`n`nCould you add a PackageUrl?"
|
|
}
|
|
"Paths" {
|
|
$out = "Please update file name and path to match this change."
|
|
}
|
|
"PendingAttendedInstaller" {
|
|
$out = "Pending:`n* https://github.com/microsoft/winget-cli/issues/910"
|
|
}
|
|
"PolicyWrapper" {
|
|
$out = "<!--`n[Policy] $UserInput`n-->"
|
|
}
|
|
"PRNoYamlFiles" {
|
|
$out = "Hi $Username`n`nThis error means that this PR diff Master had no output. In other words, it's like a merge conflict.`n> The pull request doesn't include any manifest files yaml."
|
|
}
|
|
"RemoveAsk" {
|
|
$out = "Hi $Username`n`nThis package installer is still available. Why should it be removed?"
|
|
}
|
|
"SequenceNoElements" {
|
|
$out = "> Sequence contains no elements`n`n - This error means that this PR diff Master had no output. In other words, it's like a merge conflict."
|
|
}
|
|
"Unavailable" {
|
|
$out = "Hi $Username`n`nThe installer isn't available from the publisher's website:"
|
|
}
|
|
"Unattended" {
|
|
$out = "Hi $Username`n`nThe installation isn't unattended:`n`nIs there an installer switch to bypass this and have it install automatically?"
|
|
}
|
|
"UrlBad" {
|
|
$out = "Hi $Username`n`nI'm not able to find this InstallerUrl from the PackageUrl. Is there another page on the developer's site that has a link to the package?"
|
|
}
|
|
"VersionCount" {
|
|
$out = "Hi $Username`n`nThis manifest has the highest version number for this package. Is it available from another location? (This might be in error if the version is switching from semantic to string, or string to semantic.)"
|
|
}
|
|
"WhatIsIEDS" {
|
|
$out = "Hi $Username`n`nThe label `Internal-Error-Dynamic-Scan` is a blanket error for one of a number of internal pipeline errors or issues that occurred during the Dynamic Scan step of our validation process. It only indicates a pipeline issue and does not reflect on your package. Sorry for any confusion caused."
|
|
}
|
|
"WordFilter" {
|
|
$out = "This manifest contains a term that is blocked:`n`n> $UserInput"
|
|
}
|
|
}
|
|
if (!($NotAutomated)) {
|
|
$out += "`n`n(Automated response - build $build.)"
|
|
}
|
|
if ($NoClip) {
|
|
$out
|
|
} else {
|
|
$out |clip
|
|
}
|
|
}
|
|
|
|
Function Get-AutomatedErrorAnalysis {
|
|
param(
|
|
$UserInput,
|
|
$Spacer = " | ",
|
|
$LineBreak = "`n"
|
|
)
|
|
|
|
#$UserSplit = $UserInput -replace "0x","" -replace "[^\w]"," " -split " "
|
|
$UserSplit = $UserInput -replace "0x"," " -replace "\)"," " -split " "
|
|
$UserSplit = $UserSplit | Sort-Object -Unique
|
|
|
|
if ($UserInput -match "exit code" -OR
|
|
$UserInput -match "DeliveryOptimization error" -OR
|
|
$UserInput -match "Installer failed security check" -OR
|
|
$UserInput -match "Error information") {
|
|
$ExitCodeTable = gc $ExitCodeFile | ConvertFrom-Csv
|
|
$UserInput += "$LineBreak $LineBreak | Hex | Dec | Inverted Dec | Symbol | Description | $LineBreak | --- | --- | --- | --- | --- | $LineBreak"
|
|
foreach ($ExitCode in $ExitCodeTable) {
|
|
foreach ($Word in $UserSplit) {
|
|
if (($Word -eq $ExitCode.Hex) -OR ($Word -eq $ExitCode.Dec) -OR ($Word -eq $ExitCode.InvDec) ) {
|
|
$UserInput += $Spacer + $ExitCode.Hex + $Spacer + $ExitCode.Dec + $Spacer + $ExitCode.InvDec + $Spacer + $ExitCode.Symbol + $Spacer + $ExitCode.Description + $Spacer + $LineBreak
|
|
}# end if word
|
|
}# end foreach word
|
|
}#end foreach exitcode
|
|
}#end if userinput
|
|
$UserInput = $UserInput | Select-Object -Unique
|
|
return $UserInput
|
|
}#end function
|
|
|
|
Function Get-AutoValLog {
|
|
#Needs $GitHubToken to be set up in your -PR $PROFILE or somewhere more secure. Needs permissions: workflow,
|
|
param(
|
|
$clip = (Get-Clipboard),
|
|
$PR = ($clip -split "/" | Select-String $PRRegex ),
|
|
$DestinationPath = "$MainFolder\Installers",
|
|
$LogPath = "$DestinationPath\InstallationVerificationLogs\",
|
|
$ZipPath = "$DestinationPath\InstallationVerificationLogs.zip",
|
|
[switch]$CleanoutDirectory,
|
|
[switch]$WhatIf,
|
|
[switch]$Force,
|
|
[switch]$Silent,
|
|
$notes = ""
|
|
)
|
|
$PRState = Get-PRStateFromComments $PR
|
|
if ((!($PRState | where {$_.event -eq "AutoValEnd"})) -OR (($PRState | where {$_.event -eq "PreValidation"})[-1].created_at -gt ($PRState | where {$_.event -eq "AutoValEnd"})[-1].created_at) -OR ($Force)) { #Last Prevalidation was 8 hours ago.
|
|
$DownloadSeconds = 8;
|
|
$LowerOps = $true;
|
|
$WaiverList = Get-ValidationData -Property AutoWaiverLabel
|
|
#Get-Process *photosapp* | Stop-Process
|
|
$BuildNumber = Get-BuildFromPR -PR $PR
|
|
|
|
if ($BuildNumber -gt 0) {
|
|
$FileList = $null
|
|
[int]$BackoffSeconds = 0
|
|
|
|
while ($FileList -eq $null) {
|
|
try {
|
|
#This downloads to Windows default location, which has already been set to $DestinationPath
|
|
Start-Process "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$BuildNumber/artifacts?artifactName=InstallationVerificationLogs&api-version=7.1&%24format=zip"
|
|
if ($WhatIf) {
|
|
write-host "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$BuildNumber/artifacts?artifactName=InstallationVerificationLogs&api-version=7.1&%24format=zip"
|
|
}
|
|
Start-Sleep $DownloadSeconds;
|
|
[bool]$IsZipPath = (Test-Path $ZipPath)
|
|
if (!$IsZipPath) {
|
|
#if (!$Force) {
|
|
$UserInput = "No logs."
|
|
$out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
Write-Host $UserInput
|
|
Continue;
|
|
#}
|
|
}
|
|
Remove-Item $LogPath -Recurse -ErrorAction Ignore
|
|
Expand-Archive $ZipPath -DestinationPath $DestinationPath;
|
|
Remove-Item $ZipPath
|
|
if ($CleanoutDirectory) {
|
|
Get-ChildItem $DestinationPath | Remove-Item -Recurse
|
|
}
|
|
$FileList = (Get-ChildItem $LogPath).FullName
|
|
} catch {
|
|
if ($BackoffSeconds -gt 60) {
|
|
$UserInput = "Build $BuildNumber not found."
|
|
Continue;
|
|
}
|
|
$AddSeconds = Get-Random -min 1 -max 5
|
|
$BackoffSeconds += $AddSeconds
|
|
Write-Host "Can't access $DestinationPath or a subfolder. Backing off another $AddSeconds seconds, for $BackoffSeconds total seconds."
|
|
sleep $BackoffSeconds
|
|
}
|
|
}
|
|
|
|
[Array]$UserInput = $null
|
|
foreach ($File in $filelist) {
|
|
$UserInput += (Get-Content $File) -split "`n"
|
|
}
|
|
$UserInput = $UserInput | Where-Object {
|
|
$_ -match '[[]FAIL[]]' -OR
|
|
$_ -match 'error' -OR
|
|
$_ -match 'exception' -OR
|
|
$_ -match 'exit code' -OR
|
|
$_ -match 'fail' -OR
|
|
$_ -match 'manual review' -OR
|
|
$_ -match 'No suitable' -OR
|
|
$_ -match 'not supported' -OR #not supported by this processor type
|
|
#$_ -match 'not applicable' -OR
|
|
$_ -match 'unwanted' -OR #PUA
|
|
$_ -match 'Unable to locate nested installer' -OR
|
|
$_ -match 'space' -OR
|
|
$_ -match 'cannot install'
|
|
}
|
|
if ($WhatIf) {
|
|
write-host "File $File - UserInput $UserInput Length $($UserInput.Length)"
|
|
}
|
|
$UserInput = $UserInput -split "`n" | Select-Object -Unique;
|
|
$UserInput = $UserInput -replace "Standard error: ",$null
|
|
$UserReplace = $UserInput -replace "\\","\\" -replace "\[","\["-replace "\]","\]"-replace "\*","\*"-replace "\+","\+"
|
|
|
|
if ($null -notmatch ($UserReplace)) {
|
|
if (($UserInput -match "Installer failed security check") -OR ($UserInput -match "Operation did not complete successfully because the file contains a virus or potentially unwanted software")) {
|
|
$LowerOps = $false
|
|
#$UserInput = Get-AutomatedErrorAnalysis $UserInput
|
|
write-host "DefenderFail - UserInput $UserInput"
|
|
}
|
|
if ($UserInput -match "SQL error or missing database") {
|
|
Get-GitHubPreset Retry -PR $PR
|
|
if (!($Silent)) {
|
|
Write-Output "PR $PR - SQL error or missing database"
|
|
}
|
|
Open-PRInBrowser -PR $PR
|
|
}
|
|
|
|
$UserInput = $UserInput -split "`n"
|
|
$UserInput = $UserInput -notmatch " success or error status`: 0"
|
|
$UserInput = $UserInput -notmatch "``Windows Error Reporting``"
|
|
$UserInput = $UserInput -notmatch "--- End of inner exception stack trace ---"
|
|
$UserInput = $UserInput -notmatch "AppInstallerRepositoryCore"
|
|
$UserInput = $UserInput -notmatch "api-ms-win-core-errorhandling"
|
|
$UserInput = $UserInput -notmatch "appropriate application package"
|
|
$UserInput = $UserInput -notmatch "2: 3: Error"
|
|
$UserInput = $UserInput -notmatch "because the current user does not have that package installed"
|
|
$UserInput = $UserInput -notmatch "Cannot create a file when that file already exists"
|
|
$UserInput = $UserInput -notmatch "Could not create system restore point"
|
|
$UserInput = $UserInput -notmatch "Dest filename"
|
|
$UserInput = $UserInput -notmatch "ERROR: Signature Update failed"
|
|
$UserInput = $UserInput -notmatch "Exception during executable launch operation System.InvalidOperationException: No process is associated with this object."
|
|
$UserInput = $UserInput -notmatch "Exit code`: 0"
|
|
$UserInput = $UserInput -notmatch "Failed to open available source: msstore"
|
|
$UserInput = $UserInput -notmatch "ISWEBVIEW2INSTALLED"
|
|
$UserInput = $UserInput -notmatch "MpCmdRun"
|
|
$UserInput = $UserInput -notmatch "ResultException"
|
|
$UserInput = $UserInput -notmatch "SchedNetFx"
|
|
$UserInput = $UserInput -notmatch "Setting error JSON 1.0 fields"
|
|
$UserInput = $UserInput -notmatch "Terminating context"
|
|
$UserInput = $UserInput -notmatch "The process cannot access the file because it is being used by another process"
|
|
$UserInput = $UserInput -notmatch "The FileSystemWatcher has detected an error System.IO.ErrorEventArgs"
|
|
$UserInput = $UserInput -notmatch "ThrowIfExceptional"
|
|
$UserInput = $UserInput -notmatch "Windows Installer installed the product"
|
|
$UserInput = $UserInput -notmatch "with working directory 'D"
|
|
}
|
|
$UserReplace = $UserInput -replace "\\","\\" -replace "\[","\["-replace "\]","\]"-replace "\*","\*"-replace "\+","\+"
|
|
|
|
if ($null -notmatch ($UserReplace)) {
|
|
$UserInput = $UserInput | Select-Object -Unique
|
|
|
|
$UserInput = $UserInput -replace "-",$null
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Reply-ToPR (A) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd"
|
|
} else {
|
|
$out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
|
|
|
|
if ($LowerOps -eq $true) {
|
|
$SplitInput = ($UserInput -split "`n" )
|
|
foreach ($input in $QueueInputs) {
|
|
if($SplitInput -match $input) {
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Add-PRToQueue -PR $PR"
|
|
} else {
|
|
Add-PRToQueue -PR $PR
|
|
}
|
|
|
|
}
|
|
}
|
|
$exitregex = "exit code: [0-9]{0,3}$"
|
|
$exitregex2 = "exit code: [0-9]{4,}$"
|
|
if(!(($UserInput -split "`n" ) -match $exitregex2)) { #4 digits bad
|
|
if(($UserInput -split "`n" ) -match $exitregex) { #1-3 digits good
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Get-CompletePR -PR $PR"
|
|
} else {
|
|
Get-CompletePR -PR $PR
|
|
}
|
|
}
|
|
}
|
|
}#end If LowerOps
|
|
|
|
if (!($Silent)) {
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Write-Host 'PR: $PR - $out'"
|
|
} else {
|
|
Write-Host "PR: $PR - $out"
|
|
}
|
|
}
|
|
} else {
|
|
if ($IsZipPath) {
|
|
$UserInput = "No errors to post."
|
|
$Title = ((Invoke-GitHubPRRequest -PR $PR -Type "" -Output content -JSON).title);
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Reply-ToPR (B) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd"
|
|
Write-Host "WhatIf: Get-CompletePR -PR $PR"
|
|
Write-Host "WhatIf: Get-GitHubPreset -PR $PR Waiver"
|
|
} else {
|
|
$out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
Get-CompletePR -PR $PR
|
|
foreach ($Waiver in $WaiverList) {
|
|
if ($Title -match $Waiver.PackageIdentifier) {
|
|
Get-GitHubPreset -PR $PR Waiver
|
|
}#end if title
|
|
}#end foreach waiver
|
|
}
|
|
}
|
|
}
|
|
} else {
|
|
if (!($Silent)) {
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Reply-ToPR (C) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd"
|
|
Write-Host "WhatIf: UserInput Length $($UserInput.Length)"
|
|
} else {
|
|
$out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
if ($WhatIf) {
|
|
Write-Host "WhatIf: Reply-ToPR (D) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd"
|
|
} else {
|
|
$out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
$UserInput = "Build $BuildNumber not found."
|
|
Write-Host $UserInput
|
|
$out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd
|
|
}
|
|
}
|
|
return $out
|
|
}
|
|
}
|
|
|
|
Function Get-RandomIEDS {
|
|
param(
|
|
$VM = (Get-NextFreeVM),
|
|
$IEDSPRs =(Get-SearchGitHub -Preset IEDS -nBMM),
|
|
#$IEDSPRs =(Get-SearchGitHub -Preset ToWork3),
|
|
$PR = ($IEDSPRs.number | where {$_ -notin (Get-Status).pr} | Get-Random),
|
|
$PRData = (Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$pr" -JSON),
|
|
$PRTitle = (($PRData.title -split " ")[2] | where {$_ -match "\."}),
|
|
$File = 0,
|
|
$ManifestType = "",
|
|
$OldManifestType = "",
|
|
$OldPackageIdentifier = ""
|
|
)
|
|
|
|
if ($VM -eq 0){
|
|
Write-Host "No available $OS VMs";
|
|
Get-PipelineVmGenerate -OS $OS;
|
|
Add-PRToQueue -PR $PR;
|
|
} else {
|
|
Get-CommitFile -PR $PR -VM $VM -MatchName ""
|
|
}
|
|
}
|
|
|
|
Function Get-PRManifest {
|
|
param(
|
|
$PR,
|
|
$File = 0,
|
|
$ManifestType = "",
|
|
$OldManifestType = "",
|
|
$FooterHeader = "`n@@ -0,0 +0,0 @@`n",
|
|
$CommitFile = (Get-CommitFile -PR $PR -MatchName ""),
|
|
$PackageIdentifier = ((Get-YamlValue -StringName "PackageIdentifier" $CommitFile) -replace '"',''-replace "'",''),
|
|
$PackageVersion = ((Get-YamlValue -StringName "PackageVersion" $CommitFile) -replace '"',''-replace "'",''),
|
|
$Submitter = ((Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$pr" -JSON).user.login)
|
|
)
|
|
|
|
$out = "$PackageIdentifier version $PackageVersion #$PR`n"
|
|
$out += "$Submitter wants to merge`n"
|
|
$out += $FooterHeader
|
|
$out += ($CommitFile -join "`n")
|
|
$out += $FooterHeader
|
|
return $out
|
|
}
|
|
|
|
#PR tools
|
|
#Add user to PR: Invoke-GitHubPRRequest -Method $Method -Type "assignees" -Data $User -Output StatusDescription
|
|
#Approve PR (needs work): Invoke-GitHubPRRequest -PR $PR -Method Post -Type reviews
|
|
Function Invoke-GitHubPRRequest {
|
|
param(
|
|
$PR,
|
|
[ValidateSet("GET","DELETE","PATCH","POST","PUT")][string]$Method = "GET",
|
|
[ValidateSet("assignees","comments","commits","files","labels","merge","reviews","")][string]$Type = "labels",
|
|
[string]$Data,
|
|
[ValidateSet("issues","pulls")][string]$Path = "issues",
|
|
[ValidateSet("Content","Silent","StatusDescription")][string]$Output = "StatusDescription",
|
|
[switch]$JSON,
|
|
$prData = (Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$pr/commits" -JSON),
|
|
$commit = (($prData.commit.url -split "/")[-1])
|
|
)
|
|
$Response = @{}
|
|
$ResponseType = $Type
|
|
$uri = "$GitHubApiBaseUrl/$Path/$pr/$Type"
|
|
|
|
if (($Type -eq "") -OR ($Type -eq "files") -OR ($Type -eq "reviews")){
|
|
$Path = "pulls"
|
|
$uri = "$GitHubApiBaseUrl/$Path/$pr/$Type"
|
|
} elseif ($Type -eq "comments") {
|
|
$Response.body += $Data
|
|
} elseif ($Type -eq "commits") {
|
|
$uri = "$GitHubApiBaseUrl/$Type/$commit"
|
|
} elseif ($Type -eq "merge") {
|
|
$Path = "pulls"
|
|
} elseif ($Type -eq "reviews") {
|
|
$Path = "pulls"
|
|
$Response.body = ""+$Data
|
|
$Response.commit = $commit
|
|
$Response.event = "APPROVE"
|
|
} elseif ($Type -eq "") {
|
|
#$Response.title = ""
|
|
#$Response.body = ""
|
|
$Response.state = "closed"
|
|
$Response.base = "master"
|
|
} else {
|
|
$Response.$ResponseType = @()
|
|
$Response.$ResponseType += $Data
|
|
}
|
|
|
|
$uri = $uri -replace "/$",""
|
|
|
|
if ($Method -eq "GET") {
|
|
$out = Invoke-GitHubRequest -Method $Method -Uri $uri
|
|
} else {
|
|
[string]$Body = $Response | ConvertTo-Json
|
|
$out = Invoke-GitHubRequest -Method $Method -Uri $uri -Body $Body
|
|
}
|
|
|
|
if (($JSON) -OR ($Output -eq "Content")) {
|
|
if ($null -ne $out.$Output) {
|
|
try {
|
|
$out.$Output | ConvertFrom-Json
|
|
}catch{
|
|
return ("PR: $PR - Error: $($error[0].ToString()) - Url $uri - Body: $Body")
|
|
}
|
|
} elseif ($Output -eq "Silent") {
|
|
} else {
|
|
$out.$Output
|
|
}
|
|
} else {
|
|
return "!"#"PR: $PR - No output. Method: $Method - URI: $uri"
|
|
#return ("PR: $PR - Error: $($error[0].ToString()) - Url $uri - Body: $Body")
|
|
}
|
|
}
|
|
|
|
Function Approve-PR {
|
|
param(
|
|
$PR,
|
|
[string]$Body = "",
|
|
$prData = (Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$pr/commits" -JSON),
|
|
$commit = (($prData.commit.url -split "/")[-1]),
|
|
$uri = "$GitHubApiBaseUrl/pulls/$pr/reviews"
|
|
)
|
|
|
|
$Response = @{}
|
|
$Response.body = $Body
|
|
$Response.commit = $commit
|
|
$Response.event = "APPROVE"
|
|
[string]$Body = $Response | ConvertTo-Json
|
|
|
|
$out = Invoke-GitHubRequest -Method Post -Uri $uri -Body $Body
|
|
$out.StatusDescription
|
|
Get-AddPRLabel -PR $PR -LabelName $Labels.MA
|
|
}
|
|
|
|
Function Get-ApproveBySearch {
|
|
Param(
|
|
[Parameter(mandatory=$True)][string]$Author,
|
|
$Preset = "ToWork",
|
|
$MatchText = 'Standardize formatting',
|
|
$Results = (Get-SearchGitHub -Author $Author -Preset $Preset -NoLabels)
|
|
)
|
|
$Results = $Results | ? {$_.user.login -eq $Author -and $_.title -match $MatchText -and $_.labels.name -notcontains $Labels.MA -and $_.labels.name -notcontains $Labels.CR};
|
|
$Results.number | % { write-host "$_ - " -nonewline;Approve-PR $_ };
|
|
}
|
|
|
|
Function Get-PRRange ([int]$firstPR,[int]$lastPR,[string]$Body,[string]$Preset) {
|
|
$line = 0;$firstPR..$lastPR | %{
|
|
if ($Preset -eq "closed") {
|
|
Get-GitHubPreset -Preset $Preset -PR $_ -UserInput $Body
|
|
} else {
|
|
Reply-ToPR -PR $_ -Body $Body;
|
|
Get-GitHubPreset -Preset $Preset -PR $_
|
|
}
|
|
Get-TrackerProgress -PR $_ $MyInvocation.MyCommand $line ($lastPR - $firstPR);$line++
|
|
}}
|
|
|
|
Function Get-AllPRsOnClipboard {
|
|
param(
|
|
$clip = (Get-Clipboard),
|
|
$hash = "#",
|
|
$br = "`n",
|
|
$sp = " "
|
|
)
|
|
$out = @()
|
|
($clip -replace $hash,($br+$hash) -split $br -split $sp | select-string $hash) -replace $hash,$null | %{$out += $_}
|
|
return $out
|
|
}
|
|
|
|
Function Get-AllPRsOnClipboardPreset ([string]$Body,[string]$Preset) {
|
|
$line = 0;
|
|
Get-AllPRsOnClipboard | %{
|
|
if ($Preset) {
|
|
if ($Preset -eq "closed") {
|
|
Get-GitHubPreset -Preset $Preset -PR $_ -UserInput $Body
|
|
} else {
|
|
Reply-ToPR -PR $_ -Body $Body;
|
|
Get-GitHubPreset -Preset $Preset -PR $_
|
|
}
|
|
}
|
|
Get-TrackerProgress -PR $_ $MyInvocation.MyCommand $line ($lastPR - $firstPR);$line++
|
|
}
|
|
}
|
|
|
|
Function Get-AddPRLabel {
|
|
param(
|
|
[int]$PR,
|
|
[string]$LabelName
|
|
)
|
|
(Invoke-GitHubPRRequest -PR $PR -Method POST -Type labels -Data $LabelName -Output Content).name
|
|
}
|
|
|
|
Function Get-RemovePRLabel {
|
|
param(
|
|
[int]$PR,
|
|
[string]$LabelName
|
|
)
|
|
(Invoke-GitHubRequest -Uri "$GitHubApiBaseUrl/issues/$PR/labels/$LabelName" -Method DELETE).StatusDescription
|
|
}
|
|
|
|
function Get-CompletePR ([int]$PR){
|
|
$PRLabels = (invoke-GitHubPRRequest -PR $PR -Type labels -Method GET -Output Content).name |
|
|
where {$_ -notmatch $Labels.APP} |
|
|
where {$_ -notmatch $Labels.MMC} |
|
|
where {$_ -notmatch $Labels.MA} |
|
|
where {$_ -notmatch $Labels.NM} |
|
|
where {$_ -notmatch $Labels.NP} |
|
|
where {$_ -notmatch $Labels.PD} |
|
|
where {$_ -notmatch $Labels.RET} |
|
|
where {$_ -notmatch $Labels.VC}
|
|
|
|
foreach ($label in $PRLabels) {
|
|
Get-RemovePRLabel -PR $PR -Label $label
|
|
}
|
|
if (($PRLabels -join " ") -notmatch $Labels.VDE) {
|
|
Get-AddPRLabel -PR $PR -LabelName $Labels.VC
|
|
}
|
|
}
|
|
|
|
Function Get-MergePR {
|
|
Param(
|
|
$PR,
|
|
$ShaNumber = (-1)
|
|
)
|
|
$sha = (Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$pr/commits" -JSON).sha
|
|
if ($null -ne $sha) {
|
|
if ($sha.gettype().name -eq "String") {
|
|
$sha = $sha
|
|
} else {
|
|
$sha = $sha[$ShaNumber]
|
|
}
|
|
} else {
|
|
write-host "SHA $sha not found (length $($sha.length)"
|
|
}
|
|
|
|
$out = ""
|
|
$Data = Invoke-GitHubrequest -Uri "https://api.github.com/repos/microsoft/winget-pkgs/pulls/$pr/merge" -Method PUT -Body "{`"merge_method`":`"squash`",`"sha`":`"$sha`"}"
|
|
if ($Data.Content) {
|
|
$out = $Data.Content
|
|
} else {
|
|
$out = $Data
|
|
#($Data[1..$Data.length] | convertfrom-json).message
|
|
}
|
|
|
|
$Comments = (Invoke-GitHubPRRequest -PR $PR -Type comments -Output content)
|
|
if ($out -match "Error") {
|
|
if ($Comments[-1].UserName -ne $GitHubUserName) {
|
|
Reply-ToPR -PR $PR -UserInput $out -CannedMessage MergeFail
|
|
}
|
|
}
|
|
$out
|
|
|
|
Add-PRToRecord -PR $PR -Action Squash
|
|
#invoke-GitHubprRequest -PR $PR -Method PUT -Type merge -Data "{`"merge_method`":`"squash`",`"sha`":`"$sha`"}"
|
|
}
|
|
|
|
Function Get-RetryPR {
|
|
Param(
|
|
$PR,
|
|
$Command = "@wingetbot run"
|
|
)
|
|
Invoke-GitHubPRRequest -PR $PR -Type comments -Output StatusDescription -Method POST -Data $Command
|
|
}
|
|
|
|
function Get-PushMePRYou {
|
|
Param(
|
|
$Author = "Trenly",
|
|
$MatchString = "Standardize formatting"
|
|
)
|
|
foreach ($Preset in ("Approval","ToWork")) {
|
|
write-host "$($Preset): $(get-date)";
|
|
$a = @();
|
|
$a = Get-SearchGitHub -Author $Author -Preset $Preset -NoLabels;
|
|
$a = $a | ? {$_.user.login -eq $Author -and $_.title -match $MatchString -and $_.labels.name -notcontains $Labels.MA};
|
|
$a.number | % {
|
|
write-host "$_ - " -nonewline;
|
|
Approve-PR $_
|
|
};
|
|
};
|
|
|
|
$Preset = "Complete"
|
|
write-host "$($Preset): $(get-date)";
|
|
}
|
|
|
|
Function Add-GitHubReviewComment {
|
|
param(
|
|
$PR,
|
|
[string]$Comment = "",
|
|
$Commit = (Invoke-GitHubPRRequest -PR $PR -Type commits -Output content -JSON),
|
|
$commitID = $commit.sha,
|
|
$Filename = $commit.files.filename,
|
|
$Side = "RIGHT",
|
|
$StartLine,
|
|
$Line
|
|
)
|
|
if ($Filename.GetType().BaseType.Name -eq "Array") {
|
|
$Filename = $Filename[0]
|
|
}
|
|
|
|
$Response = @{}
|
|
$Response.body = $Comment
|
|
$Response.commit_id = $commitID
|
|
$Response.path = $Filename
|
|
if ($StartLine) {
|
|
$Response.start_line = $StartLine
|
|
}
|
|
$Response.start_side = $Side
|
|
$Response.line = $Line
|
|
$Response.side = $Side
|
|
[string]$Body = $Response | ConvertTo-Json
|
|
|
|
$uri = "$GitHubApiBaseUrl/pulls/$pr/comments"
|
|
|
|
$out = Invoke-GitHubRequest -Method Post -Uri $uri -Body $Body
|
|
$out.StatusDescription
|
|
}
|
|
|
|
Function Get-BuildFromPR {
|
|
param(
|
|
$PR,
|
|
$content = (Invoke-GitHubPRRequest -PR $PR -Method GET -Type comments -Output Content),
|
|
$href = ($content.body | where {$_ -match "Validation Pipeline Run"})
|
|
)
|
|
if ($href.gettype().basetype.name -eq "Array" ) {
|
|
$href = $href[-1]
|
|
}
|
|
$PRbuild = (($href -split "=" -replace "\)")[1])
|
|
return $PRbuild
|
|
}
|
|
|
|
Function Get-LineFromBuildResult {
|
|
param(
|
|
$PR,
|
|
$PRbuild = (Get-BuildFromPR -PR $PR),
|
|
$LogNumber = (36),
|
|
$SearchString = "Specified hash doesn't match",
|
|
$content = (Invoke-WebRequest "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$PRbuild/logs/$LogNumber" -ProgressAction SilentlyContinue).content,
|
|
$Log = ($content -join "" -split "`n"),
|
|
$MatchOffset = (-1),
|
|
$MatchLine = (($Log | Select-String -SimpleMatch $SearchString).LineNumber | where {$_ -gt 0}),
|
|
$Length = 0,
|
|
$output = @()
|
|
)
|
|
foreach ($Match in $MatchLine) {
|
|
$output += ($Log[($Match + $MatchOffset)..($Match+$Length + $MatchOffset)])
|
|
}
|
|
return $output
|
|
}
|
|
|
|
Function Get-PRApproval {
|
|
param(
|
|
$Clip = (Get-Clipboard),
|
|
[int]$PR = (($Clip -split "#")[1]),
|
|
$PackageIdentifier = ((($clip -split ": ")[1] -split " ")[0]),
|
|
$auth = (Get-ValidationData -Property PackageIdentifier -Match $PackageIdentifier -Exact).GitHubUserName,
|
|
$Approver = (($auth -split "/" | Where-Object {$_ -notmatch "\("}) -join ", @"),
|
|
[switch]$DemoMode
|
|
)
|
|
Reply-ToPR -PR $PR -UserInput $Approver -CannedMessage Approve -Policy $Labels.NR
|
|
}
|
|
|
|
Function Reply-ToPR {
|
|
param(
|
|
$PR,
|
|
[string]$CannedMessage,
|
|
[string]$UserInput = ((Invoke-GitHubPRRequest -PR $PR -Type "" -Output content -JSON).user.login),
|
|
[string]$Body = (Get-CannedMessage $CannedMessage -UserInput $UserInput -NoClip),
|
|
[string]$Policy,
|
|
[Switch]$Silent
|
|
)
|
|
if ($Policy) {
|
|
$Body += "`n<!--`n[Policy] $Policy`n-->"
|
|
}
|
|
# If (($CannedMessage -eq "AutoValEnd") -OR ($CannedMessage -eq "ManValEnd")) {
|
|
# $SharedError = Get-AutomatedErrorAnalysis $SharedError
|
|
# }
|
|
if ($Silent) {
|
|
Invoke-GitHubPRRequest -PR $PR -Method Post -Type "comments" -Data $Body -Output Silent
|
|
} else {
|
|
Invoke-GitHubPRRequest -PR $PR -Method Post -Type "comments" -Data $Body -Output StatusDescription
|
|
}
|
|
}
|
|
|
|
Function Get-NonstandardPRComments {
|
|
param(
|
|
$PR,
|
|
$comments = (Invoke-GitHubPRRequest -PR $PR -Type comments -Output content).body
|
|
)
|
|
foreach ($StdComment in $StandardPRComments) {
|
|
$comments = $comments | Where-Object {$_ -notmatch $StdComment}
|
|
}
|
|
return $comments
|
|
}
|
|
|
|
Function Get-PRStateFromComments {
|
|
param(
|
|
$PR = (Get-Clipboard),
|
|
$PRComments = (Invoke-GitHubPRRequest -PR $PR -Type comments -Output content | select created_at,@{n="UserName";e={$_.user.login -replace "\[bot\]"}},body),
|
|
$PRStateData = ((Get-Content $PRStateDataFile) -replace "GitHubUserName",$GitHubUserName | ConvertFrom-Csv),
|
|
[switch]$WhatIf
|
|
)
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - Comments $($PRComments.count)"
|
|
}
|
|
$Robots = @{}
|
|
$Robots.Wingetbot = "wingetbot"
|
|
$Robots.AzurePipelines = "azure-pipelines"
|
|
$Robots.FabricBot = "microsoft-github-policy-service"
|
|
|
|
$Run = @{}
|
|
$Run.azp1 = "AzurePipelines run"
|
|
$Run.azp2 = "azp run"
|
|
$Run.wingetbot = "wingetbot run"
|
|
|
|
$States = @{}
|
|
$States.PreRun = "PreRun"
|
|
$States.PreValidation = "PreValidation"
|
|
$States.Running = "Running"
|
|
$States.PreApproval = "PreApproval"
|
|
$States.DefenderFail = "DefenderFail"
|
|
$States.InstallerAvailable = "InstallerAvailable"
|
|
$States.InstallerRemoved = "InstallerRemoved"
|
|
$States.VersionParamMismatch = "VersionParamMismatch"
|
|
$States.LabelAction = "LabelAction"
|
|
$States.DomainReview = "DomainReview"
|
|
$States.SequenceError = "SequenceError"
|
|
$States.HighestVersionRemoval = "HighestVersionRemoval"
|
|
$States.SQLMissingError = "SQLMissingError"
|
|
$States.ChangesRequested = "ChangesRequested"
|
|
$States.HashMismatch = "HashMismatch"
|
|
$States.AutoValEnd = "AutoValEnd"
|
|
$States.ManValEnd = "ManValEnd"
|
|
$States.MergeConflicts = "MergeConflicts"
|
|
$States.ValidationCompleted = "ValidationCompleted"
|
|
$States.PublishSucceeded = "PublishSucceeded"
|
|
|
|
$LabelActionComments = @{}
|
|
$LabelActionComments.URLError = "The package manager bot determined there was an issue with one of the installers listed in the url field"
|
|
$LabelActionComments.ValidationInstallationError = "The package manager bot determined there was an issue with installing the application correctly"
|
|
$LabelActionComments.InternalError = "The pull request encountered an internal error and has been assigned to a developer to investigate"
|
|
$LabelActionComments.ValidationUnattendedFailed = "this application failed to install without user input"
|
|
$LabelActionComments.ManifestValidationError = "Please verify the manifest file is compliant with the package manager"
|
|
|
|
|
|
$out = @()
|
|
foreach ($PRComment in $PRComments) {
|
|
$State = ""
|
|
$PRComment.created_at = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($PRComment.created_at, 'Pacific Standard Time')
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - created_at $($PRComment.created_at)"
|
|
}
|
|
|
|
if (($PRComment.body -match $Run.azp1) -OR
|
|
($PRComment.body -match $Run.azp2) -OR
|
|
($PRComment.body -match $Run.wingetbot)) {
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - State $($States.PreValidation)"
|
|
}
|
|
$State = $States.PreValidation
|
|
} elseif (($PRComment.UserName -eq $Robots.FabricBot) -AND (
|
|
($PRComment.body -match $LabelActionComments.URLError) -OR
|
|
($PRComment.body -match $LabelActionComments.ValidationInstallationError) -OR
|
|
($PRComment.body -match $LabelActionComments.InternalError) -OR
|
|
($PRComment.body -match $LabelActionComments.ValidationUnattendedFailed) -OR
|
|
($PRComment.body -match $LabelActionComments.ManifestValidationError)
|
|
)) {
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - State $($States.LabelAction)"
|
|
}
|
|
$State = $States.LabelAction
|
|
} else {
|
|
foreach ($Key in $States.Keys) {
|
|
$KeyData = $PRStateData | where {$_.State -eq $Key}
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - key $key - State $($States.Key) - botcomment $($KeyData.BotComment) - PRComment $($PRComment.body)"
|
|
}
|
|
if (($PRComment.body -match $KeyData.BotComment) -AND ($PRComment.UserName -eq $KeyData.User)) {
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - match $($KeyData.BotComment)"
|
|
}
|
|
$State = $States.$Key
|
|
}
|
|
}
|
|
}
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - State $State"
|
|
}
|
|
if ($State -ne "") {
|
|
if ($WhatIf) {
|
|
write-host "PR $PR - out $out"
|
|
}
|
|
$out += $PRComment | select @{n="event";e={$State}},created_at
|
|
}
|
|
}
|
|
Return $out
|
|
}
|
|
|
|
Function Get-AddToAutowaiver {
|
|
param(
|
|
$PR,
|
|
$RemoveLabel,
|
|
$AutowaiverData = (Get-Content $AutowaiverFile | ConvertFrom-Csv),
|
|
$PRData = (Get-CommitFile -PR $PR),
|
|
$PackageIdentifier = (Get-YamlValue -StringName PackageIdentifier -clip $PRData)
|
|
)
|
|
$NewLine = "" | select "PackageIdentifier","ManifestValue","ManifestKey","RemoveLabel"
|
|
$NewLine.PackageIdentifier = $PackageIdentifier
|
|
$NewLine.RemoveLabel = $RemoveLabel
|
|
if (($RemoveLabel -eq $Labels.VD) -or ($RemoveLabel -eq $Labels.VUU)) {
|
|
$NewLine.ManifestValue = ((Get-YamlValue -StringName InstallerUrl -clip $PRData) -split "/")[2]
|
|
$NewLine.ManifestKey = "InstallerUrl"
|
|
} else {
|
|
$NewLine.ManifestValue = $PackageIdentifier
|
|
$NewLine.ManifestKey = "PackageIdentifier"
|
|
}
|
|
|
|
$AutowaiverData += $NewLine
|
|
($AutowaiverData | sort PackageIdentifier | ConvertTo-Csv) | Out-File $AutowaiverFile
|
|
}
|
|
|
|
Function Get-Autowaiver {
|
|
param(
|
|
[int]$PR = (Get-PRNumber (Get-Clipboard) -Hash),
|
|
$AutowaiverData = (Get-Content $AutowaiverFile | ConvertFrom-Csv),
|
|
$PRData = (Get-CommitFile -PR $PR),
|
|
$PackageIdentifier = (Get-YamlValue -StringName PackageIdentifier -clip $PRData),
|
|
$WaiverData = ($AutowaiverData | ?{$_.PackageIdentifier -eq $PackageIdentifier})
|
|
)
|
|
if ($WaiverData) {
|
|
Add-PRToRecord -PR $PR -Action $Actions.Waiver
|
|
foreach ($Waiver in $WaiverData) {
|
|
try {
|
|
$PackageValue = (Get-YamlValue -StringName $Waiver.ManifestKey -clip $PRData)
|
|
} catch {}
|
|
if ($PackageValue -match $Waiver.ManifestValue) {
|
|
Get-RemovePRLabel -PR $PR -LabelName $Waiver.RemoveLabel
|
|
Get-RemovePRLabel -PR $pr -LabelName "Needs-Author-Feedback"
|
|
Get-RemovePRLabel -PR $pr -LabelName "Needs-Attention"
|
|
Get-AddPRLabel -PR $PR -LabelName Validation-Completed
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
Function Get-VerifyMMC {
|
|
param(
|
|
[int]$PR = (Get-PRNumber $clip -Hash)
|
|
)
|
|
$Comments = (Invoke-GitHubPRRequest -PR $PR -Type comments -Output content | select created_at,@{n="UserName";e={$_.user.login -replace "\[bot\]"}},body)
|
|
[array]$MissingProperties = ($Comments.body | ? {$_ -match "=== manifests"}) -split "`n" | ?{ $_ -notmatch "=== manifests" -AND
|
|
$_ -notmatch "Missing Properties" -AND
|
|
$_ -notmatch "Icons" -AND
|
|
$_ -notmatch "Platform" -AND
|
|
$_ -notmatch "MinimumOSVersion" -AND
|
|
$_ -notmatch "ReleaseNotes" -AND
|
|
$_ -notmatch "ReleaseNotesUrl" -AND
|
|
$_ -notmatch "ReleaseDate"}
|
|
if (!$MissingProperties) {
|
|
Get-RemovePRLabel -PR $PR -LabelName Manifest-Metadata-Consistency
|
|
}
|
|
}
|
|
|
|
Function Get-DuplicateCheck {
|
|
param(
|
|
[int]$PR
|
|
)
|
|
$PRLabels = ((Invoke-GitHubPRRequest -PR $PR -Type "labels" -Output content -JSON).name)
|
|
if ($PRLabels -match $Labels.VC) { #If this PR is VC
|
|
$Comments = (Invoke-GitHubPRRequest -PR $PR -Type comments -Output content)
|
|
$otherPR = $Comments.body | ? {$_ -match "Found duplicate pull request"}
|
|
$otherPR = $otherPR -split "`n"
|
|
[int]$otherPR = (($otherPR | where {$_ -match $hashPRRegex}) -split "#")[-1]
|
|
$otherPRLabels = ((Invoke-GitHubPRRequest -PR $otherPR -Type "labels" -Output content -JSON).name)
|
|
[int]$mainPR = 0
|
|
[int]$dupePR = 0
|
|
if ($otherPRLabels -match $Labels.VC) { #If other is VC, close the lower number as other.
|
|
if ($otherPRLabels -match $Labels.MA) { #If other is VCMA, close this.
|
|
$mainPR = $otherPR
|
|
$dupePR = $PR
|
|
} else { #If the other is not VC, close it as other.
|
|
$mainPR = [math]::Max($PR,$otherPR)
|
|
$dupePR = [math]::Min($PR,$otherPR)
|
|
}# end if Moderator-Approved
|
|
} else { #If the other is not VC, close it as other.
|
|
$mainPR = $PR
|
|
$dupePR = $otherPR
|
|
}# end if Validation-Completed
|
|
if ($dupePR -gt 0) {
|
|
Get-GitHubPreset -Preset Duplicate -PR $dupePR -UserInput $mainPR
|
|
Get-RemovePRLabel -PR $mainPR -Label $Labels.PD
|
|
}# end if dupePR
|
|
}# end if mainPRLabels
|
|
}# end function
|
|
|
|
#Network tools
|
|
#GET = Read; POST = Append; PUT = Write; DELETE = delete
|
|
Function Invoke-GitHubRequest {
|
|
param(
|
|
[Parameter(mandatory=$True)][string]$Uri,
|
|
[string]$Body,
|
|
[ValidateSet("DELETE","GET","HEAD","PATCH","POST","PUT")][string]$Method = "GET",
|
|
$Headers = @{"Authorization"="Bearer $GitHubToken"; "Accept"="application/vnd.github+json"; "X-GitHub-Api-Version"="2022-11-28"},
|
|
#[ValidateSet("content","StatusDescription")][string]$Output = "content",
|
|
[switch]$JSON,
|
|
$out = ""
|
|
)
|
|
if ($Body) {
|
|
try {
|
|
$out = (Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -Body $Body -ContentType application/json -ProgressAction SilentlyContinue)
|
|
} catch {
|
|
Write-Output ("Error: $($error[0].ToString()) - Url $Url - Body: $Body")
|
|
}
|
|
} else {
|
|
try {
|
|
$out = (Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -ProgressAction SilentlyContinue)
|
|
} catch {
|
|
Write-Output ("Error: $($error[0].ToString()) - Url $Url - Body: $Body")
|
|
}
|
|
}
|
|
#GitHub requires the value be the .body property of the variable. This makes more sense with CURL, Where-Object this is the -data parameter. However with Invoke-WebRequest it's the -Body parameter, so we end up with the awkward situation of having a Body parameter that needs to be prepended with a body property.
|
|
#if (!($Silent)) {
|
|
if (($JSON)){# -OR ($Output -eq "content")) {
|
|
$out | ConvertFrom-Json
|
|
} else {
|
|
$out
|
|
}
|
|
#}
|
|
Start-Sleep $GitHubRateLimitDelay;
|
|
}
|
|
|
|
Function Check-PRInstallerStatusInnerWrapper {
|
|
param(
|
|
$Url,
|
|
$Code = (Invoke-WebRequest $Url -Method Head -ErrorAction SilentlyContinue -ProgressAction SilentlyContinue).StatusCode
|
|
)
|
|
return $Code
|
|
}
|
|
|
|
#Validation Starts Here
|
|
#Validation Starts Here
|
|
#Validation Starts Here
|
|
Function Get-TrackerVMValidate {
|
|
param(
|
|
$clipInput = ((Get-Clipboard) -split "`n"),
|
|
$clip = ($clipInput[0..(($clipInput | Select-String "Do not share my personal information").LineNumber -1)]),
|
|
[ValidateSet("Win10","Win11")][string]$OS = (Get-OSFromVersion -clip $clip),
|
|
[int]$vm = ((Get-NextFreeVM -OS $OS) -replace"vm",""),
|
|
[switch]$NoFiles,
|
|
[ValidateSet("Configure","DevHomeConfig","Pin","Scan")][string]$Operation = "Scan",
|
|
[switch]$InspectNew,
|
|
[switch]$notElevated,
|
|
$ManualDependency,
|
|
$PackageIdentifier = ((Get-YamlValue -StringName "PackageIdentifier" $clip) -replace '"',''-replace "'",''),
|
|
$PackageVersion = ((Get-YamlValue -StringName "PackageVersion" $clip) -replace '"',''-replace "'",''),
|
|
[int]$PR = (Get-PRNumber $clip -Hash),
|
|
$RemoteFolder = "//$remoteIP/ManVal/vm/$vm",
|
|
$installerLine = "--manifest $RemoteFolder/manifest",
|
|
[ValidateSet("x86","x64","arm","arm32","arm64","neutral")][string]$Arch,
|
|
[ValidateSet("User","Machine")][string]$Scope,
|
|
$InstallerType,
|
|
[string]$Locale,
|
|
[switch]$Force,
|
|
[switch]$Silent,
|
|
[switch]$PauseAfterInstall,
|
|
$optionsLine = ""
|
|
)
|
|
<#Sections:
|
|
Construct WinGet args string and populate script variables.
|
|
- If Configure - skip all of this and just add the Configure file as the WinGet arg.
|
|
Construct the VM script from the script variables and output to commands file.
|
|
- If Configure - Construct a similar script and perform the same output.
|
|
Construct the manifest from the files in the clipboard.
|
|
- If NoFiles, skip.
|
|
Perform new package inspection.
|
|
- If not InspectNew, skip.
|
|
Revert selected VM and launch its window.
|
|
#>
|
|
|
|
Test-Admin
|
|
Get-StaleVMCheck
|
|
|
|
#Check if PR is open
|
|
$PRState = Invoke-GitHubPRRequest -PR $PR -Type "" -Output Content
|
|
|
|
$LabelList = (Invoke-GitHubPRRequest -PR $PR -Type labels -Output Content).name
|
|
if ($Force -OR !((($LabelList -join " ") -match $Labels.MA) -AND (($LabelList -join " ") -match $Labels.CR) -AND (($LabelList -join " ") -match "New-Package")) -OR ($PRState.merged -ne $False) -OR ($PRState.state -ne "open")) {
|
|
if ($vm -eq 0){
|
|
Write-Host "No available $OS VMs";
|
|
Get-PipelineVmGenerate -OS $OS;
|
|
#Break;
|
|
}
|
|
$PackageMode = "Existing"
|
|
|
|
|
|
if ($null -eq (Find-WinGetPackage $PackageIdentifier)) {
|
|
$PackageMode = "New"
|
|
}
|
|
$PostInstallPause = ""
|
|
if ($PauseAfterInstall) {
|
|
$PostInstallPause = "Read-Host 'Install complete, press ENTER to continue...'"
|
|
}
|
|
if ($Silent) {
|
|
Get-TrackerVMSetStatus "Prevalidation" $VM $PackageIdentifier -PR $PR -Mode $PackageMode -Silent
|
|
} else {
|
|
Get-TrackerVMSetStatus "Prevalidation" $VM $PackageIdentifier -PR $PR -Mode $PackageMode
|
|
}
|
|
if ((Get-VM "vm$VM").state -ne "Running") {Start-VM "vm$VM"}
|
|
|
|
$logLine = "$OS "
|
|
$nonElevatedShell = ""
|
|
$logExt = "log"
|
|
$VMFolder = "$MainFolder\vm\$vm"
|
|
$manifestFolder = "$VMFolder\manifest"
|
|
$CmdsFileName = "$VMFolder\cmds.ps1"
|
|
|
|
if ($Operation -eq "Configure") {
|
|
if (!($Silent)) {
|
|
Write-Host "Running Manual Config build $build on vm$VM for ConfigureFile"
|
|
}
|
|
$wingetArgs = "configure -f $RemoteFolder/manifest/config.yaml --accept-configuration-agreements --disable-interactivity"
|
|
$Operation = "Configure"
|
|
$InspectNew = $False
|
|
} else {
|
|
if ($PackageIdentifier -eq "") {
|
|
Write-Host "Bad PackageIdentifier: $PackageIdentifier"
|
|
#Break;
|
|
$PackageIdentifier | clip
|
|
}
|
|
if (!($Silent)) {
|
|
Write-Host "Running Manual Validation build $build on vm$VM for package $PackageIdentifier version $PackageVersion"
|
|
}
|
|
|
|
if ($PackageVersion) {
|
|
$logExt = $PackageVersion+"."+$logExt
|
|
$logLine += "version $PackageVersion "
|
|
}
|
|
if ($Locale) {
|
|
$logExt = $Locale+"."+$logExt
|
|
$optionsLine += " --locale $Locale "
|
|
$logLine += "locale $Locale "
|
|
}
|
|
if ($Scope) {
|
|
$logExt = $Scope+"."+$logExt
|
|
$optionsLine += " --scope $Scope "
|
|
$logLine += "scope $Scope "
|
|
}
|
|
if ($InstallerType) {
|
|
$logExt = $InstallerType+"."+$logExt
|
|
$optionsLine += " --installer-type $InstallerType "
|
|
$logLine += "InstallerType $InstallerType "
|
|
}
|
|
$Archs = ($clip | Select-String -notmatch "arm" | Select-String "Architecture: " )|ForEach-Object{($_ -split ": ")[1]}
|
|
$archDetect = ""
|
|
$archColor = "yellow"
|
|
if ($Archs) {
|
|
if ($Archs[0].length -ge 2) {
|
|
if ($Arch) {
|
|
$archDetect = "Selected"
|
|
} else {
|
|
$Arch = $Archs[0]
|
|
$archDetect = "Detected"
|
|
}
|
|
$archColor = "red"
|
|
} else {
|
|
if ($Archs -eq "neutral") {
|
|
$archColor = "yellow"
|
|
} else {
|
|
$Arch = $Archs
|
|
$archDetect = "Detected"
|
|
$archColor = "green"
|
|
}
|
|
}
|
|
}
|
|
if ($Arch) {
|
|
$logExt = $Arch+"."+$logExt
|
|
if (!($Silent)) {
|
|
Write-Host "$archDetect Arch $Arch of available architectures: $Archs" -f $archColor
|
|
}
|
|
$logLine += "$Arch "
|
|
}
|
|
$MDLog = ""
|
|
if ($ManualDependency) {
|
|
$MDLog = $ManualDependency
|
|
if (!($Silent)) {
|
|
Write-Host " = = = = Installing manual dependency $ManualDependency = = = = "
|
|
}
|
|
[string]$ManualDependency = "Out-Log 'Installing manual dependency $ManualDependency.';Start-Process 'winget' 'install "+$ManualDependency+" --accept-package-agreements --ignore-local-archive-malware-scan' -wait`n"
|
|
}
|
|
if ($notElevated -OR ($clip | Select-String "ElevationRequirement: elevationProhibited")) {
|
|
if (!($Silent)) {
|
|
Write-Host " = = = = Detecting de-elevation requirement = = = = "
|
|
}
|
|
$nonElevatedShell = "if ([bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match 'S-1-5-32-544')){& explorer.exe 'C:\Program Files\PowerShell\7\pwsh.exe';Stop-Process (Get-Process WindowsTerminal).id}"
|
|
#If elevated, run^^ and exit, else run cmds.
|
|
}
|
|
$packageName = ($PackageIdentifier -split "[.]")[1]
|
|
$wingetArgs = "install $optionsLine $installerLine --accept-package-agreements --ignore-local-archive-malware-scan"
|
|
}
|
|
$cmdsOut = ""
|
|
|
|
switch ($Operation) {
|
|
"Configure" {
|
|
$cmdsOut = "$nonElevatedShell
|
|
`$TimeStart = Get-Date;
|
|
`$ConfigurelLogFolder = `"$SharedFolder/logs/Configure/$(Get-Date -UFormat %B)/`$(Get-Date -Format dd)`"
|
|
Function Out-Log ([string]`$logData,[string]`$logColor='cyan') {
|
|
`$TimeStamp = (Get-Date -Format T) + ': ';
|
|
`$logEntry = `$TimeStamp + `$logData
|
|
Write-Host `$logEntry -f `$logColor;
|
|
md `$ConfigurelLogFolder -ErrorAction Ignore
|
|
`$logEntry | Out-File `"`$ConfigurelLogFolder/$PackageIdentifier.$logExt`" -Append -Encoding unicode
|
|
};
|
|
Function Out-ErrorData (`$errArray,[string]`$serviceName,`$errorName='errors') {
|
|
Out-Log `"Detected `$(`$errArray.count) `$serviceName `$(`$errorName): `"
|
|
`$errArray | ForEach-Object {Out-Log `$_ 'red'}
|
|
};
|
|
Get-TrackerVMSetStatus 'Installing'
|
|
Out-Log ' = = = = Starting Manual Validation pipeline build $build on VM $VM Configure file $logLine = = = = '
|
|
|
|
Out-Log 'Pre-testing log cleanup.'
|
|
Out-Log 'Clearing PowerShell errors.'
|
|
`$Error.Clear()
|
|
Out-Log 'Clearing Application Log.'
|
|
Clear-EventLog -LogName Application -ErrorAction Ignore
|
|
Out-Log 'Clearing WinGet Log folder.'
|
|
`$WinGetLogFolder = 'C:\Users\User\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir'
|
|
rm `$WinGetLogFolder\*
|
|
Out-Log 'Gathering WinGet info.'
|
|
`$info = winget --info
|
|
Out-ErrorData @(`$info[0],`$info[3],`$info[4],`$info[5]) 'WinGet' 'infos'
|
|
|
|
Out-Log `"Main Package Configure with args: $wingetArgs`"
|
|
`$mainpackage = (Start-Process 'winget' '$wingetArgs' -wait -PassThru);
|
|
|
|
Out-Log `"`$(`$mainpackage.processname) finished with exit code: `$(`$mainpackage.ExitCode)`";
|
|
If (`$mainpackage.ExitCode -ne 0) {
|
|
Out-Log 'Install Failed.';
|
|
explorer.exe `$WinGetLogFolder;
|
|
Out-ErrorData ((Get-ChildItem `$WinGetLogFolder).fullname | ForEach-Object {Get-Content `$_ |Where-Object {`$_ -match '[[]FAIL[]]' -OR `$_ -match 'failed' -OR `$_ -match 'error' -OR `$_ -match 'does not match'}}) 'WinGet'
|
|
Out-ErrorData '$MDLog' 'Manual' 'Dependency'
|
|
Out-ErrorData `$Error 'PowerShell'
|
|
Out-ErrorData (Get-EventLog Application -EntryType Error -after `$TimeStart -ErrorAction Ignore).Message 'Application Log'
|
|
|
|
Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for Configure file $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'ValidationCompleted'
|
|
Break;
|
|
}
|
|
Read-Host 'Configure complete, press ENTER to continue...' #Uncomment to examine installer before scanning, for when scanning disrupts the install.
|
|
|
|
Get-TrackerVMSetStatus 'Scanning'
|
|
|
|
`$WinGetLogs = ((Get-ChildItem `$WinGetLogFolder).fullname | ForEach-Object {Get-Content `$_ |Where-Object {`$_ -match '[[]FAIL[]]' -OR `$_ -match 'failed' -OR `$_ -match 'error' -OR `$_ -match 'does not match'}})
|
|
`$DefenderThreat = (Get-MPThreat).ThreatName
|
|
|
|
Out-ErrorData `$WinGetLogs 'WinGet'
|
|
Out-ErrorData `$Error 'PowerShell'
|
|
Out-ErrorData (Get-EventLog Application -EntryType Error -after `$TimeStart -ErrorAction Ignore).Message 'Application Log'
|
|
Out-ErrorData `$DefenderThreat `"Defender (with signature version `$((Get-MpComputerStatus).QuickScanSignatureVersion))`"
|
|
|
|
Out-Log `" = = = = Completing Manual Validation pipeline build $build on VM $VM for Configure file $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'ValidationCompleted'
|
|
|
|
"
|
|
}#end Configure
|
|
"Scan" {
|
|
$cmdsOut = "$nonElevatedShell
|
|
`$TimeStart = Get-Date;
|
|
`$explorerPid = (Get-Process Explorer).id;
|
|
`$ManValLogFolder = `"$SharedFolder/logs/$(Get-Date -UFormat %B)/`$(Get-Date -Format dd)`"
|
|
Function Out-Log ([string]`$logData,[string]`$logColor='cyan') {
|
|
`$TimeStamp = (Get-Date -Format T) + ': ';
|
|
`$logEntry = `$TimeStamp + `$logData
|
|
Write-Host `$logEntry -f `$logColor;
|
|
md `$ManValLogFolder -ErrorAction Ignore
|
|
`$logEntry | Out-File `"`$ManValLogFolder/$PackageIdentifier.$logExt`" -Append -Encoding unicode
|
|
};
|
|
Function Out-ErrorData (`$errArray,[string]`$serviceName,`$errorName='errors') {
|
|
Out-Log `"Detected `$(`$errArray.count) `$serviceName `$(`$errorName): `"
|
|
`$errArray | ForEach-Object {Out-Log `$_ 'red'}
|
|
};
|
|
Function Get-TrackerProgress {
|
|
param(
|
|
`$File,
|
|
`$Activity,
|
|
`$Incrementor,
|
|
`$Length,
|
|
`$Percent = [math]::round(`$Incrementor / `$length*100,2)
|
|
)
|
|
};
|
|
Get-TrackerVMSetStatus 'Installing'
|
|
Out-Log ' = = = = Starting Manual Validation pipeline build $build on VM $VM $PackageIdentifier $logLine = = = = '
|
|
|
|
Out-Log 'Pre-testing log cleanup.'
|
|
Out-Log 'Upgrading installed applications.'
|
|
Out-Log (WinGet upgrade --all --include-pinned --disable-interactivity)
|
|
Out-Log 'Clearing PowerShell errors.'
|
|
`$Error.Clear()
|
|
Out-Log 'Clearing Application Log.'
|
|
Clear-EventLog -LogName Application -ErrorAction Ignore
|
|
Out-Log 'Clearing WinGet Log folder.'
|
|
`$WinGetLogFolder = 'C:\Users\User\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir'
|
|
rm `$WinGetLogFolder\*
|
|
Out-Log 'Updating Defender signature.'
|
|
Update-MpSignature
|
|
Out-Log 'Gathering WinGet info.'
|
|
`$info = winget --info
|
|
Out-ErrorData @(`$info[0],`$info[3],`$info[4],`$info[5]) 'WinGet' 'infos'
|
|
|
|
`$InstallStart = Get-Date;
|
|
$ManualDependency
|
|
Out-Log `"Main Package Install with args: $wingetArgs`"
|
|
`$mainpackage = (Start-Process 'winget' '$wingetArgs' -wait -PassThru);
|
|
Out-Log `"`$(`$mainpackage.processname) finished with exit code: `$(`$mainpackage.ExitCode)`";
|
|
`$SleepSeconds = 15 #Sleep a few seconds for processes to complete.
|
|
if ((`$InstallStart).AddSeconds(`$SleepSeconds) -gt (Get-Date)) {
|
|
sleep ((`$InstallStart).AddSeconds(`$SleepSeconds)-(Get-Date)).totalseconds
|
|
}
|
|
`$InstallEnd = Get-Date;
|
|
|
|
If (`$mainpackage.ExitCode -ne 0) {
|
|
Out-Log 'Install Failed.';
|
|
explorer.exe `$WinGetLogFolder;
|
|
|
|
`$WinGetLogs = ((Get-ChildItem `$WinGetLogFolder).fullname | ForEach-Object {
|
|
Get-Content `$_ | Where-Object {
|
|
`$_ -match '[[]FAIL[]]' -OR
|
|
`$_ -match 'failed' -OR
|
|
`$_ -match 'error' -OR
|
|
`$_ -match 'does not match'
|
|
}
|
|
})
|
|
`$DefenderThreat = (Get-MPThreat).ThreatName
|
|
|
|
Out-ErrorData `$WinGetLogs 'WinGet'
|
|
Out-ErrorData '$MDLog' 'Manual' 'Dependency'
|
|
Out-ErrorData `$Error 'PowerShell'
|
|
Out-ErrorData (Get-EventLog Application -EntryType Error -after `$TimeStart -ErrorAction Ignore).Message 'Application Log'
|
|
Out-ErrorData `$DefenderThreat `"Defender (with signature version `$((Get-MpComputerStatus).QuickScanSignatureVersion))`"
|
|
|
|
Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
|
|
if ((`$WinGetLogs -match '\[FAIL\] Installer failed security check.') -OR
|
|
(`$WinGetLogs -match '80190194 Not found') -OR
|
|
(`$WinGetLogs -match 'Package hash verification failed') -OR
|
|
(`$WinGetLogs -match 'Operation did not complete successfully because the file contains a virus or potentially unwanted software')){
|
|
Send-SharedError -clip `$WinGetLogs
|
|
} elseif (`$DefenderThreat) {
|
|
Send-SharedError -clip `$DefenderThreat
|
|
} else {
|
|
Get-TrackerVMSetStatus 'ValidationCompleted'
|
|
}
|
|
|
|
Break;
|
|
}
|
|
$PostInstallPause
|
|
|
|
|
|
|
|
Get-TrackerVMSetStatus 'Scanning'
|
|
|
|
Out-Log 'Install complete, starting file change scan.'
|
|
`$files = ''
|
|
if (Test-Path $RemoteFolder\files.txt) {#If we have a list of files to run - a relic from before automatic file gathering.
|
|
`$files = Get-Content $RemoteFolder\files.txt
|
|
} else {
|
|
`$files1 = (
|
|
Get-ChildItem c:\ -File -Recurse -ErrorAction Ignore -Force |
|
|
Where-Object {`$_.CreationTime -gt `$InstallStart} |
|
|
Where-Object {`$_.CreationTime -lt `$InstallEnd} |
|
|
%{`$line++;Get-TrackerProgress `$_ `"lnk`" `$line `$line;return `$_}
|
|
).FullName
|
|
`$files2 = (
|
|
Get-ChildItem c:\ -File -Recurse -ErrorAction Ignore -Force |
|
|
Where-Object {`$_.LastAccessTIme -gt `$InstallStart} |
|
|
Where-Object {`$_.CreationTime -lt `$InstallEnd} |
|
|
%{`$line++;Get-TrackerProgress `$_ `"lnk`" `$line `$line;return `$_}
|
|
).FullName
|
|
`$files3 = (
|
|
Get-ChildItem c:\ -File -Recurse -ErrorAction Ignore -Force |
|
|
Where-Object {`$_.LastWriteTIme -gt `$InstallStart} |
|
|
Where-Object {`$_.CreationTime -lt `$InstallEnd} |
|
|
%{`$line++;Get-TrackerProgress `$_ `"lnk`" `$line `$line;return `$_}
|
|
).FullName
|
|
`$files = `$files1 + `$files2 + `$files3 | Select-Object -Unique
|
|
}
|
|
|
|
Out-Log `"Reading `$(`$files.count) file changes in the last `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. Starting bulk file execution:`"
|
|
`$files = `$files |
|
|
Where-Object {`$_ -notmatch 'AppRepository'} |
|
|
Where-Object {`$_ -notmatch 'assembly'} |
|
|
Where-Object {`$_ -notmatch 'CbsTemp'} |
|
|
Where-Object {`$_ -notmatch 'CryptnetUrlCache'} |
|
|
Where-Object {`$_ -notmatch 'DesktopAppInstaller'} |
|
|
Where-Object {`$_ -notmatch 'dotnet'} |
|
|
Where-Object {`$_ -notmatch 'dump64a'} |
|
|
Where-Object {`$_ -notmatch 'EdgeCore'} |
|
|
Where-Object {`$_ -notmatch 'EdgeUpdate'} |
|
|
Where-Object {`$_ -notmatch 'EdgeWebView'} |
|
|
Where-Object {`$_ -notmatch 'ErrorDialog = ErrorDlg'} |
|
|
Where-Object {`$_ -notmatch 'Microsoft.Windows.Search'} |
|
|
Where-Object {`$_ -notmatch 'Microsoft\\Edge\\Application'} |
|
|
Where-Object {`$_ -notmatch 'msedge'} |
|
|
Where-Object {`$_ -notmatch 'NativeImages'} |
|
|
Where-Object {`$_ -notmatch 'Prefetch'} |
|
|
Where-Object {`$_ -notmatch 'Provisioning'} |
|
|
Where-Object {`$_ -notmatch 'redis'} |
|
|
Where-Object {`$_ -notmatch 'servicing'} |
|
|
Where-Object {`$_ -notmatch 'System32'} |
|
|
Where-Object {`$_ -notmatch 'SysWOW64'} |
|
|
Where-Object {`$_ -notmatch 'unins'} |
|
|
Where-Object {`$_ -notmatch 'waasmedic'} |
|
|
Where-Object {`$_ -notmatch 'Windows Defender'} |
|
|
Where-Object {`$_ -notmatch 'Windows Error Reporting'} |
|
|
Where-Object {`$_ -notmatch 'WindowsUpdate'} |
|
|
Where-Object {`$_ -notmatch 'WinSxS'}
|
|
|
|
`$files | Out-File 'C:\Users\user\Desktop\ChangedFiles.txt'
|
|
`$files | Select-String '[.]exe`$' | ForEach-Object {if (`$_ -match '$packageName') {Out-Log `$_ 'green'} else{Out-Log `$_ 'cyan'}; try{Start-Process `$_}catch{}};
|
|
`$files | Select-String '[.]msi`$' | ForEach-Object {if (`$_ -match '$packageName') {Out-Log `$_ 'green'} else{Out-Log `$_ 'cyan'}; try{Start-Process `$_}catch{}};
|
|
`$files | Select-String '[.]lnk`$' | ForEach-Object {if (`$_ -match '$packageName') {Out-Log `$_ 'green'} else{Out-Log `$_ 'cyan'}; try{Start-Process `$_}catch{}};
|
|
|
|
Out-Log `" = = = = End file list. Starting Defender scan.`"
|
|
Start-MpScan;
|
|
|
|
Out-Log `"Defender scan complete, closing windows...`"
|
|
Get-Process msedge | Stop-Process -Force
|
|
Get-Process mip | Stop-Process
|
|
Get-Process powershell | where {`$_.id -ne `$PID} | Stop-Process
|
|
Get-Process explorer | where {`$_.id -ne `$explorerPid} | Stop-Process
|
|
|
|
Get-process | Where-Object { `$_.mainwindowtitle -ne '' -and `$_.processname -notmatch '$packageName' -and `$_.processname -ne 'powershell' -and `$_.processname -ne 'WindowsTerminal' -and `$_.processname -ne 'csrss' -and `$_.processname -ne 'dwm'} | Stop-Process
|
|
#Get-Process | Where-Object {`$_.id -notmatch `$PID -and `$_.id -notmatch `$explorerPid -and `$_.processname -notmatch `$packageName -and `$_.processname -ne 'csrss' -and `$_.processname -ne 'dwm'} | Stop-Process
|
|
|
|
`$WinGetLogs = ((Get-ChildItem `$WinGetLogFolder).fullname | ForEach-Object {Get-Content `$_ |Where-Object {`$_ -match '[[]FAIL[]]' -OR `$_ -match 'failed' -OR `$_ -match 'error' -OR `$_ -match 'does not match'}})
|
|
`$DefenderThreat = (Get-MPThreat).ThreatName
|
|
|
|
Out-ErrorData `$WinGetLogs 'WinGet'
|
|
Out-ErrorData '$MDLog' 'Manual' 'Dependency'
|
|
Out-ErrorData `$Error 'PowerShell'
|
|
Out-ErrorData (Get-EventLog Application -EntryType Error -after `$TimeStart -ErrorAction Ignore).Message 'Application Log'
|
|
Out-ErrorData `$DefenderThreat `"Defender (with signature version `$((Get-MpComputerStatus).QuickScanSignatureVersion))`"
|
|
|
|
if ((`$WinGetLogs -match '\[FAIL\] Installer failed security check.') -OR
|
|
(`$WinGetLogs -match 'Package hash verification failed') -OR
|
|
(`$WinGetLogs -match 'Operation did not complete successfully because the file contains a virus or potentially unwanted software')){
|
|
Send-SharedError -clip `$WinGetLogs
|
|
Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'SendStatus'
|
|
} elseif (`$DefenderThreat) {
|
|
Send-SharedError -clip `$DefenderThreat
|
|
Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'SendStatus'
|
|
} elseif ((Get-Content $RemoteTrackerModeFile) -eq 'IEDS') {
|
|
Out-Log `" = = = = Auto-Completing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'Approved'
|
|
} elseif ((Get-TrackerVMStatus | where {`$_.vm -match `$vm}).Mode -eq 'Existing') {
|
|
Out-Log `" = = = = Auto-Completing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'Approved'
|
|
} else {
|
|
Start-Process PowerShell
|
|
Out-Log `" = = = = Completing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `"
|
|
Get-TrackerVMSetStatus 'ValidationCompleted'
|
|
}
|
|
|
|
"
|
|
}#end Scan
|
|
Default {
|
|
Write-Host "Error: Bad Function"
|
|
Break;
|
|
}
|
|
}
|
|
|
|
$cmdsOut | Out-File $CmdsFileName
|
|
|
|
if ($NoFiles -eq $False) {
|
|
#Extract multi-part manifest from clipboard and write to disk
|
|
if (!($Silent)) {
|
|
Write-Host "Removing previous manifest and adding current..."
|
|
}
|
|
Get-RemoveFileIfExist "$manifestFolder" -remake -Silent
|
|
if ($Operation -eq "Configure") {
|
|
$FilePath = "$manifestFolder\config.yaml"
|
|
Out-File -FilePath $FilePath -InputObject $clipInput
|
|
} else {
|
|
$Files = @()
|
|
$Files += "Package.installer.yaml"
|
|
$FileNames = ($clip | Select-String "[.]yaml") |ForEach-Object{($_ -split "/")[-1]}
|
|
$replace = $FileNames[-1] -replace ".yaml"
|
|
$FileNames | ForEach-Object {
|
|
$Files += $_ -replace $replace,"Package"
|
|
}
|
|
$clip = $clip -join "`n" -split "@@"
|
|
for ($i=0;$i -lt $Files.length;$i++) {
|
|
$File = $Files[$i]
|
|
$inputObj = $clip[$i*2] -split "`n"
|
|
$inputObj = $inputObj[1..(($inputObj | Select-String "ManifestVersion" -SimpleMatch).LineNumber -1)] | Where-Object {$_ -notmatch "marked this conversation as resolved."}
|
|
$FilePath = "$manifestFolder\$File"
|
|
if (!($Silent)) {
|
|
Write-Host "Writing $($inputObj.length) lines to $FilePath"
|
|
}
|
|
Out-File -FilePath $FilePath -InputObject $inputObj
|
|
#Bugfix to catch package identifier appended to last line of last file.
|
|
$fileContents = (Get-Content $FilePath)
|
|
if ($fileContents[-1] -match $PackageIdentifier) {
|
|
$fileContents[-1]=($fileContents[-1] -split $PackageIdentifier)[0]
|
|
}
|
|
$fileContents -replace "0New version: ","0" -replace "0New package: ","0" -replace "0Add version: ","0" -replace "0Add package: ","0" -replace "0Add ","0" -replace "0New ","0" -replace "0package: ","0" | Out-File $FilePath
|
|
}
|
|
$filecount = (Get-ChildItem $manifestFolder).count
|
|
$filedir = "ok"
|
|
$filecolor = "green"
|
|
if ($filecount -lt 3) { $filedir = "too low"; $filecolor = "red"}
|
|
if ($filecount -gt 3) { $filedir = "high"; $filecolor = "yellow"}
|
|
if ($filecount -gt 10) { $filedir = "too high"; $filecolor = "red"}
|
|
if (!($Silent)) {
|
|
Write-Host -f $filecolor "File count $filecount is $filedir"
|
|
}
|
|
if ($filecount -lt 3) { break}
|
|
$fileContents = Get-Content "$runPath\$vm\manifest\Package.yaml"
|
|
if ($fileContents[-1] -ne "0") {
|
|
$fileContents[-1] = ($fileContents[-1] -split ".0")[0]+".0"
|
|
$fileContents | Out-File $filePath
|
|
$fileContents = Get-Content "$runPath\$vm\manifest\Package.yaml"
|
|
$fileContents -replace "1..0","1.10.0"
|
|
$fileContents | Out-File $filePath
|
|
}#end if fileContents
|
|
}#end if Operation
|
|
}#end if NoFiles
|
|
|
|
if ($InspectNew) {
|
|
$PackageResult = Find-WinGetPackage $PackageIdentifier
|
|
if (!($Silent)) {
|
|
Write-Host "Searching Winget for $PackageIdentifier"
|
|
}
|
|
Write-Host $PackageResult
|
|
if ($PackageResult -eq "No package found matching input criteria.") {
|
|
Open-AllURL
|
|
Start-Process "https://www.bing.com/search?q=$PackageIdentifier"
|
|
$a,$b = $PackageIdentifier -split "[.]"
|
|
if ($a -ne "") {
|
|
if (!($Silent)) {
|
|
Write-Host "Searching Winget for $a"
|
|
}
|
|
Find-WinGetPackage $a
|
|
}
|
|
if ($b -ne "") {
|
|
if (!($Silent)) {
|
|
Write-Host "Searching Winget for $b"
|
|
}
|
|
Find-WinGetPackage $b
|
|
}
|
|
}
|
|
}
|
|
if (!($Silent)) {
|
|
Write-Host "File operations complete, starting VM operations."
|
|
}
|
|
Get-TrackerVMRevert $VM -Silent
|
|
Get-TrackerVMLaunchWindow $VM
|
|
}
|
|
}
|
|
|
|
Function Get-TrackerVMValidateByID {
|
|
param(
|
|
$PackageIdentifier = (Get-Clipboard)
|
|
)
|
|
Get-TrackerVMValidate -installerLine "--id $PackageIdentifier" -PackageIdentifier $PackageIdentifier -NoFiles #-notElevated
|
|
}
|
|
|
|
Function Get-TrackerVMValidateByConfig {
|
|
param(
|
|
$PackageIdentifier = "Microsoft.Devhome",
|
|
$ManualDependency = "Git.Git"
|
|
)
|
|
|
|
Get-TrackerVMValidate -installerLine "--id $PackageIdentifier" -PackageIdentifier $PackageIdentifier -NoFiles -ManualDependency $ManualDependency -Operation "DevHomeConfig"
|
|
Start-Sleep 2
|
|
Get-TrackerVMValidate -installerLine "--id $ManualDependency" -PackageIdentifier $ManualDependency -NoFiles -Operation "Config"
|
|
}
|
|
|
|
Function Get-TrackerVMValidateByArch {
|
|
param(
|
|
)
|
|
Get-TrackerVMValidate -Arch x64;
|
|
Start-Sleep 2;
|
|
Get-TrackerVMValidate -Arch x86;
|
|
}
|
|
|
|
Function Get-TrackerVMValidateByScope {
|
|
param(
|
|
)
|
|
Get-TrackerVMValidate -Scope Machine;
|
|
Start-Sleep 2;
|
|
Get-TrackerVMValidate -Scope User;
|
|
}
|
|
|
|
Function Get-TrackerVMValidateBothArchAndScope {
|
|
param(
|
|
)
|
|
Get-TrackerVMValidate -Arch x64 -Scope Machine;
|
|
Start-Sleep 2;
|
|
Get-TrackerVMValidate -Arch x86 -Scope Machine;
|
|
Start-Sleep 2;
|
|
Get-TrackerVMValidate -Arch x64 -Scope User;
|
|
Start-Sleep 2;
|
|
Get-TrackerVMValidate -Arch x86 -Scope User;
|
|
}
|
|
|
|
#Manifests Etc
|
|
Function Get-SingleFileAutomation {
|
|
param(
|
|
$PR,
|
|
$clip = (Get-Clipboard),
|
|
$PackageIdentifier = (Get-YamlValue PackageIdentifier -clip $clip),
|
|
$version = ((Get-YamlValue PackageVersion -clip $clip) -replace "'","" -replace '"',""),
|
|
$listing = (Get-ManifestListing $PackageIdentifier),
|
|
$VM = (Get-ManifestFile -clip $clip)[-1]
|
|
)
|
|
|
|
for ($File = 0; $File -lt $listing.length;$File++) {
|
|
Get-ManifestFile $VM -clip (Get-FileFromGitHub -PackageIdentifier $PackageIdentifier -Version $version -FileName $listing[$File]) -PR $PR
|
|
}
|
|
}
|
|
|
|
Function Get-InstallerFileAutomation {
|
|
Param(
|
|
$PR = (Get-Clipboard),
|
|
$InstallerFile = (Get-CommitFile -PR $PR -MatchName "")
|
|
)
|
|
Get-SingleFileAutomation -PR $pr -clip $InstallerFile
|
|
}
|
|
|
|
Function Get-ManifestAutomation {
|
|
param(
|
|
$VM = (Get-NextFreeVM),
|
|
$PR =0,
|
|
$Arch,
|
|
$OS,
|
|
$Scope
|
|
)
|
|
|
|
#Read-Host "Copy Installer file to clipboard, then press Enter to continue."
|
|
(Get-Clipboard) -join "" | clip;
|
|
$null = Get-ManifestFile $VM
|
|
|
|
Read-Host "Copy defaultLocale file to clipboard, then press Enter to continue."
|
|
(Get-Clipboard) -join "" | clip;
|
|
$null = Get-ManifestFile $VM
|
|
|
|
Read-Host "Copy version file to clipboard, then press Enter to continue."
|
|
(Get-Clipboard) -join "" | clip;
|
|
if ($Arch) {
|
|
$null = Get-ManifestFile $VM -Arch $Arch
|
|
} elseif ($OS) {
|
|
$null = Get-ManifestFile $VM -OS $OS
|
|
} elseif ($Scope) {
|
|
$null = Get-ManifestFile $VM -Scope $Scope
|
|
} else {
|
|
$null = Get-ManifestFile $VM -PR $PR
|
|
}
|
|
}
|
|
|
|
Function Get-ManifestOtherAutomation {
|
|
param(
|
|
$Clip = (Get-Clipboard),
|
|
$Title = ($Clip -split " version "),
|
|
$Version = ($Title[1] -split " #"),
|
|
$PR = ($Version[1]),
|
|
[switch]$Installer
|
|
)
|
|
$Title = $Title[0]
|
|
$Version = $Version[0]
|
|
if ($Installer) {
|
|
$File = (Get-FileFromGitHub $Title $Version)
|
|
}
|
|
}
|
|
|
|
Function Get-Generate {
|
|
$out = "
|
|
# Created by Validation Pipeline build $build
|
|
# If a human is reading this, then something has gone wrong.
|
|
|
|
PackageIdentifier: $PackageIdentifier
|
|
PackageVersion: $PackageVersion
|
|
DefaultLocale: $Locale
|
|
ManifestType: version
|
|
ManifestVersion: $ManifestVersion"
|
|
|
|
}
|
|
|
|
Function Get-ManifestFile {
|
|
param(
|
|
[int]$vm = ((Get-NextFreeVM) -replace "vm",""),
|
|
$clip = (Get-SecondMatch),
|
|
$FileName = "Package",
|
|
$PackageIdentifier = ((Get-YamlValue -StringName "PackageIdentifier" -clip $clip) -replace '"','' -replace "'",'' -replace ",",''),
|
|
$PR = 0,
|
|
$Arch,
|
|
$OS,
|
|
$Scope
|
|
);
|
|
#Write-Output "PackageIdentifier: $PackageIdentifier"
|
|
$manifestFolder = "$MainFolder\vm\$vm\manifest"
|
|
$clip = $clip | Where-Object {$_ -notmatch "marked this conversation as resolved."}
|
|
|
|
$YamlValue = (Get-YamlValue ManifestType $clip)
|
|
switch ($YamlValue) {
|
|
"defaultLocale" {
|
|
$Locale = (Get-YamlValue PackageLocale $clip)
|
|
$FileName = "$FileName.locale.$Locale"
|
|
}
|
|
"Locale" {
|
|
$Locale = (Get-YamlValue PackageLocale $clip)
|
|
$FileName = "$FileName.locale.$Locale"
|
|
}
|
|
"installer" {
|
|
Get-RemoveFileIfExist "$manifestFolder" -remake
|
|
$FileName = "$FileName.installer"
|
|
}
|
|
"version" {
|
|
if ($Arch) {
|
|
Get-TrackerVMValidate -vm $VM -NoFiles -Arch $Arch -PR $PR -PackageIdentifier $PackageIdentifier
|
|
} elseif ($OS) {
|
|
Get-TrackerVMValidate -vm $VM -NoFiles -OS $OS -PR $PR -PackageIdentifier $PackageIdentifier
|
|
} elseif ($Scope) {
|
|
Get-TrackerVMValidate -vm $VM -NoFiles -Scope $Scope -PR $PR -PackageIdentifier $PackageIdentifier
|
|
} else {
|
|
Get-TrackerVMValidate -vm $VM -NoFiles -PR $PR -PackageIdentifier $PackageIdentifier
|
|
}
|
|
}
|
|
Default {
|
|
Write-Output "Error: Bad ManifestType"
|
|
Write-Output $clip
|
|
}
|
|
}
|
|
$FilePath = "$manifestFolder\$FileName.yaml"
|
|
Write-Output "Writing $($clip.length) lines to $FilePath"
|
|
$clip -replace "0New version: ","0" -replace "0Add version: ","0" -replace "0Add ","0" -replace "0New ","0" | Out-File $FilePath -Encoding unicode
|
|
return $VM
|
|
}
|
|
|
|
Function Get-ManifestListing {
|
|
param(
|
|
$PackageIdentifier,
|
|
$Version = (Find-WinGetPackage $PackageIdentifier -MatchOption Equals).version,
|
|
$Path = ($PackageIdentifier -replace "[.]","/"),
|
|
$FirstLetter = ($PackageIdentifier[0].tostring().tolower()),
|
|
$Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/$Version/",
|
|
[Switch]$Versions
|
|
)
|
|
If ($Versions) {
|
|
$Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/"
|
|
}
|
|
try{
|
|
$out = (Invoke-GitHubRequest -Uri $Uri -JSON).name
|
|
}catch{
|
|
$out = "Error"
|
|
}
|
|
return $out -replace "$($PackageIdentifier)[.]",""
|
|
}
|
|
|
|
Function Get-ListingDiff {
|
|
param(
|
|
$Clip = (Get-Clipboard),
|
|
$PackageIdentifier = (Get-YamlValue PackageIdentifier $Clip -replace '"',""),
|
|
$PRManifest = ($clip -split "`n" | Where-Object {$_ -match ".yaml"} | Where-Object {$_ -match $PackageIdentifier} |%{($_ -split "/")[-1] -replace "$($PackageIdentifier)[.]",""}),
|
|
$Returnables = ""
|
|
)
|
|
if ($PRManifest.count -gt 2){
|
|
$CurrentManifest = (Get-ManifestListing $PackageIdentifier)
|
|
if ($CurrentManifest -eq "Error") {
|
|
$Returnables = diff $CurrentManifest $PRManifest
|
|
} else {
|
|
$Returnables = $CurrentManifest
|
|
}
|
|
}
|
|
Return $Returnables
|
|
}
|
|
|
|
Function Get-OSFromVersion ($clip) {
|
|
try{
|
|
if ([system.version](Get-YamlValue -StringName MinimumOSVersion -clip $clip) -ge [system.version]"10.0.22000.0"){"Win11"} else{"Win10"}
|
|
} catch {
|
|
"Win10"
|
|
}
|
|
}
|
|
|
|
#VM Image Management
|
|
Function Get-PipelineVmGenerate {
|
|
param(
|
|
[int]$vm = (Get-Content $vmCounter),
|
|
[ValidateSet("Win10","Win11")][string]$OS = "Win10",
|
|
[int]$version = (Get-TrackerVMVersion -OS $OS),
|
|
$destinationPath = "$imagesFolder\$vm\",
|
|
$VMFolder = "$MainFolder\vm\$vm",
|
|
$newVmName = "vm$VM",
|
|
$startTime = (Get-Date)
|
|
)
|
|
Test-Admin
|
|
Write-Host "Creating VM $newVmName version $version OS $OS"
|
|
[int]$vm+1|Out-File $vmCounter
|
|
"`"$vm`",`"Generating`",`"$version`",`"$OS`",`"`",`"1`",`"Creation`",`"0`""|Out-File $StatusFile -Append -Encoding unicode
|
|
Get-RemoveFileIfExist $destinationPath -remake
|
|
Get-RemoveFileIfExist $VMFolder -remake
|
|
$vmImageFolder = (ls "$imagesFolder\$OS-image\Virtual Machines\" *.vmcx).fullname
|
|
|
|
Write-Host "Takes about 120 seconds..."
|
|
Import-VM -Path $vmImageFolder -Copy -GenerateNewId -VhdDestinationPath $destinationPath -VirtualMachinePath $destinationPath;
|
|
Rename-VM (Get-VM | Where-Object {($_.CheckpointFileLocation)+"\" -eq $destinationPath}) -NewName $newVmName
|
|
Start-VM $newVmName
|
|
Remove-VMCheckpoint -VMName $newVmName -Name "Backup"
|
|
Get-TrackerVMRevert $VM
|
|
Get-TrackerVMLaunchWindow $VM
|
|
Write-Host "Took $(((Get-Date)-$startTime).TotalSeconds) seconds..."
|
|
}
|
|
|
|
Function Get-PipelineVmDisgenerate {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$destinationPath = "$imagesFolder\$vm\",
|
|
$VMFolder = "$MainFolder\vm\$vm",
|
|
$vmName = "vm$VM"
|
|
)
|
|
Test-Admin
|
|
Get-TrackerVMSetStatus 'Disgenerate' $VM
|
|
Get-ConnectedVM | Where-Object {$_.vm -match $VMName} | ForEach-Object {Stop-Process -id $_.id}
|
|
Stop-TrackerVM $VM
|
|
Remove-VM -Name $vmName -Force
|
|
|
|
$out = Get-Status
|
|
$out = $out | Where-Object {$_.vm -notmatch $VM}
|
|
Write-Status $out
|
|
|
|
$delay = 15
|
|
0..$delay | ForEach-Object {
|
|
$pct = $_ / $delay * 100
|
|
Write-Progress -Activity "Remove VM" -Status "$_ of $delay" -PercentComplete $pct
|
|
Start-Sleep $GitHubRateLimitDelay
|
|
}
|
|
Get-RemoveFileIfExist $destinationPath
|
|
Get-RemoveFileIfExist $VMFolder
|
|
Write-Progress -Activity "Remove VM" -Completed
|
|
}
|
|
|
|
Function Get-ImageVMStart {
|
|
param(
|
|
[ValidateSet("Win10","Win11")][string]$OS = "Win10"
|
|
)
|
|
Test-Admin
|
|
$VM = 0
|
|
Start-VM $OS;
|
|
Get-TrackerVMRevert $VM $OS;
|
|
Get-TrackerVMLaunchWindow $VM $OS
|
|
}
|
|
|
|
Function Get-ImageVMStop {
|
|
param(
|
|
[ValidateSet("Win10","Win11")][string]$OS = "Win10"
|
|
)
|
|
Test-Admin
|
|
$VM = 0
|
|
$OriginalLoc = ""
|
|
switch ($OS) {
|
|
"Win10" {
|
|
$OriginalLoc = $Win10Folder
|
|
}
|
|
"Win11" {
|
|
$OriginalLoc = $Win11Folder
|
|
}
|
|
}
|
|
$ImageLoc = "$imagesFolder\$OS-image\"
|
|
[int]$version = [int](Get-TrackerVMVersion -OS $OS) + 1
|
|
Write-Host "Writing $OS version $version"
|
|
Get-TrackerVMSetVersion -Version $Version -OS $OS
|
|
Stop-Process -id ((Get-ConnectedVM)|Where-Object {$_.VM -match "$OS"}).id -ErrorAction Ignore
|
|
Redo-Checkpoint $VM $OS;
|
|
Stop-TrackerVM $VM $OS;
|
|
Write-Host "Letting VM cool..."
|
|
Start-Sleep 30;
|
|
Robocopy.exe $OriginalLoc $ImageLoc -mir
|
|
}
|
|
|
|
Function Get-ImageVMMove {
|
|
param(
|
|
[ValidateSet("Win10","Win11")][string]$OS = "Win10",
|
|
$CurrentVMName = "",
|
|
$newLoc = "$imagesFolder\$OS-Created$(get-date -f MMddyy)-Original"
|
|
)
|
|
Test-Admin
|
|
switch ($OS) {
|
|
"Win10" {
|
|
$CurrentVMName = "Windows 10 MSIX packaging environment"
|
|
}
|
|
"Win11" {
|
|
$CurrentVMName = "Windows 11 dev environment"
|
|
}
|
|
}
|
|
$VM = Get-VM | where {$_.Name -match $CurrentVMName}
|
|
Move-VMStorage -VM $VM -DestinationStoragePath $newLoc
|
|
Rename-VM -VM $VM -NewName $OS
|
|
}
|
|
|
|
#VM Pipeline Management
|
|
Function Get-TrackerVMLaunchWindow {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$VMName = "vm$VM"
|
|
)
|
|
Test-Admin
|
|
Get-ConnectedVM | Where-Object {$_.vm -match $VMName} | ForEach-Object {Stop-Process -id $_.id}
|
|
C:\Windows\System32\vmconnect.exe localhost $VMName
|
|
}
|
|
|
|
Function Get-TrackerVMRevert {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$VMName = "vm$VM",
|
|
[Switch]$Silent
|
|
)
|
|
Test-Admin
|
|
if ($Silent) {
|
|
Get-TrackerVMSetStatus "Restoring" $VM -Silent
|
|
} else {
|
|
Get-TrackerVMSetStatus "Restoring" $VM
|
|
}
|
|
Restore-VMCheckpoint -Name $CheckpointName -VMName $VMName -Confirm:$False
|
|
}
|
|
|
|
Function Complete-TrackerVM {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$VMFolder = "$MainFolder\vm\$vm",
|
|
$filesFileName = "$VMFolder\files.txt"
|
|
)
|
|
Test-Admin
|
|
Get-TrackerVMSetStatus "Completing" $VM
|
|
Stop-Process -id ((Get-ConnectedVM)|Where-Object {$_.VM -match "vm$VM"}).id -ErrorAction Ignore
|
|
Stop-TrackerVM $VM
|
|
Get-RemoveFileIfExist $filesFileName
|
|
Get-TrackerVMSetStatus "Ready" $VM " " 1 "Ready"
|
|
}
|
|
|
|
Function Stop-TrackerVM {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$VMName = "vm$VM"
|
|
)
|
|
Test-Admin
|
|
Stop-VM $VMName -TurnOff
|
|
}
|
|
|
|
#VM Status
|
|
Function Get-TrackerVMSetStatus {
|
|
param(
|
|
[ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","Setup","SetupComplete","Starting","Updating","ValidationCompleted")]
|
|
$Status = "Complete",
|
|
[Parameter(mandatory=$True)]$VM,
|
|
[string]$Package,
|
|
[int]$PR,
|
|
[ValidateSet("New","Creating","Existing","Ready","Unknown")]
|
|
[string]$Mode,
|
|
[Switch]$Silent
|
|
)
|
|
$out = Get-Status
|
|
if ($Status) {
|
|
($out | Where-Object {$_.vm -match $VM}).Status = $Status
|
|
}
|
|
if ($Package) {
|
|
($out | Where-Object {$_.vm -match $VM}).Package = $Package
|
|
}
|
|
if ($PR) {
|
|
($out | Where-Object {$_.vm -match $VM}).PR = $PR
|
|
}
|
|
if ($Mode) {
|
|
($out | Where-Object {$_.vm -match $VM}).Mode = $Mode
|
|
}
|
|
if ($Silent) {
|
|
Write-Status $out -Silent
|
|
} else {
|
|
Write-Status $out
|
|
Write-Host "Setting $VM $Package $PR state $Status"
|
|
}
|
|
}
|
|
|
|
Function Write-Status {
|
|
Param(
|
|
$out,
|
|
[Switch]$Silent
|
|
)
|
|
if (!($Silent)) {
|
|
Write-Host "Writing $($out.length) lines to $StatusFile."
|
|
}
|
|
$out | ConvertTo-Csv | Out-File $StatusFile -Encoding unicode
|
|
}
|
|
|
|
Function Get-Status {
|
|
param(
|
|
[int]$vm,
|
|
[ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","Setup","SetupComplete","Starting","Updating","ValidationCompleted")]
|
|
$Status,
|
|
[ValidateSet("Win10","Win11")][string]$OS,
|
|
$out = (Get-Content $StatusFile | ConvertFrom-Csv)
|
|
)
|
|
$out
|
|
}
|
|
|
|
Function Get-TrackerVMResetStatus {
|
|
$VMs = (Get-Status | Where-Object {$_.Status -ne "Ready"} | Where-Object {$_.RAM -eq 0}).VM
|
|
$VMs += (Get-Status | Where-Object {$_.Status -ne "Ready"} | Where-Object {$_.Package -eq ""}).VM
|
|
Foreach ($VM in $VMs) {
|
|
Get-TrackerVMSetStatus Complete $VM
|
|
}
|
|
if (!(Get-ConnectedVM)){
|
|
Get-Process *vmwp* | Stop-Process
|
|
}
|
|
}
|
|
|
|
Function Get-TrackerVMRebuildStatus {
|
|
$Status = Get-VM |
|
|
Where-Object {$_.name -notmatch "vm0"} |
|
|
Where-Object {$_.name -notmatch "Win10"} |
|
|
Where-Object {$_.name -notmatch "Win11"} |
|
|
Select-Object @{n="vm";e={$_.name -replace "vm",$null}},
|
|
@{n="status";e={"Ready"}},
|
|
@{n="version";e={(Get-TrackerVMVersion -OS "Win10")}},
|
|
@{n="OS";e={"Win10"}},
|
|
@{n="Package";e={""}},
|
|
@{n="PR";e={"1"}},
|
|
@{n="Mode";e={"Unknown"}},
|
|
@{n="RAM";e={"0"}}
|
|
Write-Status $Status
|
|
}
|
|
|
|
#VM Versioning
|
|
Function Get-TrackerVMVersion {
|
|
param(
|
|
[ValidateSet("Win10","Win11")][string]$OS = "Win10",
|
|
[int]$VM = ((Get-Content $VMversion | ConvertFrom-Csv | Where-Object {$_.OS -eq $OS}).version)
|
|
)
|
|
Return $VM
|
|
}
|
|
|
|
Function Get-TrackerVMSetVersion {
|
|
param(
|
|
[int]$Version,
|
|
[ValidateSet("Win10","Win11")][string]$OS = "Win10",
|
|
$Versions = (Get-Content $VMversion | ConvertFrom-Csv)
|
|
)
|
|
($Versions | Where-Object {$_.OS -eq $OS}).Version = $Version
|
|
$Versions | ConvertTo-Csv|Out-File $VMversion
|
|
}
|
|
|
|
Function Get-TrackerVMRotate {
|
|
param(
|
|
$status = (Get-Status),
|
|
$OS = "Win10",
|
|
$VMs = ($status | Where-Object {$_.version -lt (Get-TrackerVMVersion -OS $OS)} | Where-Object {$_.OS -eq $OS})
|
|
)
|
|
if ($VMs){
|
|
if (!(($status | Where-Object {$_.status -ne "Ready"}).count)) {
|
|
Get-TrackerVMSetStatus Regenerate ($VMs.VM | Get-Random)
|
|
}
|
|
}
|
|
}
|
|
|
|
#VM Orchestration
|
|
Function Get-TrackerVMCycle {
|
|
param(
|
|
$VMs = (Get-Status)
|
|
)
|
|
Foreach ($VM in $VMs) {
|
|
Switch ($VM.status) {
|
|
"AddVCRedist" {
|
|
Add-ToValidationFile $VM.vm
|
|
}
|
|
"Approved" {
|
|
#Add-Waiver $VM.PR
|
|
$PRLabels = ((Invoke-GitHubPRRequest -PR $VM.PR -Type "labels" -Output content -JSON).name) -join " "
|
|
if ($PRLabels -match $Labels.VC) {
|
|
Approve-PR -PR $VM.PR
|
|
} else {
|
|
Get-CompletePR -PR $VM.PR
|
|
}
|
|
Get-TrackerVMSetStatus "Complete" $VM.vm
|
|
}
|
|
"CheckpointReady" {
|
|
Redo-Checkpoint $VM.vm
|
|
}
|
|
"Complete" {
|
|
if (($VMs | Where-Object {$_.vm -eq $VM.vm} ).version -lt (Get-TrackerVMVersion -OS $VM.os)) {
|
|
Get-TrackerVMSetStatus "Regenerate" $VM.vm
|
|
} else {
|
|
Complete-TrackerVM $VM.vm
|
|
}
|
|
}
|
|
"Disgenerate" {
|
|
Get-PipelineVmDisgenerate $VM.vm
|
|
}
|
|
"Revert" {
|
|
Get-TrackerVMRevert $VM.vm
|
|
}
|
|
"Regenerate" {
|
|
Get-PipelineVmDisgenerate $VM.vm
|
|
Get-PipelineVmGenerate -OS $VM.os
|
|
}
|
|
"SendStatus-Complete" {
|
|
Get-SendStatus -Status "Complete"
|
|
}
|
|
"SendStatus-Approved" {
|
|
Get-SendStatus -Status "Approved"
|
|
}
|
|
"SendStatus" {
|
|
Get-SendStatus -Status "Complete"
|
|
}
|
|
"ValidationCompleted" {
|
|
# if ($VM.Mode -eq "Existing") {
|
|
# Get-CompletePR -PR $VM.PR
|
|
# Get-TrackerVMSetStatus "Complete" $VM.vm
|
|
# }
|
|
}
|
|
default {
|
|
#Write-Host "Complete"
|
|
}
|
|
}; #end switch
|
|
}
|
|
}
|
|
|
|
Function Get-TrackerMode {
|
|
param(
|
|
$mode = (Get-Content $TrackerModeFile)
|
|
)
|
|
$mode
|
|
}
|
|
|
|
Function Get-TrackerVMSetMode {
|
|
param(
|
|
[ValidateSet("Approving","Idle","IEDS","Validating")]
|
|
$Status = "Validating"
|
|
)
|
|
$Status | Out-File $TrackerModeFile -NoNewLine
|
|
}
|
|
|
|
Function Get-ConnectedVM {
|
|
Test-Admin
|
|
(Get-Process *vmconnect*) | Select-Object id, @{n="VM";e={ForEach-Object{$_.mainwindowtitle[0..5] -join ""}}}
|
|
}
|
|
|
|
Function Get-NextFreeVM {
|
|
param(
|
|
[ValidateSet("Win10","Win11")][string] $OS = "Win10",
|
|
$Status = "Ready"
|
|
)
|
|
Test-Admin
|
|
try {
|
|
$out_status = Get-Status
|
|
$out_status = $out_status | Where-Object {$_.OS -eq $OS}
|
|
$out_status = ($out_status | Where-Object {$_.version -eq (Get-TrackerVMVersion -OS $OS)} | Where-Object {$_.status -eq $Status}).vm
|
|
$out_status = $out_status |Get-Random -ErrorAction SilentlyContinue
|
|
return $out_status;
|
|
} catch {
|
|
Write-Host "No available $OS VMs"
|
|
return 0
|
|
}
|
|
}
|
|
|
|
Function Redo-Checkpoint {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$VMName = "vm$VM"
|
|
)
|
|
Test-Admin
|
|
Get-TrackerVMSetStatus "Checkpointing" $VM
|
|
Remove-VMCheckpoint -Name $CheckpointName -VMName $VMName
|
|
Checkpoint-VM -SnapshotName $CheckpointName -VMName $VMName
|
|
Get-TrackerVMSetStatus "Complete" $VM
|
|
}
|
|
|
|
#File Management
|
|
Function Get-SecondMatch {
|
|
param(
|
|
$clip = (Get-Clipboard),
|
|
$depth = 1
|
|
)
|
|
#If $current and $prev don't match, return the $prev element, which is $depth lines below the $current line. Start at $clip[$depth] and go until the end - this starts $current at $clip[$depth], and $prev gets moved backwards to $clip[0] and moves through until $current is at the end of the array, $clip[$clip.length], and $prev is $depth previous, at $clip[$clip.length - $depth].
|
|
for ($depthUnit = $depth;$depthUnit -lt $clip.length; $depthUnit++){
|
|
$current = ($clip[$depthUnit] -split ": ")[0]
|
|
$prevUnit = $clip[$depthUnit - $depth]
|
|
$Prev = ($prevUnit -split ": ")[0]
|
|
if ($current -ne $Prev) {
|
|
$prevUnit
|
|
}
|
|
}
|
|
#Then complete the last $depth items of the array by starting at $clip[-$depth] and work backwards through the last items in reverse order to $clip[-1].
|
|
for ($depthUnit = $depth ;$depthUnit -gt 0; $depthUnit--){
|
|
$clip[-$depthUnit]
|
|
}
|
|
}
|
|
|
|
Function Get-SendStatus {
|
|
Param(
|
|
$PR,
|
|
[ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","Setup","SetupComplete","Starting","Updating","ValidationCompleted")]
|
|
$Status = "Complete",
|
|
$SharedError = ((Get-Content $SharedErrorFile) -split "`n")
|
|
)
|
|
$SharedError = $SharedError -replace "`r",""
|
|
$SharedError = $SharedError -replace " (caller: 00007FFA008A5769)",""
|
|
$SharedError = $SharedError -replace " (caller: 00007FFA008AA79F)",""
|
|
$SharedError = $SharedError -replace "Exception(1)",""
|
|
$SharedError = $SharedError -replace "Exception(2)",""
|
|
$SharedError = $SharedError -replace "Exception(4)",""
|
|
$SharedError = $SharedError -replace "tid(f1c)",""
|
|
$SharedError = $SharedError -replace "C:\\__w\\1\\s\\external\\pkg\\src\\AppInstallerCommonCore\\Downloader.cpp(185)\\WindowsPackageManager.dll!00007FFA008A37C9:",""
|
|
$SharedError = $SharedError -join "`n"
|
|
#$SharedError = Get-AutomatedErrorAnalysis $SharedError
|
|
if ((($SharedError -join " ") -match "Installer failed security check") -OR (($SharedError -join " ") -match "Detected 1 Defender")) {
|
|
Get-AddPRLabel -PR $PR -LabelName $Labels.VDE
|
|
}
|
|
Reply-ToPR -PR $VM.PR -UserInput $SharedError -CannedMessage ManValEnd
|
|
Get-TrackerVMSetStatus $Status $VM.vm
|
|
}
|
|
|
|
Function Get-TrackerVMRotateLog {
|
|
$logYesterDate = (Get-Date -f dd) - 1
|
|
Move-Item "$writeFolder\logs\$logYesterDate" "$logsFolder\$logYesterDate"
|
|
}
|
|
|
|
Function Get-RemoveFileIfExist {
|
|
param(
|
|
$FilePath,
|
|
[switch]$remake,
|
|
[switch]$Silent
|
|
)
|
|
if (Test-Path $FilePath) {Remove-Item $FilePath -Recurse}
|
|
if ($Silent) {
|
|
if ($remake) {$null = New-Item -ItemType Directory -Path $FilePath}
|
|
} else {
|
|
if ($remake) {New-Item -ItemType Directory -Path $FilePath}
|
|
}
|
|
|
|
}
|
|
|
|
Function Get-LoadFileIfExists {
|
|
param(
|
|
$FileName,
|
|
$FileContents,
|
|
[Switch]$Silent
|
|
)
|
|
if (Test-Path $FileName) {
|
|
$FileContents = Get-Content $FileName | ConvertFrom-Csv
|
|
if (!($Silent)) {
|
|
Write-Host "Loaded $($FileContents.count) entries from $FileName." -f green
|
|
Return $FileContents
|
|
}
|
|
} else {
|
|
if (!($Silent)) {
|
|
Write-Host "File $FileName not found!" -f red
|
|
}
|
|
}
|
|
}
|
|
|
|
Function Get-FileFromGitHub {
|
|
param(
|
|
$PackageIdentifier,
|
|
$Version,
|
|
$FileName = "installer.yaml",
|
|
$Path = ($PackageIdentifier -replace "[.]","/"),
|
|
$FirstLetter = ($PackageIdentifier[0].tostring().tolower())
|
|
)
|
|
try{
|
|
$content = (Invoke-GitHubRequest -Uri "$GitHubContentBaseUrl/master/manifests/$FirstLetter/$Path/$Version/$PackageIdentifier.$FileName").content
|
|
}catch{
|
|
$content = "Error"
|
|
}
|
|
return ($content -split "`n")
|
|
}
|
|
|
|
Function Get-ManifestEntryCheck {
|
|
param(
|
|
$PackageIdentifier,
|
|
$Version,
|
|
$Entry = "DisplayVersion"
|
|
)
|
|
$content = Get-FileFromGitHub $PackageIdentifier $Version
|
|
$out = ($content | Where-Object {$_ -match $Entry})
|
|
if ($out) {$True} else {$False}
|
|
}
|
|
|
|
Function Get-DecodeGitHubFile {
|
|
param(
|
|
[string]$Base64String,
|
|
$Bits = ([Convert]::FromBase64String($Base64String)),
|
|
$String = ([System.Text.Encoding]::UTF8.GetString($Bits))
|
|
)
|
|
return $String -split "`n"
|
|
}
|
|
|
|
Function Get-CommitFile {
|
|
param(
|
|
$PR = (Get-Clipboard),
|
|
$Commit = (Invoke-GitHubPRRequest -PR $PR -Type commits -Output content -JSON),
|
|
$MatchName = "installer",
|
|
$PRData = (Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$pr" -JSON),
|
|
$PRTitle = (($PRData.title -split " ") | where {$_ -match "[A-Za-z0-9]\.[A-Za-z0-9]"} | where {$_ -notmatch "[0-9].[0-9]"}),
|
|
#$PRTitle = (($PRData.title -split " ")[2] | where {$_ -match "\."}),
|
|
$FileList = ($Commit.files.contents_url | where {$_ -match $MatchName} | where {$_ -match $PRTitle}),
|
|
[int]$VM = 0
|
|
)
|
|
$FileList | %{
|
|
"File: $_"
|
|
try {
|
|
$EncodedFile = (invoke-GithubRequest -Uri $_ -JSON)
|
|
} catch {
|
|
write-host $error[0].Message
|
|
}
|
|
$DecodedFile = Get-DecodeGitHubFile $EncodedFile.content
|
|
if ($VM -gt 0) {
|
|
Get-ManifestFile -vm $VM -PR $PR -clip $DecodedFile
|
|
} else {
|
|
$DecodedFile -join "`n"
|
|
}
|
|
}
|
|
}
|
|
|
|
#Inject dependencies
|
|
Function Add-ToValidationFile {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
[ValidateSet("Microsoft.VCRedist.2015+.x64","Microsoft.DotNet.DesktopRuntime.8","Oracle.JavaRuntimeEnvironment")]$Common = "Microsoft.VCRedist.2015+.x64",
|
|
$Dependency = $Common,
|
|
$VMFolder = "$MainFolder\vm\$vm",
|
|
$manifestFolder = "$VMFolder\manifest",
|
|
$FilePath = "$manifestFolder\Package.installer.yaml",
|
|
$fileContents = (Get-Content $FilePath),
|
|
$Selector = "Installers:",
|
|
$offset = 1,
|
|
$lineNo = (($fileContents | Select-String $Selector -List).LineNumber -$offset),
|
|
$fileInsert = "Dependencies:`n PackageDependencies:`n - PackageIdentifier: $Dependency",
|
|
$fileOutput = ($fileContents[0..($lineNo -1)]+$fileInsert+$fileContents[$lineNo..($fileContents.length)])
|
|
)
|
|
Write-Host "Writing $($fileContents.length) lines to $FilePath"
|
|
Out-File -FilePath $FilePath -InputObject $fileOutput
|
|
Get-TrackerVMSetStatus "Revert" $VM;
|
|
}
|
|
|
|
Function Add-InstallerSwitch {
|
|
param(
|
|
[Parameter(mandatory=$True)][int]$vm,
|
|
$Data = '/qn',
|
|
$Selector = "ManifestType:",
|
|
[ValidateSet("EXE","MSI","MSIX","Inno","Nullsoft","InstallShield")]
|
|
[string]$InstallerType
|
|
|
|
)
|
|
switch ($InstallerType) {
|
|
"MSIX"{
|
|
$Data = '/quiet'
|
|
}
|
|
"Inno"{
|
|
$Data = '/SILENT'
|
|
}
|
|
"Nullsoft"{
|
|
$Data = '/S'
|
|
}
|
|
"InstallShield"{
|
|
$Data = '/s' #or -s
|
|
}
|
|
}
|
|
$fileInsert = " InstallerSwitches:`n Silent: $Data"
|
|
Add-ToValidationFile $VM -Selector $Selector -fileInsert $fileInsert #-Force
|
|
}
|
|
|
|
Function Get-UpdateHashInPR {
|
|
param(
|
|
$PR,
|
|
$ManifestHash,
|
|
$PackageHash,
|
|
$LineNumbers = ((Get-CommitFile -PR $PR | Select-String $ManifestHash).LineNumber),
|
|
$ReplaceString = (" InstallerSha256: $($PackageHash.toUpper())"),
|
|
$comment = "``````suggestion`n$ReplaceString`n```````n`n(Automated response - build $build.)"
|
|
)
|
|
foreach ($Line in $LineNumbers) {
|
|
Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Labels.NAF
|
|
}
|
|
}
|
|
|
|
Function Get-UpdateHashInPR2 {
|
|
param(
|
|
$PR,
|
|
$Clip = (Get-Clipboard),
|
|
$SearchTerm = "Expected hash",
|
|
$ManifestHash = (Get-YamlValue $SearchTerm -Clip $Clip),
|
|
$LineNumbers = ((Get-CommitFile -PR $PR | Select-String $ManifestHash).LineNumber),
|
|
$ReplaceTerm = "Actual hash",
|
|
$ReplaceString = (" InstallerSha256: "+(Get-YamlValue $ReplaceTerm -Clip $Clip).toUpper()),
|
|
$comment = "``````suggestion`n$ReplaceString`n```````n`n(Automated response - build $build.)"
|
|
)
|
|
foreach ($Line in $LineNumbers) {
|
|
Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Labels.NAF
|
|
}
|
|
}
|
|
|
|
Function Get-UpdateArchInPR {
|
|
param(
|
|
$PR,
|
|
$SearchTerm = " Architecture: x86",
|
|
$LineNumbers = ((Get-CommitFile -PR $PR | Select-String $SearchTerm).LineNumber),
|
|
[string]$ReplaceTerm = (($SearchTerm -split ": ")[1]),
|
|
[ValidateSet("x86","x64","arm","arm32","arm64","neutral")]
|
|
[string]$ReplaceArch = (("x86","x64") | where {$_ -notmatch $ReplaceTerm}),
|
|
$ReplaceString = ($SearchTerm -replace $ReplaceTerm,$ReplaceArch),
|
|
$comment = "``````suggestion`n$ReplaceString`n```````n`n(Automated response - build $build.)"
|
|
)
|
|
foreach ($Line in $LineNumbers) {
|
|
Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Labels.NAF
|
|
}
|
|
}
|
|
|
|
Function Add-DependencyToPR {
|
|
param(
|
|
$PR,
|
|
$Dependency = "Microsoft.VCRedist.2015+.x64",
|
|
$SearchString = "Installers:",
|
|
$LineNumbers = ((Get-CommitFile -PR $PR | Select-String $SearchString).LineNumber),
|
|
$ReplaceString = "Dependencies:`n PackageDependencies:`n - PackageIdentifier: $Dependency`nInstallers:",
|
|
$comment = "``````suggestion`n$ReplaceString`n```````n`n(Automated response - build $build.)"
|
|
)
|
|
$out = ""
|
|
foreach ($Line in $LineNumbers) {
|
|
$out += Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Labels.NAF
|
|
}
|
|
}
|
|
|
|
#PR Queue
|
|
Function Add-PRToQueue {
|
|
param(
|
|
$PR,
|
|
$PRExclude = ((gc $PRExcludeFile) -split "`n")
|
|
)
|
|
if ($PRExclude -notcontains $Pr) {
|
|
$PR | Out-File $PRQueueFile -Append
|
|
|
|
}
|
|
}
|
|
|
|
Function Get-PopPRQueue {
|
|
[array]$PRQueue = gc $PRQueueFile
|
|
$PRQueue = $PRQueue -split "`n"
|
|
$PRQueue = (diff $PRQueue (Get-Status).pr | where {$_.SideIndicator -eq "<="}).inputobject
|
|
$out = $PRQueue[0]
|
|
$PRQueue = $PRQueue[1..$PRQueue.length] | Select-Object -unique
|
|
$PRQueue | Out-File $PRQueueFile
|
|
return $out
|
|
}
|
|
|
|
Function Get-PRQueueCount {
|
|
$count = ((Get-Content $PRQueueFile) -split "`n").count
|
|
return $count
|
|
}
|
|
|
|
#Reporting
|
|
Function Add-PRToRecord {
|
|
param(
|
|
$PR,
|
|
[ValidateSet("Approved","Blocking","Feedback","Retry","Manual","Closed","Project","Squash","Waiver")]
|
|
$Action,
|
|
$Title
|
|
)
|
|
$Title = ($Title -split "#")[0]
|
|
"$PR,$Action,$Title" | Out-File $LogFile -Append
|
|
}
|
|
|
|
Function Get-PRPopulateRecord {
|
|
param(
|
|
$Logs = (Get-Content $LogFile | ConvertFrom-Csv -Header ("PR","Action","Title"))
|
|
)
|
|
Foreach ($Log in $Logs) {
|
|
#Populate the Title column where blank, so all lines with the same PR number also have the same title, preventing the API calls for the lookup.
|
|
$Log.title = ($Logs | Where-Object {$_.title} | Where-Object {$_.PR -match $Log.PR}).title | Sort-Object -Unique
|
|
}
|
|
$Logs | ConvertTo-Csv|Out-File $LogFile
|
|
}
|
|
|
|
Function Get-PRFromRecord {
|
|
param(
|
|
[ValidateSet("Approved","Blocking","Feedback","Retry","Manual","Closed","Project","Squash","Waiver")]
|
|
$Action
|
|
)
|
|
Get-PRPopulateRecord
|
|
(Get-Content $LogFile) | ConvertFrom-Csv -Header ("PR","Action","Title") | Where-Object {$_.Action -match $Action}
|
|
}
|
|
|
|
Function Get-PRReportFromRecord {
|
|
param(
|
|
[ValidateSet("Approved","Blocking","Feedback","Retry","Manual","Closed","Project","Squash","Waiver")]
|
|
$Action,
|
|
$out = "",
|
|
$line = 0,
|
|
$Record = ((Get-PRFromRecord $Action) | Sort-Object PR -Unique),
|
|
[switch]$NoClip
|
|
)
|
|
|
|
$LogContents = (Get-Content $LogFile | ConvertFrom-Csv | Where-Object {$_.Action -notmatch $Action} | ConvertTo-Csv)
|
|
Out-File -FilePath $LogFile -InputObject $LogContents
|
|
#Get everything that doesn't match the action and put it back in the CSV.
|
|
|
|
Foreach ($PR in $Record) {
|
|
$line++
|
|
$Title = $PR.Title
|
|
$PR = $PR.PR
|
|
if (!($Title)) {
|
|
$Title = (Invoke-GitHubPRRequest -PR $PR -Type "" -Output content -JSON).title
|
|
}
|
|
Get-TrackerProgress -PR $PR ("$($MyInvocation.MyCommand) $Action") $line $Record.length
|
|
$out += "$Title #$PR`n";
|
|
}
|
|
if ($NoClip) {
|
|
return $out
|
|
} else {
|
|
$out | clip
|
|
}
|
|
Write-Progress -Completed
|
|
}
|
|
|
|
Function Get-PRFullReport {
|
|
param(
|
|
$Month = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month),
|
|
$Today = (get-date -f MMddyy),
|
|
$ReportName = "$logsFolder\$Month\$Today-Report.txt",
|
|
$HeaderList = ($Actions.Feedback,"Blocking","Waiver","Retry","Manual","Closed","Project","Squash","Approved")
|
|
)
|
|
Write-Host "Generating report for $Today"
|
|
$null | Out-File $ReportName
|
|
$HeaderList | %{
|
|
$_ | Out-File $ReportName -Append;
|
|
Get-PRReportFromRecord $_ -NoClip | Out-File $ReportName -Append
|
|
}
|
|
Write-Host "Report for $Today complete"
|
|
}
|
|
|
|
#Clipboard
|
|
Function Get-PRNumber {
|
|
param(
|
|
$out = (Get-Clipboard),
|
|
[switch]$NoClip,
|
|
[switch]$Hash
|
|
)
|
|
if ($Hash) {
|
|
$out = ($out -split " " | Select-String $hashPRRegex) -replace '#','' | Sort-Object -unique
|
|
$NoClip = $True
|
|
} else {
|
|
$out = $out | Select-String $hashPRRegexEnd | Sort-Object -descending
|
|
}
|
|
|
|
if ($NoClip) {
|
|
$out
|
|
} else {
|
|
$out | clip
|
|
}
|
|
}
|
|
|
|
Function Get-SortedClipboard {
|
|
param(
|
|
$out = ((Get-Clipboard) -split "`n")
|
|
)
|
|
$out | Sort-Object -Unique | clip
|
|
}
|
|
|
|
Function Open-AllURL {
|
|
param(
|
|
$out = (Get-Clipboard)
|
|
)
|
|
$out = $out -split " "
|
|
$out = $out | Select-String "`^http"
|
|
$out = $out | Select-String -NotMatch "[.]exe$"
|
|
$out = $out | Select-String -NotMatch "[.]msi$"
|
|
$out = $out | Select-String -NotMatch "[.]zip$"
|
|
$out = $out | Sort-Object -unique
|
|
$out = $out | ForEach-Object {start-process $_}
|
|
}
|
|
|
|
Function Open-PRInBrowser {
|
|
param(
|
|
$PR,
|
|
[Switch]$Files
|
|
)
|
|
$URL = "$GitHubBaseUrl/pull/$PR#issue-comment-box"
|
|
if ($Files) {
|
|
$URL = "$GitHubBaseUrl/pull/$PR/files"
|
|
}
|
|
Start-Process $URL
|
|
Start-Sleep $GitHubRateLimitDelay
|
|
}#end Function
|
|
|
|
Function Get-YamlValue {
|
|
param(
|
|
[string]$StringName,
|
|
$clip = (Get-Clipboard)
|
|
)
|
|
$clip = ($clip -split "`n" | where {$_ -match $StringName})
|
|
$clip = ($clip -split ": ")[1]
|
|
$clip = ($clip -split "#")[0]
|
|
$clip = ((($clip.ToCharArray()) | where {$_ -match "\S"}) -join "")
|
|
Return $clip
|
|
}
|
|
|
|
#Etc
|
|
Function Test-Admin {
|
|
if ().groups -match "S-1-5-32-544")){Write-Host "Try elevating your session.";break}
|
|
}
|
|
|
|
Function Get-LazySearchWinGet {
|
|
#I am out of names and scraping the bottom of the barrel.
|
|
param(
|
|
[String]$SearchTerm,
|
|
[String]$Name,
|
|
[String]$ID,
|
|
$Version,
|
|
$Results = (Find-WinGetPackage $SearchTerm)
|
|
)
|
|
foreach ($Item in ("Name","ID","Version")) {
|
|
If ($Item) {
|
|
$itemContents = (Invoke-Command -ScriptBlock ([Scriptblock]::Create("$"+$item)))
|
|
$Results = $Results | where {$_.$Item -match $itemContents}
|
|
}
|
|
}
|
|
Return $Results
|
|
}
|
|
|
|
Function Get-TrackerProgress {
|
|
param(
|
|
$PR,
|
|
$Activity,
|
|
$Incrementor,
|
|
$Length,
|
|
$Percent = [math]::round($Incrementor / $length*100,2)
|
|
)
|
|
Write-Progress -Activity $Activity -Status "$PR - $Incrementor / $Length = $Percent %" -PercentComplete $Percent
|
|
}
|
|
|
|
Function Get-ArraySum {
|
|
param(
|
|
$in = 0,
|
|
$out = 0
|
|
)
|
|
$in |ForEach-Object{$out += $_*1}
|
|
[math]::Round($out,2)
|
|
}
|
|
|
|
Function Get-GitHubRateLimit {
|
|
param(
|
|
$Url = "https://api.github.com/rate_limit"
|
|
)
|
|
(Get-Date)
|
|
#Time, as a number, constantly increases.
|
|
$Response = Invoke-WebRequest -Uri $Url -ProgressAction SilentlyContinue
|
|
$Content = $Response.content | ConvertFrom-Json;
|
|
#Write-Output "Headers:"
|
|
#$Response.Headers
|
|
$Content.rate | select @{n="source";e={"Unlogged"}}, limit, used, remaining, @{n="reset";e={([System.DateTimeOffset]::FromUnixTimeSeconds($_.reset)).DateTime.AddHours(-8)}}
|
|
$Response = invoke-GitHubRequest -Uri $Url -JSON;
|
|
$Response.rate | select @{n="source";e={"Logged"}}, limit, used, remaining, @{n="reset";e={([System.DateTimeOffset]::FromUnixTimeSeconds($_.reset)).DateTime.AddHours(-8)}}
|
|
}
|
|
|
|
Function Get-ValidationData {
|
|
param(
|
|
$Property = "",
|
|
$Match = "",
|
|
$data = (Get-Content $DataFileName | ConvertFrom-Csv | Where-Object {$_.$Property} | Where-Object {$_.$Property -match $Match}),
|
|
[switch]$Exact
|
|
)
|
|
if ($Exact -eq $True) {
|
|
$data = $data | Where-Object {$_.$Property -eq $Match}
|
|
}
|
|
Return $data
|
|
}
|
|
|
|
Function Add-ValidationData {
|
|
param(
|
|
[Parameter(mandatory=$True)][string]$PackageIdentifier,
|
|
[string]$GitHubUserName,
|
|
[ValidateSet("should","must")][string]$authStrictness,
|
|
[ValidateSet("auto","manual")][string]$authUpdateType,
|
|
[string]$AutoWaiverLabel,
|
|
[string]$versionParamOverrideUserName,
|
|
[int]$versionParamOverridePR,
|
|
[string]$code200OverrideUserName,
|
|
[int]$code200OverridePR,
|
|
[int]$AgreementOverridePR,
|
|
[string]$AgreementURL,
|
|
[string]$reviewText,
|
|
$data = (Get-Content $DataFileName | ConvertFrom-Csv)
|
|
)
|
|
$out = ($data | where {$_.PackageIdentifier -eq $PackageIdentifier} | Select-Object "PackageIdentifier","GitHubUserName","authStrictness","authUpdateType","AutoWaiverLabel","versionParamOverrideUserName","versionParamOverridePR","code200OverrideUserName","code200OverridePR","AgreementOverridePR","AgreementURL","reviewText")
|
|
if ($null -eq $out) {
|
|
$out = ( "" | Select-Object "PackageIdentifier","GitHubUserName","authStrictness","authUpdateType","AutoWaiverLabel","versionParamOverrideUserName","versionParamOverridePR","code200OverrideUserName","code200OverridePR","AgreementOverridePR","AgreementURL","reviewText")
|
|
$out.PackageIdentifier = $PackageIdentifier
|
|
}
|
|
|
|
$out.GitHubUserName = $GitHubUserName
|
|
$out.authStrictness = $authStrictness
|
|
$out.authUpdateType = $authUpdateType
|
|
$out.AutoWaiverLabel = $AutoWaiverLabel
|
|
$out.versionParamOverrideUserName = $versionParamOverrideUserName
|
|
$out.versionParamOverridePR = $versionParamOverridePR
|
|
$out.code200OverrideUserName = $code200OverrideUserName
|
|
$out.code200OverridePR = $code200OverridePR
|
|
$out.AgreementURL = $AgreementURL
|
|
$out.AgreementOverridePR = $AgreementOverridePR
|
|
$out.reviewText = $reviewText
|
|
$data += $out
|
|
$data | sort PackageIdentifier | ConvertTo-Csv | Out-File $DataFileName
|
|
}
|
|
|
|
#PR Watcher Utility functions
|
|
Function Get-Sandbox {
|
|
#Terminates any current sandbox and makes a new one.
|
|
param(
|
|
[string]$PRNumber = (Get-Clipboard)
|
|
)
|
|
$FirstLetter = $PRNumber[0]
|
|
if ($FirstLetter -eq "#") {
|
|
[string]$PRNumber = $PRNumber[1..$PRNumber.length] -join ""
|
|
}
|
|
Get-Process *sandbox* | ForEach-Object {Stop-Process $_}
|
|
Get-Process *wingetautomator* | ForEach-Object {Stop-Process $_}
|
|
$version = "1.6.1573-preview"
|
|
$process ="wingetautomator://install?pull_request_number=$PRNumber&winget_cli_version=v$version&watch=yes"
|
|
Start-Process -PR $PRocess
|
|
}
|
|
|
|
Function Get-PadRight {
|
|
param(
|
|
[string]$PackageIdentifier,
|
|
[int]$PadChars = 45
|
|
)
|
|
$out = $PackageIdentifier
|
|
if ($PackageIdentifier.Length -lt $PadChars) {
|
|
$out = $PackageIdentifier +(" "*($PadChars - $PackageIdentifier.Length -1))
|
|
} elseif ($PackageIdentifier.Length -lt $PadChars) {
|
|
$out = $PackageIdentifier[0..($PadChars -1)]
|
|
}
|
|
|
|
if ($out.GetType().name -eq "Array") {
|
|
|
|
}
|
|
$out = $out -join ""
|
|
|
|
$out
|
|
}
|
|
|
|
$WordFilterList = "accept_gdpr ", "accept-licenses", "accept-license","eula","downloadarchive.documentfoundation.org","paypal"
|
|
|
|
$CountrySet = "Default","Warm","Cool","Random","Afghanistan","Albania","Algeria","American Samoa","Andorra","Angola","Anguilla","Antigua And Barbuda","Argentina","Armenia","Aruba","Australia","Austria","Azerbaijan","Bahamas","Bahrain","Bangladesh","Barbados","Belarus","Belgium","Belize","Benin","Bermuda","Bhutan","Bolivia","Bosnia And Herzegovina","Botswana","Bouvet Island","Brazil","Brunei Darussalam","Bulgaria","Burkina Faso","Burundi","Cabo Verde","Cambodia","Cameroon","Canada","Central African Republic","Chad","Chile","China","Colombia","Comoros","Cook Islands","Costa Rica","Croatia","Cuba","Curacao","Cyprus","Czechia","Cöte D'Ivoire","Democratic Republic Of The Congo","Denmark","Djibouti","Dominica","Dominican Republic","Ecuador","Egypt","El Salvador","Equatorial Guinea","Eritrea","Estonia","Eswatini","Ethiopia","Fiji","Finland","France","French Polynesia","Gabon","Gambia","Georgia","Germany","Ghana","Greece","Grenada","Guatemala","Guinea","Guinea-Bissau","Guyana","Haiti","Holy See (Vatican City State)","Honduras","Hungary","Iceland","India","Indonesia","Iran","Iraq","Ireland","Israel","Italy","Jamaica","Japan","Jordan","Kazakhstan","Kenya","Kiribati","Kuwait","Kyrgyzstan","Laos","Latvia","Lebanon","Lesotho","Liberia","Libya","Liechtenstein","Lithuania","Luxembourg","Madagascar","Malawi","Malaysia","Maldives","Mali","Malta","Marshall Islands","Mauritania","Mauritius","Mexico","Micronesia","Moldova","Monaco","Mongolia","Montenegro","Morocco","Mozambique","Myanmar","Namibia","Nauru","Nepal","Netherlands","New Zealand","Nicaragua","Niger","Nigeria","Niue","Norfolk Island","North Korea","North Macedonia","Norway","Oman","Pakistan","Palau","Palestine","Panama","Papua New Guinea","Paraguay","Peru","Philippines","Pitcairn Islands","Poland","Portugal","Qatar","Republic Of The Congo","Romania","Russian Federation","Rwanda","Saint Kitts And Nevis","Saint Lucia","Saint Vincent And The Grenadines","Samoa","San Marino","Sao Tome And Principe","Saudi Arabia","Senegal","Serbia","Seychelles","Sierra Leone","Singapore","Slovakia","Slovenia","Solomon Islands","Somalia","South Africa","South Korea","South Sudan","Spain","Sri Lanka","Sudan","Suriname","Sweden","Switzerland","Syrian Arab Republic","Tajikistan","Tanzania"," United Republic Of","Thailand","Togo","Tonga","Trinidad And Tobago","Tunisia","Turkey","Turkmenistan","Tuvalu","Uganda","Ukraine","United Arab Emirates","United Kingdom","United States","Uruguay","Uzbekistan","Vanuatu","Venezuela","Vietnam","Yemen","Zambia","Zimbabwe","Åland Islands"
|
|
|
|
#Misc Data
|
|
$StandardPRComments = ("Validation Pipeline Badge",#Pipeline status
|
|
"wingetbot run",#Run pipelines
|
|
"azp run",#Run pipelines
|
|
"AzurePipelines run",#Run pipelines
|
|
"Azure Pipelines successfully started running 1 pipeline",#Run confirmation
|
|
"The check-in policies require a moderator to approve PRs from the community",#Validation complete
|
|
"microsoft-github-policy-service agree",#CLA acceptance
|
|
"wingetbot waivers Add",#Any waivers
|
|
"The pull request encountered an internal error and has been assigned to a developer to investigate",#IEDS or other error
|
|
"Manifest Schema Version: 1.4.0 less than 1.5.0 for ID:",#Manifest depreciation for 1.4.0
|
|
"This account is bot account and belongs to CoolPlayLin",#CoolPlayLin's automation
|
|
"This account is automated by Github Actions and the source code was created by CoolPlayLin",#Exorcism0666's automation
|
|
"Poke 👉", #gama-bot's automation
|
|
"Response status code does not indicate success",#My automation - removal PR where URL failed status check.
|
|
"Automatic Validation ended with",#My automation - Validation output might be immaterial if unactioned.
|
|
"Manual Validation ended with",#My automation - Validation output might be immaterial if unactioned.
|
|
"No errors to post",#My automation - AutoValLog with no logs.
|
|
"The package didn't pass a Defender or similar security scan",#My automation - DefenderFail.
|
|
"Installer failed security check",#My automation - AutoValLog DefenderFail.
|
|
"Sequence contains no elements",#New Sequence error.
|
|
"Missing Properties value based on version",#New property detection.
|
|
"Azure Pipelines could not run because the pipeline triggers exclude this branch/path"#Pipeline error.
|
|
)
|
|
|
|
#VM Window Management
|
|
Function Get-TrackerVMWindowLoc {
|
|
param(
|
|
$VM,
|
|
$Rectangle = (New-Object RECT),
|
|
$VMProcesses = (Get-Process vmconnect),
|
|
$MWHandle = ($VMProcesses | where {$_.MainWindowTitle -match "vm$VM"}).MainWindowHandle
|
|
)
|
|
[window]::GetWindowRect($MWHandle,[ref]$Rectangle)
|
|
Return $Rectangle
|
|
}
|
|
|
|
Function Get-TrackerVMWindowSet {
|
|
param(
|
|
$VM,
|
|
$Left,
|
|
$Top,
|
|
$Right,
|
|
$Bottom,
|
|
$VMProcesses = (Get-Process vmconnect),
|
|
$MWHandle = ($VMProcesses | where {$_.MainWindowTitle -match "vm$VM"}).MainWindowHandle
|
|
)
|
|
$null = [window]::MoveWindow($MWHandle,$Left,$Top,$Right,$Bottom,$True)
|
|
}
|
|
|
|
Function Get-TrackerVMWindowArrange {
|
|
param(
|
|
$VMs = (Get-Status |where {$_.status -ne "Ready"}|where {$_.status -ne "ImagePark"}).vm
|
|
)
|
|
If ($VMs) {
|
|
Get-TrackerVMWindowSet $VMs[0] 900 0 1029 860
|
|
$Base = Get-TrackerVMWindowLoc $VMs[0]
|
|
|
|
For ($n = 1;$n -lt $VMs.count;$n++) {
|
|
$VM = $VMs[$n]
|
|
|
|
$Left = ($Base.left - (100 * $n))
|
|
$Top = ($Base.top + (66 * $n))
|
|
Get-TrackerVMWindowSet $VM $Left $Top 1029 860
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
Add-Type @"
|
|
using System;
|
|
using System.Runtime.InteropServices;
|
|
|
|
public class Window {
|
|
[DllImport("user32.dll")]
|
|
[return: MarshalAs(UnmanagedType.Bool)]
|
|
public static extern bool GetWindowRect(IntPtr hWnd, out RECT lpRect);
|
|
[DllImport("user32.dll")]
|
|
public static extern bool MoveWindow(IntPtr hWnd, int X, int Y, int nWidth, int nHeight, bool bRepaint);
|
|
|
|
}
|
|
public struct RECT {
|
|
public int Left; // x position of upper-left corner
|
|
public int Top; // y position of upper-left corner
|
|
public int Right; // x position of lower-right corner
|
|
public int Bottom; // y position of lower-right corner
|
|
}
|
|
|
|
"@
|
|
|
|
|
|
|
|
#Index of each column name is where prev column ends and this one starts. |