MSEndpointMgr

Install Visual C++ Redistributable applications with PowerShell in MDT

Creating the perfect reference image is a time consuming task and there’s always something to tune. Over the years I’ve used various scripts and wrappers created by community members to improve the reference image creation process, in addition to a bunch of scripts that I’ve made myself. With Windows 10, more and more organizations are looking to deploy the new version and for that you’ll need a reference image. Reference images can be thick, thin or “optimal”, but in my experience there are always some sort of application baseline that you end up including in the image. Visual C++ Redistributable files are a perfect example of such baseline applications.
From time to time, Microsoft releases a new Visual C++ version that we want to include in the reference image. There are many great community scripts out there to both download and install these for and during the reference image creation process, using either MDT or ConfigMgr. But I wanted to create a script that would be dynamic in terms that you’d not have to amend the script every time a new Visual C++ redistributable was released (to be frank, it doesn’t happen very often). I also like to make things what I call future proof, meaning that you should not have to amend the solution in place, rather add new content.
With this set in mind, I’ve (finally) written a PowerShell script that is able to enumerate a Source folder for containing the desired Visual C++ executables that should be included in the reference image. Below you’ll find the code, save it as Install-VisualCRedist.ps1 or jump over to my GitHub repository and download the script from there in MDT\Reference Image.

Script

<#
.SYNOPSIS
    Dynamically install Microsoft Visual C++ Redistributables by architecture
.DESCRIPTION
    This script will install Microsoft Visual C++ Redistributables by specified architecture.
    It requires a supported folder layout e.g. like the following:
    .\Install-VisualCRedist.ps1
    .\Source\2008x86
    .\Source\2008x64
    .\Source\2010x86
    .\Source\2010x64
    Place the script in the same folder where you create the 'Source' folder. The 'Source' folder is hard-coded
    into the script and cannot be named something else. If the source folder does not exist, the script will fail.
    There's a requirement of either x86 or x64 in the sub-folder names, or the script will fail as well.
    Desired executables for each version and architecture should be placed in the supported sub-folders.
.PARAMETER Architecture
    Select desired architecture to install Visual C++ applications on. You can specify both x86 and x64 as a string array.
.PARAMETER ShowProgress
    Show a progressbar displaying the current operation.
.EXAMPLE
    Install Visual C++ Redistributables for both x86 and x64 architectures, in addition to show the current progress:
    .\Install-VisualCRedist.ps1 -Architecture x86, x64 -ShowProgress
.NOTES
    Script name: Install-VisualCRedist.ps1
    Author:      Nickolaj Andersen
    Contact:     @NickolajA
    DateCreated: 2016-02-29
