Core/Utils-Module.psm1

$ErrorActionPreference = "Stop"

function RefreshEnvironment {
    $env:Path = [System.Environment]::GetEnvironmentVariable("Path", "Machine") + ";" + [System.Environment]::GetEnvironmentVariable("Path", "User") 
    refreshenv | Out-Null
}

function DownloadAndUnzip {
    [CmdletBinding()]
    Param(
        [string]$ToolName,
        [string]$DownloadFullPath,
        [string]$DownloadURL,
        [string]$TargetDir
    )

    if (Test-Path -Path $TargetDir) {
        if (Test-Path -Path $DownloadFullPath) {
            Remove-Item "$DownloadFullPath" -Recurse -Force | Out-Null
        }

        Write-Output "Downloading $ToolName..."
        Start-BitsTransfer -Source $DownloadURL -Destination $DownloadFullPath
    
        Write-Output "Extracting $ToolName to $TargetDir..."
        Expand-Archive $DownloadFullPath -DestinationPath $TargetDir -Force
    }
    else {
        Write-Error "'$TargetDir' does not exist..."
    }
}

function LoadLatestPSModule {
    [CmdletBinding()]
    Param
    (
        [string]$Name,
        [string]$Repository
    )

    try {
        Write-Warning "HERE WE ARE"
        $latestModule = Find-Module -Name $Name -Repository $Repository 

        if (Get-Module $Name -ListAvailable) {
            $currentModule = Import-Module -Name $Name -PassThru
            if ($latestModule.version -gt $currentModule.version) {
                Install-Module -Name $Name -RequiredVersion $latestModule.version -Repository $Repository -AllowClobber -Force
            
                # workaround because of PS issues
                if ($Name -eq "SqlServer") {
                    Write-Warning "PowerShell restart is needed because of a SqlServer module update. Please, restart PowerShell."
                    Start-Sleep 1800
                    exit 0
                }
            }
        }
        else {
            Install-Module -Name $Name -RequiredVersion $latestModule.version -Repository $Repository -AllowClobber -Force
        }

        Get-Module -Name $Name | Remove-Module -Force
        Import-Module -Name $Name -RequiredVersion $latestModule.version
    }
    catch {
        Write-Warning "SAF was not able to install the latest $Name PowerShell module. This may cause issues. In case of errors, please install the module manually..."
        Start-Sleep 10

        if (Get-Module $Name -ListAvailable) {
            Get-Module -Name $Name | Remove-Module -Force
            Import-Module -Name $Name
        }
    }
}

function SetDirectoryAccess {
    [CmdletBinding()]
    Param
    (
        [string]$Directory,
        [string]$AppPoolName
    )

    Write-Output "Give '$AppPoolName' access to '$Directory' started..."
    
    $params = @{
        Path        = "$PSScriptRoot\set-directory-access.json"
        Directory   = $Directory
        AppPoolName = $AppPoolName
    }
    Install-SitecoreConfiguration @params

    Write-Output "Give '$AppPoolName' access to '$Directory' done."
}

function GetSIFConfiguration {
    [CmdletBinding()]
    Param
    (
        [string]$Name,
        [string]$ContextPath
    )
  
    $version = $SAFConfiguration.sitecore.version
    $startIndex = $version.LastIndexOf('.')
    $patch = $version.Substring($startIndex + 1)

    $patchInt = [int]$patch
    $result = "$ContextPath\$patchInt\$Name"

    while (!(Test-Path $result)) {
        $patchInt = $patchInt - 1
        $result = "$ContextPath\$patchInt\$Name"
        if ($patchInt -eq 0) {
            break
        }
    }

    return $result
}

function ReplaceStringInFile {
    [CmdletBinding()]
    Param
    (
        [string]$FilePath,
        [string]$OldValue,
        [string]$NewValue
    )

    Write-Output "Updating '$OldValue' to '$NewValue' in '$FilePath'"
    ((Get-Content -Path "$FilePath" -Raw) -Replace "$OldValue", "$NewValue") | Set-Content -Path "$FilePath" -Encoding "UTF8" -Force | Out-Null
    Write-Output "Done."
}

