PSDependScripts/Chocolatey.ps1

<#
    .SYNOPSIS
        Installs a Chocolatey package a repository.

    .DESCRIPTION
        Installs a package from a Chocolatey repository like Chocolatey.org.

        Relevant Dependency metadata:
            Name: The name of the package
            Version: Used to identify existing installs meeting this criteria. Defaults to 'latest'
            Source: Source Uri. Defaults to https://chocolatey.org/api/v2/

    .PARAMETER Force
        If specified and the package is already installed, force the install again.

    .PARAMETER PSDependAction
        Test, or Install the package. Defaults to Install

        Test: Return true or false on whether the dependency is in place
        Install: Install the dependency

    .EXAMPLE

        @{
            'git' = @{
                DependencyType = 'Chocolatey'
                Version = '2.0.2'
            }
        }

        # Install version 2.0.2 of git via Chocolatey.org

    .EXAMPLE

        @{
            'git' = @{
                DependencyType = 'Chocolatey'
                Source = 'https://feed.mycompany.com'
            }
        }

        # Install the latest version of git from the Chocolatey feed at https://feed.mycompany.com

    .EXAMPLE

        @{
            PSDependOptions = @{
                DependencyType = 'Chocolatey'
            }
            'git.portable' = @{
                Version = 'latest'
                Parameters = @{
                    Force = $true
                }
            }
            'lessmsi' = 'latest'
            'putty' = 'latest'
        }

        # Installs the list of Chocolatey packages from Chocolatey.org using the Global PSDependOptions to limit repetition.

#>

[CmdletBinding()]
param(
    [PSTypeName('PSDepend.Dependency')]
    [psobject[]]$Dependency,

    [switch]$Force,

    [string]$ChocoInstallScriptUrl = 'https://chocolatey.org/install.ps1',

    [ValidateSet('Test', 'Install')]
    [string[]]$PSDependAction = @('Install')
)

function Get-ChocoInstalledPackage
{
    [CmdletBinding()]
    param (
        [string]$Name
    )

    $chocoParams = @('list', "$Name", '--limit-output', '--exact', '--local-only')
    Invoke-ExternalCommand -Command 'choco.exe' -Arguments $chocoParams -PassThru | ConvertFrom-Csv -Header 'Name', 'Version' -Delimiter "|"
}

function Get-ChocoLatestPackage
{
    [CmdletBinding()]
    param (
        [string]$Name,

        [string]$Source,

        [Management.Automation.PSCredential]$Credential
    )

    $chocoParams = @('list', "$Name", '--limit-output', '--exact')
    if ($Source)
    {
        $chocoParams += "--source='$Source'"
    }

    if ($Credential)
    {
        $username = $credential.UserName
        $password = $credential.GetNetworkCredential().Password
        $chocoParams += "--username='$username'"
        $chocoParams += "--password='$password'"
    }

    Invoke-ExternalCommand -Command 'choco.exe' -Arguments $chocoParams -PassThru | ConvertFrom-Csv -Header 'Name', 'Version' -Delimiter "|"
}

function Invoke-ChocoInstallPackage
{
    [CmdletBinding()]
    param (
        [string]$Name,

        [string]$Version,

        [string]$Source,

        [switch]$Force,

        [Management.Automation.PSCredential]$Credential
    )

    $chocoParams = @('upgrade', "$Name", '--limit-output', '--exact', '--no-progress', '--allow-downgrade')
    if ($Force.IsPresent)
    {
        $chocoParams += "--force"
    }

    if ($Source)
    {
        $chocoParams += "--source='$Source'"
    }

    if ($Version -and $Version -ne 'latest' -and $Version -ne '')
    {
        $chocoParams += "--version='$Version'"
    }

    if ($Credential)
    {
        $username = $credential.UserName
        $password = $credential.GetNetworkCredential().Password
        $chocoParams += "--username='$username'"
        $chocoParams += "--password='$password'"
    }

    Invoke-ExternalCommand -Command 'choco.exe' -Arguments $chocoParams
}

