Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Step towards experimental group of settings in ADMX Policies #789

Merged
merged 12 commits into from
Jan 24, 2025
15 changes: 14 additions & 1 deletion Sources/Policies/ADMX/WAU.admx
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,15 @@
<definitions>
<definition name="SUPPORTED_WAU_1_16_0" displayName="$(string.SUPPORTED_WAU_1_16_0)"/>
<definition name="SUPPORTED_WAU_1_16_5" displayName="$(string.SUPPORTED_WAU_1_16_5)"/>
<definition name="SUPPORTED_WAU_EXPERIMENTAL" displayName="$(string.SUPPORTED_WAU_EXPERIMENTAL)"/>
</definitions>
</supportedOn>
<categories><category displayName="$(string.WAU)" name="WAU"/></categories>
<categories>
<category displayName="$(string.WAU)" name="WAU"/>
<category name="Experimental" displayName="$(string.WAUEX)">
<parentCategory ref="WAU" />
</category>
</categories>
<policies>
<policy name="ActivateGPOManagement_Enable" class="Machine" displayName="$(string.ActivateGPOManagement_Name)" explainText="$(string.ActivateGPOManagement_Explain)" key="Software\Policies\Romanitho\Winget-AutoUpdate" valueName="WAU_ActivateGPOManagement">
<parentCategory ref="WAU"/>
Expand Down Expand Up @@ -349,6 +355,13 @@
<elements>
<text id="MaxLogSize" valueName="WAU_MaxLogSize" />
</elements>
</policy>
<policy name="WingetSourceCustom_Enable" class="Machine" displayName="$(string.WingetSourceCustom_Name)" explainText="$(string.WingetSourceCustom_Explain)" key="Software\Policies\Romanitho\Winget-AutoUpdate" presentation="$(presentation.WingetSourceCustom)" >
<parentCategory ref="Experimental"/>
<supportedOn ref="WAU:SUPPORTED_WAU_EXPERIMENTAL"/>
<elements>
<text id="WingetSourceCustom" valueName="WAU_WingetSourceCustom" />
</elements>
</policy>
</policies>
</policyDefinitions>
14 changes: 14 additions & 0 deletions Sources/Policies/ADMX/en-US/WAU.adml
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,10 @@
<resources >
<stringTable >
<string id="WAU">Winget-AutoUpdate</string>
<string id="WAUEX">Experimental</string>
<string id="SUPPORTED_WAU_1_16_0">Winget-AutoUpdate version 1.16.0 or later</string>
<string id="SUPPORTED_WAU_1_16_5">Winget-AutoUpdate version 1.16.5 or later</string>
<string id="SUPPORTED_WAU_EXPERIMENTAL">Winget-AutoUpdate Experimental, subject to change, do not use on PROD</string>
<string id="ActivateGPOManagement_Name">Activate WAU GPO Management</string>
<string id="ActivateGPOManagement_Explain">This policy setting is an overriding toggle for GPO Management of Winget-AutoUpdate.</string>
<string id="BypassListForUsers_Name">Bypass Black/White list for User</string>
Expand Down Expand Up @@ -140,6 +142,13 @@ If this policy is disabled or not configured, the default number is used.</strin
Default size is 1048576 = 1 MB

If this policy is disabled or not configured, the default size is used.</string>
<string id="WingetSourceCustom_Name">Use custom Winget Source repository</string>
<string id="WingetSourceCustom_Explain">This policy setting specifies whether to use winget tool with custom repository or not:
(WAU - Check for updated Apps)

If this policy is enabled, WAU will TRY to use a custom repo instead of the built-in/default one called winget.

If this policy is disabled or not configured, the default is always the built-in winget.</string>
</stringTable>
<presentationTable>
<presentation id="BlackList">
Expand Down Expand Up @@ -182,6 +191,11 @@ If this policy is disabled or not configured, the default size is used.</string>
<label>Size of the log file:</label>
</textBox>
</presentation>
<presentation id="WingetSourceCustom">
<textBox refId="WingetSourceCustom">
<label>Name of custom winget source:</label>
</textBox>
</presentation>
</presentationTable>
</resources>
</policyDefinitionResources>
192 changes: 118 additions & 74 deletions Sources/Winget-AutoUpdate/Winget-Upgrade.ps1
Original file line number Diff line number Diff line change
@@ -1,60 +1,103 @@
<# LOAD FUNCTIONS #>

