Public/Get-VcList.ps1

Function Get-VcList {
    <#
        .SYNOPSIS
            Returns an object of Microsoft Visual C++ Redistributables for use with other VcRedist functions.

        .DESCRIPTION
            This function reads the Visual C++ Redistributables listed in an internal manifest (or an external JSON file) into an object that can be passed to other VcRedist functions.

            A complete listing of the supported and all known redistributables is included in the module. By default, Get-VcList will only return a list of the supported Visual C++ Redistributables. To return any of the unsupported Redistributables, the -Export parameter is required with the output filtered with Where-Object.
            
            The internal manifest can be exported with Export-VcManifest.
        
        .NOTES
            Author: Aaron Parker
            Twitter: @stealthpuppy

        .LINK
            https://stealthpuppy.com/VcRedist/get-vclist.html

        .PARAMETER Manifest
            The JSON file that contains the details about the Visual C++ Redistributables. This must be in the expected format.

        .PARAMETER Export
            Defines the list of Visual C++ Redistributables to export - All, Supported or Unsupported Redistributables.
            Defaults to exporting the Supported Redistributables.

        .PARAMETER Release
            Specifies the release (or version) of the redistributables to return.

        .PARAMETER Architecture
            Specifies the processor architecture to of the redistributables to return. Can be x86 or x64.

        .EXAMPLE
            Get-VcList

            Description:
            Return an object of the supported Visual C++ Redistributables from the embedded manifest.

        .EXAMPLE
            Get-VcList

            Description:
            Returns the supported 2010, 2012, 2013 and 2019, x86 and x64 versions of the supported Visual C++ Redistributables from the embedded manifest.

        .EXAMPLE
            Get-VcList -Export All

            Description:
            Returns a list of the all Visual C++ Redistributables from the embedded manifest, including unsupported versions.

        .EXAMPLE
            Get-VcList -Export Supported

            Description:
            Returns the full list of supported Visual C++ Redistributables from the embedded manifest. This is the same as running Get-VcList with no parameters.

        .EXAMPLE
            Get-VcList -Export Unsupported | Where-Object { $_.Release -eq "2008" }

            Description:
            Returns the full list of unsupported Visual C++ Redistributables from the embedded manifest and filters for the 2008 versions of the Redistributables.

        .EXAMPLE
            Get-VcList -Release 2013, 2019 -Architecture x86

            Description:
            Returns the 2013 and 2019 x86 Visual C++ Redistributables from the list of supported Redistributables in the embedded manifest.

        .EXAMPLE
            Get-VcList -Path ".\VisualCRedistributables.json"

            Description:
            Returns a list of the Visual C++ Redistributables listed in the external manifest VisualCRedistributables.json.
    #>

    [OutputType([System.Management.Automation.PSObject])]
    [CmdletBinding(DefaultParameterSetName = 'Manifest', HelpURI = "https://stealthpuppy.com/VcRedist/get-vclist.html")]
    Param (
        [Parameter(Mandatory = $False, Position = 0, ParameterSetName = 'Manifest')]
        [ValidateSet('2005', '2008', '2010', '2012', '2013', '2015', '2017', '2019')]
        [System.String[]] $Release = @("2010", "2012", "2013", "2019"),

        [Parameter(Mandatory = $False, Position = 1, ParameterSetName = 'Manifest')]
        [ValidateSet('x86', 'x64')]
        [System.String[]] $Architecture = @("x86", "x64"),

        [Parameter(Mandatory = $False, Position = 2, ValueFromPipeline, ParameterSetName = 'Manifest')]
        [ValidateNotNull()]
        [ValidateScript( { If (Test-Path -Path $_ -PathType 'Leaf' -ErrorAction "SilentlyContinue") { $True } Else { Throw "Cannot find file $_" } })]
        [Alias("Xml")]
        [System.String] $Path = (Join-Path -Path $MyInvocation.MyCommand.Module.ModuleBase -ChildPath "VisualCRedistributables.json"),

        [Parameter(Mandatory = $False, Position = 0, ParameterSetName = 'Export')]
        [ValidateSet('Supported', 'All', 'Unsupported')]
        [System.String] $Export = "Supported"
    )

    Process {
        try {
            Write-Verbose -Message "$($MyInvocation.MyCommand): Reading JSON document [$Path]."
            $content = Get-Content -Raw -Path $Path -ErrorAction "SilentlyContinue"
        }
        catch [System.Exception] {
            Write-Warning -Message "$($MyInvocation.MyCommand): Unable to read manifest [$Path]."
            Throw $_.Exception.Message
        }
        try {
            # Convert the JSON content to an object
            Write-Verbose -Message "$($MyInvocation.MyCommand): Converting JSON."
            $json = $content | ConvertFrom-Json -ErrorAction "SilentlyContinue"
        }
        catch [System.Exception] {
            Write-Warning -Message "$($MyInvocation.MyCommand): Unable to convert manifest JSON to required object. Please validate the input manifest."
            Throw $_.Exception.Message
        }

        If ($Null -ne $json) {
            If ($PSBoundParameters.ContainsKey('Export')) {
                Switch ($Export) {
                    "Supported" {
                        Write-Verbose -Message "$($MyInvocation.MyCommand): Exporting supported VcRedists."
                        [System.Management.Automation.PSObject] $output = $json.Supported
                    }
                    "All" {
                        Write-Verbose -Message "$($MyInvocation.MyCommand): Exporting all VcRedists."
                        Write-Warning -Message "$($MyInvocation.MyCommand): This list includes unsupported Visual C++ Redistributables."
                        [System.Management.Automation.PSObject] $output = $json.Supported + $json.Unsupported
                    }
                    "Unsupported" {
                        Write-Verbose -Message "$($MyInvocation.MyCommand): Exporting unsupported VcRedists."
                        Write-Warning -Message "$($MyInvocation.MyCommand): This list includes unsupported Visual C++ Redistributables."
                        [System.Management.Automation.PSObject] $output = $json.Unsupported
                    }
                }
            }
            Else {
                # Filter the list for architecture and release
                If ($json | Get-Member -Name "Supported" -MemberType "Properties") {
                    [System.Management.Automation.PSObject] $supported = $json.Supported
                }
                Else {
                    [System.Management.Automation.PSObject] $supported = $json
                }
                [System.Management.Automation.PSObject] $output = $supported | Where-Object { $Release -contains $_.Release } | `
                    Where-Object { $Architecture -contains $_.Architecture }
            }

            # Get the count of items in $output; Because it's a PSCustomObject we can't use the .count property so need to measure th object
            # Grab a NoteProperty and count how many of those there are to get the object count
            try {
                $Property = $output | Get-Member -ErrorAction "SilentlyContinue" | Where-Object { $_.MemberType -eq "NoteProperty" } | Select-Object -ExpandProperty "Name" | Select-Object -First 1
                $Count = $output.$Property.Count - 1
            }
            catch {
                $Count = 0
            }

            # Replace strings in the manifest
            Write-Verbose -Message "$($MyInvocation.MyCommand): Object count is: $($output.$Property.Count)."
            For ($i = 0; $i -le $Count; $i++) {
                try {
                    $output[$i].SilentUninstall = $output[$i].SilentUninstall `
                        -replace "#Installer", $(Split-Path -Path $output[$i].Download -Leaf) `
                        -replace "#ProductCode", $output[$i].ProductCode
                }
                catch {
                    Write-Verbose -Message "Failed to replace strings in: $($json[$i].Name)."
                }
            }
            Write-Output -InputObject $output
        }
    }
}