Public/Update-VcMdtApplication.ps1

function Update-VcMdtApplication {
    <#
        .EXTERNALHELP VcRedist-help.xml
    #>

    [CmdletBinding(SupportsShouldProcess = $true, HelpURI = "https://vcredist.com/update-vcmdtapplication/")]
    [OutputType([System.Management.Automation.PSObject])]
    param (
        [Parameter(
            Mandatory = $true,
            Position = 0,
            ValueFromPipeline = $true,
            HelpMessage = "Pass a VcList object from Save-VcRedist.")]
        [ValidateNotNullOrEmpty()]
        [System.Management.Automation.PSObject] $VcList,

        [Parameter(Mandatory = $false)]
        [System.ObsoleteAttribute("This parameter is not longer supported. The Path property must be on the object passed to -VcList.")]
        [System.String] $Path,

        [Parameter(Mandatory = $true)]
        [ValidateScript( { if (Test-Path -Path $_ -PathType 'Container') { $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)]
        [System.Management.Automation.SwitchParameter] $Silent,

        [Parameter(Mandatory = $false, Position = 2)]
        [ValidatePattern("^[a-zA-Z0-9]+$")]
        [System.String] $MdtDrive = "DS099",

        [Parameter(Mandatory = $false, Position = 3)]
        [ValidatePattern("^[a-zA-Z0-9]+$")]
        [System.String] $Publisher = "Microsoft"
    )

    begin {
        # If running on PowerShell Core, error and exit.
        if (Test-PSCore) {
            $Msg = "We can't load the MicrosoftDeploymentToolkit module on PowerShell Core. Please use PowerShell 5.1."
            throw [System.TypeLoadException]::New($Msg)
        }

        # Import the MDT module and create a PS drive to MdtPath
        if (Import-MdtModule) {
            if ($PSCmdlet.ShouldProcess($MdtPath, "Mapping")) {
                try {
                    $params = @{
                        Drive       = $MdtDrive
                        Path        = $MdtPath
                        ErrorAction = "Continue"
                    }
                    New-MdtDrive @params > $null
                    Restore-MDTPersistentDrive -Force > $null
                }
                catch [System.Exception] {
                    $Msg = "Failed to map drive to: $MdtPath. Error: $($_.Exception.Message)"
                    throw $Msg
                }
            }
        }
        else {
            $Msg = "Failed to import the MDT PowerShell module. Please install the MDT Workbench and try again."
            throw [System.Management.Automation.InvalidPowerShellStateException]::New($Msg)
        }

        $MdtTargetFolder = "$(Edit-MdtDrive -Drive $MdtDrive)\Applications\$AppFolder"
        Write-Verbose -Message "Update applications in: $MdtTargetFolder"
    }

    process {

        # Make sure that $VcList has the required properties
        if ((Test-VcListObject -VcList $VcList) -ne $true) {
            $Msg = "Required properties not found. Please ensure the output from Save-VcRedist is sent to this function. "
            throw [System.Management.Automation.PropertyNotFoundException]::New($Msg)
        }

        if (Test-Path -Path $MdtTargetFolder) {
            foreach ($VcRedist in $VcList) {

                # Get the existing VcRedist applications in the MDT share
                $params = @{
                    Path        = $MdtTargetFolder
                    ErrorAction = "Continue"
                }
                $ExistingVcRedist = Get-ChildItem @params | Where-Object { $_.ShortName -match "$($VcRedist.Release) $($VcRedist.Architecture)" }

                if ($null -ne $ExistingVcRedist) {
                    try {
                        Write-Verbose -Message "Found application: [$($ExistingVcRedist.ShortName)]."

                        # Determine whether update is required
                        $Update = $false
                        if ($ExistingVcRedist.UninstallKey -ne $VcRedist.ProductCode) { $Update = $true }
                        if ([System.Version]$ExistingVcRedist.Version -lt [System.Version]$VcRedist.Version) { $Update = $true }
                        if ($ExistingVcRedist.CommandLine -ne ".\$(Split-Path -Path $VcRedist.URI -Leaf) $(if ($Silent.IsPresent) { $VcRedist.SilentInstall } else { $VcRedist.Install })") { $Update = $true }
                        if ($Update -eq $true) {

                            # Copy the updated executable
                            try {
                                Write-Verbose -Message "Copy VcRedist installer."
                                #$SourceFolder = [System.IO.Path]::Combine((Resolve-Path -Path $Path), $VcRedist.Release, $VcRedist.Version, $VcRedist.Architecture)
                                $SourceFolder = $(Split-Path -Path $VcRedist.Path -Parent)
                                $ContentLocation = [System.IO.Path]::Combine((Resolve-Path -Path $MdtPath), "Applications", "$Publisher VcRedist", $VcRedist.Release, $VcRedist.Version, $VcRedist.Architecture)
                                $params = @{
                                    FilePath     = "$env:SystemRoot\System32\robocopy.exe"
                                    ArgumentList = "*.exe `"$SourceFolder`" `"$ContentLocation`" /S /XJ /R:1 /W:1 /NP /NJH /NJS /NFL /NDL"
                                }
                                $result = Invoke-Process @params
                            }
                            catch {
                                $ExeTarget = Join-Path -Path $ContentLocation -ChildPath $(Split-Path -Path $VcRedist.URI -Leaf)
                                if (Test-Path -Path $ExeTarget) {
                                    Write-Verbose -Message "Copy successful: '$ExeTarget'."
                                }
                                else {
                                    Write-Warning -Message "Failed to copy Redistributables from '$SourceFolder' to '$ContentLocation'."
                                    Write-Warning -Message "Captured error (if any): [$result]."
                                    throw $_
                                }
                            }

                            # Check the existing command line on the application and update
                            if ($PSCmdlet.ShouldProcess($ExistingVcRedist.PSPath, "Update CommandLine")) {
                                $params = @{
                                    Path  = (Join-Path -Path $MdtTargetFolder -ChildPath $ExistingVcRedist.Name)
                                    Name  = "CommandLine"
                                    Value = ".\$(Split-Path -Path $VcRedist.URI -Leaf) $(if ($Silent.IsPresent) { $VcRedist.SilentInstall } else { $VcRedist.Install })"
                                }
                                Set-ItemProperty @params > $null
                            }

                            # Update ProductCode
                            if ($PSCmdlet.ShouldProcess($ExistingVcRedist.PSPath, "Update UninstallKey")) {
                                $sipParams = @{
                                    Path  = (Join-Path -Path $MdtTargetFolder -ChildPath $ExistingVcRedist.Name)
                                    Name  = "UninstallKey"
                                    Value = $VcRedist.ProductCode
                                }
                                Set-ItemProperty @sipParams > $null
                            }

                            # Update Version number
                            if ($PSCmdlet.ShouldProcess($ExistingVcRedist.PSPath, "Update Version")) {
                                $sipParams = @{
                                    Path  = (Join-Path -Path $MdtTargetFolder -ChildPath $ExistingVcRedist.Name)
                                    Name  = "Version"
                                    Value = $VcRedist.Version
                                }
                                Set-ItemProperty @sipParams > $null
                            }

                            if ($PSCmdlet.ShouldProcess($ExistingVcRedist.PSPath, "Update Source")) {
                                $sipParams = @{
                                    Path  = (Join-Path -Path $MdtTargetFolder -ChildPath $ExistingVcRedist.Name)
                                    Name  = "Source"
                                    Value = $ExistingVcRedist.Source -replace "(\d+(\.\d+){1,4})", $VcRedist.Version
                                }
                                Set-ItemProperty @sipParams > $null
                            }

                            if ($PSCmdlet.ShouldProcess($ExistingVcRedist.PSPath, "Update WorkingDirectory")) {
                                $sipParams = @{
                                    Path  = (Join-Path -Path $MdtTargetFolder -ChildPath $ExistingVcRedist.Name)
                                    Name  = "WorkingDirectory"
                                    Value = $ExistingVcRedist.WorkingDirectory -replace "(\d+(\.\d+){1,4})", $VcRedist.Version
                                }
                                Set-ItemProperty @sipParams > $null
                            }

                            if ($PSCmdlet.ShouldProcess($ExistingVcRedist.PSPath, "Update Name")) {
                                $sipParams = @{
                                    Path  = (Join-Path -Path $MdtTargetFolder -ChildPath $ExistingVcRedist.Name)
                                    Name  = "Name"
                                    Value = $ExistingVcRedist.Name -replace "(\d+(\.\d+){1,4})", $VcRedist.Version
                                }
                                Set-ItemProperty @sipParams > $null
                            }
                        }
                    }
                    catch [System.Exception] {
                        throw $_
                    }
                }
            }
        }
        else {
            Write-Warning -Message "Failed to find path $MdtTargetFolder."
        }
    }

    end {
        if (Test-Path -Path $MdtTargetFolder) {

            # Get the imported Visual C++ Redistributables applications to return on the pipeline
            Write-Verbose -Message "Getting Visual C++ Redistributables from the deployment share"
            Write-Output -InputObject (Get-ChildItem -Path $MdtTargetFolder | Where-Object { $_.Name -like "*Visual C++*" | Select-Object -Property * })
        }
        else {
            Write-Warning -Message "Failed to find path $MdtTargetFolder."
        }
    }
}