Public/Start-cChocoEx.ps1

<#
.SYNOPSIS
Bootstraps the cChoco PowerShell DSC Module
 
.DESCRIPTION
Bootstraps the cChoco PowerShell DSC Module
#>

function Start-cChocoEx {
    [CmdletBinding()]
    param (
        [Parameter()]
        [string]
        $SettingsURI,
        # Chocolatey Installation Directory
        [Parameter()]
        [string]
        $InstallDir = "$env:ProgramData\chocolatey",
        # Chocolatey Installation Script URL
        [Parameter()]
        [string]
        $ChocoInstallScriptUrl = 'https://chocolatey.org/install.ps1',
        # URL to chocolatey nupkg
        [Parameter()]
        [string]
        $ChocoDownloadUrl,
        # URL to cChoco sources configuration file
        [Parameter()]
        [string]
        $SourcesConfig,
        # URL to cCHoco packages
        [Parameter()]
        [array]
        $PackageConfig,
        # URL to cChoco Chocolatey configuration file
        [Parameter()]
        [string]
        $ChocoConfig,
        # URL to cChoco Chocolatey features configuration file
        [Parameter()]
        [string]
        $FeatureConfig,
        # Do not cache configuration files
        [Parameter()]
        [switch]
        $NoCache,
        # Wipe locally cached psd1 configurations
        [Parameter()]
        [switch]
        $WipeCache,
        # RandomDelay
        [Parameter()]
        [switch]
        $RandomDelay,
        # Loop the Function
        [Parameter()]
        [Switch]
        $Loop,
        # Loop Delay in Minutes
        [Parameter()]
        [int]
        $LoopDelay = 60,
        # Legacy Migration Automation
        [Parameter()]
        [Switch]
        $MigrateLegacyConfigurations
    )

    #Ensure Running as Administrator
    if (-Not ([Security.Principal.WindowsPrincipal][Security.Principal.WindowsIdentity]::GetCurrent()).IsInRole([Security.Principal.WindowsBuiltInRole] "Administrator")) {
        Write-Warning "This function requires elevated access, please reopen PowerShell as an Administrator"
        Break
    }    

    $i = 0
    do {
        $i++
        #Enable TLS 1.2
        #https://docs.microsoft.com/en-us/dotnet/api/system.net.securityprotocoltype?view=net-5.0
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072
    
        #Start-DSCConfiguation
        $Global:ModuleBase = (Get-Module -Name 'cChoco' -ListAvailable -ErrorAction Stop | Sort-Object -Property Version | Select-Object -Last 1).ModuleBase
        $Global:MaintenanceWindowEnabled = $True
        $Global:MaintenanceWindowActive = $True
        $Global:cChocoExDataFolder = (Join-Path -Path $env:ProgramData -ChildPath 'cChocoEx')
        $Global:cChocoExConfigurationFolder = (Join-Path -Path $Global:cChocoExDataFolder -ChildPath 'config')
        $Global:cChocoExTMPConfigurationFolder = (Join-Path -Path "$env:TEMP\cChocoEx" -ChildPath 'config')
        $Global:LogPath = (Join-Path -Path $Global:cChocoExDataFolder -ChildPath "logs")
        $Global:TSEnv = Test-TSEnv

        #Ensure cChocoEx Data Folder Structure is Created
        $null = New-Item -ItemType Directory -Path $cChocoExDataFolder -Force -ErrorAction SilentlyContinue
        $null = New-Item -ItemType Directory -Path $cChocoExConfigurationFolder -Force -ErrorAction SilentlyContinue
        $null = New-Item -ItemType Directory -Path $cChocoExTMPConfigurationFolder -Force -ErrorAction SilentlyContinue
        $null = New-Item -ItemType Directory -Path $LogPath -Force -ErrorAction SilentlyContinue

        #Ensure cChoco Module Is Present and Available
        if (-not($ModuleBase)) {
            Write-Log -Severity 'Error' -Message 'Required Module cChoco Not Found'
            Break
        }

        if ($MigrateLegacyConfigurations) {
            Move-LegacyConfigurations
        }
        
        Write-Log -Severity 'Information' -Message "Task Sequence Environemnt Detected: $TSEnv"

        #cChocoInstaller
        $Configuration = @{
            InstallDir            = $InstallDir
            ChocoInstallScriptUrl = $ChocoInstallScriptUrl
        }
            
        Start-cChocoInstaller -Configuration $Configuration

        $CurrentExecutionPolicy = Get-ExecutionPolicy
        try {
            $null = Set-ExecutionPolicy Bypass -Scope CurrentUser
        }
        catch {
            Write-Log -Severity 'Warning' -Message "Error Changing Execution Policy"
        }

        try {
            Write-Log -Severity 'Information' -Message 'cChocoEx Started'
        }
        catch {
            Write-Warning "Error Starting Log, wiping and retrying"
            Write-Log -Severity 'Information' -Message 'cChoco Bootstrap Started' -New

        }

        #Evaluate Random Delay Switch
        if ($RandomDelay) {
            $RandomSeconds = Get-Random -Minimum 0 -Maximum 900
            Write-Log -Severity 'Information' -Message "Random Delay Enabled"
            Write-Log -Severity 'Information' -Message "Delay: $RandomSeconds`s"
            Start-Sleep -Seconds $RandomSeconds
        }

        #Settings
        if ($SettingsURI) {
            $Destination = (Join-Path $cChocoExTMPConfigurationFolder "bootstrap-cchoco.psd1")
            switch (Test-PathEx -Path $SettingsURI) {
                'URL' { Invoke-WebRequest -Uri $SettingsURI -UseBasicParsing -OutFile $Destination }
                'FileSystem' { Copy-Item -Path $SettingsURI -Destination $Destination -Force }
            }    
            $SettingsFile = Import-PowerShellDataFile -Path $Destination
            $Settings = $SettingsFile | ForEach-Object { $_.Keys | ForEach-Object { $SettingsFile.$_ } } 
    
            #Variables
            $InstallDir = $Settings.InstallDir
            $ChocoInstallScriptUrl = $Settings.ChocoInstallScriptUrl
            $SourcesConfig = $Settings.SourcesConfig
            $PackageConfig = $Settings.PackageConfig
            $ChocoConfig = $Settings.ChocoConfig
            $FeatureConfig = $Settings.FeatureConfig
        }

        Write-Log -Severity 'Information' -Message "cChocoEx Settings"
        Write-Log -Severity 'Information' -Message "SettingsURI: $SettingsURI"
        Write-Log -Severity 'Information' -Message "InstallDir: $InstallDir"
        Write-Log -Severity 'Information' -Message "ChocoInstallScriptUrl: $ChocoInstallScriptUrl"
        Write-Log -Severity 'Information' -Message "SourcesConfig: $SourcesConfig"
        Write-Log -Severity 'Information' -Message "PackageConfig: $PackageConfig"
        Write-Log -Severity 'Information' -Message "ChocoConfig: $ChocoConfig"
        Write-Log -Severity 'Information' -Message "FeatureConfig: $FeatureConfig"

        #Set Enviromental Variable for chocolatey url to nupkg
        $env:chocolateyDownloadUrl = $ChocoDownloadUrl

        if ($WipeCache) {
            Write-Log -Severity 'Information' -Message 'WipeCache Enabled. Wiping any previously downloaded psd1 configuration files'
            Get-ChildItem -Path $cChocoExConfigurationFolder -Filter *.psd1 | Remove-Item -Recurse -Force
        }
        #Preclear any previously downloaded NoCache configuration files
        if ($NoCache) {
            Write-Log -Severity 'Information' -Message 'NoCache Enabled. Wiping any previously downloaded NoCache configuration files from temp'
            Get-ChildItem -Path $cChocoExTMPConfigurationFolder -Filter *.psd1 | Remove-Item -Recurse -Force
        }

        #Copy Config Config?
        $Global:ChocoConfigDestination = (Join-Path $cChocoExConfigurationFolder "config.psd1")
        if ($ChocoConfig) {
            if ($NoCache) {
                $Global:ChocoConfigDestination = (Join-Path $cChocoExTMPConfigurationFolder "config.psd1")
            }
            switch (Test-PathEx -Path $ChocoConfig) {
                'URL' { Invoke-WebRequest -Uri $ChocoConfig -UseBasicParsing -OutFile $ChocoConfigDestination }
                'FileSystem' { Copy-Item -Path $ChocoConfig -Destination $ChocoConfigDestination -Force }
            }
            Write-Log -Severity 'Information' -Message 'Chocolatey Config File Set.'
        }

        #Copy Sources Config
        $Global:SourcesConfigDestination = (Join-Path $cChocoExConfigurationFolder "sources.psd1")
        if ($SourcesConfig) {
            if ($NoCache) {
                $Global:SourcesConfigDestination = (Join-Path $cChocoExTMPConfigurationFolder "sources.psd1")
            }
            switch (Test-PathEx -Path $SourcesConfig) {
                'URL' { Invoke-WebRequest -Uri $SourcesConfig -UseBasicParsing -OutFile $SourcesConfigDestination }
                'FileSystem' { Copy-Item -Path $SourcesConfig -Destination $SourcesConfigDestination -Force }
            }
            Write-Log -Severity 'Information' -Message 'Chocolatey Sources File Set.'
        }

        #Copy Features Config
        $Global:FeatureConfigDestination = (Join-Path $cChocoExConfigurationFolder "features.psd1")
        if ($FeatureConfig) {
            if ($NoCache) {
                $Global:FeatureConfigDestination = (Join-Path $cChocoExTMPConfigurationFolder "features.psd1")
            }
            switch (Test-PathEx -Path $FeatureConfig) {
                'URL' { Invoke-WebRequest -Uri $FeatureConfig -UseBasicParsing -OutFile $FeatureConfigDestination }
                'FileSystem' { Copy-Item -Path $FeatureConfig -Destination $FeatureConfigDestination -Force }
            }
            Write-Log -Severity 'Information' -Message 'Chocolatey Feature File Set.'
        }

        #Copy Package Config
        $Global:PackageConfigDestination = $cChocoExConfigurationFolder
        if ($PackageConfig) {
            if ($NoCache) {
                $Global:PackageConfigDestination = $cChocoExTMPConfigurationFolder
            }
            $PackageConfig | ForEach-Object {
                $Path = $_
                $Destination = (Join-Path $PackageConfigDestination ($_ | Split-Path -Leaf))
                switch (Test-PathEx -Path $_) {
                    'URL' { Invoke-WebRequest -Uri $Path -UseBasicParsing -OutFile $Destination }
                    'FileSystem' { Copy-Item -Path $Path -Destination $Destination -Force }
                }
            }
            Write-Log -Severity 'Information' -Message 'Chocolatey Package File Set.'
        }

        #cChocoConfig
        if (Test-Path $ChocoConfigDestination ) {
            $ConfigImport = $null
            $ConfigImport = Import-PowerShellDataFile $ChocoConfigDestination
            Start-cChocoConfig -ConfigImport $ConfigImport
        }
        else {
            Write-Log -Severity 'Warning'  -Message "File not found, configuration will not be modified"
        }

        #cChocoFeature
        if (Test-Path $FeatureConfigDestination ) {
            $ConfigImport = $null
            $ConfigImport = Import-PowerShellDataFile $FeatureConfigDestination
            Start-cChocoFeature -ConfigImport $ConfigImport
        }
        else {
            Write-Log -Severity 'Information' -Message "File not found, features will not be modified"
        }

        #cChocoSource
        if (Test-Path $SourcesConfigDestination ) {
            $ConfigImport = $null
            $ConfigImport = Import-PowerShellDataFile $SourcesConfigDestination
            Start-cChocoSource -ConfigImport $ConfigImport
        }
        else {
            Write-Log -Severity 'Information' -Message "File not found, sources will not be modified"
        }

        #cChocoPackageInstall
        [array]$Configurations = $null
        Get-ChildItem -Path $PackageConfigDestination -Filter *.psd1 | Where-Object { $_.Name -notmatch "sources.psd1|config.psd1|features.psd1" } | ForEach-Object {
            $ConfigImport = $null
            $ConfigImport = Import-PowerShellDataFile $_.FullName 
            $Configurations += $ConfigImport | ForEach-Object { $_.Keys | ForEach-Object { $ConfigImport.$_ } }
        }

        if ($Configurations ) {
            Start-cChocoPackageInstall -Configurations $Configurations
        }
        else {
            Write-Log -Severity 'Warning' -Message "File not found, packages will not be modified"
        }
    
        #Cleanup
        #Preclear any previously downloaded NoCache configuration files
        if ($NoCache) {
            Write-Log -Severity "Information" -Message "Preclear any previously downloaded NoCache configuration files"
            Get-ChildItem -Path $cChocoExTMPConfigurationFolder -Filter *.psd1 | Remove-Item -Recurse -Force
        }
        $null = Set-ExecutionPolicy $CurrentExecutionPolicy -Scope CurrentUser -ErrorAction SilentlyContinue
        RotateLog

        if ($Loop -and (-not($TSEnv))) {
            Write-Log -Severity "Information" -Message "Function Looping Enabled"
            Write-Log -Severity "Information" -Message "Looping Delay: $LoopDelay Minutes"
            Write-Log -Severity "Information" -Message "Loop Count: $i"
            Start-Sleep -Seconds ($LoopDelay * 60)
        }

    } until (($Loop -eq $false) -or ($TSEnv))
}