Public/New-VcMdtBundle.ps1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
function New-VcMdtBundle {
    <#
        .EXTERNALHELP VcRedist-help.xml
    #>

    [CmdletBinding(SupportsShouldProcess = $true, HelpURI = "https://vcredist.com/import-vcmdtapplication/")]
    [OutputType([System.Management.Automation.PSObject])]
    param (
        [Parameter(Mandatory = $true, Position = 0, ValueFromPipeline)]
        [ValidateScript( { if (Test-Path -Path $_ -PathType "Container") { $true } else { throw "Cannot find path $_" } })]
        [System.String] $MdtPath,

        [Parameter(Mandatory = $false, Position = 1)]
        [ValidatePattern("^[a-zA-Z0-9]+$")]
        [ValidateNotNullOrEmpty()]
        [System.String] $AppFolder = "VcRedists",

        [Parameter(Mandatory = $false)]
        [System.Management.Automation.SwitchParameter] $Force,

        [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",

        [Parameter(Mandatory = $false, Position = 4)]
        [ValidatePattern("^[a-zA-Z0-9\+ ]+$")]
        [System.String] $BundleName = "Visual C++ Redistributables",

        [Parameter(Mandatory = $false, Position = 5)]
        [ValidatePattern("^[a-zA-Z0-9-]+$")]
        [System.String] $Language = "en-US"
    )

    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($Path, "Mapping")) {
                try {
                    $params = @{
                        Drive       = $MdtDrive
                        Path        = $MdtPath
                        ErrorAction = "Continue"
                    }
                    New-MdtDrive @params > $null
                    Restore-MDTPersistentDrive -Force > $null
                }
                catch [System.Exception] {
                    Write-Warning -Message "Failed to map drive to: $MdtPath, with: $($_.Exception.Message)"
                    throw $_
                }
            }
        }
        else {
            $Msg = "Failed to import the MDT PowerShell module. Please install the MDT Workbench and try again."
            throw [System.Management.Automation.InvalidPowerShellStateException]::New($Msg)
        }
    }

    process {
        Write-Verbose -Message "Getting existing Visual C++ Redistributables the deployment share"
        $TargetMdtFolder = "$($MdtDrive):\Applications\$AppFolder"
        $existingVcRedists = Get-ChildItem -Path $TargetMdtFolder -ErrorAction "SilentlyContinue" | Where-Object { $_.Name -like "*Visual C++*" }
        if ($null -eq $existingVcRedists) {
            Write-Warning -Message "Failed to find existing VcRedist applications in the MDT share. Please import the VcRedists with Import-VcMdtApplication."
        }

        if (($null -ne $existingVcRedists) -and (Test-Path -Path $TargetMdtFolder)) {

            # Remove the existing bundle if -Force was specified
            if ($PSBoundParameters.ContainsKey("Force")) {
                if (Test-Path -Path $("$TargetMdtFolder\$Publisher $BundleName")) {
                    if ($PSCmdlet.ShouldProcess("$($Publisher) $($BundleName)", "Remove bundle")) {
                        Remove-Item -Path $("$TargetMdtFolder\$Publisher $BundleName") -Force
                    }
                }
            }

            # Create the application bundle
            if (Test-Path -Path "$TargetMdtFolder\$Publisher $BundleName") {
                Write-Verbose "'$($Publisher) $($BundleName)' exists. Use -Force to overwrite the existing bundle."
            }
            else {
                if ($PSCmdlet.ShouldProcess("$($Publisher) $($BundleName)", "Create bundle")) {

                    # Grab the Visual C++ Redistributable application guids; Sort added VcRedists by version so they are ordered correctly
                    Write-Verbose -Message "Gathering VcRedist applications in: $TargetMdtFolder"
                    $existingVcRedists = $existingVcRedists | Sort-Object -Property @{ Expression = { [System.Version]$_.Version }; Descending = $false }
                    $dependencies = @(); foreach ($app in $existingVcRedists) { $dependencies += $app.guid }

                    # Import the bundle
                    try {
                        # Splat the Import-MDTApplication parameters
                        $importMDTAppParams = @{
                            Path       = $TargetMdtFolder
                            Name       = "$($Publisher) $($BundleName)"
                            Enable     = $true
                            Reboot     = $false
                            Hide       = $false
                            Comments   = "Application bundle for installing Visual C++ Redistributables. Generated by $($MyInvocation.MyCommand)"
                            ShortName  = $BundleName
                            Version    = $(Get-Date -Format (([System.Globalization.CultureInfo]::CurrentUICulture.DateTimeFormat).ShortDatePattern))
                            Publisher  = $Publisher
                            Language   = $Language
                            Dependency = $dependencies
                            Bundle     = $true
                        }
                        Import-MDTApplication @importMDTAppParams > $null
                    }
                    catch [System.Exception] {
                        Write-Warning -Message "Error importing the VcRedist bundle. If -Force was specified, the original bundle will have been removed."
                        throw $_
                    }
                }
            }
        }
        else {
            Write-Error -Message "Failed to find path $TargetMdtFolder."
        }

        if (Test-Path -Path $TargetMdtFolder) {
            # Return list of apps to the pipeline
            Write-Output -InputObject (Get-ChildItem -Path "$TargetMdtFolder\$($Publisher) $($BundleName)" | Select-Object -Property *)
        }
        else {
            Write-Error -Message "Failed to find path $TargetMdtFolder."
        }
    }
}