SifHelper.psm1

#Requires -RunAsAdministrator
#Requires -Modules PKI,WebAdministration

Set-StrictMode -Version Latest

# Pass verbose on if required
$verboseSetting = $false
if ($PSBoundParameters.ContainsKey('Verbose')) {
    $verboseSetting = $PSBoundParameters["Verbose"]
}

$whatifSetting = $false
if ($PSBoundParameters.ContainsKey('WhatIf')) {
    $whatifSetting = $PSBoundParameters["WhatIf"]
}

$DestinationFolder = Split-Path $PSScriptRoot -Parent
$filename = "SifHelper.{0:yyMMdd}" -f (Get-Date)

$counter = 2
$fullPath = Join-Path $DestinationFolder "$filename.log"
while (Test-Path $fullPath) {
    $fullPath = Join-Path $DestinationFolder "$filename ($($counter)).log"
    $counter++
}

Start-Transcript -Path $fullpath -IncludeInvocationHeader

try {

    $nugetPackageProvider = Get-PackageProvider -Name NuGet -Force -Verbose:$verboseSetting -ErrorAction Stop
    if (!$nugetPackageProvider) {
        Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force -Confirm:$false -Verbose:$verboseSetting
    }

    # TODO remove the module imports for PKI and WebAdministration.. should be done in module .PSD1
    if (!(Get-Module PKI)) { Import-Module PKI -ErrorAction Stop -Verbose:$verboseSetting }

    if (!(Get-Module WebAdministration) -or (!(Get-PSDrive IIS -ErrorAction SilentlyContinue -Verbose:$verboseSetting))) {
        Get-Module WebAdministration | Remove-Module -Force -Confirm:$false
        Import-Module WebAdministration -ErrorAction Stop -Force -Verbose:$verboseSetting
    }

    $SitecoreGalleryUrl = "https://sitecore.myget.org/F/sc-powershell/api/v2"

    if (-not(Get-PSRepository -name SitecoreGallery)) {
        Register-PSRepository -Name SitecoreGallery -SourceLocation $SitecoreGalleryUrl -InstallationPolicy Trusted -Verbose:$verboseSetting
    }

    ("SitecoreInstallFramework", "SqlServer") | ForEach-Object -Verbose:$verboseSetting {

        if ((Get-InstalledModule -Name $_ -Verbose:$verboseSetting -ErrorAction SilentlyContinue)) {
            Update-Module $_ -Confirm:$false -Verbose:$verboseSetting -Force
        }
        else {
            Install-Module $_ -Confirm:$false -AllowClobber -SkipPublisherCheck -Force -Verbose:$verboseSetting
        }

        if (!(Get-Module $_)) {
            Write-Warning "Module '$_' is not loaded!"
            Import-Module $_ -Force -Verbose:$verboseSetting
        }
    }

    $scriptRoot = Split-Path -Parent $MyInvocation.MyCommand.Path

    $privates = Join-Path -Path $scriptRoot -ChildPath 'Private'
    $publics = Join-Path -Path $scriptRoot -ChildPath 'Public'

    Get-ChildItem -Path $privates -Filter '*.psm1' |
        ForEach-Object {
        Import-Module $_.FullName -Force -Verbose:$verboseSetting
    }

    Get-ChildItem -Path $publics -Filter '*.psm1;*.ps1' |
        ForEach-Object {
        Import-Module $_.FullName -Global -Force -Verbose:$verboseSetting
    }

    # Dot source to scope
    # Private must be sourced first - usage in public functions during load
    ('Private' , 'Public') | ForEach-Object {

        Get-ChildItem -Path (Join-Path $scriptRoot $_) -Include *.ps1 -Exclude *.Tests.ps1 -File -Recurse |
            ForEach-Object {
            try {
                . $_.FullName
            }
            catch {
                Write-Warning $_.Exception.Message
            }
        }
    }

    # Export Public functions from the module
    Get-ChildItem (Join-Path $scriptRoot Public) -Include *.ps1 -Exclude *.Tests.ps1 -File -Recurse |
        ForEach-Object {
        Export-ModuleMember -Function $_.BaseName
    }

    $dacFxBinPath = $null

    function Get-DacFxPath {

        function Install-DacFx {

            Write-Verbose "Installing DacFx 17.3"

            function silentInstallMsi {
                param (
                    [ValidateScript( { Test-Path $_ -IsValid })]
                    [string]$path
                )
                $DataStamp = get-date -Format yyyyMMddTHHmmss
                $file = get-item $path
                $logFile = '{0}-{1}.log' -f $file.fullname, $DataStamp
                $MSIArguments = @(
                    "/i"
                    ('"{0}"' -f $file.fullname)
                    "/qn"
                    "/norestart"
                    "/L*v"
                    $logFile
                )
                Start-Process "msiexec.exe" -ArgumentList $MSIArguments -Wait -NoNewWindow
            }

            $sqlClrTypes = 'https://download.microsoft.com/download/C/0/2/C02DBE78-3265-4779-9AE1-634A4BF1CD6E/EN/SQL140/amd64/SQLSysClrTypes.msi'
            $sqlClrTypesFilename = Split-Path $sqlClrTypes -Leaf
            $sqlClrTypesTempFile = Join-Path $env:TEMP $sqlClrTypesFilename

            $dacFx173 = 'https://download.microsoft.com/download/3/7/F/37F3C5CE-E96B-41AC-B361-27735365AA16/EN/x64/DacFramework.msi'
            $dacFx173Filename = Split-Path $dacFx173 -Leaf
            $dacFx173TempFile = Join-Path $env:TEMP $dacFx173Filename

            Start-BitsTransfer -Source $sqlClrTypes, $dacFx173 -Destination $sqlClrTypesTempFile, $dacFx173TempFile

            # install sql clr types
            silentInstallMsi -path $sqlClrTypesTempFile

            # install dac fx 17.3
            silentInstallMsi -path $dacFx173TempFile

            Write-Verbose "Completed DacFx 17.3 installation."
        }


        $dacVersion = $null

        $sqlPackagePath = Get-SQLPackagePath

        if ($sqlPackagePath) {
            $dacFxBinPath = Split-Path -Path $sqlPackagePath -Parent
        }

        if ($dacFxBinPath) {
            $dacFxPath = Split-Path $dacFxBinPath -Parent
            $dacVersionPath = Split-Path $dacFxPath -Parent
            $dacVersion = Split-Path $dacVersionPath -Leaf
        }

        if (!$dacVersion -or ($dacVersion -and $dacVersion -ne 140)) {

            Install-DacFx

        }
    }

    $dacFxBinPath = Get-DacFxPath

    $chocoInstallScript = (New-Object System.Net.WebClient).DownloadString('https://chocolatey.org/install.ps1')
    Set-ExecutionPolicy Bypass -Scope Process -Force
    Invoke-Expression $chocoInstallScript
    choco upgrade webdeploy -y -f

    $msDeployKeyName = 'HKLM:\SOFTWARE\Microsoft\IIS Extensions\MSDeploy\3'
    $msDeployKeyProperties = Get-ItemProperty -Path $msDeployKeyName -ErrorAction SilentlyContinue

    if ($msDeployKeyProperties) {

        $dacFxPathKeyProp = $msDeployKeyProperties | Select-Object -ExpandProperty DacFxPath -ErrorAction SilentlyContinue

        if (!$dacFxPathKeyProp) {
            New-ItemProperty -Path $msDeployKeyName -Name 'DacFxPath' -Value $dacFxBinPath -Force
        }
        else {
            Set-ItemProperty -Path $msDeployKeyName -Name 'DacFxPath' -Value $dacFxBinPath -Force
        }

        $dacFxDependenciesPathKeyProp = $msDeployKeyProperties | Select-Object -ExpandProperty DacFxDependenciesPath -ErrorAction SilentlyContinue

        if (!$dacFxDependenciesPathKeyProp) {
            New-ItemProperty -Path $msDeployKeyName -Name 'DacFxDependenciesPath' -Value $dacFxBinPath -Force
        }
        else {
            Set-ItemProperty -Path $msDeployKeyName -Name 'DacFxDependenciesPath' -Value $dacFxBinPath -Force
        }
    }
    else {
        Write-Warning 'Could not find MSDeploy in registry.'
    }

    choco upgrade urlrewrite -y -f

}
catch {
    Write-Error $_
    throw
}
finally {
    Stop-Transcript
}