function FormatAsXML {
    [CmdletBinding()]
    Param
    (
        [string]$Text
    )

    $stringWriter = New-Object System.IO.StringWriter 
    $xmlWriter = New-Object System.XMl.XmlTextWriter $stringWriter 

    $xmlWriter.Formatting = "indented" 
    $xmlWriter.Indentation = 2
    
    [xml]$xml = New-Object System.Xml.XmlDocument
    $xml.PreserveWhitespace = $false;
    $xml.LoadXml($Text)

    $xml.WriteContentTo($xmlWriter) 
    $xmlWriter.Flush()
    $stringWriter.Flush() 

    return $stringWriter.ToString()
}

function TestURI {
    [CmdletBinding(DefaultParameterSetName = "Default")]
    Param(
        [Parameter(Position = 0, Mandatory, HelpMessage = "Enter the URI path starting with HTTP or HTTPS")]
        [ValidatePattern( "^(http|https)://" )]
        [string]$URI,
        [ValidateScript( { $_ -ge 0 })]
        [int]$Timeout = 30
    )
     
    try {
        
        $paramHash = @{
            UseBasicParsing  = $true
            DisableKeepAlive = $true
            Uri              = $URI
            Method           = 'Head'
            ErrorAction      = 'Stop'
            TimeoutSec       = $Timeout
        }
     
        $test = Invoke-WebRequest @paramHash
       
        if ($test.statuscode -ne 200) {
            return $false
        }
        else {
            return $true
        }
    }
    catch {
        return $false
    }
}

function FormatAsXML {
    [CmdletBinding()]
    Param
    (
        [string]$Text
    )

    $stringWriter = New-Object System.IO.StringWriter 
    $xmlWriter = New-Object System.XMl.XmlTextWriter $stringWriter 

    $xmlWriter.Formatting = "indented" 
    $xmlWriter.Indentation = 2
    
    [xml]$xml = New-Object System.Xml.XmlDocument
    $xml.PreserveWhitespace = $false;
    $xml.LoadXml($Text)

    $xml.WriteContentTo($xmlWriter) 
    $xmlWriter.Flush()
    $stringWriter.Flush() 

    return $stringWriter.ToString()
}

function FindParentDirectory {
    [CmdletBinding()]
    Param(
        [string]$CurrentDirectory,
        [string]$Search
    )

    $maxRecursionCount = 10
    $tries = 0
    $path = "$CurrentDirectory"
    while ($path -and !(Test-Path (Join-Path $path "$Search"))) {
        $tries = $tries + 1
        if ($tries -eq $maxRecursionCount) {
            throw "Can not find '$Search' directory..."
        }
        $path = Split-Path $path -Parent
    }

    $result = Join-Path $path "$Search"
    return $result
}

function InvokeProcess {
    [CmdletBinding()]
    Param
    (
        [string]$FilePath,
        [string]$ArgumentList
    )

    try {
        $stdErrTempFile = "$env:TEMP\$((New-Guid).Guid)"

        $startProcessParams = @{
            FilePath              = $FilePath
            ArgumentList          = $ArgumentList
            RedirectStandardError = $stdErrTempFile
            Wait                  = $true;
            PassThru              = $true;
            NoNewWindow           = $true;
        }
        $cmd = Start-Process @startProcessParams
        
        if ($cmd.ExitCode -ne 0) {
            $cmdError = Get-Content -Path $stdErrTempFile -Raw
            Write-Error "EXE Exception..."
            Write-Error $cmdError.Trim()
        }
    }
    catch {
        Write-Error "SAF Unexpected error..."
    }
    finally {
        Remove-Item -Path $stdErrTempFile -Force -ErrorAction Ignore
    }
}

Export-ModuleMember -Function "DownloadAndUnzip"
Export-ModuleMember -Function "RefreshEnvironment"
Export-ModuleMember -Function "LoadLatestPSModule"
Export-ModuleMember -Function "SetDirectoryAccess"
Export-ModuleMember -Function "GetSIFConfiguration"
Export-ModuleMember -Function "ReplaceStringInFile"
Export-ModuleMember -Function "FormatAsXML"
Export-ModuleMember -Function "TestURI"
Export-ModuleMember -Function "FindParentDirectory"
Export-ModuleMember -Function "InvokeProcess"