#Get the Working Dir
$Script:WorkingDir = $PSScriptRoot
#Get Functions
Get-ChildItem "$WorkingDir\functions" -File -Filter "*.ps1" -Depth 0 | ForEach-Object { . $_.FullName }
#region LOAD FUNCTIONS
# Get the Working Dir
[string]$Script:WorkingDir = $PSScriptRoot;

# Get Functions
Get-ChildItem -Path "$($Script:WorkingDir)\functions" -File -Filter "*.ps1" -Depth 0 | ForEach-Object { . $_.FullName; }
#endregion LOAD FUNCTIONS

<# MAIN #>

#Config console output encoding
$null = cmd /c ''
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$Script:ProgressPreference = 'SilentlyContinue'
# Config console output encoding
$null = cmd /c '';
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8;
$Script:ProgressPreference = [System.Management.Automation.ActionPreference]::SilentlyContinue;

# Set GitHub Repo
[string]$Script:GitHub_Repo = "Winget-AutoUpdate";

# Log initialization
[string]$LogFile = [System.IO.Path]::Combine($Script:WorkingDir, 'logs', 'updates.log');

#region Get settings and Domain/Local Policies (GPO) if activated.
Write-ToLog "Reading WAUConfig";
$Script:WAUConfig = Get-WAUConfig;

if ($WAUConfig.WAU_ActivateGPOManagement -eq 1) {
Write-ToLog "WAU Policies management Enabled.";
}
#endregion Get settings and Domain/Local Policies (GPO) if activated.

#region Winget Source Custom
# Default name of winget repository used within this script
[string]$DefaultWingetRepoName = 'winget';

#Set GitHub Repo
$Script:GitHub_Repo = "Winget-AutoUpdate"
# Defining custom repository for winget tool (only if GPO management is active)
if($Script:WAUConfig.WAU_ActivateGPOManagement) {
if($null -eq $Script:WAUConfig.WAU_WingetSourceCustom) {
[string]$Script:WingetSourceCustom = $DefaultWingetRepoName;
}
else {
[string]$Script:WingetSourceCustom = $Script:WAUConfig.WAU_WingetSourceCustom.Trim();
}
Write-ToLog "Selecting winget repository named '$($Script:WingetSourceCustom)'";
}
#endregion Winget Source Custom

#Log initialization
$LogFile = "$WorkingDir\logs\updates.log"
#region Checking execution context
# Check if running account is system or interactive logon System(default) otherwise User
[bool]$Script:IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem;

# Check for current session ID (O = system without ServiceUI)
[Int32]$Script:SessionID = [System.Diagnostics.Process]::GetCurrentProcess().SessionId;
#endregion

