Public/Update-VcMdtBundle.ps1
Function Update-VcMdtBundle { <# .SYNOPSIS Updates Visual C++ Redistributable application bundles in a Microsoft Deployment Toolkit share. .DESCRIPTION After importing or adding Visual C++ Redistributable applications in a Microsoft Deployment Toolkit share, an existing application bundle can be updated with GUIDs for the new Visual C++ Redistributable applications. The bundle will be updated into the MDT Deployment share with the default properties similar to the following: Location: Applications\VcRedists Name: Microsoft Visual C++ Redistributables Comments: Application bundle for installing Visual C++ Redistributables. Generated by New-VcMdtBundle Short name: Visual C++ Redistributables Version:2021-Mar-18 Publisher: Microsoft Language: en-US Dependencies: (VcRedists in the MDT share) .NOTES Author: Aaron Parker Twitter: @stealthpuppy .LINK https://stealthpuppy.com/VcRedist/update-vcmdtbundle.html .PARAMETER MdtPath The local or network path to the MDT deployment share. .PARAMETER AppFolder A sub-folder of Applications that the Visual C++ Redistributables are in. Defaults to "VcRedists". .PARAMETER Publisher Publisher name for the Visual C++ Redistributables bundle. Defaults to "Microsoft". .PARAMETER BundleName Application name for the bundle. Defaults to "Visual C++ Redistributables". .EXAMPLE Get-VcList | Save-VcRedist -Path C:\Temp\VcRedist Update-VcMdtApplication -VcList (Get-VcList) -Path C:\Temp\VcRedist -MdtPath \\server\deployment Update-VcMdtBundle -MdtPath \\server\deployment Description: Retrieves the list of Visual C++ Redistributables, downloads them to C:\Temp\VcRedist and updates each Redistributable in the MDT deployment share at \\server\deployment. #> [CmdletBinding(SupportsShouldProcess = $True, HelpURI = "https://stealthpuppy.com/VcRedist/update-vcmdtbundle.html")] [OutputType([System.Management.Automation.PSObject])] Param ( [Parameter(Mandatory = $True, Position = 0, ValueFromPipeline)] [ValidateScript( { If (Test-Path -Path $_ -PathType 'Container' -ErrorAction "SilentlyContinue") { $True } Else { Throw "Cannot find path $_" } })] [System.String] $MdtPath, [Parameter(Mandatory = $False)] [ValidatePattern('^[a-zA-Z0-9]+$')] [ValidateNotNullOrEmpty()] [System.String] $AppFolder = "VcRedists", [Parameter(Mandatory = $False, Position = 1)] [ValidatePattern('^[a-zA-Z0-9]+$')] [System.String] $MdtDrive = "DS001", [Parameter(Mandatory = $False, Position = 2)] [ValidatePattern('^[a-zA-Z0-9]+$')] [System.String] $Publisher = "Microsoft", [Parameter(Mandatory = $False, Position = 3)] [ValidatePattern('^[a-zA-Z0-9\+ ]+$')] [System.String] $BundleName = "Visual C++ Redistributables" ) Begin { # Variables $Applications = "Applications" Write-Warning -Message "$($MyInvocation.MyCommand): Attempting to update bundle: [$Publisher $BundleName]." # If running on PowerShell Core, error and exit. If (Test-PSCore) { Write-Warning -Message "$($MyInvocation.MyCommand): PowerShell Core doesn't support PSSnapins. We can't load the MicrosoftDeploymentToolkit module." Throw [System.Management.Automation.InvalidPowerShellStateException] Exit } } Process { # Import the MDT module and create a PS drive to MdtPath If (Import-MdtModule) { If ($PSCmdlet.ShouldProcess($Path, "Mapping")) { try { $params = @{ Drive = $MdtDrive Path = $MdtPath ErrorAction = "SilentlyContinue" } New-MdtDrive @params > $Null Restore-MDTPersistentDrive -Force > $Null } catch [System.Exception] { Write-Warning -Message "$($MyInvocation.MyCommand): Failed to map drive to [$MdtPath]." Throw $_.Exception.Message Exit } } } Else { Write-Warning -Message "$($MyInvocation.MyCommand): Failed to import the MDT PowerShell module. Please install the MDT Workbench and try again." Throw [System.Management.Automation.InvalidPowerShellStateException] Exit } # Get properties from the existing bundle/s try { $gciParams = @{ Path = "$($MdtDrive):\$Applications" Recurse = $True ErrorAction = "SilentlyContinue" } $Bundles = Get-ChildItem @gciParams | Where-Object { $_.Name -eq "$Publisher $BundleName" } } catch [System.Exception] { Write-Warning -Message "$($MyInvocation.MyCommand): Failed to retrieve the existing Visual C++ Redistributables bundle." Throw $_.Exception.Message Exit } ForEach ($Bundle in $Bundles) { Write-Verbose -Message "$($MyInvocation.MyCommand): Found bundle: [$($Bundle.Name)]." # Grab the Visual C++ Redistributable application guids; Sort added VcRedists by version so they are ordered correctly $target = "$($MdtDrive):\$Applications\$AppFolder" Write-Verbose -Message "$($MyInvocation.MyCommand): Gathering VcRedist applications in: $target" $existingVcRedists = Get-ChildItem -Path $target | Where-Object { ($_.Name -like "*Visual C++*") -and ($_.guid -ne $bundle.guid) -and ($_.CommandLine -ne "") } $existingVcRedists = $existingVcRedists | Sort-Object -Property @{ Expression = { [System.Version]$_.Version }; Descending = $false } $dependencies = @(); ForEach ($app in $existingVcRedists) { $dependencies += $app.guid } If ($PSCmdlet.ShouldProcess($bundle.PSPath, "Update dependencies")) { try { $sipParams = @{ Path = ($bundle.PSPath.Replace($bundle.PSProvider, "")).Trim(":") Name = "Dependency" Value = $dependencies ErrorAction = "SilentlyContinue" Force = $True } Set-ItemProperty @sipParams > $Null } catch [System.Exception] { Write-Warning -Message "$($MyInvocation.MyCommand): Error updating VcRedist bundle dependencies." Throw $_.Exception.Message Continue } } If ($PSCmdlet.ShouldProcess($bundle.PSPath, "Update version")) { try { $sipParams = @{ Path = ($bundle.PSPath.Replace($bundle.PSProvider, "")).Trim(":") Name = "Version" Value = (Get-Date -Format "yyyy-MMM-dd") ErrorAction = "SilentlyContinue" Force = $True } Set-ItemProperty @sipParams > $Null } catch [System.Exception] { Write-Warning -Message "$($MyInvocation.MyCommand): Error updating VcRedist bundle version." Throw $_.Exception.Message Continue } } # Write the bundle to the pipeline Write-Output -InputObject ($bundle | Select-Object -Property * ) } } } |