PSDependScripts/Package.ps1

<#
    .SYNOPSIS
        EXPERIMENTAL: Installs a package using the PackageManagement module
 
    .DESCRIPTION
        EXPERIMENTAL: Installs a package using the PackageManagement module
 
        Relevant Dependency metadata:
            Name: The name for this Package
            Version: Used to identify existing installs meeting this criteria, and as RequiredVersion for installation. Defaults to 'latest'
            Target: Used as 'Scope' for PowerShellGet provider, Destination for Nuget provider
            Source: Package source to use (Get-PackageSource, Register-PackageSource)
            Parameters: Every parameter you specify is splatted against Install-Package
 
        If you don't have the Nuget package provider, we install it for you
 
    .PARAMETER ProviderName
        Optionally specify the Provider name to use (Get-PackageProvider, Register-PackageProvider)
 
    .PARAMETER PSDependAction
        Test, Install, or Import the module. Defaults to Install
 
        Test: Return true or false on whether the dependency is in place
        Install: Install the dependency
 
    .EXAMPLE
        @{
            jquery = @{
                DependencyType = 'Package'
                Target = 'C:\MyProject'
                Source = 'nuget.org'
            }
        }
 
        # Install jquery from the nuget.org PackageSource to C:\MyProject
        # IMPORTANT: Only certain providers support specifying a target destination
 
    .EXAMPLE
        @{
            jquery = @{
                DependencyType = 'Package'
                Source = 'https://my.internal.nuget.feed/api'
                Target = 'C:\MyProject'
                Parameters = @{
                    ProviderName = 'nuget'
                }
            }
        }
 
        # Install jquery from my internal nuget feed to C:\MyProject
 
#>

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

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

    [String]$ProviderName
)

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

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

$PackageSources = @( Get-PackageSource )
if ($PackageSources.Name -notcontains $Source -and -not $PSBoundParameters.ContainsKey('ProviderName')) {
    Write-Error "PackageSource [$Source] is not valid. Valid sources:`n$($PackageSources.ProviderName | Out-String)"
    return
}

$PackageProviders = @( Get-PackageProvider )
if ($PSBoundParameters.ContainsKey('ProviderName') -and $PackageProviders.Name -notcontains $ProviderName) {
    Write-Error "ProviderName [$ProviderName] is not valid. Valid sources:`n$($PackageProviders.Name | Out-String)"
    return
}

Write-Verbose -Message "Getting dependency [$name] from Package source [$Source]"

if ($PSBoundParameters.ContainsKey('ProviderName')) {
    $ThisProvider = $ProviderName
}
else { # Pick providername from this packagesource
    $ThisProvider = $PackageSources | Where-Object { $_.Name -eq $Source } | Select-Object -ExpandProperty ProviderName
}

$GetParam = @{
    Name         = $Name
    ProviderName = $ThisProvider
    ErrorAction  = 'SilentlyContinue'
}
$InstallParam = @{
    Name   = $Name
    Source = $Source
    Force  = $True
}
if ($Version -notlike 'latest') {
    $GetParam.add('RequiredVersion', $Version)
    $InstallParam.add('RequiredVersion', $Version)
}

# Parse target for PowerShellGet
If ($ThisProvider -eq 'PowerShellGet') {
    $ValidScope = 'CurrentUser', 'AllUsers'
    if (-not $Dependency.Target) {
        $Scope = 'AllUsers'
    }
    else {
        $Scope = $Dependency.Target
    }
    if ($ValidScope -contains $Scope) {
        $InstallParam.Add('Scope', $Scope)
    }
}
# Parse target for Nuget
if ($ThisProvider -eq 'Nuget') {
    if (-not $Dependency.Target) {
        throw 'Nuget provider requires that you specify a target destination. Use the dependency Target for this.'
    }
    $GetParam.Add('Destination', $Dependency.Target)
    $InstallParam.Add('Destination', $Dependency.Target)
}


# Add arbitrary keys to support DynamicOptions...
if ($Dependency.Parameters.Keys.Count -gt 0) {
    foreach ($Key in $Dependency.Parameters.Keys) {
        if (-not $InstallParam.ContainsKey($Key)) {
            $InstallParam.add($Key, $Dependency.Parameters.$Key)
        }
        else {
            $InstallParam.$Key = $Dependency.Parameters.$Key
        }
    }
}

$Existing = $null
Write-Verbose "Running Get-Package with $($GetParam | Out-String)"
$Existing = Get-Package @GetParam

if ($Existing) {
    Write-Verbose "Found existing package [$Name]"

    if ($Version -and $Version -ne 'latest') {
        $matchedInstall = $Existing | Where-Object { Test-VersionEquality $Version $_.Version } | Select-Object -First 1
        if ($matchedInstall) {
            Write-Verbose "You have the requested version [$Version] of [$Name]"
            if ($PSDependAction -contains 'Test') {
                return $True
            }
            return $null
        }
    }

    # Thanks to Brandon Padgett!
    $ExistingVersion = $Existing | Measure-Object -Property Version -Maximum | Select-Object -ExpandProperty Maximum
    $GetSourceVersion = { Find-Package -Name $Name -Source $Source | Measure-Object -Property Version -Maximum | Select-Object -ExpandProperty Maximum }

    $SourceVersion = (& $GetSourceVersion)
    [System.Version]$parsedExistingVersion = $null
    [System.Version]$parsedSourceVersion = $null
    [System.Management.Automation.SemanticVersion]$parsedExistingSemanticVersion = $null
    [System.Management.Automation.SemanticVersion]$parsedSourceSemanticVersion = $null
    $isSourceVersionLessEquals = if (
        [System.Management.Automation.SemanticVersion]::TryParse([string]$ExistingVersion, [ref]$parsedExistingSemanticVersion) -and
        [System.Management.Automation.SemanticVersion]::TryParse([string]$SourceVersion, [ref]$parsedSourceSemanticVersion)
    ) {
        $parsedSourceSemanticVersion -le $parsedExistingSemanticVersion
    }
    elseif (
        [System.Version]::TryParse([string]$ExistingVersion, [ref]$parsedExistingVersion) -and
        [System.Version]::TryParse([string]$SourceVersion, [ref]$parsedSourceVersion)
    ) {
        $parsedSourceVersion -le $parsedExistingVersion
    }
    else {
        $false
    }

    # latest, and we have latest
    if ( $Version -and
        ($Version -eq 'latest' -or $Version -like '') -and
        $isSourceVersionLessEquals
    ) {
        Write-Verbose "You have the latest version of [$Name], with installed version [$ExistingVersion] and package source version [$SourceVersion]"
        if ($PSDependAction -contains 'Test') {
            return $True
        }
        return $null
    }

    Write-Verbose "Continuing to install [$Name]: Requested version [$version], existing version [$ExistingVersion]"
}

#No dependency found, return false if we're testing alone...
if ( $PSDependAction -contains 'Test' -and $PSDependAction.count -eq 1) {
    return $False
}

if ($PSDependAction -contains 'Install') {
    Write-Verbose "Installing [$Name] with params $($InstallParam | Out-String)"
    Install-Package @InstallParam
}