AppManiProgramManager.psm1


# This function is to mitigate the Invoke-WebRequest error where it won't run because IE First Run Customization hasn't been done yet. Using the switch parameter UseBasicParsing would work for regular web requests, but not for Downloads
Function Test-WebRequest {
    Param (
        $URI
    )

    # Loop until system is able to successfully invoke a web request
    while ($null -eq $webRequest) {
        try {
            $webRequest = Invoke-WebRequest -Uri $URI
        }
        # Catches the exception where IE first run customization has not been done yet
        catch [System.NotSupportedException] {
            Write-Host "Disabling IE First RunCustomization..." -NoNewline
            try {
                Set-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Internet Explorer\Main" -Name "DisableFirstRunCustomize" -Value 2
            }
            catch {
                Write-Warning "The script ran into an issue: $($Error[0])"
                return $null
            }
        }

        # catches other exceptions
        catch {
            Write-Warning "The script ran into an issue: $($Error[0])"
            return $null
        }
    }
    return $webrequest
}
   
# Downloads installer
Function Get-Installer {
    Param (
        $DownloadLink,
        $SavePath,
        $FileName
    )

    # Tests if save path is existing
    if (Test-Path $savePath) {

        # If a preferred filename is not provided, the test after the last '/' of the download link will serve as the filename of the downloaded file
        if ($null -eq $FileName) {
            $filename = $DownloadLink.Substring($DownloadLink.LastIndexOf("/") + 1)
        }
        $SavePath = $SavePath + $fileName
        
        # Downloads the file
        try {
            Invoke-WebRequest -Uri $downloadLink -OutFile $savePath
        }
        catch {
            Write-Warning "Unable to download installer: $($Error[0])"
            return $null
        }
        return $SavePath
    }
    else {
        Write-Warning "Download path $SavePath not existing. Please specify a valid path."
        return $null
    }
}

#Deletes installer
Function Remove-Installer {
    Param (
        $InstallerLocation
    )

    # Removes a file
    try {
        Remove-Item -Path $InstallerLocation -Force -ErrorAction Stop
    }
    catch {
        Write-Warning "The script ran into an issue: $($Error[0])"
        return $null
    }
}

# Checks the registry for entries of the installed program and returns information about it
Function Get-InstalledProgram {
    Param (
        $Program
    )
    $Apps = @()
    $Apps += Get-ItemProperty "HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\*" # 32 Bit
    $Apps += Get-ItemProperty "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*"             # 64 Bit
    $installedProgram = $Apps | Where-Object DisplayName -like "$Program*"
    
    return $installedProgram
}

# Checks the registry for entries of the isntalled service and returns information about it
Function Get-InstalledService {
    Param (
        $Program
    )
    $RegistryPath = "HKLM:\SYSTEM\CurrentControlSet\Services\$Program"

    $installedService = Get-ItemProperty -Path $RegistryPath -ErrorAction SilentlyContinue

    return $installedService

}


#Installs program using a one-liner msiexec or calls the installer executable with additional arguments
Function Install-Program {
    Param (
        $InstallCommand,
        $Program
    )
    try {
        cmd /c $InstallCommand
    }
    catch {
        Write-Warning "Unable to install $($Program): $($Error[0])"
        return $null
    }
}

Function Confirm-ProgramInstallation {
    Param (
        $Program
    )
    # Loops X number of times to check registry keys for the program
    $tries = 0
    while ($tries -le 30) {
        $tries++
        Write-Host "Verifying installation. Tries: $tries"

        $installedProgram = Get-InstalledProgram -Program $Program
        
        if ($null -ne $installedProgram) {
            return $installedProgram
        }

        Start-Sleep -s 15
    }
    Write-Warning "Script has reached the maximum number of retries on installation verification. Please investigate for issues."
    return $null
}

Function Confirm-ServiceInstallation {
    Param (
        $Program
    )
    # Loops X number of times to check registry keys for the service
    $tries = 0
    while ($tries -le 30) {
        $tries++
        Write-Host "Verifying installation. Tries: $tries"

        $installedService = Get-InstalledService -Program $Program
        
        if ($null -ne $installedService) {
            return $installedService
        }

        Start-Sleep -s 15
    }
    Write-Warning "Script has reached the maximum number of retries on installation verification. Please investigate for issues."
    return $null
}

# Compares current version of a program from the registry and what's on the download link. There are programs that won't have registry entries and programs that won't have their versions on the download link, so please check first before using
Function Compare-Versions {
    Param (
        $InstalledProgram,
        $DownloadLink,
        $downloadLinkRegex
    )

    $DownloadLink -match $downloadLinkRegex | Out-Null
    $latestVersion =  $matches[1] -replace '[.]',''
    $currentVersion = $($InstalledProgram.DisplayVersion) -replace '[.]',''

    if ($latestVersion.equals($currentVersion)) {
        return $false
    }
    else {
        return $true
    }
}

Export-ModuleMember -Function 'Test-WebRequest'
Export-ModuleMember -Function 'Get-Installer'
Export-ModuleMember -Function 'Remove-Installer'
Export-ModuleMember -Function 'Get-InstalledProgram'
Export-ModuleMember -Function 'Get-InstalledService'
Export-ModuleMember -Function 'Install-Program'
Export-ModuleMember -Function 'Confirm-ProgramInstallation'
Export-ModuleMember -Function 'Confirm-ServiceInstallation'
Export-ModuleMember -Function 'Compare-Versions'