Deployment Instructions:
- 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
# Purpose: to check whether a computer is domain connected and use choco to maintain certain mandatory applications
# User entered variables
$clientApps=@( # keyword-search, version, installation-appName
@('Firefox','77.0.1','Firefox'),
@('Chrome','83.0.4103.97','GoogleChrome')
)
$serverApps=@(
@('Chrome','101.0.4951.54','GoogleChrome')
)
$privateRepoName='kimconnectrepo'
$companyDns='10.10.10.10','20.20.20.20'
$privateRepoUrl='https://choco.kimconnect.com/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
)
# 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. Courtesy of Tyler Kocheff
$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*"|select -First 1}
$chocoVersion=.{[void]($chocoAppExists -match ' ([\d+\.]+)');if($matches){return $matches[1]}else{0}}
$isChocoLowerVersion=higherVersion $appVersion $chocoVersion
$appwizAppExists=.{$matchApp=$installedApps|?{$_.Name -like "*$appName*"|select -First 1 }
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
}
if($domainConnected){
if($computerRole -eq 'client'){
chocoAppsMaintenance $clientApps $installedApps $privateRepo
}elseif($computerRole -eq 'memberserver'){
chocoAppsMaintenance $serverApps $installedApps $privateRepo
}
}else{
write-warning "$env:computername is not connected to the domain"
}