# Extract data from Dependency
$Name = $Dependency.Name
if (-not $Name)
{
    $Name = $Dependency.DependencyName
}

$Version = $Dependency.Version
if (-not $Dependency.Version -or $Version -eq '')
{
    $Version = 'latest'
}

$Source = $Dependency.Source
if (-not $Dependency.Source -or $Source -eq '')
{
    $Source = 'https://chocolatey.org/api/v2/'
}

$Credential = $Dependency.Credential

if (-not (Get-Command -Name 'choco.exe' -ErrorAction SilentlyContinue)) {
    Write-Verbose "Chocolatey is not installed. Installing from [$ChocoInstallScriptUrl]"
    # download and run the Chocolatey script
    # Add TLS 1.2 support
    [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol -bor [Net.SecurityProtocolType]::Tls12

    do
    {
        $scriptPath = Join-Path -Path $env:TEMP -ChildPath ("{0}.ps1" -f [GUID]::NewGuid().ToString())
    } while (Test-Path -Path $scriptPath)

    try
    {
        Invoke-WebRequest -UseBasicParsing -Uri $ChocoInstallScriptUrl -OutFile $scriptPath
        & $scriptPath
    }
    catch
    {
        throw "Unable to install Chocolatey from '$scriptUrl'."
    }
}

# if this is a forced install we don't need to check anything, just install the package version requested
if ($Force.IsPresent -and $PSDependAction -contains 'Install')
{
    $params = @{
        Name    = $Name
        Version = $Version
        Source  = $Source
        Force   = $Force.IsPresent
    }

    if ($Credential)
    {
        $params.Credential = $Credential
    }

    Write-Verbose "Forced install of Chocolatey package [$Name] from Chocolatey source [$Source] with Version [$Version]"
    Invoke-ChocoInstallPackage @params

    return
}

# get the package if it is installed
Write-Verbose "Getting package [$Name] version, if it is installed."
$existingVersion = (Get-ChocoInstalledPackage -Name $Name).Version
if ($existingVersion)
{
    Write-Verbose "Found package [$Name] installed with version [$Version]."
}
else {
    Write-Verbose "Package [$Name] not installed."
}

# Version latest requested, and equal to current
if ($Version -ne 'latest' -and $Version -eq $existingVersion)
{
    Write-Verbose "You have the requested version [$Version] of [$Name]"
    if($PSDependAction -contains 'Test')
    {
        return $true
    }

    return
}

# get the latest version from the source
$repoParams = @{
    Name   = $Name
    Source = $Source
}
if ($Credential)
{
    $repoParams.Credential = Credential
}

Write-verbose "Getting latest package [$Name] version from source [$Source]."
$repositoryVersion = (Get-ChocoLatestPackage @repoParams).Version
if ($repositoryVersion)
{
    Write-Verbose "Found package [$Name] version [$Version] on source [$Source]."
}
else
{
    Write-Verbose "Package [$Name] not found on source [$Source]. Nothing more can be done."
    return  # cannot continue
}

# If the version in the remote repository is less than or equal to the version installed, then we have the latest already
if ($Version -eq 'latest' -and ([System.Version]$repositoryVersion -le [System.Version]$existingVersion))
{
    Write-Verbose "You have the latest version of [$Name], with installed version [$existingVersion] and Source version [$repositoryVersion]"
    if($PSDependAction -contains 'Test')
    {
        return $true
    }

    return
}

# if we get here then we do not have the latest version installed and that is what has been requested
Write-Verbose "You do not have the version requested of [$Name]: Requested version [$Version], existing version [$existingVersion], available version [$repositoryVersion]."
if ($PSDependAction -contains 'Install')
{
    $params = @{
        Name    = $Name
        Version = $Version
        Source  = $Source
        Force   = $Force.IsPresent
    }

    if ($Credential)
    {
        $params.Credential = $Credential
    }

    Invoke-ChocoInstallPackage @params
}
elseif ($PSDependAction -contains 'Test' -and $PSDependAction.count -eq 1)
{
    return $false
}