Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/GitFlow_Make-Release-and-Sync-to-Dev.yml
Original file line number Diff line number Diff line change
Expand Up @@ -128,6 +128,16 @@ jobs:

<picture>![Install counter](https://img.shields.io/github/downloads/Romanitho/Winget-AutoUpdate/v${{ steps.release_version.outputs.NextSemVer }}/WAU_InstallCounter?style=flat-square&label=Total%20reported%20installations%20for%20this%20release&color=blue)</picture>

sync:
name: Sync develop with main
runs-on: ubuntu-latest
needs: build
steps:
- name: Checkout code
uses: actions/[email protected]
with:
fetch-depth: 0

# Step 5: Configure Git for merge back to develop
- name: Configure Git
shell: bash
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/GitFlow_Nightly-builds.yml
Original file line number Diff line number Diff line change
Expand Up @@ -38,9 +38,9 @@ jobs:
id: check_prs
shell: powershell
run: |
# Find the latest tag of any type
$LATEST_TAG = git for-each-ref --sort=-creatordate --format '%(refname:short)' refs/tags | Select-Object -First 1
Write-Host "Latest tag: $LATEST_TAG"
# Get the latest release of any type
$LATEST_TAG = git tag -l --sort=-version:refname | Select-Object -First 1
Write-Host "Latest release: $LATEST_TAG"

# Get merged PRs since last tag using Git directly
$MERGED_PRS = git log --merges --grep="Merge pull request" --oneline "$LATEST_TAG..${{ env.BRANCH }}"
Expand Down
35 changes: 29 additions & 6 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -175,10 +175,25 @@ Default is 1048576 = 1 MB (ca. 7500 lines)
Specify Winget-AutoUpdate installation location. Default: `C:\Program Files\Winget-AutoUpdate` (Recommended to leave default).

### Deploy with Intune
You can use [Winget-Install](https://github.com/Romanitho/Winget-AutoUpdate/blob/main/Sources/Winget-AutoUpdate/Winget-Install.ps1) to deploy the package for example in Intune:
You can use [Winget-Install](https://github.com/Romanitho/Winget-AutoUpdate/blob/main/Sources/Winget-AutoUpdate/Winget-Install.ps1) to deploy the package (this example with an override of parameters):
```batch
"%systemroot%\sysnative\WindowsPowerShell\v1.0\powershell.exe" -noprofile -executionpolicy bypass -file "C:\Program Files\Winget-AutoUpdate\Winget-Install.ps1" -AppIDs "Romanitho.Winget-AutoUpdate --scope machine --override \"/qn RUN_WAU=YES USERCONTEXT=1 STARTMENUSHORTCUT=1 NOTIFICATIONLEVEL=SuccessOnly UPDATESINTERVAL=Daily""
"%systemroot%\sysnative\WindowsPowerShell\v1.0\powershell.exe" -noprofile -executionpolicy bypass -file "C:\Program Files\Winget-AutoUpdate\Winget-Install.ps1" -AppIDs "Adobe.Acrobat.Reader.64-bit --scope machine --override \"-sfx_nu /sAll /rs /msi EULA_ACCEPT=YES DISABLEDESKTOPSHORTCUT=1""
```
### Deploy with SCCM
You can also use [Winget-Install](https://github.com/Romanitho/Winget-AutoUpdate/blob/main/Sources/Winget-AutoUpdate/Winget-Install.ps1) to deploy the same package in **SCCM**:
```batch
powershell.exe -noprofile -executionpolicy bypass -file "C:\Program Files\Winget-AutoUpdate\Winget-Install.ps1" -AppIDs "Adobe.Acrobat.Reader.64-bit --scope machine --override \"-sfx_nu /sAll /rs /msi EULA_ACCEPT=YES DISABLEDESKTOPSHORTCUT=1""
```
Instead of including the override parameters in the install string you can use a **Mod** (**mods\Adobe.Acrobat.Reader.64-bit-override.txt**) with the content:
```batch
"-sfx_nu /sAll /rs /msi EULA_ACCEPT=YES DISABLEDESKTOPSHORTCUT=1"
```
* A standard single installation: **-AppIDs Notepad++.Notepad++**
* Multiple installations: **-AppIDs "7zip.7zip, Notepad++.Notepad++"**

As a detection script use **config\winget-detect.ps1** (change app to detect [**Application ID**]) in **Intune**/**SCCM** ([winget-detect.ps1](Sources/Winget-AutoUpdate/Tools/Detection/winget-detect.ps1))

A nice feature is if you're already using the deprecated standalone script **winget-install.ps1** from the [old repo](https://github.com/Romanitho/Winget-Install) and have placed it somwhere locally on all clients you can make a **SymLink** in its place and keep using the old path (avoiding a lot of work) in your deployed applications (**Winget-Install.ps1** takes care of the SymLink logic).

## GPO / Intune Management
Read more in the [Policies section](https://github.com/Romanitho/Winget-AutoUpdate/tree/main/Sources/Policies).
Expand All @@ -191,6 +206,8 @@ If **ExitCode** is **1** from `_WAU-mods.ps1` then **Re-run WAU**.

Likewise `_WAU-mods-postsys.ps1` can be used to do things at the end of the **SYSTEM context WAU** process before the user run.

You can find more information in [README Mods for WAU](Sources/Winget-AutoUpdate/mods/README.md)

## Custom scripts (Mods feature for Apps)
The Mods feature allows you to run additional scripts when upgrading or installing an app.
Just put the scripts in question with the **AppID** followed by the `-preinstall`, `-upgrade`, `-install`, `-installed` or `-notinstalled` suffix in the **mods** folder.
Expand All @@ -207,18 +224,24 @@ The **-install** mod will be used for upgrades too if **-upgrade** doesn't exist
> Example:<br>
If you want to run a script that removes the shortcut from **%PUBLIC%\Desktop** (we don't want to fill the desktop with shortcuts our users can't delete) just after installing **Acrobat Reader DC** (32-bit), prepare a powershell script that removes the Public Desktop shortcut **Acrobat Reader DC.lnk** and name your script like this: `Adobe.Acrobat.Reader.32-bit-installed.ps1` and put it in the **mods** folder.

You can find more information on [Winget-Install Repo](https://github.com/Romanitho/Winget-AutoUpdate?tab=readme-ov-file#custom-script-mods-for-wau), as it's a related feature.<br>
Read more in the `README.md` under the directory **mods**.
You can find more information in [README Mods for WAU](Sources/Winget-AutoUpdate/mods/README.md), as it's a related feature.

Share your mods with the community:<br>
<https://github.com/Romanitho/Winget-AutoUpdate/discussions/categories/mods>

### Winget native parameters
Another finess is the **AppID** followed by the `-override` suffix as a **text file** (.**txt**) that you can place under the **mods** folder.
> Example:<br>
**Canneverbe.CDBurnerXP-override.txt** with the content `ADDLOCAL=All REMOVE=Desktop_Shortcut /qn`
**Adobe.Acrobat.Reader.64-bit-override.txt** with the content `"-sfx_nu /sAll /rs /msi EULA_ACCEPT=YES DISABLEDESKTOPSHORTCUT=1"`

This will use the **content** of the text file as a native **winget --override** parameter when upgrading.

Likewise you can use the **AppID** followed by the `-custom` suffix as a **text file** (.**txt**) that you can place under the **mods** folder (*Arguments to be passed on to the installer in addition to the defaults*).
> Example:<br>
**Adobe.Acrobat.Reader.64-bit-custom.txt** with the content `"DISABLEDESKTOPSHORTCUT=1"`

This will use the **content** of the text file as a native **winget --custom** parameter when upgrading.

This will use the **content** of the text file as a native **winget --override** parameter when upgrading (as proposed by [JonNesovic](https://github.com/JonNesovic) in [Mod for --override argument #244](https://github.com/Romanitho/Winget-AutoUpdate/discussions/244#discussion-4637666)).

## Known issues
* As reported by [soredake](https://github.com/soredake), Powershell from MsStore is not supported with WAU in system context. See <https://github.com/Romanitho/Winget-AutoUpdate/issues/113>
Expand Down
62 changes: 62 additions & 0 deletions Sources/Tools/Detection/winget-detect.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
<#
.SYNOPSIS
Helper script to use as detection method with Intune or SCCM.

.DESCRIPTION
This script uses `winget export` to detect if a specific application is installed.
Intended for use as a detection rule script in Intune or SCCM deployments.
#>

#Change app to detect [Application ID]
$AppToDetect = "Notepad++.Notepad++"


<# FUNCTIONS #>

Function Get-WingetCmd {

$WingetCmd = $null

#Get WinGet Path
try {
#Get Admin Context Winget Location
$WingetInfo = (Get-Item "$env:ProgramFiles\WindowsApps\Microsoft.DesktopAppInstaller_*_8wekyb3d8bbwe\winget.exe").VersionInfo | Sort-Object -Property FileVersionRaw
#If multiple versions, pick most recent one
$WingetCmd = $WingetInfo[-1].FileName
}
catch {
#Get User context Winget Location
if (Test-Path "$env:LocalAppData\Microsoft\WindowsApps\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\winget.exe") {
$WingetCmd = "$env:LocalAppData\Microsoft\WindowsApps\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\winget.exe"
}
}

return $WingetCmd
}

<# MAIN #>

#Get WinGet Location Function
$winget = Get-WingetCmd

#Set json export file
$JsonFile = "$env:TEMP\InstalledApps.json"

#Get installed apps and version in json file
& $Winget export -o $JsonFile --accept-source-agreements | Out-Null

#Get json content
$Json = Get-Content $JsonFile -Raw | ConvertFrom-Json

#Get apps and version in hashtable
$Packages = $Json.Sources.Packages

#Remove json file
Remove-Item $JsonFile -Force

# Search for specific app and version
$Apps = $Packages | Where-Object { $_.PackageIdentifier -eq $AppToDetect }

if ($Apps) {
return "Installed!"
}
155 changes: 65 additions & 90 deletions Sources/Winget-AutoUpdate/Winget-Install.ps1
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
<#
.SYNOPSIS
Install apps with Winget through Intune or SCCM.
Can be used standalone.
(Can be used standalone.) - Deprecated in favor of Winget-AutoUpdate.

.DESCRIPTION
Allow to run Winget in System Context to install your apps.
https://github.com/Romanitho/Winget-Install
(https://github.com/Romanitho/Winget-Install) - Deprecated in favor of Winget-AutoUpdate.

.PARAMETER AppIDs
Forward Winget App ID to install. For multiple apps, separate with ",". Case sensitive.
Expand Down Expand Up @@ -90,59 +90,39 @@ function Confirm-Exist ($AppID) {

#Check if install modifications exist in "mods" directory
function Test-ModsInstall ($AppID) {
#Check current location
if (Test-Path ".\mods\$AppID-preinstall.ps1") {
$ModsPreInstall = ".\mods\$AppID-preinstall.ps1"
}
#Else, check in WAU mods
elseif (Test-Path "$WAUModsLocation\$AppID-preinstall.ps1") {
$ModsPreInstall = "$WAUModsLocation\$AppID-preinstall.ps1"
}

if (Test-Path ".\mods\$AppID-install.ps1") {
$ModsInstall = ".\mods\$AppID-install.ps1"
}
elseif (Test-Path "$WAUModsLocation\$AppID-install.ps1") {
$ModsInstall = "$WAUModsLocation\$AppID-install.ps1"
}

if (Test-Path ".\mods\$AppID-installed-once.ps1") {
$ModsInstalledOnce = ".\mods\$AppID-installed-once.ps1"
}

if (Test-Path ".\mods\$AppID-installed.ps1") {
$ModsInstalled = ".\mods\$AppID-installed.ps1"
}
elseif (Test-Path "$WAUModsLocation\$AppID-installed.ps1") {
$ModsInstalled = "$WAUModsLocation\$AppID-installed.ps1"
if (Test-Path "$Mods\$AppID-*") {
if (Test-Path "$Mods\$AppID-preinstall.ps1") {
$ModsPreInstall = "$Mods\$AppID-preinstall.ps1"
}
if (Test-Path "$Mods\$AppID-override.txt") {
$ModsOverride = (Get-Content "$Mods\$AppID-override.txt" -Raw).Trim()
}
if (Test-Path "$Mods\$AppID-custom.txt") {
$ModsCustom = (Get-Content "$Mods\$AppID-custom.txt" -Raw).Trim()
}
if (Test-Path "$Mods\$AppID-install.ps1") {
$ModsInstall = "$Mods\$AppID-install.ps1"
}
if (Test-Path "$Mods\$AppID-installed.ps1") {
$ModsInstalled = "$Mods\$AppID-installed.ps1"
}
}

return $ModsPreInstall, $ModsInstall, $ModsInstalledOnce, $ModsInstalled
return $ModsPreInstall, $ModsOverride, $ModsCustom, $ModsInstall, $ModsInstalled
}

#Check if uninstall modifications exist in "mods" directory
function Test-ModsUninstall ($AppID) {
#Check current location
if (Test-Path ".\mods\$AppID-preuninstall.ps1") {
$ModsPreUninstall = ".\mods\$AppID-preuninstall.ps1"
}
#Else, check in WAU mods
elseif (Test-Path "$WAUModsLocation\$AppID-preuninstall.ps1") {
$ModsPreUninstall = "$WAUModsLocation\$AppID-preuninstall.ps1"
}

if (Test-Path ".\mods\$AppID-uninstall.ps1") {
$ModsUninstall = ".\mods\$AppID-uninstall.ps1"
}
elseif (Test-Path "$WAUModsLocation\$AppID-uninstall.ps1") {
$ModsUninstall = "$WAUModsLocation\$AppID-uninstall.ps1"
}

if (Test-Path ".\mods\$AppID-uninstalled.ps1") {
$ModsUninstalled = ".\mods\$AppID-uninstalled.ps1"
}
elseif (Test-Path "$WAUModsLocation\$AppID-uninstalled.ps1") {
$ModsUninstalled = "$WAUModsLocation\$AppID-uninstalled.ps1"
if (Test-Path "$Mods\$AppID-*") {
if (Test-Path "$Mods\$AppID-preuninstall.ps1") {
$ModsPreUninstall = "$Mods\$AppID-preuninstall.ps1"
}
if (Test-Path "$Mods\$AppID-uninstall.ps1") {
$ModsUninstall = "$Mods\$AppID-uninstall.ps1"
}
if (Test-Path "$Mods\$AppID-uninstalled.ps1") {
$ModsUninstalled = "$Mods\$AppID-uninstalled.ps1"
}
}

return $ModsPreUninstall, $ModsUninstall, $ModsUninstalled
Expand All @@ -152,23 +132,38 @@ function Test-ModsUninstall ($AppID) {
function Install-App ($AppID, $AppArgs) {
$IsInstalled = Confirm-Installation $AppID
if (!($IsInstalled) -or $AllowUpgrade ) {
#Check if mods exist (or already exist) for preinstall/install/installedonce/installed
$ModsPreInstall, $ModsInstall, $ModsInstalledOnce, $ModsInstalled = Test-ModsInstall $($AppID)
#Check if mods exist (or already exist) for preinstall/override/custom/install/installed
$ModsPreInstall, $ModsOverride, $ModsCustom, $ModsInstall, $ModsInstalled = Test-ModsInstall $($AppID)

#If PreInstall script exist
if ($ModsPreInstall) {
Write-ToLog "-> Modifications for $AppID before install are being applied..." "Yellow"
& "$ModsPreInstall"
Write-ToLog "Modifications for $AppID before install are being applied..." "DarkYellow"
$preInstallResult = & "$ModsPreInstall"
if ($preInstallResult -eq $false) {
Write-ToLog "PreInstall script for $AppID requested to skip this installation" "Yellow"
return # Exit the function early
}
}

#Install App
Write-ToLog "-> Installing $AppID..." "Yellow"
$WingetArgs = "install --id $AppID -e --accept-package-agreements --accept-source-agreements -s winget -h $AppArgs" -split " "
Write-ToLog "-> Installing $AppID..." "DarkYellow"
if ($ModsOverride) {
Write-ToLog "-> Arguments (overriding default): $ModsOverride" # Without -h (user overrides default)
$WingetArgs = "install --id $AppID -e --accept-package-agreements --accept-source-agreements -s winget --override $ModsOverride" -split " "
}
elseif ($ModsCustom) {
Write-ToLog "-> Arguments (customizing default): $ModsCustom" # With -h (user customizes default)
$WingetArgs = "install --id $AppID -e --accept-package-agreements --accept-source-agreements -s winget -h --custom $ModsCustom" -split " "
}
else {
$WingetArgs = "install --id $AppID -e --accept-package-agreements --accept-source-agreements -s winget -h $AppArgs" -split " "
}

Write-ToLog "-> Running: `"$Winget`" $WingetArgs"
& "$Winget" $WingetArgs | Where-Object { $_ -notlike " *" } | Tee-Object -file $LogFile -Append

if ($ModsInstall) {
Write-ToLog "-> Modifications for $AppID during install are being applied..." "Yellow"
Write-ToLog "-> Modifications for $AppID during install are being applied..." "DarkYellow"
& "$ModsInstall"
}

Expand All @@ -177,26 +172,11 @@ function Install-App ($AppID, $AppArgs) {
if ($IsInstalled) {
Write-ToLog "-> $AppID successfully installed." "Green"

if ($ModsInstalledOnce) {
Write-ToLog "-> Modifications for $AppID after install (one time) are being applied..." "Yellow"
& "$ModsInstalledOnce"
}
elseif ($ModsInstalled) {
Write-ToLog "-> Modifications for $AppID after install are being applied..." "Yellow"
if ($ModsInstalled) {
Write-ToLog "-> Modifications for $AppID after install are being applied..." "DarkYellow"
& "$ModsInstalled"
}

#Add mods if deployed from Winget-Install
if (Test-Path ".\mods\$AppID-*") {
#Check if WAU default install path exists
$Mods = "$WAUModsLocation"
if (Test-Path $Mods) {
#Add mods
Write-ToLog "-> Add modifications for $AppID to WAU 'mods'"
Copy-Item ".\mods\$AppID-*" -Destination "$Mods" -Exclude "*installed-once*", "*uninstall*" -Force
}
}

#Add to WAU White List if set
if ($WAUWhiteList) {
Add-WAUWhiteList $AppID
Expand All @@ -220,18 +200,22 @@ function Uninstall-App ($AppID, $AppArgs) {

#If PreUninstall script exist
if ($ModsPreUninstall) {
Write-ToLog "-> Modifications for $AppID before uninstall are being applied..." "Yellow"
& "$ModsPreUninstall"
Write-ToLog "Modifications for $AppID before uninstall are being applied..." "DarkYellow"
$preUnInstallResult = & "$ModsPreUnInstall"
if ($preUnInstallResult -eq $false) {
Write-ToLog "PreUnInstall script for $AppID requested to skip this uninstallation" "Yellow"
return # Exit the function early
}
}

#Uninstall App
Write-ToLog "-> Uninstalling $AppID..." "Yellow"
Write-ToLog "-> Uninstalling $AppID..." "DarkYellow"
$WingetArgs = "uninstall --id $AppID -e --accept-source-agreements -h $AppArgs" -split " "
Write-ToLog "-> Running: `"$Winget`" $WingetArgs"
& "$Winget" $WingetArgs | Where-Object { $_ -notlike " *" } | Tee-Object -file $LogFile -Append

if ($ModsUninstall) {
Write-ToLog "-> Modifications for $AppID during uninstall are being applied..." "Yellow"
Write-ToLog "-> Modifications for $AppID during uninstall are being applied..." "DarkYellow"
& "$ModsUninstall"
}

Expand All @@ -240,21 +224,10 @@ function Uninstall-App ($AppID, $AppArgs) {
if (!($IsInstalled)) {
Write-ToLog "-> $AppID successfully uninstalled." "Green"
if ($ModsUninstalled) {
Write-ToLog "-> Modifications for $AppID after uninstall are being applied..." "Yellow"
Write-ToLog "-> Modifications for $AppID after uninstall are being applied..." "DarkYellow"
& "$ModsUninstalled"
}

#Remove mods if deployed from Winget-Install
if (Test-Path ".\mods\$AppID-*") {
#Check if WAU default install path exists
$Mods = "$WAUModsLocation"
if (Test-Path "$Mods\$AppID*") {
Write-ToLog "-> Remove $AppID modifications from WAU 'mods'"
#Remove mods
Remove-Item -Path "$Mods\$AppID-*" -Exclude "*uninstall*" -Force
}
}

#Remove from WAU White List if set
if ($WAUWhiteList) {
Remove-WAUWhiteList $AppID
Expand Down Expand Up @@ -321,7 +294,9 @@ $Script:IsElevated = $CurrentPrincipal.IsInRole([Security.Principal.WindowsBuilt
#Get WAU Installed location
$WAURegKey = "HKLM:\SOFTWARE\Romanitho\Winget-AutoUpdate\"
$Script:WAUInstallLocation = Get-ItemProperty $WAURegKey -ErrorAction SilentlyContinue | Select-Object -ExpandProperty InstallLocation
$Script:WAUModsLocation = Join-Path -Path $WAUInstallLocation -ChildPath "mods"

# Use the Working Dir (even if it is from a symlink)
$Mods = "$realPath\mods"

#Log file & LogPath initialization
if ($IsElevated) {
Expand Down
Loading
Loading