Skip to content

Instantly share code, notes, and snippets.

@lollilol
Last active July 9, 2026 17:02
Show Gist options
  • Select an option

  • Save lollilol/b9214ced8a91267587d57b25c263414d to your computer and use it in GitHub Desktop.

Select an option

Save lollilol/b9214ced8a91267587d57b25c263414d to your computer and use it in GitHub Desktop.
deploy packages using a gpo startup script
# pkgdeploy
# Copyright (C) 2026 Jascha Johnsen
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program. If not, see <https://www.gnu.org/licenses/>.
# defining variables
$scriptName = [System.IO.Path]::GetFileNameWithoutExtension($MyInvocation.MyCommand.Name)
$LogDir = "C:\temp\company"
$LogFile = "$LogDir\$scriptName-$(Get-Date -Format 'yyyy-MM-dd').log"
# create log directory
mkdir -ErrorAction SilentlyContinue $LogDir
# clean logs older than 30 days
Get-ChildItem "$LogDir\$scriptName-*.log" | Where-Object {$_.LastWriteTime -lt (Get-Date).AddDays(-30)} | Remove-Item
# can be removed later
rm -ErrorAction SilentlyContinue C:\temp\company\domain_wide_at_startup.log
rm -ErrorAction SilentlyContinue C:\temp\company\domain_wide_at_startup*.log
# make winget work when running as SYSTEM
$wingetpath = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.DesktopAppInstaller_*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
$winget_folder = $wingetpath.Path
$vclibspath = (Resolve-Path "C:\Program Files\WindowsApps\Microsoft.VCLibs*UWPDesktop*_x64__8wekyb3d8bbwe" | Sort-Object -Property Path | Select-Object -Last 1)
$vclibs_folder = $vclibspath.Path
$env:PATH = "$env:PATH;$winget_folder;$vclibs_folder"
# defining functions
# example
# Write-Log "This is an error" "ERROR"
# Write-Log "This is an info"
# example 2
# try {
# some command
# Write-Log "Successful" "INFO"
# } catch {
# Write-Log "ERROR: $($_.Exception.Message)" "ERROR"
# }
function Write-Log {
param([string]$Message, [string]$Level = "INFO")
$timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
"$timestamp [$Level] $Message" | Out-File -FilePath $LogFile -Append -Encoding UTF8
}
function Install-Application {
param(
[Parameter(Mandatory=$true)]
[ValidateSet("LocalFile", "Winget")]
[string]$InstallType,
[Parameter(Mandatory=$true)]
[string]$AppName,
[string]$AppId,
[string]$ExecutablePath,
[string]$Arguments,
[string]$GroupName
)
$computerName = $env:COMPUTERNAME
$shouldInstall = $true
# Check group membership if GroupName is specified
if ($GroupName) {
$shouldInstall = $false
try {
$root = [ADSI]"LDAP://DC=company,DC=local"
$searcher = New-Object System.DirectoryServices.DirectorySearcher($root)
$searcher.Filter = "(&(objectClass=computer)(cn=$computerName))"
$result = $searcher.FindOne()
if ($result) {
$computerDN = $result.Properties["distinguishedname"][0]
$group = [ADSI]"LDAP://CN=$GroupName,OU=Software,OU=Berechtigungen,OU=Gruppen,OU=stuff,DC=company,DC=local"
$group.RefreshCache()
$shouldInstall = $group.Properties["member"] -contains $computerDN
}
} catch {
Write-Log "ERROR: $($_.Exception.Message)" "ERROR"
return
}
}
# Install if applicable
if ($shouldInstall) {
try {
if ($InstallType -eq "LocalFile") {
Start-Process -FilePath $ExecutablePath -ArgumentList $Arguments -NoNewWindow
} else {
& winget install --accept-source-agreements --accept-package-agreements -e --id $AppId
}
} catch {
Write-Log "ERROR: $($_.Exception.Message)" "ERROR"
}
}
}
## Usage
# If -GroupName is not specified, it will be installed for ALL machines!
# The group must be in OU=Software,OU=Berechtigungen,OU=Gruppen,OU=stuff,DC=company,DC=local
# and contain machines, not users!
## Usage examples:
# Brave for all:
# Install-Application -InstallType LocalFile -AppName "Brave Browser" -ExecutablePath "\\s-fs01\Software\BraveBrowser\BraveBrowserSetup.exe" -Arguments "/silent", "/install"
# Notepad++ for all:
# Install-Application -InstallType Winget -AppName "Notepad++" -AppId "Notepad++.Notepad++"
# Nextcloud Desktop restricted to the group "NextcloudDesktop":
# Install-Application -InstallType Winget -AppName "Nextcloud" -AppId "Nextcloud.NextcloudDesktop" -GroupName "NextcloudDesktop"
#### NO EDITS BEFORE THIS LINE
### all
# Brave Browser
Install-Application -InstallType LocalFile -AppName "Brave Browser" -ExecutablePath "\\s-fs01\Software\BraveBrowser\BraveBrowserSetup.exe" -Arguments "/silent /install"
# Notepad++
Install-Application -InstallType Winget -AppName "Notepad++" -AppId "Notepad++.Notepad++"
### restricted to groups
# Nextcloud Desktop
Install-Application -GroupName "NextcloudDesktop" -InstallType Winget -AppName "Nextcloud" -AppId "Nextcloud.NextcloudDesktop"
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment