Find-ChocoApp.ps1


<#PSScriptInfo
 
.VERSION 1.0.2
 
.GUID d8d8b0bc-d1dd-4138-9166-dab64a38e8f6
 
.AUTHOR Robert Bleattler
 
.COMPANYNAME Coast Technologies LLC
 
.COPYRIGHT Coast Technologies LLC 2022
 
.TAGS choco chocolatey
 
.LICENSEURI https://gist.github.com/rbleattler/3cdac104214bcab3d3c1e7d5ee29dc77#file-license
 
.PROJECTURI https://gist.github.com/rbleattler/3cdac104214bcab3d3c1e7d5ee29dc77
 
.ICONURI
 
.EXTERNALMODULEDEPENDENCIES
 
.REQUIREDSCRIPTS
 
.EXTERNALSCRIPTDEPENDENCIES
 
.RELEASENOTES
 
 
.PRIVATEDATA
 
#>


<#
 
.DESCRIPTION
 Imports the Find-ChocoApp function; a command which will search chocolatey for a given package, and return a PowerShell object.
 
#>
 
Param()


function Find-ChocoApp {
    <#
.LINK
    https://gist.github.com/rbleattler/3cdac104214bcab3d3c1e7d5ee29dc77#file-find-chocoapp-ps1
.SYNOPSIS
    A command which will search chocolatey for a given package, and return a PowerShell object.
.DESCRIPTION
    A command which will search chocolatey for a given package, and return a PowerShell object.
    The output can be detailed or terse (default).
.PARAMETER Name
    The name of the package to search for.
.PARAMETER Version
    Specifies a specific version to search for
.PARAMETER IncludePending
    Specifies whether to include pending (un-approved) chocolatey packages
.PARAMETER Detailed
    Output detailed package information
.PARAMETER AsJson
    Specifies to output results as json
.EXAMPLE
    C:\PS> Find-ChocoApp -Name nvm -Detailed -IncludePending
    Name : nvm
    Version : 1.1.9
    Status : Pending
    Title : NVM
    Published : 1/1/1900
    Package testing status : Passing : 2/12/2022 7:54:42 PM
    Number of Downloads : 250506
    Downloads for this version : 24
    Chocolatey Package Source : https://github.com/asheroto/ChocolateyPackages/tree/mast
                                er/nvm
    Package Checksum : 'LgW7K3QHx8dNMo3a2OYDo1B6L7J+oDZg0Tozee/k0dg0XQhaNh1A6r8
                                KPuFF7xvc3D6WdD2oHbbCGfXcEMSYXA==' (SHA512)
    Tags : {nvm, node, nodejs, node.js…}
    Software Site : https://github.com/coreybutler/nvm-windows
    Software License : https://github.com/coreybutler/nvm-windows/blob/master/L
                                ICENSE
    Summary : A node.js version management utility for Windows.
    Description : Manage multiple installations of node.js on a Windows
                                computer.
 
    Name : nvm
    Version : 1.1.5
    Status : Approved
    Title : NVM
    Published : 1/1/1900
    Package testing status : Passing : 2/12/2022 7:54:42 PM
    Number of Downloads : 250506
    Downloads for this version : 24
    Chocolatey Package Source : https://github.com/asheroto/ChocolateyPackages/tree/mast
                                er/nvm
    Package Checksum : 'LgW7K3QHx8dNMo3a2OYDo1B6L7J+oDZg0Tozee/k0dg0XQhaNh1A6r8
                                KPuFF7xvc3D6WdD2oHbbCGfXcEMSYXA==' (SHA512)
    Tags : {nvm, node, nodejs, node.js…}
    Software Site : https://github.com/coreybutler/nvm-windows
    Software License : https://github.com/coreybutler/nvm-windows/blob/master/L
                                ICENSE
    Summary : A node.js version management utility for Windows.
    Description : Manage multiple installations of node.js on a Windows
                                computer.
 
    Name : nvm
    Version : 1.1.1
    Status : Approved
    Title : NVM
    Published : 1/1/1900
    Package testing status : Passing : 2/12/2022 7:54:42 PM
    Number of Downloads : 250506
    Downloads for this version : 24
    Chocolatey Package Source : https://github.com/asheroto/ChocolateyPackages/tree/mast
                                er/nvm
    Package Checksum : 'LgW7K3QHx8dNMo3a2OYDo1B6L7J+oDZg0Tozee/k0dg0XQhaNh1A6r8
                                KPuFF7xvc3D6WdD2oHbbCGfXcEMSYXA==' (SHA512)
    Tags : {nvm, node, nodejs, node.js…}
    Software Site : https://github.com/coreybutler/nvm-windows
    Software License : https://github.com/coreybutler/nvm-windows/blob/master/L
                                ICENSE
    Summary : A node.js version management utility for Windows.
    Description : Manage multiple installations of node.js on a Windows
                                computer.
 
.EXAMPLE
    C:\PS> Find-ChocoApp -Name nvm
 
    Name Version Status
    ---- ------- ------
    nvm 1.1.5 Approved
    nvm 1.1.1 Approved
.EXAMPLE
    C:\PS> Find-ChocoApp -Name nvm -Version 1.1.9 -IncludePending
 
    Name Version Status
    ---- ------- ------
    nvm 1.1.9 Pending
.EXAMPLE
    C:\PS> Find-ChocoApp -Name nvm -Version 1.1.9 -IncludePending -AsJson
 
    {
        "Name": "nvm",
        "Version": "1.1.9",
        "Status": "Pending"
    }
.EXAMPLE
    C:\PS> Find-ChocoApp -Name nvm -Version 1.1.9 -IncludePending -Detailed -AsJson
 
    {
        "Name": "nvm",
        "Version": "1.1.9",
        "Status": "Pending",
        "Title": "NVM",
        "Published": "1/1/1900",
        "Package testing status": {
            "Status": "Passing",
            "Date": "2022-02-12T19:54:42"
        },
        "Number of Downloads": "250506",
        "Downloads for this version": "24",
        "Chocolatey Package Source": "https://github.com/asheroto/ChocolateyPackages/tree/master/nvm",
        "Package Checksum": "'LgW7K3QHx8dNMo3a2OYDo1B6L7J+oDZg0Tozee/k0dg0XQhaNh1A6r8KPuFF7xvc3D6WdD2oHbbCGfXcEMSYXA==' (SHA512)",
        "Tags": [
            "nvm",
            "node",
            "nodejs",
            "node.js",
            "version",
            "management",
            "windows",
            "admin"
        ],
        "Software Site": "https://github.com/coreybutler/nvm-windows",
        "Software License": "https://github.com/coreybutler/nvm-windows/blob/master/LICENSE",
        "Summary": "A node.js version management utility for Windows.",
        "Description": "Manage multiple installations of node.js on a Windows computer."
    }
 
.OUTPUTS
    [Object[]]
.NOTES
    Designed with PowerShell in mind
.FUNCTIONALITY
    Chcolatey Handler
#>

    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [string]
        $Name,
        [Parameter()]
        [version]
        $Version,
        [Parameter()]
        [switch]
        $IncludePending,
        [Parameter()]
        [switch]
        $Detailed,
        [Parameter()]
        [switch]
        $AsJson
    )
    begin {
        Write-Debug "Enter [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
        $ChocoTest = try { & choco 3>$null 2>$null }catch {}
        if ($null -eq $ChocoTest) {
            Write-Warning "Chocolatey is not installed!"
            break 1;
        }
    }
    process {
        $ChocoApps = choco find $Name --all -e
        $ChocoApps = Trim-ChocoResults $ChocoApps
        $PackageCount = $ChocoApps[-1][0]
        if ($PackageCount -gt 0) {
            $ChocoApps = $ChocoApps | ForEach-Object { 
                $Out = ConvertFrom-Csv $_ -Header 'Name', 'Version', 'Status' -Delimiter ' ' 
                if ([string]::IsNullOrWhiteSpace($Out.Status)) {
                    try { $Out.Status = 'Pending' } catch {}
                }
                if ($Out.Status -eq '[Approved]') {
                    $Out.Status = 'Approved'
                }
                $Out
            }
            if (!$IncludePending) {
                $ChocoApps = $ChocoApps.Where{ $PSItem.Status -eq 'Approved' }
            }
        
            if ($null -ne $Version) {
                Write-Debug "Looking for version $Version"
                $ChocoApps = ($ChocoApps.Where{ $PSItem.Name -eq $Name -and $PSItem.Version -like $Version.ToString() })
            } else {
                $ChocoApps = $ChocoApps.Where{ $PSItem.Name -eq $Name } | Sort-Object -Property Version -Descending
            }
            
            Write-Debug "Detailed : $Detailed"
            if ($Detailed) {
                Write-Debug "Building Detailed Output... $($ChocoApps.Count)"
                $NewChocoApps = [System.Collections.Generic.List[object]]::new()
                $ChocoApps.ForEach{
                    $ParsedDetail = Parse-ChocoDetail -InputObject $PSItem
                    Write-Debug "Parsed Detail : "
                    Write-Debug "$($ParsedDetail | ConvertTo-Json)"
                    $NewChocoApps.Add($ParsedDetail)
                }
                $ChocoApps = $NewChocoApps
            } 
        }
    }
    end {
        if ($AsJson) {
            $ChocoApps | ConvertTo-Json
        } else {
            $ChocoApps
        }
        Write-Debug "Exit [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
    }
}

function Parse-ChocoDetail {
    param(
        $InputObject
    )
    $RawDetail = (choco find $InputObject.name --version $InputObject.version -e --detail) -join "`n"
    $RawDetail = $RawDetail[$RawDetail.IndexOf('Title:')..($RawDetail.Length - 1)] -join ''

    $SplitInput = $InputString.Split("`n")
    for ($i = 0; $i -lt $($SplitInput.Count - 1); $i++) {
        $ProcessItem = $SplitInput[$i]
        Write-Debug "ProcessItem $ProcessItem"
        if ($ProcessItem -like "*|*") {
            Write-Debug "ProcessItem Like *|*"
            $ItemDefinitionRaw = $ProcessItem.Split('|')
            Write-Debug "ItemDefinitionRaw = $ItemDefinitionRaw"
            $ItemDefinitionRaw.ForEach{
                $RawSplit = $PSItem.Split(':').Trim()
                $InputObject | Add-Member -MemberType NoteProperty -Name $($RawSplit[0]).Trim() -Value $($RawSplit[1]).Trim() -Force
            }
        } elseif ($ProcessItem -like "*:*") {
            $RawSplit = $ProcessItem.Split(':', 2).Trim()
            $Name = $($RawSplit[0]).Trim()
            $Value = $($RawSplit[1]).Trim()
            if ($Name -eq 'Tags') {
                $Value = $Value.Split(' ')
            }
            if ($Name -eq 'Package testing status') {
                $Value = [PSCustomObject]@{
                    Status = $Value.Split(' ')[0]
                    Date   = [DateTime]::Parse($Value.Split("on")[1].Trim('.'))
                }
                $Value | Add-Member -Name ToString -MemberType ScriptMethod -Value {
                    $OutString = '{0} : {1}' -f $this.Status, $this.Date
                    $OutString
                } -Force
            }
            $InputObject | Add-Member -MemberType NoteProperty -Name $Name -Value $Value
        }
    }
    $InputObject
}

