PowerShell: Deploy Choco Apps

Deployment Instructions:
  1. Create a batch file with this content to call this PowerShell Script
@echo off
set ScriptPath=%~dp0
set ScriptName=deployChocoApps.ps1
PowerShell -ExecutionPolicy Bypass -Command "&'%ScriptPath%%ScriptName%' -Verbose"

Explanation: Powershell will not execute at startup if the computer cannot contact a DC.

2. Ensure that the VPN client perform ‘gpupdate’ upon connection to the domain. Here’s an example for Forticlient:

<on_connect>
<script>
<os>windows</os>
<script>
<![CDATA[gpupdate]]>
</script>
</script>
</on_connect>

Explanation: Fortinet Forticlient recommended xml config addition to enable VPN users to map drives and pull GPOs upon successful VPN connections

3. Create a GPO and apply it at a test OU Container
Create GPO > edit new GPO > User configuration > Preferences > Control Panel Settings > Scheduled Tasks > right-click on scheduled tasks > New > Scheduled Task (At Least Windows 7) > Input these properties:
– Name = Deploy Choco Apps
– Action = replace
– When running the task, use the following user account = NT Authority\System
– Run whether user is logged on or not = True
– Run with highest privileges = Checked
– Hidden = Checked
– Triggers = At Startup, repeat the task every 1 hour indefinitely, enabled
– Actions = Start a program
– Program Script = \\%userdnsdomain%\sysvol\%userdnsdomain%\scripts\deployChocoApps\deployChocoApps.ps1
– start in = \\%userdnsdomain%\sysvol\%userdnsdomain%\scripts\deployChocoApps
– arguments = leave blank or -NonInteractive -WindowStyle Hidden -executionpolicy bypass -ErrorAction SilentlyContinue
– Settings = Allow task to run on demand
– Common = Remove this item when it is no longer applied
– Click OK to apply

# deployChocoApps.ps1
# Function: to check whether a computer is domain connected and use choco to maintain certain mandatory applications. Exit program if the Windows OS is 'server', instead of 'client'

# User entered variables
$apps=@( # keyword-search, version, installation-appName
    @('Firefox','77.0.1','Firefox'),
    @('Chrome','83.0.4103.97','GoogleChrome')    
    )
$privateRepoName='kimconnectRepo'
$privateRepoUrl='https://choco.kimconnect.net/chocolatey'
$priority=1

# Stagger execution timing of script execution
$randomInterval=get-random -Minimum 0 -Maximum 50.00
#start-sleep $randomInterval # Uncomment this line to stagger check-ins

# Autogen variables
$privateRepo="'$privateRepoName' -s '$privateRepoUrl' --priority=$priority"
$computerRole=switch ((Get-CimInstance -ClassName Win32_OperatingSystem).ProductType){
                1 {'client'} # ClientOs
                2 {'domaincontroller'} #ServerOs with DC role
                3 {'memberserver'} #ServerOs machines
                }
$installedApps=Get-CimInstance -ClassName win32_InstalledWin32Program -ErrorAction Stop|select Name,Version
$domainConnected=.{
            try {
                [void]::([System.DirectoryServices.ActiveDirectory.Domain]::GetComputerDomain())
                return $true
                }
            catch{
                return $false
                }
            }

function higherVersion ($a,$b){
    # This assumes the query as version $a is greater than $b by reconstructing PowerShell version object
    $regexVersion='^(\d+)\.{1}(\d+)\.{0,1}(\d+){0,1}\.{0,1}(\d+){0,1}'
    [void]($a -match $regexVersion)
1..4|%{new-variable "a$_" -value $matches[$_] -force}   
    [void]($b -match $regexVersion)
1..4|%{new-variable "b$_" -value $matches[$_] -force}
    return [Version]::new($a1,$a2,$a3,$a4) -gt [Version]::new($b1,$b2,$b3,$b4)
}

function chocoAppsMaintenance{
    param(
        $apps,
        $installedApps,
        $privateRepo,
        $domainConnected,
        $computerRole
        )

    if ($domainConnected -and $computerRole -match 'client'){   
        # Install Chocolatey from the Intranet private repo
        if (!(Get-Command choco.exe -ErrorAction SilentlyContinue)) {
        Set-ExecutionPolicy Bypass -Scope Process -Force; iex ((New-Object System.Net.WebClient).DownloadString('https://choco.kimconnect.com/install.ps1'))}
        
        # Set private repo source if it doesn't exist.
        $sources=choco source list
        $privateRepoExists=$sources -match $privateRepoName        
        if (!$privateRepoExists){
            invoke-expression "choco source add -n=$privateRepo"
            }
        
        # Install app if it's not already there, or upgrade if its version is outdated        
        $chocoInstalledApps=choco list -l

        foreach ($app in $apps){
            $appName=$app[0]
            $appVersion=$app[1]
            $appInstall=$app[2]            
            $chocoAppExists=$chocoInstalledApps|?{$_ -like "*$appName*"}
            $chocoVersion=.{[void]($chocoAppExists -match ' ([\d+\.]+)');return $matches[1]}
            $isChocoLowerVersion=higherVersion $appVersion $chocoVersion            
            
            $appwizAppExists=.{$matchApp=$installedApps|?{$_.Name -like "*$appName*" }
                            if($matchApp){$matchApp}else{$false}
                            }
            $appwizVersion=if($appwizAppExists){$appwizAppExists.Version}else{$false}
            if($appwizVersion){
                $isAppwizLowerVersion=higherVersion $appVersion $appwizVersion
                }

            write-host "Checking $appName $appVersion`r`nChoco: $chocoVersion`r`nAppwiz: $appwizVersion"
            if (!$chocoAppExists -and !$appwizAppExists){choco install $appInstall -y}
            elseif ($isChocoLowerVersion -and $isAppwizLowerVersion){choco upgrade $appInstall -y}       
            }  
 
        # Upgrade all choco installed apps
        # choco upgrade all -y
            }
    else{
        # Skip
        } 
}

chocoAppsMaintenance $apps $installedApps $privateRepo $domainConnected $computerRole

Leave a Reply

Your email address will not be published. Required fields are marked *