Public/Save-VcRedist.ps1
Function Save-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://docs.stealthpuppy.com/docs/vcredist/usage/downloading-the-redistributables .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 ForceWebRequest Forces the use of Invoke-WebRequest over Start-BitsTransfer .EXAMPLE Save-VcRedist -VcList (Get-VcList) -Path C:\Redist Description: Downloads the supported Visual C++ Redistributables to C:\Redist. .EXAMPLE Get-VcList | Save-VcRedist -Path C:\Redist -ForceWebRequest Description: Passes the list of supported Visual C++ Redistributables to Save-VcRedist and uses Invoke-WebRequest to download the Redistributables to C:\Redist. .EXAMPLE $VcList = Get-VcList -Release 2013, 2019 -Architecture x86 Save-VcRedist -VcList $VcList -Path C:\Redist -ForceWebRequest Description: Passes the list of 2013 and 2019 x86 supported Visual C++ Redistributables to Save-VcRedist and uses Invoke-WebRequest to download the Redistributables to C:\Redist. #> [Alias("Get-VcRedist")] [CmdletBinding(SupportsShouldProcess = $True, HelpURI = "https://docs.stealthpuppy.com/docs/vcredist/usage/downloading-the-redistributables")] [OutputType([Array])] Param ( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline)] [ValidateNotNull()] [PSCustomObject] $VcList, [Parameter(Mandatory = $False, Position = 1)] [ValidateScript( { If (Test-Path $_ -PathType 'Container') { $True } Else { Throw "Cannot find path $_" } })] [string] $Path, [Parameter(Mandatory = $False)] [switch] $ForceWebRequest ) Begin { } Process { # Loop through each Redistributable and download to the target path ForEach ($Vc in $VcList) { Write-Verbose "[$($Vc.Name)][$($Vc.Release)][$($Vc.Architecture)]" # Create the folder to store the downloaded file. Skip if it exists $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")) { try { New-Item -Path $folder -Type Directory -Force -ErrorAction SilentlyContinue | Out-Null } catch { Throw "Failed to create folder $folder." } } } # Test whether the VcRedist is already on disk $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 } # The VcRedist needs to be downloaded If ($download) { # If -ForceWebRequest or running on PowerShell Core (or Start-BitsTransfer is unavailable) download with Invoke-WebRequest If ($ForceWebRequest -or (!(Get-Command -Name Start-BitsTransfer -ErrorAction SilentlyContinue))) { If ($pscmdlet.ShouldProcess($Vc.Download, "WebDownload")) { # Use Invoke-WebRequest in instances where Start-BitsTransfer isn't supported or won't work try { Invoke-WebRequest -Uri $Vc.Download -OutFile $target } catch { Throw "Failed to download VcRedist from $Vc.Download." } } } Else { If ($pscmdlet.ShouldProcess($Vc.Download, "BitsDownload")) { # Use Start-BitsTransfer try { Start-BitsTransfer -Source $Vc.Download -Destination $target ` -Priority High -ErrorAction Continue -ErrorVariable $ErrorBits ` -DisplayName "Visual C++ Redistributable Download" -Description $Vc.Name } catch { Throw "Failed to download VcRedist from $Vc.Download." } } } } Else { Write-Verbose "$($target) exists." } } } End { # Return the $VcList array on the pipeline so that we can act on what was downloaded Write-Output $filteredVcList } } |