function Trim-ChocoResults {
    Param(
        $ChocoResults
    )
    begin {
        Write-Debug "Enter [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
        $PSBoundParameters.Keys.ForEach{
            if ($PSBoundParameters.PSItem -is [string]) {
                Write-Debug "$_ : $($PSBoundParameters.Item($_))"
            } else {
                Write-Debug "$_ : $($PSBoundParameters.Item($_).GetType())"
            }
        }
        $ChocoVersion = choco --version
        $ChocoMessages = @("A license was found for a licensed version of Chocolatey, but is invalid:", "Could not validate existing license", "Chocolatey v$ChocoVersion")
        $PackageCount = $ChocoResults[-1][0]
        $PackageCountMessage = $ChocoResults.Where{ $PSItem -like "*packages found*" }
        Write-Debug "Package Count = $PackageCount"
        Write-Debug "PackageCountMessage = $PackageCountMessage"
        $StartIndex = 0
        
    }
    process {
        $ChocoResults = $ChocoResults.Where{ 
            $ThisItem = $PSItem
            -not [string]::IsNullOrWhiteSpace($ThisItem) `
                -and ($ThisItem -notlike "*$($ChocoMessages[0])*" -and $ThisItem -notlike "*$($ChocoMessages[1])*")
        }
        $ChocoVersionLine = $ChocoResults.Where{ $PSItem -eq $ChocoMessages[-1] }
        $StartIndex = $ChocoResults.IndexOf($ChocoVersionLine) + 1
        
        $EndIndex = ($ChocoResults.IndexOf($ChocoResults.Where{ $PSItem -eq $PackageCountMessage }) - 1)
        
    }
    end {
        $ChocoResults[$StartIndex..$EndIndex]
        Write-Debug "Exit [$($PSCmdlet.MyInvocation.MyCommand.Name)]..."
    }
}