diff --git a/ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_install.ps1 b/ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_install.ps1 new file mode 100644 index 0000000000..605ff7299a --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_install.ps1 @@ -0,0 +1,38 @@ +# Learn more about .exe install scripts: +# http://fleetdm.com/learn-more-about/exe-install-scripts +# +# The Visual C++ Redistributable ships as a WiX "burn" bootstrapper (.exe). It +# installs machine-wide and registers its own ARP entry. Silent switches come +# from the winget installer manifest (burn bundles use /quiet /norestart). + +$exeFilePath = "${env:INSTALLER_PATH}" + +try { + if (-not (Test-Path $exeFilePath)) { + Write-Host "Error: Installer file not found at: $exeFilePath" + Exit 1 + } + + $processOptions = @{ + FilePath = "$exeFilePath" + ArgumentList = "/quiet /norestart" + PassThru = $true + Wait = $true + NoNewWindow = $true + } + + $process = Start-Process @processOptions + $exitCode = $process.ExitCode + Write-Host "Install exit code: $exitCode" + + # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated + if ($exitCode -eq 3010 -or $exitCode -eq 1641) { + Exit 0 + } + + Exit $exitCode + +} catch { + Write-Host "Error: $_" + Exit 1 +} diff --git a/ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_uninstall.ps1 b/ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_uninstall.ps1 new file mode 100644 index 0000000000..fea07d1117 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_uninstall.ps1 @@ -0,0 +1,73 @@ +# Uninstalls the Microsoft Visual C++ Redistributable WiX "burn" bundle. +# +# The redistributable installs as a burn bootstrapper that registers a *bundle* +# ARP entry (keyed by the bundle ProductCode) alongside several MSI component +# entries ("...X64 Minimum Runtime...", "...Additional Runtime..."). Only the +# bundle entry removes the whole redistributable, and it uninstalls by running +# its cached bootstrapper .exe with /uninstall -- never via msiexec. We target +# the bundle by its ProductCode (injected by the ingester) and fall back to the +# cached bootstrapper in the Package Cache. + +$productCode = ${PACKAGE_ID} + +function Invoke-Uninstaller { + param([string]$exe, [string]$exeArgs) + if ($exeArgs -notmatch '/uninstall') { $exeArgs = "/uninstall $exeArgs" } + if ($exeArgs -notmatch '/quiet') { $exeArgs = "$exeArgs /quiet" } + if ($exeArgs -notmatch '/norestart') { $exeArgs = "$exeArgs /norestart" } + $exeArgs = $exeArgs.Trim() + Write-Host "Uninstall command: $exe" + Write-Host "Uninstall args: $exeArgs" + $process = Start-Process -FilePath $exe -ArgumentList $exeArgs -NoNewWindow -PassThru -Wait + return $process.ExitCode +} + +$exitCode = $null + +# 1) Preferred: the bundle ARP entry, looked up by the bundle ProductCode. Its +# UninstallString/QuietUninstallString points to the cached bootstrapper .exe. +$keys = @( + "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\$productCode", + "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\$productCode" +) + +foreach ($key in $keys) { + if (-not (Test-Path $key)) { continue } + $entry = Get-ItemProperty $key -ErrorAction SilentlyContinue + if (-not $entry) { continue } + + $raw = $entry.QuietUninstallString + if (-not $raw) { $raw = $entry.UninstallString } + if (-not $raw) { continue } + + # Parse into executable + args, handling quoted/unquoted/bare shapes. + if ($raw -match '^\s*"([^"]+)"\s*(.*)$') { + $exe = $matches[1]; $exeArgs = $matches[2].Trim() + } elseif ($raw -match '(?i)^\s*(.+?\.exe)\s*(.*)$') { + $exe = $matches[1]; $exeArgs = $matches[2].Trim() + } else { + $exe = $raw; $exeArgs = "" + } + + $exitCode = Invoke-Uninstaller -exe $exe -exeArgs $exeArgs + break +} + +# 2) Fallback: run the cached bootstrapper directly from the Package Cache, which +# burn names after the bundle ProductCode. +if ($null -eq $exitCode) { + $cached = Get-ChildItem -Path "C:\ProgramData\Package Cache\$productCode" -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -First 1 + if ($cached) { + $exitCode = Invoke-Uninstaller -exe $cached.FullName -exeArgs "" + } +} + +if ($null -eq $exitCode) { + Write-Host "Uninstall entry not found for product code: $productCode" + Exit 0 +} + +Write-Host "Uninstall exit code: $exitCode" +# 0 = success, 3010 = success but reboot required, 1641 = reboot initiated +if ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 } +Exit $exitCode diff --git a/ee/maintained-apps/inputs/winget/vc-redist-2013-x64.json b/ee/maintained-apps/inputs/winget/vc-redist-2013-x64.json new file mode 100644 index 0000000000..e9e9af7713 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/vc-redist-2013-x64.json @@ -0,0 +1,13 @@ +{ + "name": "Microsoft Visual C++ 2013 Redistributable (x64)", + "slug": "vc-redist-2013-x64/windows", + "package_identifier": "Microsoft.VCRedist.2013.x64", + "unique_identifier": "Microsoft Visual C++ 2013 Redistributable (x64)", + "exists_query": "SELECT 1 FROM programs WHERE name LIKE 'Microsoft Visual C++ 2013 Redistributable (x64)%' AND publisher = 'Microsoft Corporation';", + "installer_arch": "x64", + "installer_type": "exe", + "installer_scope": "machine", + "install_script_path": "ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_install.ps1", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_uninstall.ps1", + "default_categories": ["Developer tools"] +} diff --git a/ee/maintained-apps/inputs/winget/vc-redist-x64.json b/ee/maintained-apps/inputs/winget/vc-redist-x64.json new file mode 100644 index 0000000000..ba7af81174 --- /dev/null +++ b/ee/maintained-apps/inputs/winget/vc-redist-x64.json @@ -0,0 +1,13 @@ +{ + "name": "Microsoft Visual C++ 2015-2022 Redistributable (x64)", + "slug": "vc-redist-x64/windows", + "package_identifier": "Microsoft.VCRedist.2015+.x64", + "unique_identifier": "Microsoft Visual C++ 2015-2022 Redistributable (x64)", + "exists_query": "SELECT 1 FROM programs WHERE name LIKE 'Microsoft Visual C++ 2015-2022 Redistributable (x64)%' AND publisher = 'Microsoft Corporation';", + "installer_arch": "x64", + "installer_type": "exe", + "installer_scope": "machine", + "install_script_path": "ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_install.ps1", + "uninstall_script_path": "ee/maintained-apps/inputs/winget/scripts/vc_redist_x64_uninstall.ps1", + "default_categories": ["Developer tools"] +} diff --git a/ee/maintained-apps/outputs/apps.json b/ee/maintained-apps/outputs/apps.json index a6a08384d0..20ea0a6283 100644 --- a/ee/maintained-apps/outputs/apps.json +++ b/ee/maintained-apps/outputs/apps.json @@ -2577,6 +2577,20 @@ "unique_identifier": "com.utmapp.UTM", "description": "UTM is a virtual machines UI using QEMU." }, + { + "name": "Microsoft Visual C++ 2013 Redistributable (x64)", + "slug": "vc-redist-2013-x64/windows", + "platform": "windows", + "unique_identifier": "Microsoft Visual C++ 2013 Redistributable (x64)", + "description": "Microsoft Visual C++ 2013 Redistributable (x64) installs the runtime components of the Visual C++ libraries required to run 64-bit applications built with Visual C++ 2013." + }, + { + "name": "Microsoft Visual C++ 2015-2022 Redistributable (x64)", + "slug": "vc-redist-x64/windows", + "platform": "windows", + "unique_identifier": "Microsoft Visual C++ 2015-2022 Redistributable (x64)", + "description": "Microsoft Visual C++ 2015-2022 Redistributable (x64) installs the runtime components of the Visual C++ libraries required to run 64-bit applications built with Visual C++ 2015, 2017, 2019, and 2022." + }, { "name": "VirtualBox", "slug": "virtualbox/darwin", diff --git a/ee/maintained-apps/outputs/vc-redist-2013-x64/windows.json b/ee/maintained-apps/outputs/vc-redist-2013-x64/windows.json new file mode 100644 index 0000000000..73bf7aa004 --- /dev/null +++ b/ee/maintained-apps/outputs/vc-redist-2013-x64/windows.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "12.0.40664.0", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name LIKE 'Microsoft Visual C++ 2013 Redistributable (x64)%' AND publisher = 'Microsoft Corporation';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name LIKE 'Microsoft Visual C++ 2013 Redistributable (x64)%' AND publisher = 'Microsoft Corporation' AND version_compare(version, '12.0.40664.0') < 0);" + }, + "installer_url": "https://download.visualstudio.microsoft.com/download/pr/10912041/cee5d6bca2ddbcd039da727bf4acb48a/vcredist_x64.exe", + "install_script_ref": "65654cc8", + "uninstall_script_ref": "72bee0a9", + "sha256": "a4bba7701e355ae29c403431f871a537897c363e215cafe706615e270984f17c", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "65654cc8": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n#\n# The Visual C++ Redistributable ships as a WiX \"burn\" bootstrapper (.exe). It\n# installs machine-wide and registers its own ARP entry. Silent switches come\n# from the winget installer manifest (burn bundles use /quiet /norestart).\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n if (-not (Test-Path $exeFilePath)) {\n Write-Host \"Error: Installer file not found at: $exeFilePath\"\n Exit 1\n }\n\n $processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"/quiet /norestart\"\n PassThru = $true\n Wait = $true\n NoNewWindow = $true\n }\n\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode\n Write-Host \"Install exit code: $exitCode\"\n\n # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated\n if ($exitCode -eq 3010 -or $exitCode -eq 1641) {\n Exit 0\n }\n\n Exit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n", + "72bee0a9": "# Uninstalls the Microsoft Visual C++ Redistributable WiX \"burn\" bundle.\n#\n# The redistributable installs as a burn bootstrapper that registers a *bundle*\n# ARP entry (keyed by the bundle ProductCode) alongside several MSI component\n# entries (\"...X64 Minimum Runtime...\", \"...Additional Runtime...\"). Only the\n# bundle entry removes the whole redistributable, and it uninstalls by running\n# its cached bootstrapper .exe with /uninstall -- never via msiexec. We target\n# the bundle by its ProductCode (injected by the ingester) and fall back to the\n# cached bootstrapper in the Package Cache.\n\n$productCode = '{042d26ef-3dbe-4c25-95d3-4c1b11b235a7}'\n\nfunction Invoke-Uninstaller {\n param([string]$exe, [string]$exeArgs)\n if ($exeArgs -notmatch '/uninstall') { $exeArgs = \"/uninstall $exeArgs\" }\n if ($exeArgs -notmatch '/quiet') { $exeArgs = \"$exeArgs /quiet\" }\n if ($exeArgs -notmatch '/norestart') { $exeArgs = \"$exeArgs /norestart\" }\n $exeArgs = $exeArgs.Trim()\n Write-Host \"Uninstall command: $exe\"\n Write-Host \"Uninstall args: $exeArgs\"\n $process = Start-Process -FilePath $exe -ArgumentList $exeArgs -NoNewWindow -PassThru -Wait\n return $process.ExitCode\n}\n\n$exitCode = $null\n\n# 1) Preferred: the bundle ARP entry, looked up by the bundle ProductCode. Its\n# UninstallString/QuietUninstallString points to the cached bootstrapper .exe.\n$keys = @(\n \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$productCode\",\n \"HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$productCode\"\n)\n\nforeach ($key in $keys) {\n if (-not (Test-Path $key)) { continue }\n $entry = Get-ItemProperty $key -ErrorAction SilentlyContinue\n if (-not $entry) { continue }\n\n $raw = $entry.QuietUninstallString\n if (-not $raw) { $raw = $entry.UninstallString }\n if (-not $raw) { continue }\n\n # Parse into executable + args, handling quoted/unquoted/bare shapes.\n if ($raw -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $exe = $matches[1]; $exeArgs = $matches[2].Trim()\n } elseif ($raw -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $exe = $matches[1]; $exeArgs = $matches[2].Trim()\n } else {\n $exe = $raw; $exeArgs = \"\"\n }\n\n $exitCode = Invoke-Uninstaller -exe $exe -exeArgs $exeArgs\n break\n}\n\n# 2) Fallback: run the cached bootstrapper directly from the Package Cache, which\n# burn names after the bundle ProductCode.\nif ($null -eq $exitCode) {\n $cached = Get-ChildItem -Path \"C:\\ProgramData\\Package Cache\\$productCode\" -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -First 1\n if ($cached) {\n $exitCode = Invoke-Uninstaller -exe $cached.FullName -exeArgs \"\"\n }\n}\n\nif ($null -eq $exitCode) {\n Write-Host \"Uninstall entry not found for product code: $productCode\"\n Exit 0\n}\n\nWrite-Host \"Uninstall exit code: $exitCode\"\n# 0 = success, 3010 = success but reboot required, 1641 = reboot initiated\nif ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\nExit $exitCode\n" + } +} diff --git a/ee/maintained-apps/outputs/vc-redist-x64/windows.json b/ee/maintained-apps/outputs/vc-redist-x64/windows.json new file mode 100644 index 0000000000..d60d754c32 --- /dev/null +++ b/ee/maintained-apps/outputs/vc-redist-x64/windows.json @@ -0,0 +1,22 @@ +{ + "versions": [ + { + "version": "14.51.36231.0", + "queries": { + "exists": "SELECT 1 FROM programs WHERE name LIKE 'Microsoft Visual C++ 2015-2022 Redistributable (x64)%' AND publisher = 'Microsoft Corporation';", + "patched": "SELECT 1 WHERE NOT EXISTS (SELECT 1 FROM programs WHERE name LIKE 'Microsoft Visual C++ 2015-2022 Redistributable (x64)%' AND publisher = 'Microsoft Corporation' AND version_compare(version, '14.51.36231.0') < 0);" + }, + "installer_url": "https://download.visualstudio.microsoft.com/download/pr/c1bd4f2c-3672-468e-8480-7ed419dbb641/90E48ADE404E4576D023ABFA374F323555F233982A8805EA9AC63DCA9491A16B/VC_redist.x64.exe", + "install_script_ref": "65654cc8", + "uninstall_script_ref": "5077ddcb", + "sha256": "90e48ade404e4576d023abfa374f323555f233982a8805ea9ac63dca9491a16b", + "default_categories": [ + "Developer tools" + ] + } + ], + "refs": { + "5077ddcb": "# Uninstalls the Microsoft Visual C++ Redistributable WiX \"burn\" bundle.\n#\n# The redistributable installs as a burn bootstrapper that registers a *bundle*\n# ARP entry (keyed by the bundle ProductCode) alongside several MSI component\n# entries (\"...X64 Minimum Runtime...\", \"...Additional Runtime...\"). Only the\n# bundle entry removes the whole redistributable, and it uninstalls by running\n# its cached bootstrapper .exe with /uninstall -- never via msiexec. We target\n# the bundle by its ProductCode (injected by the ingester) and fall back to the\n# cached bootstrapper in the Package Cache.\n\n$productCode = '{c157798c-9519-4e56-98d9-f696f78f4a61}'\n\nfunction Invoke-Uninstaller {\n param([string]$exe, [string]$exeArgs)\n if ($exeArgs -notmatch '/uninstall') { $exeArgs = \"/uninstall $exeArgs\" }\n if ($exeArgs -notmatch '/quiet') { $exeArgs = \"$exeArgs /quiet\" }\n if ($exeArgs -notmatch '/norestart') { $exeArgs = \"$exeArgs /norestart\" }\n $exeArgs = $exeArgs.Trim()\n Write-Host \"Uninstall command: $exe\"\n Write-Host \"Uninstall args: $exeArgs\"\n $process = Start-Process -FilePath $exe -ArgumentList $exeArgs -NoNewWindow -PassThru -Wait\n return $process.ExitCode\n}\n\n$exitCode = $null\n\n# 1) Preferred: the bundle ARP entry, looked up by the bundle ProductCode. Its\n# UninstallString/QuietUninstallString points to the cached bootstrapper .exe.\n$keys = @(\n \"HKLM:\\SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$productCode\",\n \"HKLM:\\SOFTWARE\\WOW6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\$productCode\"\n)\n\nforeach ($key in $keys) {\n if (-not (Test-Path $key)) { continue }\n $entry = Get-ItemProperty $key -ErrorAction SilentlyContinue\n if (-not $entry) { continue }\n\n $raw = $entry.QuietUninstallString\n if (-not $raw) { $raw = $entry.UninstallString }\n if (-not $raw) { continue }\n\n # Parse into executable + args, handling quoted/unquoted/bare shapes.\n if ($raw -match '^\\s*\"([^\"]+)\"\\s*(.*)$') {\n $exe = $matches[1]; $exeArgs = $matches[2].Trim()\n } elseif ($raw -match '(?i)^\\s*(.+?\\.exe)\\s*(.*)$') {\n $exe = $matches[1]; $exeArgs = $matches[2].Trim()\n } else {\n $exe = $raw; $exeArgs = \"\"\n }\n\n $exitCode = Invoke-Uninstaller -exe $exe -exeArgs $exeArgs\n break\n}\n\n# 2) Fallback: run the cached bootstrapper directly from the Package Cache, which\n# burn names after the bundle ProductCode.\nif ($null -eq $exitCode) {\n $cached = Get-ChildItem -Path \"C:\\ProgramData\\Package Cache\\$productCode\" -Filter *.exe -ErrorAction SilentlyContinue | Select-Object -First 1\n if ($cached) {\n $exitCode = Invoke-Uninstaller -exe $cached.FullName -exeArgs \"\"\n }\n}\n\nif ($null -eq $exitCode) {\n Write-Host \"Uninstall entry not found for product code: $productCode\"\n Exit 0\n}\n\nWrite-Host \"Uninstall exit code: $exitCode\"\n# 0 = success, 3010 = success but reboot required, 1641 = reboot initiated\nif ($exitCode -eq 3010 -or $exitCode -eq 1641) { Exit 0 }\nExit $exitCode\n", + "65654cc8": "# Learn more about .exe install scripts:\n# http://fleetdm.com/learn-more-about/exe-install-scripts\n#\n# The Visual C++ Redistributable ships as a WiX \"burn\" bootstrapper (.exe). It\n# installs machine-wide and registers its own ARP entry. Silent switches come\n# from the winget installer manifest (burn bundles use /quiet /norestart).\n\n$exeFilePath = \"${env:INSTALLER_PATH}\"\n\ntry {\n if (-not (Test-Path $exeFilePath)) {\n Write-Host \"Error: Installer file not found at: $exeFilePath\"\n Exit 1\n }\n\n $processOptions = @{\n FilePath = \"$exeFilePath\"\n ArgumentList = \"/quiet /norestart\"\n PassThru = $true\n Wait = $true\n NoNewWindow = $true\n }\n\n $process = Start-Process @processOptions\n $exitCode = $process.ExitCode\n Write-Host \"Install exit code: $exitCode\"\n\n # 0 = success, 3010 = success but reboot required, 1641 = reboot initiated\n if ($exitCode -eq 3010 -or $exitCode -eq 1641) {\n Exit 0\n }\n\n Exit $exitCode\n\n} catch {\n Write-Host \"Error: $_\"\n Exit 1\n}\n" + } +} diff --git a/frontend/pages/SoftwarePage/components/icons/VcRedistX64.tsx b/frontend/pages/SoftwarePage/components/icons/VcRedistX64.tsx new file mode 100644 index 0000000000..478167cd51 --- /dev/null +++ b/frontend/pages/SoftwarePage/components/icons/VcRedistX64.tsx @@ -0,0 +1,14 @@ +import * as React from "react"; + +import type { SVGProps } from "react"; + +const VcRedistX64 = (props: SVGProps) => ( + + + +); +export default VcRedistX64; diff --git a/frontend/pages/SoftwarePage/components/icons/index.ts b/frontend/pages/SoftwarePage/components/icons/index.ts index eddbc589cd..8e11535ad0 100644 --- a/frontend/pages/SoftwarePage/components/icons/index.ts +++ b/frontend/pages/SoftwarePage/components/icons/index.ts @@ -268,6 +268,7 @@ import Transmit from "./Transmit"; import Tunnelblick from "./Tunnelblick"; import Twingate from "./Twingate"; import Utm from "./Utm"; +import VcRedistX64 from "./VcRedistX64"; import VirtualBox from "./VirtualBox"; import VirtualBuddy from "./VirtualBuddy"; import Viscosity from "./Viscosity"; @@ -477,6 +478,7 @@ export const SOFTWARE_NAME_TO_ICON_MAP = { "microsoft outlook": MicrosoftOutlook, "microsoft powerpoint": MicrosoftPowerPoint, "microsoft teams": Teams, + "microsoft visual c++": VcRedistX64, "microsoft visual studio code": VisualStudioCode, "microsoft word": Word, miro: Miro, diff --git a/website/assets/images/app-icon-vc-redist-2013-x64-60x60@2x.png b/website/assets/images/app-icon-vc-redist-2013-x64-60x60@2x.png new file mode 100644 index 0000000000..c8eb4096d0 Binary files /dev/null and b/website/assets/images/app-icon-vc-redist-2013-x64-60x60@2x.png differ diff --git a/website/assets/images/app-icon-vc-redist-x64-60x60@2x.png b/website/assets/images/app-icon-vc-redist-x64-60x60@2x.png new file mode 100644 index 0000000000..c8eb4096d0 Binary files /dev/null and b/website/assets/images/app-icon-vc-redist-x64-60x60@2x.png differ