WTerraform.psm1

$Script:Path = Join-Path -Path $env:LOCALAPPDATA -ChildPath "WTerraform"

New-Alias -Name terraform -Value Invoke-WTerraform
<#
.SYNOPSIS
Get the TerraformVersion saved for current Location
.DESCRIPTION
Convert the crrent Path to ProviderPath and look up the version.
#>

function Get-WTerraformVersion {
    [CmdletBinding()]
    param ()

    begin {
        $currentPath = Convert-Path -Path $PWD
    }

    process {
        $versionMap = Get-WTerraformVersionMap
        return $versionMap."$currentPath"
    }
}
<#
.SYNOPSIS
Load the VersionMap of Folders to Terraform Versions
.DESCRIPTION
Returns Empty if no VersionMap Found
#>

function Get-WTerraformVersionMap {
    [CmdletBinding()]
    param (

    )

    begin {
        $versionMap = @{}
        $cachePath = Join-Path -Path $env:LOCALAPPDATA -ChildPath "WTerraform"
        $versionMapPath = Join-Path -Path $cachePath -ChildPath "versionmap.json"
    }

    process {
        if (Test-Path $versionMapPath) {
            $versionMap = Get-Content -LiteralPath $versionMapPath | ConvertFrom-Json
        }
    }

    end {
        return $versionMap
    }
}
<#
.SYNOPSIS
Downloads the specified Terraform Version if not present
.DESCRIPTION
Downloads and extracts release from hashicorp.
#>

function Install-WTerraform {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [ValidateNotNullOrEmpty()]
        [ValidateScript( {
                $_ -match "^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-((?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*)(?:\.(?:0|[1-9]\d*|\d*[a-zA-Z-][0-9a-zA-Z-]*))*))?(?:\+([0-9a-zA-Z-]+(?:\.[0-9a-zA-Z-]+)*))?$"
            })]
        [String]$Version,
        [Parameter(Mandatory)]
        [ValidateSet("windows")]
        [String]$OS,
        [Parameter(Mandatory)]
        [ValidateSet("amd64", "386")]
        [String]$Architecture
    )

    begin {
        $baseUri = "https://releases.hashicorp.com/terraform"
        $OS = $OS.ToLower()
        $Architecture = $Architecture.ToLower()
        if (-not (Test-Path -Path $Script:Path)) {
            New-Item -Path $script:Path -ItemType Directory
        }
    }

    process {
        $terraformFullVersion = "terraform_$($Version)_$($OS)_$($Architecture)"
        $versionPath = Join-Path -Path $Script:Path -ChildPath $terraformFullVersion
        $exePath = Join-Path -Path $versionPath -ChildPath "terraform.exe"
        if (Test-Path -LiteralPath $exePath) {
            Write-Verbose "$terraformFullVersion already present in $exePath"
        } else {
            $zipPath = Join-Path -Path $Script:Path -ChildPath "$terraformFullVersion.zip"
            Invoke-WebRequest -Uri "$baseUri/$Version/$terraformFullVersion.zip" -OutFile $zipPath
            Expand-Archive -Path $zipPath -DestinationPath $versionPath
        }
    }

    end {
        Remove-Item -Path (Join-Path -Path $Script:Path -ChildPath "*.zip")
    }
}
<#
.SYNOPSIS
Wrapper for terraform
.DESCRIPTION
Runs terraform in version specified by Set-WTerraformVersion.
Parameters are just forwarded to terraform
.Example
Invoke-WTerraform -version
Throws error if no Terraform Version was specified earlier. Otherwise runs command 'terraform -version'
#>

function Invoke-WTerraform {
    $pwdVersion = Get-WTerraformVersion
    $wTerraformPath = Join-Path -Path $env:LOCALAPPDATA -ChildPath "WTerraform"
    if ($pwdVersion) {
        $path =  Join-Path -Path $wTerraformPath -ChildPath $pwdVersion | Join-Path -ChildPath "terraform.exe"
    } elseif ($terraformCommand = Get-Command -Name "terraform.exe" -CommandType Application -ErrorAction SilentlyContinue) {
        $path = $terraformCommand.Source
        if (-not $path.StartsWith($wTerraformPath)) {
            Write-Warning -Message "Using terraform in $path. This is not installed by WTerraform!"
        }
    } else {
        throw "No Version for $pwd specified. Please Run Set-WTerraformVersion."
    }
    if (Test-Path -LiteralPath $path) {
        & $path $args
    } else {
        #TODO: Redownload terraform
        throw "$pwdVersion is not found"
    }
}
<#
.SYNOPSIS
Specify the Terraform Version to use in this folder.
.DESCRIPTION
Checks if specified Version is already present. If not download from Terraform. Also saves the Version for this folder so Invoke-WTerraform will use this Version.
.PARAMETER Version
Version of Terraform to use in this folder
.PARAMETER Global
Set the Version globally (in userPath) instead of local folder
.EXAMPLE
Set-WTerraformVersion -Version 0.14.4
Downloads Terraform Version 0.14.0 if not present and saves the specified version for later use with Invoke-WTerraform
#>

function Set-WTerraformVersion {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory)]
        [String]$Version,
        [switch]$Global
    )

    begin {
        $baseUri = "https://releases.hashicorp.com/terraform"
        $cachePath = Join-Path -Path $env:LOCALAPPDATA -ChildPath "WTerraform"
        $versionMapPath = Join-Path -Path $cachePath -ChildPath "versionmap.json"
        $currentPath = Convert-Path $pwd.Path
        if (-not (Test-Path -LiteralPath $cachePath)) {
            New-Item -Path $cachePath -ItemType Directory
        }
        $terraformFullVersion = "terraform_$($Version)_windows_amd64"
    }

    process {
        Install-WTerraform -Version $Version -OS "windows" -Architecture "amd64"
        if ($Global.IsPresent) {
            $regex = $cachePath
            $regex = [regex]::Escape($regex)
            $regex = $regex + "\\(terraform_\d+\.\d+\.\d+_\w+_\w+);?"
            $versionPath = $cachePath | Join-Path -ChildPath $terraformFullVersion
            $path = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
            if ($path -match $regex) {
                Write-Warning "Set Terraform Version from $($matches[1]) to $terraformFullVersion globally"
                $path = $path -replace $regex, ""
            }
            $path = $path + ";" + $versionPath
            [System.Environment]::SetEnvironmentVariable("Path", $path, [System.EnvironmentVariableTarget]::User)
            $env:Path = [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::Machine) + ";"+  [System.Environment]::GetEnvironmentVariable("Path", [System.EnvironmentVariableTarget]::User)
        } else {
            $versionMap = Get-WTerraformVersionMap
            $oldVersion = Get-WTerraformversion
            $versionChange = $false
            if ($oldVersion -eq $terraformFullVersion) {
                Write-Verbose "Terraform Version for $currentPath is already $oldVersion"
            } elseif ($oldVersion -and $oldVersion -ne $terraformFullVersion) {
                Write-Warning "Set Terraform Version from $oldVersion to $terraformFullVersion for $currentPath"
                $versionMap."$currentPath" = $terraformFullVersion
                $versionChange = $true
            } else {
                Write-Verbose "Set Terraform Version to $terraformFullVersion for $currentPath"
                Add-Member -InputObject $versionMap -MemberType NoteProperty -Name $currentPath -Value $terraformFullVersion
                $versionChange = $true
            }

            if ($true -eq $versionChange) {
                Set-Content -Value ($versionMap | ConvertTo-Json) -LiteralPath $versionMapPath
            }
        }
    }
}