Public/Get-VcRedist.ps1
Function Get-VcRedist { <# .SYNOPSIS Downloads the Visual C++ Redistributables from an array returned by Get-VcXml. .DESCRIPTION Downloads the Visual C++ Redistributables from an array returned by Get-VcXml into a folder structure that represents release and processor architecture. If the redistributable exists in the specified path, it will not be re-downloaded. .OUTPUTS System.Array .NOTES Author: Aaron Parker Twitter: @stealthpuppy .LINK https://github.com/aaronparker/Install-VisualCRedistributables .PARAMETER VcList Sepcifies the array that lists the Visual C++ Redistributables to download .PARAMETER Path Specify a target folder to download the Redistributables to, otherwise use the current folder. .PARAMETER Release Specifies the release (or version) of the redistributables to download or install. .PARAMETER Architecture Specifies the processor architecture to download or install. .EXAMPLE Get-VcXml | Get-VcRedist -Path C:\Redist Description: Downloads the supported Visual C++ Redistributables to C:\Redist. .EXAMPLE Get-VcRedist -VcXml $VcRedists -Release "2012","2013",2017" Description: Downloads only the 2012, 2013 & 2017 releases of the Visual C++ Redistributables listed in $VcRedists .EXAMPLE Get-VcList | Get-VcRedist -Path C:\Temp\VcRedist -Architecture x64 Description: Downloads only the 64-bit versions of the Visual C++ Redistributables listed in $VcRedists. #> [Alias("Save-VcRedist")] [CmdletBinding(SupportsShouldProcess = $True)] [OutputType([Array])] Param ( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline = $True, ValueFromPipelineByPropertyName = $False, ` HelpMessage = ".")] [ValidateNotNull()] [array] $VcList, [Parameter(Mandatory = $False, Position = 1, HelpMessage = "Specify a target path to download the Redistributables to.")] [ValidateScript( { If (Test-Path $_ -PathType 'Container') { $True } Else { Throw "Cannot find path $_" } })] [string] $Path, [Parameter(Mandatory = $False, HelpMessage = "Specify the version of the Redistributables to download.")] [ValidateSet('2005', '2008', '2010', '2012', '2013', '2015', '2017')] [string[]] $Release = @("2008", "2010", "2012", "2013", "2015", "2017"), [Parameter(Mandatory = $False, HelpMessage = "Specify the processor architecture/s to download.")] [ValidateSet('x86', 'x64')] [string[]] $Architecture = @("x86", "x64") ) Begin { $output = @() } Process { # Filter release and architecture if specified If ( $PSBoundParameters.ContainsKey('Release') ) { Write-Verbose "Filtering releases for platform." $VcList = $VcList | Where-Object { $_.Release -eq $Release } } If ( $PSBoundParameters.ContainsKey('Architecture') ) { Write-Verbose "Filtering releases for architecture." $VcList = $VcList | Where-Object { $_.Architecture -eq $Architecture } } # Loop through each Redistributable and download to the target path ForEach ($Vc in $VcList) { Write-Verbose "Downloading: [$($Vc.Name)][$($Vc.Release)][$($Vc.Architecture)]" $output += $Vc # Create the folder to store the downloaded file. Skip if it exists # $folder = "$($(Get-Item -Path $Path).FullName)\$($Vc.Release)\$($Vc.Architecture)\$($Vc.ShortName)" $folder = Join-Path (Join-Path (Join-Path $(Resolve-Path -Path $Path) $Vc.Release) $Vc.Architecture) $Vc.ShortName If (Test-Path -Path $folder) { Write-Verbose "Folder '$folder' exists. Skipping." } Else { If ($pscmdlet.ShouldProcess($folder, "Create")) { New-Item -Path $folder -Type Directory -Force -ErrorAction SilentlyContinue | Out-Null } } $target = Join-Path $folder $(Split-Path -Path $Vc.Download -Leaf) Write-Verbose "Testing target: $($target)" If (Test-Path -Path $target -PathType Leaf) { $ProductVersion = $(Get-FileMetadata -Path $target).ProductVersion # If the target Redistributable is already downloaded, compare the version If (($Vc.Version -gt $ProductVersion) -or ($Null -eq $ProductVersion)) { # Download the newer version Write-Verbose "$($Vc.Version) > $ProductVersion." $download = $True } Else { Write-Verbose "Manifest version: $($Vc.Version) matches file version: $ProductVersion." $download = $False } } Else { $download = $True } If ($download) { # If running on Windows PowerShell use Start-BitsTransfer, otherwise use Invoke-WebRequest If ( Get-Command Start-BitsTransfer -ErrorAction SilentlyContinue ) { If ( $pscmdlet.ShouldProcess($Vc.Download, "BitsDownload") ) { Start-BitsTransfer -Source $Vc.Download -Destination $target ` -Priority High -ErrorAction Continue -ErrorVariable $ErrorBits ` -DisplayName "Visual C++ Redistributable Download" -Description $Vc.Name } } Else { If ( $pscmdlet.ShouldProcess($Vc.Download, "WebDownload") ) { Invoke-WebRequest -Uri $Vc.Download -OutFile $target } } } Else { Write-Verbose "$($target) exists." } } } End { # Return the $VcList array on the pipeline so that we can act on what was downloaded Write-Output $output } } |