#Check if running account is system or interactive logon
$Script:IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem
#Check for current session ID (O = system without ServiceUI)
$Script:SessionID = [System.Diagnostics.Process]::GetCurrentProcess().SessionId
# Preparation to run in current context
if ($true -eq $IsSystem) {

#Check if running as system
if ($IsSystem) {
#If log file doesn't exist, force create it
if (!(Test-Path -Path $LogFile)) {
Write-ToLog "New log file created"
Write-ToLog "New log file created";
}

# paths
[string]$IntuneLogsDir = "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs";
[string]$fp0 = [System.IO.Path]::Combine($IntuneLogsDir, 'WAU-updates.log');
[string]$fp1 = [System.IO.Path]::Combine($Script:WorkingDir, 'logs', 'install.log');
[string]$fp2 = [System.IO.Path]::Combine($IntuneLogsDir, 'WAU-install.log');

# Check if Intune Management Extension Logs folder exists
if ((Test-Path -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs" -ErrorAction SilentlyContinue)) {
if (Test-Path -Path $IntuneLogsDir -PathType Container -ErrorAction SilentlyContinue) {

# Check if symlink WAU-updates.log exists, make symlink (doesn't work under ServiceUI)
if (!(Test-Path -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log" -ErrorAction SilentlyContinue)) {
$null = New-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log" -ItemType SymbolicLink -Value $LogFile -Force -ErrorAction SilentlyContinue
Write-ToLog "SymLink for 'update' log file created in Intune Management Extension log folder"
if (!(Test-Path -Path $fp0 -ErrorAction SilentlyContinue)) {
New-Item -Path $fp0 -ItemType SymbolicLink -Value $LogFile -Force -ErrorAction SilentlyContinue | Out-Null;
Write-ToLog "SymLink for 'update' log file created in in $($IntuneLogsDir) folder";
}

# Check if install.log and symlink WAU-install.log exists, make symlink (doesn't work under ServiceUI)
if ((Test-Path -Path ('{0}\logs\install.log' -f $WorkingDir) -ErrorAction SilentlyContinue) -and !(Test-Path -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log" -ErrorAction SilentlyContinue)) {
$null = (New-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log" -ItemType SymbolicLink -Value ('{0}\logs\install.log' -f $WorkingDir) -Force -Confirm:$False -ErrorAction SilentlyContinue)
Write-ToLog "SymLink for 'install' log file created in Intune Management Extension log folder"
if ( (Test-Path -Path $fp1 -ErrorAction SilentlyContinue) -and !(Test-Path -Path $fp2 -ErrorAction SilentlyContinue) ) {
New-Item -Path $fp2 -ItemType SymbolicLink -Value $fp1 -Force -Confirm:$False -ErrorAction SilentlyContinue | Out-Null;
Write-ToLog "SymLink for 'install' log file created in $($IntuneLogsDir) folder"
}
}

#Check if running with session ID 0
if ($SessionID -eq 0) {
#Check if ServiceUI exists
$ServiceUI = Test-Path "$WorkingDir\ServiceUI.exe"
if ($ServiceUI) {
[string]$fp3 = [System.IO.Path]::Combine($Script:WorkingDir, 'ServiceUI.exe');
[bool]$ServiceUI = Test-Path $fp3 -PathType Leaf;
if ($true -eq $ServiceUI) {
#Check if any connected user
$explorerprocesses = @(Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue)
$explorerprocesses = @(Get-CimInstance -Query "SELECT * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue);
if ($explorerprocesses.Count -gt 0) {
#Rerun WAU in system context with ServiceUI
Start-Process "ServiceUI.exe" -ArgumentList "-process:explorer.exe $env:windir\System32\conhost.exe --headless powershell.exe -NoProfile -ExecutionPolicy Bypass -File winget-upgrade.ps1" -WorkingDirectory $WorkingDir
Wait-Process "ServiceUI" -ErrorAction SilentlyContinue
Exit 0
Write-ToLog "Rerun WAU in system context with ServiceUI";
Start-Process `
-FilePath $fp3 `
-ArgumentList "-process:explorer.exe $env:windir\System32\conhost.exe --headless powershell.exe -NoProfile -ExecutionPolicy Bypass -File winget-upgrade.ps1" `
-WorkingDirectory $WorkingDir;
Wait-Process "ServiceUI" -ErrorAction SilentlyContinue;
Exit 0;
}
else {
Write-ToLog -LogMsg "CHECK FOR APP UPDATES (System context)" -IsHeader
Expand All @@ -72,90 +115,91 @@ else {
Write-ToLog -LogMsg "CHECK FOR APP UPDATES (User context)" -IsHeader
}

#Get settings and Domain/Local Policies (GPO) if activated.
$Script:WAUConfig = Get-WAUConfig
if ($($WAUConfig.WAU_ActivateGPOManagement -eq 1)) {
Write-ToLog "WAU Policies management Enabled."
}

#Log running context and more...
if ($IsSystem) {
#region Log running context
if ($true -eq $IsSystem) {

# Maximum number of log files to keep. Default is 3. Setting MaxLogFiles to 0 will keep all log files.
$MaxLogFiles = $WAUConfig.WAU_MaxLogFiles
if ($null -eq $MaxLogFiles) {
[int32] $MaxLogFiles = 3
[int32]$MaxLogFiles = 3;
}
else {
[int32] $MaxLogFiles = $MaxLogFiles
[int32]$MaxLogFiles = $MaxLogFiles;
}

# Maximum size of log file.
$MaxLogSize = $WAUConfig.WAU_MaxLogSize
$MaxLogSize = $WAUConfig.WAU_MaxLogSize;
if (!$MaxLogSize) {
[int64] $MaxLogSize = 1048576 # in bytes, default is 1048576 = 1 MB
[int64]$MaxLogSize = [int64]1MB; # in bytes, default is 1 MB = 1048576
}
else {
[int64] $MaxLogSize = $MaxLogSize
[int64]$MaxLogSize = $MaxLogSize;
}

#LogRotation if System
$LogRotate = Invoke-LogRotation $LogFile $MaxLogFiles $MaxLogSize
if ($LogRotate -eq $False) {
[bool]$LogRotate = Invoke-LogRotation $LogFile $MaxLogFiles $MaxLogSize;
if ($false -eq $LogRotate) {
Write-ToLog "An Exception occurred during Log Rotation..."
}
}
#endregion Log running context

#Run Scope Machine function if run as System
Add-ScopeMachine
#region Run Scope Machine function if run as System
if ($true -eq $IsSystem) {
Add-ScopeMachine;
}
#endregion Run Scope Machine function if run as System

#Get Notif Locale function
$LocaleDisplayName = Get-NotifLocale
Write-ToLog "Notification Level: $($WAUConfig.WAU_NotificationLevel). Notification Language: $LocaleDisplayName" "Cyan"
#region Get Notif Locale function
[string]$LocaleDisplayName = Get-NotifLocale;
Write-ToLog "Notification Level: $($WAUConfig.WAU_NotificationLevel). Notification Language: $LocaleDisplayName" "Cyan";
#endregion

#Check network connectivity
if (Test-Network) {

#Check prerequisites
if ($IsSystem) {
Install-Prerequisites
if ($true -eq $IsSystem) {
Install-Prerequisites;
}

#Check if Winget is installed and get Winget cmd
$Script:Winget = Get-WingetCmd
[string]$Script:Winget = Get-WingetCmd;
Write-ToLog "Selected winget instance: $($Script:Winget)";

if ($Winget) {
if ($Script:Winget) {

if ($IsSystem) {
if ($true -eq $IsSystem) {

#Get Current Version
$WAUCurrentVersion = $WAUConfig.ProductVersion
Write-ToLog "WAU current version: $WAUCurrentVersion"
$WAUCurrentVersion = $WAUConfig.ProductVersion;
Write-ToLog "WAU current version: $WAUCurrentVersion";

#Check if WAU update feature is enabled or not if run as System
$WAUDisableAutoUpdate = $WAUConfig.WAU_DisableAutoUpdate
$WAUDisableAutoUpdate = $WAUConfig.WAU_DisableAutoUpdate;
#If yes then check WAU update if run as System
if ($WAUDisableAutoUpdate -eq 1) {
Write-ToLog "WAU AutoUpdate is Disabled." "Gray"
Write-ToLog "WAU AutoUpdate is Disabled." "Gray";
}
else {
Write-ToLog "WAU AutoUpdate is Enabled." "Green"
Write-ToLog "WAU AutoUpdate is Enabled." "Green";
#Get Available Version
$Script:WAUAvailableVersion = Get-WAUAvailableVersion
$Script:WAUAvailableVersion = Get-WAUAvailableVersion;
#Compare
if ([version]$WAUAvailableVersion.replace("-n", "") -gt [version]$WAUCurrentVersion.replace("-n", "")) {
#If new version is available, update it
Write-ToLog "WAU Available version: $WAUAvailableVersion" "Yellow"
Update-WAU
Write-ToLog "WAU Available version: $WAUAvailableVersion" "Yellow";
Update-WAU;
}
else {
Write-ToLog "WAU is up to date." "Green"
Write-ToLog "WAU is up to date." "Green";
}
}

#Delete previous list_/winget_error (if they exist) if run as System
if (Test-Path "$WorkingDir\logs\error.txt") {
Remove-Item "$WorkingDir\logs\error.txt" -Force
[string]$fp4 = [System.IO.Path]::Combine($Script:WorkingDir, 'logs', 'error.txt');
if (Test-Path $fp4) {
Remove-Item $fp4 -Force;
}

#Get External ListPath if run as System
Expand Down Expand Up @@ -285,8 +329,8 @@ if (Test-Network) {
}

#Get outdated Winget packages
Write-ToLog "Checking application updates on Winget Repository..." "yellow"
$outdated = Get-WingetOutdatedApps
Write-ToLog "Checking application updates on Winget Repository named '$($Script:WingetSourceCustom)' .." "yellow"
$outdated = Get-WingetOutdatedApps -src $Script:WingetSourceCustom;

#If something unusual happened or no update found
if ($outdated -like "No update found.*") {
Expand Down Expand Up @@ -379,7 +423,7 @@ if (Test-Network) {
Else {
#Get Winget system apps to escape them before running user context
Write-ToLog "User logged on, get a list of installed Winget apps in System context..."
Get-WingetSystemApps
Get-WingetSystemApps -src $Script:WingetSourceCustom;

#Run user context scheduled task
Write-ToLog "Starting WAU in User context..."
Expand Down
22 changes: 13 additions & 9 deletions Sources/Winget-AutoUpdate/functions/Get-WingetCmd.ps1
Original file line number Diff line number Diff line change
@@ -1,23 +1,27 @@
#Function to get the winget command regarding execution context (User, System...)

Function Get-WingetCmd {

$WingetCmd = $null
[OutputType([String])]
$WingetCmd = [string]::Empty;

#Get WinGet Path
# default winget path (in system context)
[string]$ps = "$env:ProgramFiles\WindowsApps\Microsoft.DesktopAppInstaller_*_8wekyb3d8bbwe\winget.exe";

#default winget path (in user context)
[string]$pu = "$env:LocalAppData\Microsoft\WindowsApps\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe\winget.exe";

try {
#Get Admin Context Winget Location
$WingetInfo = (Get-Item "$env:ProgramFiles\WindowsApps\Microsoft.DesktopAppInstaller_*_8wekyb3d8bbwe\winget.exe").VersionInfo | Sort-Object -Property FileVersionRaw
$WingetInfo = (Get-Item -Path $ps).VersionInfo | Sort-Object -Property FileVersionRaw -Descending | Select-Object -First 1;
#If multiple versions, pick most recent one
$WingetCmd = $WingetInfo[-1].FileName
$WingetCmd = $WingetInfo.FileName;
}
catch {
Copy link
Contributor

@KnifMelti KnifMelti Jan 25, 2025

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When the user part is executed it doesn't enter the catch thereby making $WingetCmd empty...
...and 17:52:56 - Checking application updates on Winget Repository named '' .. it looks like it doesn't use a Repo...

image

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

...nope it doesn't use a repo at all; not finding the usually skipped ones:

16:51:49 - Epic Games Launcher : Skipped upgrade because it is in the excluded app list
16:51:49 - Windows Assessment and Deployment Kit - Windows 10 : Skipped upgrade because it is in the excluded app list
16:51:49 - Ubisoft Connect : Skipped upgrade because it is in the excluded app list
16:51:49 - Mozilla Firefox (x64 en-GB) : Skipped upgrade because it is *wildcard* in the excluded app list
16:51:49 - MSTeams : Skipped upgrade because it is *wildcard* in the excluded app list

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AndrewDemski-ad-gmail-com @Romanitho
Maybe inserting -ErrorAction Break in the Admin context check is enough for the problem with executing the user part (works in my small test)?:

#Get Admin Context Winget Location
$WingetInfo = (Get-Item -Path $ps -ErrorAction Break).VersionInfo | Sort-Object -Property FileVersionRaw -Descending | Select-Object -First 1;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The only thing that comes to my mind is that these two commands behave differently whether 'Path' argument is used or not:

  • (Get-Item -Path $ps)
  • (Get-Item $ps)

..which would be weird, because that was the only change in that section.

But you are right @KnifMelti, The try block should be started above those two strings are defined and -EA should be specified

#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"
if (Test-Path -Path $pu -PathType Leaf) {
$WingetCmd = $pu;
}
}

return $WingetCmd

return $WingetCmd;
}
Loading
Loading