#>
[CmdletBinding(SupportsShouldProcess=$true)]
param(
    [parameter(Mandatory=$true, HelpMessage="Select desired architecture to install Visual C++ applications on. You can specify both x86 and x64 as a string array.")]
    [ValidateNotNullOrEmpty()]
    [ValidateSet("x86","x64")]
    [string[]]$Architecture = "x86, x64",
    [parameter(Mandatory=$false, HelpMessage="Show a progressbar displaying the current operation.")]
    [switch]$ShowProgress = $true
)
Process {
    # Functions
    function Install-ApplicationExectuable {
        param(
            [parameter(Mandatory=$true)]
            [ValidateNotNullOrEmpty()]
            [ValidateSet("x86","x64")]
            [string]$ApplicationArchitecture,
            [parameter(Mandatory=$true)]
            [ValidateNotNullOrEmpty()]
            [string]$CurrentWorkingDirectory
        )
        if ($Script:PSBoundParameters["ShowProgress"]) {
            $ProgressCount = 0
        }
        # Determine application executable list
        $ApplicationExecutableFolders = Get-ChildItem -LiteralPath $CurrentWorkingDirectory -Filter "*$($ApplicationArchitecture)*" | Select-Object -ExpandProperty FullName
        # Validate that the Source directory is not empty
        if ($ApplicationExecutableFolders -ne $null) {
            $ApplicationExecutableFolderCount = ($ApplicationExecutableFolders | Measure-Object).Count
            foreach ($ApplicationExecutableFolder in $ApplicationExecutableFolders) {
                $CurrentApplicationPath = Get-ChildItem -LiteralPath $ApplicationExecutableFolder | Select-Object -ExpandProperty FullName
                # Validate executable count
                if (($CurrentApplicationPath | Measure-Object).Count -eq 1) {
                    # Validate that executable file exists
                    if (($CurrentApplicationPath -ne $null) -and ([System.IO.Path]::GetExtension((Split-Path -Path $CurrentApplicationPath -Leaf)) -like ".exe")) {
                        $CurrentFileDescription = (Get-Item -LiteralPath $CurrentApplicationPath | Select-Object -Property VersionInfo).VersionInfo.FileDescription
                        if ($Script:PSBoundParameters["ShowProgress"]) {
                            $ProgressCount++
                            Write-Progress -Activity "Installing Microsoft Visual C++ Redistributables ($($ApplicationArchitecture))" -Id 1 -Status "$($ProgressCount) / $($ApplicationExecutableFolderCount)" -CurrentOperation "Installing: $($CurrentFileDescription)" -PercentComplete (($ProgressCount / $ApplicationExecutableFolderCount) * 100)
                        }
                        Write-Verbose -Message "Installing: $($CurrentFileDescription)"
                        # Install the current executable
                        $ReturnValue = Start-Process -FilePath $CurrentApplicationPath -ArgumentList "/q /norestart" -Wait -PassThru
                        if (($ReturnValue.ExitCode -eq 0) -or ($ReturnValue.ExitCode -eq 3010)) {
                            Write-Verbose -Message "Successfully installed: $($CurrentFileDescription)"
                        }
                        else {
                            Write-Verbose -Message "Failed to install: $($CurrentFileDescription)"
                        }
                    }
                    else {
                        Write-Warning -Message "Unsupported file extension found in folder: $($ApplicationExecutableFolder)"
                    }
                }
                else {
                    Write-Warning -Message "Skipping folder due to unsupported number of files in: $($ApplicationExecutableFolder)"
                }
            }
            if ($Script:PSBoundParameters["ShowProgress"]) {
                Write-Progress -Activity "Installing Microsoft Visual C++ Redistributables ($($ApplicationArchitecture))" -Id 1 -Completed -Status "Completed"
            }
        }
    }
    # Install Microsoft Visual C++ Redistributables
    foreach ($Arch in $Architecture) {
        Install-ApplicationExectuable -ApplicationArchitecture $Arch -CurrentWorkingDirectory (Join-Path -Path (Split-Path -Path $MyInvocation.MyCommand.Definition -Parent) -ChildPath "\Source")
    }
}

Using the script in MDT

I’m gonna show you an example of how we can leverage this script, with the desired Visual C++ redistributables already downloaded, as an Application in MDT 2013. In this example we’ll be including Visual C++ redistributables for both x86 and x64. You’ll need
1. Either save the script from above, or download it from my GitHub repository and place it in e.g. C:\SourceFiles\Apps\Install – Visual C++ Redistributables, or wherever you store source files for importing an application in MDT. Create a folder called Source in the same folder where you placed the PowerShell script, like shown below:
185_1
2. As you may already have read in the description of the script itself, you need to create a certain folder structure in the Source folder for the script to function properly. This structure is a no brainer, simply create a structure like show below for each Visual C++ redistributable and place it on the corresponding folder:
185_2
It’s important that you at least include the correct architecture in each folder name, like in the screenshot above, since it’s a requirement for the script.
3. Open the Deployment WorkBench, right click on Applications and select New Application.
185_3
4. Select Application with source files and click Next.
5. In the Application Name field, enter a suitable name e.g. Install – Visual C++ Redistributables and click Next.
185_4
6. Browse to the location where you’ve saved the script file and create the required folder structure, in my example that would be C:\SourceFiles\Apps\Install – Visual C++ Redistributables and click Next.
185_5
7. Click Next on the Destination page.
8. As the Quiet install command, enter the following:

powershell.exe -ExecutionPolicy ByPass -Command "& .\Install-VisualCRedist.ps1 -Architecture 'x64','x86' -ShowProgress -Verbose"

Note the double and single quotations in the above command line. Click Next.
185_6
9. On the Summary page, click Next.
10. Click Finish.
You can now add the application in your task sequence, e.g. like shown below:
185_7

Summary

By implementing this script in your reference image creation process, you’ll simplify how Visual C++ redistributables are installed and in the long run give you a more dynamic approach. Just to give you an overview of how the script looks in action, I’ve recorded a short video of it running in my lab environment:


Let me know if you have any questions by leaving a comment below.

(18146)

Nickolaj Andersen

Chief Technical Architect and Enterprise Mobility MVP since 2016. Nickolaj has been in the IT industry for the past 10 years specializing in Enterprise Mobility and Security, Windows devices and deployments including automation. Awarded as PowerShell Hero in 2015 by the community for his script and tools contributions. Creator of ConfigMgr Prerequisites Tool, ConfigMgr OSD FrontEnd, ConfigMgr WebService to name a few. Frequent speaker at conferences such as Microsoft Ignite, NIC Conference and IT/Dev Connections including nordic user groups.

15 comments

  • https://docs.stealthpuppy.com/vcredist/usage/importing-into-configmgr
    i just use a cmd:
    .\2008\x64\SP1MFC\vcredist_x64.exe /Q
    .\2008\x86\SP1MFC\vcredist_x86.exe /Q
    .\2010\x64\SP1\vcredist_x64.exe /Q
    .\2010\x86\SP1\vcredist_x86.exe /Q
    .\2012\x64\Update4\vcredist_x64.exe /Q
    .\2012\x86\Update4\vcredist_x86.exe /Q
    .\2013\x64\Update5\vcredist_x64.exe /q /norestart
    .\2013\x86\Update5\vcredist_x86.exe /q /norestart
    .\2017\x64\RTM\vc_redist.x64.exe /q /norestart
    .\2017\x86\RTM\vc_redist.x86.exe /q /norestart
    echo off
    rem .\2005\x64\SP1MFC\vcredist_x64.EXE /Q
    rem .\2005\x86\SP1MFC\vcredist_x86.EXE /Q
    rem .\2015\x64\Update3\vcredist_x64.exe /q /norestart
    rem .\2015\x86\Update3\vcredist_x86.exe /q /norestart
    exit
    msiexec /x {5FCE6D76-F5DC-37AB-B2B8-22AB8CEDB1D4} /q
    msiexec /x {9BE518E6-ECC6-35A9-88E4-87755C07200F} /q
    msiexec /x {1D8E6291-B0D5-35EC-8441-6616F567A0F7} /q
    msiexec /x {F0C3E5D1-1ADE-321E-8167-68EF0DE699A5} /q
    msiexec /x {CA67548A-5EBE-413A-B50C-4B9CEB6D66C6} /q
    msiexec /x {33D1FD90-4274-48A1-9BC1-97E33D9C2D6F} /q
    msiexec /x {042D26EF-3DBE-4C25-95D3-4C1B11B235A7} /q
    msiexec /x {9DFF3540-FC85-4ED5-AC84-9E3C7FD8BECE} /q
    msiexec /x {5FB2083A-F3CC-4B78-93FF-BD9788B5DE01} /q
    msiexec /x {2FF11A2A-F7AC-4A6C-8CD4-C7BB974F3642} /q
    echo off
    rem msiexec /x {AD8A2FA1-06E7-4B0D-927D-6E54B3D31028} /q
    rem msiexec /x {710F4C1C-CC18-4C49-8CBF-51240C89A1A2} /q
    rem msiexec /x {D992C12E-CAB2-426F-BDE3-FB8C53950B0D} /q
    rem msiexec /x {E2803110-78B3-4664-A479-3611A381656A} /q
    exit

  • What I super script! I use it but I discovered that when you have 2017×86/2017×64 together with folders 2015×86/2005×64 it will first install 2017 and error on 2015 because there is a bug with 2017 not letting install 2015.
    Do you have the same Nikolaj?

    • Hi Michael,
      Yes, the script doesn’t know what it cannot install and what i can. It’ll just attempt to install anything you put in the directories. Just remove 2015 as it’s superseded by 2017.
      Regards,
      Nickolaj

  • Same here manual the script works perfect only in a task sequence of sccm can’t get this working!
    Anybody some tips?

  • Hi,
    Can this also be used in an SCCM task sequence? Can’t quite seem to get it to work for me. (with 2017 redist also)

  • […] 7zip – MSIEXEC /i 7z1604-x64.msi /q Adobe DC Reader – AcroRdrDC1700920044_en_US.exe /sAll /msi /norestart ALLUSERS=1 EULA_ACCEPT=YES Google Chrome – MSIEXEC /i googlechromestandaloneenterprise64.msi /qn ID-tarvkara – Open-EID-17.2.0.1693_x86.exe /quiet AutoUpdate=0 RunQesteidutil=0 VLC Media Player – “vlc-2.2.4-win32.exe” /L=1033 /S Visual C++ Redistributables – powershell.exe -ExecutionPolicy ByPass -Command “& .Install-VisualCRedist.ps1 -Architecture ‘x64′,’x86’ -ShowProgress -Verbose” (C++ poole pealt oli suureks abiks see: Install Visual C++ Redistributable applications with PowerShell in MDT) […]

  • Seriously Nickolaj,
    This is great stuff, it really takes the pain away of installing all the redistributables.
    Unfortunately, a few runtimes (I believe the 2005 ones) gave error messages. I removed the ‘/norestart’ argument in the argumentlist part of your script. After that it ran flawlessly…
    I also noticed that when I downloaded the .ps1 file from GitHub, I got something else than the script itself. So I copied the script from this post to fix it.
    Nevertheless, awesome stuff and keep up the good work.

      • Hi Nickolaj,
        I tried to download the script from the link mentioned in the post itself. It is possible that the issue is more PEBKAC related 😉
        I also noticed different behaviour in the script when trying to build and capture a Windows 7 reference image. I followed your blog to the letter. The script asked for pipeline inputs after running the x64 installs. I didn’t get this behaviour at Windows 10.
        I didn’t install any WMF package prior to run this script.
        Is there a PowerShell version requirement for this script?
        Kind regards,
        Marc

      • Hi Marc,
        There seems to have been a slight “bug” in the script where the Write-Progress cmdlet used for completing the current progress required the -Status parameter on PowerShell 2.0. I’ve now updated the script and tested it on a Windows 7 SP1 system with PowerShell 2.0, where it worked fine. Let me know if you still run into any issues.
        Regards,
        Nickolaj

    • Regarding 2005 not supporting the /norestart switch, add this instead.
      if ($CurrentApplicationPath -like “*VC++2005x*”) {
      $ReturnValue = Start-Process -FilePath $CurrentApplicationPath -ArgumentList “/Q” -Wait -PassThru
      }
      else {
      $ReturnValue = Start-Process -FilePath $CurrentApplicationPath -ArgumentList “/q /norestart” -Wait -PassThru
      }

  • Thank you , this is great,
    Could you share other scripts/tasks/suggestions that you adhere to when you prepare the reference image.

    • Hi kitaab,
      I’ll be posting my Remove Built-in Apps script in the near future. Are there any other steps that you were thinking about?
      Regards,
      Nickolaj

Sponsors