Patch/Register-PatchHelper.ps1

<#
.SYNOPSIS
    Configures default parameters for PatchHelper
.DESCRIPTION
    Configures default parameters for PatchHelper. Such as default instance to install patches and extension to and URL adress of the remote server to report patch installation.
.EXAMPLE
    Register-PatchHelper -instanceName BC140 -customerName "our-beloved-customer2" -reportURL "https://report.com:443/mothership" -patchFolder C:\Patches\
.NOTES
#>

function Register-PatchHelper {
    [Alias("rgph")]
    [CmdletBinding()]
    param(
        # Default destination BC instance where objects should be imported to.
        [Parameter(Mandatory = $true, ParameterSetName = "register")]
        [string]$instanceName,
        # Default patch source folder
        [Parameter(Mandatory = $True, ParameterSetName = "register")]
        [string]$patchFolder,
        # URL of the endpoint for reporting
        [Parameter(Mandatory = $false, ParameterSetName = "register")]
        [string]$reportURL,
        # Name of the dealer to be reported
        [Parameter(Mandatory = { $PSBoundParameters.ContainsKey('reportURL') }, ParameterSetName = "register")]
        [string]$customerName,
        # Layer name for automatic patch download
        [Parameter(Mandatory = $false, ParameterSetName = "register")]
        [string]$layerName,
        # List of extensions to upgrade automatically
        [Parameter(Mandatory = $false, ParameterSetName = "register")]
        [string[]]$apps,
        # Creates background scheduled task to pereodicaly run Automagic at specified time on Mondays and Wednesdays
        [Parameter(Mandatory = $false, ParameterSetName = "register")]
        [string]$scheduleAt,
        # Remove registration
        [Alias("wipe")]
        [Parameter(Mandatory = $false, ParameterSetName = "unregister")]
        [switch]$unregister
    )
    $ErrorActionPreference = "Stop"

    $ConfigFolder = Join-Path "$Env:ProgramData" "ADSPatchHelper"
    if (!(Test-Path $ConfigFolder)) { New-Item -Path $ConfigFolder -ItemType Directory | Out-Null }
    $PatchHelperConfigFile = Join-Path $ConfigFolder "PatchHelper.config.json"
    if ($unregister) {
        Remove-Item -Path $PatchHelperConfigFile -ErrorAction Continue
        Remove-Item -Path $ConfigFolder -ErrorAction Continue
        if (Get-ScheduledJob $JobName) { Unregister-ScheduledJob -Name $JobName }
        return;
    }
    if (!$PSBoundParameters.ContainsKey('layerName')) {
        Write-Warning "You didn't specify 'layerName'. Only core layer patches will be downloaded."
    }
    Test-Path $patchFolder -PathType Container -ErrorAction Stop | Out-Null
    if (!(Test-Path (Join-Path $patchFolder "Backup"))) {
        New-Item -Path (Join-Path $patchFolder "Backup") -ItemType Directory | Out-Null
    }
    if ($reportURL) { $reportURL = $reportURL.TrimEnd('/') }
    Set-Variable -scope Script -Name PatchHelperConfig -Value ([PSCustomObject]@{
            ReportURL          = $reportURL
            CustomerName       = $customerName
            DefaultInstance    = $instanceName
            DefaultPatchFolder = $patchFolder
            LayerName          = $layerName
            Apps               = $apps
            Version            = '1.2'
        })
    Write-Verbose $PatchHelperConfigFile
    $PatchHelperConfig | ConvertTo-Json | Out-File $PatchHelperConfigFile
    Get-PatchHelperConfig -Verbose:$false | Out-Null

    #region Create scheduled job
    if ($scheduleAt) {
        $logFolder = Join-Path $patchFolder "Log"
        if (!(Test-Path $logFolder)) { New-Item -Path $logFolder -ItemType Directory | Out-Null }
        $JobName = "PatchHelper_Automagic"
        if (Get-ScheduledJob $JobName -ErrorAction SilentlyContinue) { Unregister-ScheduledJob -Name $JobName }
        $automagic = {
            param($logPath)
            $logPath = (Join-Path $logPath "$(get-date -Format 'MM_dd_yyyy').log")
            try { $Error.Clear(); Automagic -autoInstall *>> $logPath } catch { $_ >> $logPath; $error >> $logPath}
        }
        Register-ScheduledJob -Name $JobName `
            -Trigger @{Frequency = "Weekly"; At = $scheduleAt; DaysOfWeek = "Monday", "Wednesday"; RandomDelay = "00:30:00" } `
            -ArgumentList @($logFolder) -ScriptBlock $automagic | Out-Null
    }
    #endregion
}

$InstanceNameArgumentCompleter = {
    param($commandName, $parameterName, $wordToComplete, $commandAst, $fakeBoundParameters)
    if ($PatchHelperConfig.DefaultInstance) { """$($PatchHelperConfig.DefaultInstance)""" }
    else {
        Import-NavModule -Admin
        Get-NAVServerInstance | % { $_.ServerInstance -replace ".*\$", "" } | `
                Where-Object { $_ -like "$wordToComplete*" }
    }
}

$DefaultValueArgumentCompleter = {
    param($commandName, $parameterName)
    switch ($parameterName) {
        "patchFolder" { """$($PatchHelperConfig["DefaultPatchFolder"])"""; break; }
        "instanceName" { """$($PatchHelperConfig["DefaultInstance"])"""; break; }
        "apps" { ($PatchHelperConfig["$parameterName"] | % { """$($_)""" } ) -join ","; break; }
        Default { """$($PatchHelperConfig["$parameterName"])"""; break; }
    }
}

Register-ArgumentCompleter -CommandName "Register-PatchHelper" -ParameterName "instanceName" -ScriptBlock $InstanceNameArgumentCompleter
Register-ArgumentCompleter -CommandName "Register-PatchHelper" -ParameterName "patchFolder" -ScriptBlock $DefaultValueArgumentCompleter
Register-ArgumentCompleter -CommandName "Register-PatchHelper" -ParameterName "reportURL" -ScriptBlock $DefaultValueArgumentCompleter
Register-ArgumentCompleter -CommandName "Register-PatchHelper" -ParameterName "customerName" -ScriptBlock $DefaultValueArgumentCompleter
Register-ArgumentCompleter -CommandName "Register-PatchHelper" -ParameterName "layerName" -ScriptBlock $DefaultValueArgumentCompleter
Register-ArgumentCompleter -CommandName "Register-PatchHelper" -ParameterName "apps" -ScriptBlock $DefaultValueArgumentCompleter

Export-ModuleMember -Alias "rgph" -Function "Register-PatchHelper"