diff --git a/Winget-AutoUpdate-Install.ps1 b/Winget-AutoUpdate-Install.ps1 index 8bceb7f..eb175e3 100644 --- a/Winget-AutoUpdate-Install.ps1 +++ b/Winget-AutoUpdate-Install.ps1 @@ -46,6 +46,9 @@ Specify the time of the update interval execution time. Default 6AM .PARAMETER RunOnMetered Run WAU on metered connection. Default No. +.PARAMETER BypassListForUsers +Configure WAU to bypass the Black/White list when run in user context + .EXAMPLE .\winget-install-and-update.ps1 -Silent -DoNotUpdate @@ -77,7 +80,8 @@ param( [Parameter(Mandatory = $False)] [ValidateSet("Full", "SuccessOnly", "None")] [String] $NotificationLevel = "Full", [Parameter(Mandatory = $False)] [Switch] $UpdatesAtLogon = $false, [Parameter(Mandatory = $False)] [ValidateSet("Daily", "Weekly", "BiWeekly", "Monthly", "Never")] [String] $UpdatesInterval = "Daily", - [Parameter(Mandatory = $False)] [DateTime] $UpdatesAtTime = ("06am") + [Parameter(Mandatory = $False)] [DateTime] $UpdatesAtTime = ("06am"), + [Parameter(Mandatory = $False)] [Switch] $BypassListForUsers = $false ) <# APP INFO #> @@ -265,6 +269,15 @@ function Install-WingetAutoUpdate { $task = New-ScheduledTask -Action $taskAction -Principal $taskUserPrincipal -Settings $taskSettings -Trigger $taskTriggers Register-ScheduledTask -TaskName 'Winget-AutoUpdate' -InputObject $task -Force | Out-Null + # Settings for the scheduled task in User context + $taskAction = New-ScheduledTaskAction –Execute "wscript.exe" -Argument "`"$($WingetUpdatePath)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WingetUpdatePath)\winget-upgrade.ps1`"`"" + $taskUserPrincipal = New-ScheduledTaskPrincipal -GroupId S-1-5-11 + $taskSettings = New-ScheduledTaskSettingsSet -Compatibility Win8 -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit 03:00:00 + + # Set up the task for user apps + $task = New-ScheduledTask -Action $taskAction -Principal $taskUserPrincipal -Settings $taskSettings + Register-ScheduledTask -TaskName 'Winget-AutoUpdate-UserContext' -InputObject $task -Force | Out-Null + # Settings for the scheduled task for Notifications $taskAction = New-ScheduledTaskAction –Execute "wscript.exe" -Argument "`"$($WingetUpdatePath)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WingetUpdatePath)\winget-notify.ps1`"`"" $taskUserPrincipal = New-ScheduledTaskPrincipal -GroupId S-1-5-11 @@ -274,6 +287,14 @@ function Install-WingetAutoUpdate { $task = New-ScheduledTask -Action $taskAction -Principal $taskUserPrincipal -Settings $taskSettings Register-ScheduledTask -TaskName 'Winget-AutoUpdate-Notify' -InputObject $task -Force | Out-Null + #Set task readable/runnable for all users + $scheduler = New-Object -ComObject "Schedule.Service" + $scheduler.Connect() + $task = $scheduler.GetFolder("").GetTask("Winget-AutoUpdate") + $sec = $task.GetSecurityDescriptor(0xF) + $sec = $sec + '(A;;GRGX;;;AU)' + $task.SetSecurityDescriptor($sec, 0) + # Configure Reg Key $regPath = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate" New-Item $regPath -Force | Out-Null @@ -304,6 +325,9 @@ function Install-WingetAutoUpdate { if ($ListPath){ New-ItemProperty $regPath -Name ListPath -Value $ListPath -Force | Out-Null } + if ($BypassListForUsers){ + New-ItemProperty $regPath -Name WAU_BypassListForUsers -Value 1 -PropertyType DWord -Force | Out-Null + } Write-host "WAU Installation succeeded!" -ForegroundColor Green Start-sleep 1 @@ -337,7 +361,8 @@ function Uninstall-WingetAutoUpdate { Get-ChildItem -Path $InstallLocation -Exclude *.txt,mods,logs | Remove-Item -Recurse -Force } Get-ScheduledTask -TaskName "Winget-AutoUpdate" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False - Get-ScheduledTask -TaskName "Winget-AutoUpdate-Notify" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False + Get-ScheduledTask -TaskName "Winget-AutoUpdate-Notify" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False + Get-ScheduledTask -TaskName "Winget-AutoUpdate-UserContext" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False & reg delete "HKCR\AppUserModelId\Windows.SystemToast.Winget.Notification" /f | Out-Null & reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate" /f | Out-Null @@ -420,10 +445,4 @@ else { } Write-host "`nEnd of process." -ForegroundColor Cyan - -if (!$Silent) { - Timeout 10 -} -else { - Start-Sleep 1 -} +Start-Sleep 3 diff --git a/Winget-AutoUpdate/WAU-Uninstall.ps1 b/Winget-AutoUpdate/WAU-Uninstall.ps1 index 9ce09c7..8189dff 100644 --- a/Winget-AutoUpdate/WAU-Uninstall.ps1 +++ b/Winget-AutoUpdate/WAU-Uninstall.ps1 @@ -48,7 +48,8 @@ try { Get-ChildItem -Path $InstallLocation -Exclude *.txt,mods,logs | Remove-Item -Recurse -Force } Get-ScheduledTask -TaskName "Winget-AutoUpdate" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False - Get-ScheduledTask -TaskName "Winget-AutoUpdate-Notify" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False + Get-ScheduledTask -TaskName "Winget-AutoUpdate-Notify" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False + Get-ScheduledTask -TaskName "Winget-AutoUpdate-UserContext" -ErrorAction SilentlyContinue | Unregister-ScheduledTask -Confirm:$False & reg delete "HKCR\AppUserModelId\Windows.SystemToast.Winget.Notification" /f | Out-Null & reg delete "HKLM\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate" /f | Out-Null if (Test-Path "HKLM:\SOFTWARE\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate") { diff --git a/Winget-AutoUpdate/functions/Get-WingetCmd.ps1 b/Winget-AutoUpdate/functions/Get-WingetCmd.ps1 index 5138c45..29c7aa8 100644 --- a/Winget-AutoUpdate/functions/Get-WingetCmd.ps1 +++ b/Winget-AutoUpdate/functions/Get-WingetCmd.ps1 @@ -14,11 +14,7 @@ Function Get-WingetCmd { if ($WingetCmd) { $Script:Winget = $WingetCmd.Source } - #Get Winget Location in System context (WinGet < 1.17) - elseif (Test-Path "$WingetPath\AppInstallerCLI.exe") { - $Script:Winget = "$WingetPath\AppInstallerCLI.exe" - } - #Get Winget Location in System context (WinGet > 1.17) + #Get Winget Location in System context elseif (Test-Path "$WingetPath\winget.exe") { $Script:Winget = "$WingetPath\winget.exe" } @@ -28,7 +24,7 @@ Function Get-WingetCmd { } #Run winget to list apps and accept source agrements (necessary on first run) - & $Winget list --accept-source-agreements | Out-Null + & $Winget list --accept-source-agreements -s winget | Out-Null #Log Winget installed version $WingetVer = & $Winget --version diff --git a/Winget-AutoUpdate/functions/Get-WingetOutdatedApps.ps1 b/Winget-AutoUpdate/functions/Get-WingetOutdatedApps.ps1 index 153a8af..1b209d2 100644 --- a/Winget-AutoUpdate/functions/Get-WingetOutdatedApps.ps1 +++ b/Winget-AutoUpdate/functions/Get-WingetOutdatedApps.ps1 @@ -52,5 +52,11 @@ function Get-WingetOutdatedApps { } } + #If current user is not system, remove system apps from list + if ($IsSystem -eq $false) { + $SystemApps = Get-Content -Path "$WorkingDir\winget_system_apps.txt" + $upgradeList = $upgradeList | Where-Object {$SystemApps -notcontains $_.Id} + } + return $upgradeList | Sort-Object {Get-Random} } \ No newline at end of file diff --git a/Winget-AutoUpdate/functions/Get-WingetSystemApps.ps1 b/Winget-AutoUpdate/functions/Get-WingetSystemApps.ps1 new file mode 100644 index 0000000..50aa605 --- /dev/null +++ b/Winget-AutoUpdate/functions/Get-WingetSystemApps.ps1 @@ -0,0 +1,15 @@ +function Get-WingetSystemApps { + + #Json File where to export system installed apps + $jsonFile = "$WorkingDir\winget_system_apps.txt" + + #Get list of installed Winget apps to json file + & $Winget export -o $jsonFile --accept-source-agreements -s winget | Out-Null + + #Convert json file to txt file with app ids + $InstalledApps = get-content $jsonFile | ConvertFrom-Json + + #Return app list + Set-Content $InstalledApps.Sources.Packages.PackageIdentifier -Path $jsonFile + +} diff --git a/Winget-AutoUpdate/functions/Invoke-PostUpdateActions.ps1 b/Winget-AutoUpdate/functions/Invoke-PostUpdateActions.ps1 index f03fae8..b1609e1 100644 --- a/Winget-AutoUpdate/functions/Invoke-PostUpdateActions.ps1 +++ b/Winget-AutoUpdate/functions/Invoke-PostUpdateActions.ps1 @@ -87,6 +87,36 @@ function Invoke-PostUpdateActions { } } + #Set new User Context task and Set system task readable/runnable for all users + $UserTask = Get-ScheduledTask -TaskName "Winget-AutoUpdate-UserContext" -ErrorAction SilentlyContinue + if (!$UserTask){ + # Settings for the scheduled task in User context + $taskAction = New-ScheduledTaskAction -Execute "wscript.exe" -Argument "`"$($WorkingDir)\Invisible.vbs`" `"powershell.exe -NoProfile -ExecutionPolicy Bypass -File `"`"`"$($WorkingDir)\winget-upgrade.ps1`"`"" + $taskUserPrincipal = New-ScheduledTaskPrincipal -GroupId S-1-5-11 + $taskSettings = New-ScheduledTaskSettingsSet -Compatibility Win8 -AllowStartIfOnBatteries -DontStopIfGoingOnBatteries -ExecutionTimeLimit 03:00:00 + # Set up the task for user apps + $task = New-ScheduledTask -Action $taskAction -Principal $taskUserPrincipal -Settings $taskSettings + Register-ScheduledTask -TaskName 'Winget-AutoUpdate-UserContext' -InputObject $task -Force | Out-Null + + #Set System task runnable for users + $scheduler = New-Object -ComObject "Schedule.Service" + $scheduler.Connect() + $task = $scheduler.GetFolder("").GetTask("Winget-AutoUpdate") + $sec = $task.GetSecurityDescriptor(0xF) + $sec = $sec + '(A;;GRGX;;;AU)' + $task.SetSecurityDescriptor($sec, 0) + } + + #Set ACL for users on logfile + $NewAcl = Get-Acl -Path $LogFile + $identity = New-Object System.Security.Principal.SecurityIdentifier S-1-5-11 + $fileSystemRights = "Modify" + $type = "Allow" + $fileSystemAccessRuleArgumentList = $identity, $fileSystemRights, $type + $fileSystemAccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $fileSystemAccessRuleArgumentList + $NewAcl.SetAccessRule($fileSystemAccessRule) + Set-Acl -Path $LogFile -AclObject $NewAcl + #Reset WAU_UpdatePostActions Value $WAUConfig | New-ItemProperty -Name WAU_PostUpdateActions -Value 0 -Force diff --git a/Winget-AutoUpdate/functions/Start-Init.ps1 b/Winget-AutoUpdate/functions/Start-Init.ps1 index 6dd41a3..7d79a44 100644 --- a/Winget-AutoUpdate/functions/Start-Init.ps1 +++ b/Winget-AutoUpdate/functions/Start-Init.ps1 @@ -9,33 +9,25 @@ function Start-Init { $Log = "`n##################################################`n# CHECK FOR APP UPDATES - $(Get-Date -Format (Get-culture).DateTimeFormat.ShortDatePattern)`n##################################################" $Log | Write-host - #Logs initialisation if admin - try { + #Logs initialisation + $Script:LogFile = "$WorkingDir\logs\updates.log" + + if (!(Test-Path $LogFile)) { + #Create file if doesn't exist + New-Item -ItemType File -Path $LogFile -Force - $LogPath = "$WorkingDir\logs" - - if (!(Test-Path $LogPath)) { - New-Item -ItemType Directory -Force -Path $LogPath - } - - #Log file - $Script:LogFile = "$LogPath\updates.log" - $Log | out-file -filepath $LogFile -Append - + #Set ACL for users on logfile + $NewAcl = Get-Acl -Path $LogFile + $identity = New-Object System.Security.Principal.SecurityIdentifier S-1-5-11 + $fileSystemRights = "Modify" + $type = "Allow" + $fileSystemAccessRuleArgumentList = $identity, $fileSystemRights, $type + $fileSystemAccessRule = New-Object -TypeName System.Security.AccessControl.FileSystemAccessRule -ArgumentList $fileSystemAccessRuleArgumentList + $NewAcl.SetAccessRule($fileSystemAccessRule) + Set-Acl -Path $LogFile -AclObject $NewAcl } - #Logs initialisation if non-admin - catch { - - $LogPath = "$env:USERPROFILE\Winget-AutoUpdate\logs" - - if (!(Test-Path $LogPath)) { - New-Item -ItemType Directory -Force -Path $LogPath - } - #Log file - $Script:LogFile = "$LogPath\updates.log" - $Log | out-file -filepath $LogFile -Append - - } + #Log file + $Log | out-file -filepath $LogFile -Append } \ No newline at end of file diff --git a/Winget-AutoUpdate/functions/Start-NotifTask.ps1 b/Winget-AutoUpdate/functions/Start-NotifTask.ps1 index 1d1b862..b505e0d 100644 --- a/Winget-AutoUpdate/functions/Start-NotifTask.ps1 +++ b/Winget-AutoUpdate/functions/Start-NotifTask.ps1 @@ -23,11 +23,8 @@ function Start-NotifTask ($Title, $Message, $MessageType, $Balise, $OnClickActio "@ - #Check if running account is system or interactive logon - $currentPrincipal = [bool](([System.Security.Principal.WindowsIdentity]::GetCurrent()).groups -match "S-1-5-4") - #if not "Interactive" user, run as system - if ($currentPrincipal -eq $false) { + if ($IsSystem) { #Save XML to File $ToastTemplateLocation = "$env:ProgramData\Winget-AutoUpdate\config\" diff --git a/Winget-AutoUpdate/functions/Test-PendingReboot.ps1 b/Winget-AutoUpdate/functions/Test-PendingReboot.ps1 index 795be9c..d126aa4 100644 --- a/Winget-AutoUpdate/functions/Test-PendingReboot.ps1 +++ b/Winget-AutoUpdate/functions/Test-PendingReboot.ps1 @@ -18,10 +18,6 @@ function Test-PendingReboot { if (([WmiClass]"\\$Computer\ROOT\CCM\ClientSDK:CCM_ClientUtilities").DetermineIfRebootPending().RebootPending -eq $true) {$PendingReboot = $true} } - # [PSCustomObject]@{ - # ComputerName = $Computer.ToUpper() - # PendingReboot = $PendingReboot - # } } return $PendingReboot diff --git a/Winget-AutoUpdate/winget-upgrade.ps1 b/Winget-AutoUpdate/winget-upgrade.ps1 index 2732fb0..24430c1 100644 --- a/Winget-AutoUpdate/winget-upgrade.ps1 +++ b/Winget-AutoUpdate/winget-upgrade.ps1 @@ -8,9 +8,20 @@ Get-ChildItem "$WorkingDir\functions" | ForEach-Object { . $_.FullName } <# MAIN #> +#Check if running account is system or interactive logon +$Script:IsSystem = [System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem + #Run log initialisation function Start-Init +#Log running context +if ($IsSystem) { + Write-Log "Running in System context" +} +else{ + Write-Log "Running in User context" +} + #Get WAU Configurations $Script:WAUConfig = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate" @@ -20,7 +31,7 @@ if (!($WAUConfig.WAU_PostUpdateActions -eq 0)) { } #Run Scope Machine funtion if run as system -if ([System.Security.Principal.WindowsIdentity]::GetCurrent().IsSystem) { +if ($IsSystem) { $SettingsPath = "$Env:windir\system32\config\systemprofile\AppData\Local\Microsoft\WinGet\Settings\defaultState\settings.json" Add-ScopeMachine $SettingsPath } @@ -51,7 +62,12 @@ if (Test-Network) { if ([version]$WAUAvailableVersion -gt [version]$WAUCurrentVersion) { #If new version is available, update it Write-Log "WAU Available version: $WAUAvailableVersion" "Yellow" - Update-WAU + if ($IsSystem) { + Update-WAU + } + else{ + Write-Log "WAU Needs to run as system to update" "Yellow" + } } else { Write-Log "WAU is up to date." "Green" @@ -95,6 +111,13 @@ if (Test-Network) { #Count good update installations $Script:InstallOK = 0 + #Trick under user context when -BypassListForUsers is used + if ($IsSystem -eq $false -and $WAUConfig.WAU_BypassListForUsers -eq $true){ + Write-Log "Bypass system list in user context is Enabled." + $UseWhiteList = $false + $toSkip = $null + } + #If White List if ($UseWhiteList) { #For each app, notify and update @@ -139,6 +162,24 @@ if (Test-Network) { } } +#Run WAU in user context if currently as system +if ($IsSystem) { + + #Get Winget system apps to excape them befor running user context + Get-WingetSystemApps + + #Run user context scheduled task + $UserScheduledTask = Get-ScheduledTask -TaskName "Winget-AutoUpdate-UserContext" -ErrorAction SilentlyContinue + if ($UserScheduledTask){ + Write-Log "Starting WAU in User context" + Start-ScheduledTask $UserScheduledTask.TaskName -ErrorAction SilentlyContinue + Exit 0 + } + else { + Write-Log "User context execution not installed" + } +} + #End Write-Log "End of process!" "Cyan" -Start-Sleep 3 \ No newline at end of file +Start-Sleep 3