Skip to content

Instantly share code, notes, and snippets.

@bryanjhv
Forked from donno/fetch_vcdist.py
Created April 26, 2021 19:40
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save bryanjhv/e9c499ae7ae4fc3fbe1aaa9eb2a7357a to your computer and use it in GitHub Desktop.
Save bryanjhv/e9c499ae7ae4fc3fbe1aaa9eb2a7357a to your computer and use it in GitHub Desktop.
Downloads and extract the Visual C++ Redistributables.
"""Downloads and extract the Visual C++ Redistributables.
This is useful when working with minidump files as the user may be running
with a new different version of the runtime. This script aims to maintain
a copy of the various versions.
Versions are normally added once I encounter them.
This requires dark.exe from Wix (http://wixtoolset.org/releases/) and
expand.exe (File Expansion Utility - this comes with Microsoft Windows).
"""
from __future__ import print_function
import os
import requests
import subprocess
import tempfile
import zipfile
def download_file(uri, dest):
"""Download the uri to dest."""
if os.path.isfile(dest):
# Skipping, already downloaded.
return dest
r = requests.get(uri, stream=True)
with open(dest, 'wb') as f:
for chunk in r.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
f.write(chunk)
return dest
def fetch_runtimes(download_directory):
"""Fetches the Visual C++ x64 Redistributable from Microsoft.
download_directory: The directory to write the resulting files in.
Return the (version, runtime_file) for each known runtime.
"""
# Some of these packages came from:
# https://blogs.technet.microsoft.com/jagbal/2017/09/04/where-can-i-download-the-old-visual-c-redistributables/
# Others came from Choclately (https://chocolatey.org/)
runtime_downloads = [
(
'14.0.23026.0',
'https://download.microsoft.com/download/9/3/F/93FCF1E7-E6A4-478B-96E7-D4B285925B00/vc_redist.x64.exe',
# This next one seems to be the same version.
#'https://download.microsoft.com/download/4/7/a/47a9d485-9e3a-4707-be1d-26011ff15f42/vc_redist.x64.exe',
),
(
'14.0.25325.0',
'https://download.visualstudio.microsoft.com/download/pr/11100230/15ccb3f02745c7b206ad10373cbca89b/VC_redist.x64.exe',
),
(
'14.10.25017',
'https://download.microsoft.com/download/3/b/f/3bf6e759-c555-4595-8973-86b7b4312927/vc_redist.x64.exe',
),
(
'14.10.25008.0',
'https://download.microsoft.com/download/8/9/d/89d195e1-1901-4036-9a75-fbe46443fc5a/vc_redist.x64.exe',
),
(
'14.10.25017.0',
'https://download.microsoft.com/download/3/b/f/3bf6e759-c555-4595-8973-86b7b4312927/vc_redist.x64.exe',
),
(
'14.11.25325.0',
'https://download.visualstudio.microsoft.com/download/pr/11100230/15ccb3f02745c7b206ad10373cbca89b/VC_redist.x64.exe',
),
(
'14.12.25810',
'https://download.visualstudio.microsoft.com/download/pr/100349091/2cd2dba5748dc95950a5c42c2d2d78e4/VC_redist.x64.exe',
),
(
'14.12.2581',
'https://download.visualstudio.microsoft.com/download/pr/100349091/2cd2dba5748dc95950a5c42c2d2d78e4/VC_redist.x64.exe',
),
]
for version, download_uri in runtime_downloads:
filename = version + '_' + os.path.basename(download_uri)
destination = download_file(download_uri, os.path.join(download_directory, filename))
yield version, destination
def fetch_wix(download_directory):
"""Downloads the WiX toolset.
This is used to extract the runtime packages.
"""
zip_path = os.path.join(download_directory, '__wix.zip')
if not os.path.isfile(zip_path):
wix = 'https://github.com/wixtoolset/wix3/releases/download/' + \
'wix3111rtm/wix311-binaries.zip'
download_file(wix, zip_path)
with zipfile.ZipFile(zip_path, 'r') as zip_file:
zip_file.extractall(os.path.join(download_directory, '__wix'))
return os.path.join(download_directory, '__wix')
def extract_burn_bundle(wix_tool_location, bundle_exe):
"""Extracts a burn bundle to a temporary directory.
bundle_exe: The bundle executable to extract.
"""
dark_exe = os.path.join(wix_tool_location, 'dark.exe')
output_directory = tempfile.mkdtemp()
subprocess.call([dark_exe, "-nologo", "-x", output_directory, bundle_exe])
return output_directory
def find_cabs(directory):
base_path = os.path.join(directory, 'AttachedContainer', 'packages')
for name in os.listdir(base_path):
if name.endswith('_amd64'):
yield os.path.join(base_path, name, 'cab1.cab')
def extract_cab(cab_source, destination):
subprocess.call(['expand.exe', "-F:*", cab_source, destination])
def fetch_all(base_directory):
download_directory = os.path.join(base_directory, 'Downloads')
wix_tool_location = fetch_wix(download_directory)
for ver, installer in fetch_runtimes(download_directory):
output_directory = os.path.join(base_directory, 'vcruntime_' + ver)
if not os.path.isdir(output_directory):
os.makedirs(output_directory)
if os.listdir(output_directory):
print('Already have ' + ver)
continue
for cab in find_cabs(extract_burn_bundle(wix_tool_location, installer)):
extract_cab(cab, output_directory)
if __name__ == '__main__':
fetch_all(r'd:\Microsoft\Runtimes')
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment