Merge branch 'user-approval' of https://github.com/Romanitho/Winget-AutoUpdate into user-approval

draft-user-approval
romanitho 2023-05-09 12:00:29 +02:00
commit ddcd23b2d6
49 changed files with 1304 additions and 516 deletions

View File

@ -11,6 +11,10 @@
'PSPossibleIncorrectComparisonWithNull',
'PSAvoidTrailingWhitespace',
'PSUseApprovedVerbs',
'PSAvoidUsingWMICmdlet'
'PSAvoidUsingWMICmdlet',
'PSReviewUnusedParameter',
'PSUseDeclaredVarsMoreThanAssignment',
'PSUseShouldProcessForStateChangingFunctions',
'PSUseDeclaredVarsMoreThanAssignments'
)
}

View File

@ -1,8 +1,11 @@
---
name: Close inactive issues
on:
schedule:
- cron: "30 1 * * *"
permissions: read-all
jobs:
close-issues:
runs-on: ubuntu-latest
@ -10,7 +13,7 @@ jobs:
issues: write
pull-requests: write
steps:
- uses: actions/stale@v4
- uses: actions/stale@v8
with:
days-before-issue-stale: 30
days-before-issue-close: 14

View File

@ -0,0 +1,102 @@
---
name: WAU - Auto Create Pre-Release Version
on:
schedule:
- cron: "0 0 * * *"
permissions:
contents: write
jobs:
check_merged:
name: Compare latest merge and tag
runs-on: ubuntu-latest
outputs:
should_run: ${{ steps.should_run.outputs.SHOULD_RUN }}
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
fetch-depth: 0
- name: Check if latest merged is older than latest tag
id: should_run
run: |
echo "Latest tag:"
git log --tags --pretty="%ci - %h - %s %d" -n 1
LATEST_TAG_DATE=$(git log --tags -n 1 --pretty="%ct")
echo $LATEST_TAG_DATE
echo "Latest merge:"
git log --merges --pretty="%ci - %h - %s %d" -n 1
LATEST_MERGE_DATE=$(git log --merges -n 1 --pretty="%ct")
echo $LATEST_MERGE_DATE
if [[ $LATEST_MERGE_DATE -gt $LATEST_TAG_DATE ]]; then
echo "Latest tag is older than latest merge. Nightly will be created."
echo "SHOULD_RUN=true" >> $GITHUB_OUTPUT
else
echo "Latest merge is not older than latest tag. No new release needed."
echo "SHOULD_RUN=false" >> $GITHUB_OUTPUT
fi
build:
name: Create Release Asset
needs: [check_merged]
if: ${{ needs.check_merged.outputs.should_run == 'true' }}
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
lfs: "true"
fetch-depth: 0
- name: Auto Increment Semver Action
uses: MCKanpolat/auto-semver-action@1.0.10
id: versioning
with:
releaseType: prerelease
incrementPerCommit: false
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Next Release Number
id: WAU_version
run: |
echo "Next Release version: ${{ steps.versioning.outputs.version }}"
- name: Overwrite Version.txt file
uses: DamianReeves/write-file-action@v1.2
with:
path: Winget-AutoUpdate/Version.txt
write-mode: overwrite
contents: ${{ steps.versioning.outputs.version }}
- name: Commit & Push
uses: actions-js/push@v1.4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: main
force: true
message: "Changed version to ${{ steps.versioning.outputs.version }}"
- name: Build project
run: |
zip -r WAU Winget-AutoUpdate/*
zip -r WAU Winget-AutoUpdate-Install.ps1
zip -r WAU excluded_apps.txt
zip -r WAU install.bat
zip -r WAU uninstall.bat
- name: Create release
uses: "ncipollo/release-action@v1"
id: release
with:
tag: "v${{ steps.versioning.outputs.version }}"
prerelease: true
generateReleaseNotes: true
name: "v${{ steps.versioning.outputs.version }} [Nightly Build]"
artifacts: "WAU.zip"
- name: URL to release
run: echo "Release -> ${{ steps.release.outputs.html_url }}"

View File

@ -0,0 +1,71 @@
---
name: WAU - Create New Version
on:
workflow_dispatch:
inputs:
version:
type: choice
default: "Patch"
description: Select next release type
options:
- Patch
- Minor
- Major
required: true
pre-release:
type: boolean
description: Set as Pre-release version
permissions:
contents: write
jobs:
build:
name: Create Release Asset
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
with:
lfs: "true"
- name: Auto Increment Semver Action
uses: MCKanpolat/auto-semver-action@1.0.10
id: versioning
with:
releaseType: ${{ github.event.inputs.version }}
incrementPerCommit: false
github_token: ${{ secrets.GITHUB_TOKEN }}
- name: Overwrite Version.txt file
uses: DamianReeves/write-file-action@v1.2
with:
path: Winget-AutoUpdate/Version.txt
write-mode: overwrite
contents: "${{ steps.versioning.outputs.version }}"
- name: Commit & Push
uses: actions-js/push@v1.4
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
branch: main
force: true
message: "Changed version to ${{ steps.versioning.outputs.version }}"
- name: Build project
run: |
zip -r WAU Winget-AutoUpdate/*
zip -r WAU Winget-AutoUpdate-Install.ps1
zip -r WAU excluded_apps.txt
zip -r WAU install.bat
zip -r WAU uninstall.bat
- name: Create release
uses: "ncipollo/release-action@v1.12.0"
with:
tag: "v${{ steps.versioning.outputs.version }}"
prerelease: ${{ github.event.inputs.pre-release }}
generateReleaseNotes: true
name: "v${{ steps.versioning.outputs.version }}"
artifacts: "WAU.zip"

View File

@ -5,7 +5,7 @@ name: MegaLinter
on:
# Trigger mega-linter at every push. Action will also be visible from Pull Requests to main
push: # Comment this line to trigger action only on pull-requests (not recommended if you don't pay for GH Actions)
#push: # Comment this line to trigger action only on pull-requests (not recommended if you don't pay for GH Actions)
pull_request:
branches: [master, main]
@ -41,16 +41,16 @@ jobs:
id: ml
# You can override MegaLinter flavor used to have faster performances
# More info at https://megalinter.github.io/flavors/
uses: megalinter/megalinter@v6
uses: oxsecurity/megalinter@v6
env:
# All available variables are described in documentation
# https://megalinter.github.io/configuration/
VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/master' }} # Validates all source when push on main, else just the git diff with main. Override with true if you always want to lint all sources
VALIDATE_ALL_CODEBASE: ${{ github.event_name == 'push' && github.ref == 'refs/heads/main' }} # Validates all source when push on main, else just the git diff with main. Override with true if you always want to lint all sources
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
SPELL_CSPELL_CONFIG_FILE: .github/cspell.json
POWERSHELL_POWERSHELL_CONFIG_FILE: .github/.powershell-psscriptanalyzer.psd1
DISABLE_ERRORS_LINTERS: REPOSITORY_DEVSKIM,SPELL_CSPELL,SPELL_PROSELINT,COPYPASTE_JSCPD,MARKDOWN_MARKDOWN_LINK_CHECK
FILTER_REGEX_EXCLUDE: (.github/workflows/)
DISABLE_ERRORS_LINTERS: REPOSITORY_DEVSKIM,REPOSITORY_CHECKOV,REPOSITORY_GIT_DIFF,SPELL_CSPELL,SPELL_PROSELINT,COPYPASTE_JSCPD,MARKDOWN_MARKDOWN_LINK_CHECK
FILTER_REGEX_EXCLUDE: (workflows/)
# Upload MegaLinter artifacts
- name: Archive production artifacts
@ -67,7 +67,7 @@ jobs:
- name: Create Pull Request with applied fixes
id: cpr
if: steps.ml.outputs.has_updated_sources == 1 && (env.APPLY_FIXES_EVENT == 'all' || env.APPLY_FIXES_EVENT == github.event_name) && env.APPLY_FIXES_MODE == 'pull_request' && (github.event_name == 'push' || github.event.pull_request.head.repo.full_name == github.repository) && !contains(github.event.head_commit.message, 'skip fix')
uses: peter-evans/create-pull-request@v4
uses: peter-evans/create-pull-request@v5
with:
token: ${{ secrets.GITHUB_TOKEN }}
commit-message: "[MegaLinter] Apply linters automatic fixes"

58
.github/workflows/powershell-tests.yaml vendored Normal file
View File

@ -0,0 +1,58 @@
---
name: WAU Powershell Test Runs
# yamllint disable-line rule:truthy
on:
pull_request:
branches: [master, main]
workflow_dispatch:
permissions:
contents: read
pull-requests: read
jobs:
powershell-tests:
name: Pester test and PSScriptAnalyzer
runs-on: windows-latest
steps:
- name: Check out repository code
uses: actions/checkout@v3
- name: Perform a Pester test for the WAU installation
shell: powershell
run: |
$command = New-PesterContainer -Path Winget-AutoUpdate-Install.ps1 -Data @{ Silent = $true }
Invoke-Pester -PassThru -Container $command -ErrorAction Continue
- name: Perform a Pester test for WAU run
shell: powershell
run: |
$command = New-PesterContainer -Path C:\ProgramData\Winget-AutoUpdate\user-run.ps1
Invoke-Pester -PassThru -Container $command -ErrorAction Continue
#- name: Read WAU Log
# id: package
# uses: juliangruber/read-file-action@v1
# with:
# path: 'C:\ProgramData\Winget-AutoUpdate\Logs\updates.log'
#- name: Display WAU Log
# run: type "${{ steps.package.outputs.content }}"
- name: Install PSScriptAnalyzer module from PSGallery
shell: powershell
run: |
Set-PSRepository PSGallery -InstallationPolicy Trusted
Install-Module PSScriptAnalyzer -ErrorAction Stop
- name: Lint with PSScriptAnalyzer
shell: powershell
run: |
Invoke-ScriptAnalyzer -Path *.ps1 -Recurse -Outvariable issues
$errors = $issues.Where({$_.Severity -eq 'Error'})
$warnings = $issues.Where({$_.Severity -eq 'Warning'})
if ($($errors.Count) -gt 0) {
$ErrorAction = "Stop"
} else {
$ErrorAction = "Continue"
}
if ($errors) {
Write-Error "There were $($errors.Count) errors and $($warnings.Count) warnings total." -ErrorAction $ErrorAction
} else {
Write-Output "There were $($errors.Count) errors and $($warnings.Count) warnings total."
}

View File

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="utf-8"?>
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="4.7" xsi:schemaLocation="" schemaVersion="1.0" xmlns="http://www.microsoft.com/GroupPolicy/PolicyDefinitions">
<policyDefinitions xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="4.9" xsi:schemaLocation="" schemaVersion="1.0" xmlns="http://www.microsoft.com/GroupPolicy/PolicyDefinitions">
<policyNamespaces>
<target prefix="WAU" namespace="Romanitho.Policies.WAU"/>
</policyNamespaces>
<resources minRequiredRevision="4.7" fallbackCulture="en-us"/>
<resources minRequiredRevision="4.8" fallbackCulture="en-us"/>
<supportedOn>
<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_1_18_0" displayName="$(string.SUPPORTED_WAU_1_18_0)"/>
</definitions>
</supportedOn>
<categories><category displayName="$(string.WAU)" name="WAU"/></categories>
@ -99,6 +101,13 @@
<text id="ModsPath" valueName="WAU_ModsPath" />
</elements>
</policy>
<policy name="BlobURL_Enable" class="Machine" displayName="$(string.BlobURL_Name)" explainText="$(string.BlobURL_Explain)" key="Software\Policies\Romanitho\Winget-AutoUpdate" presentation="$(presentation.BlobURL)" >
<parentCategory ref="WAU"/>
<supportedOn ref="WAU:SUPPORTED_WAU_1_16_5"/>
<elements>
<text id="BlobURL" valueName="WAU_AzureBlobSASURL" />
</elements>
</policy>
<policy name="NotificationLevel_Enable" class="Machine" displayName="$(string.NotificationLevel_Name)" explainText="$(string.NotificationLevel_Explain)" key="Software\Policies\Romanitho\Winget-AutoUpdate" presentation="$(presentation.NotificationLevel)">
<parentCategory ref="WAU"/>
<supportedOn ref="WAU:SUPPORTED_WAU_1_16_0"/>
@ -341,6 +350,16 @@
<elements>
<text id="MaxLogSize" valueName="WAU_MaxLogSize" />
</elements>
</policy>
<policy name="UserApproval_Enable" class="Machine" displayName="$(string.UserApproval_Name)" explainText="$(string.UserApproval_Explain)" key="Software\Policies\Romanitho\Winget-AutoUpdate" valueName="WAU_UserApproval">
<parentCategory ref="WAU"/>
<supportedOn ref="WAU:SUPPORTED_WAU_1_18_0"/>
<enabledValue>
<decimal value="1" />
</enabledValue>
<disabledValue>
<decimal value="0" />
</disabledValue>
</policy>
</policies>
</policyDefinitions>

View File

@ -1,11 +1,13 @@
<?xml version="1.0" encoding="utf-8"?>
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="4.7" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<policyDefinitionResources xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" revision="4.9" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>WinGet-AutoUpdate</displayName>
<description>WinGet-AutoUpdate GPO Management</description>
<resources >
<stringTable >
<string id="WAU">Winget-AutoUpdate</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_1_18_0">Winget-AutoUpdate version 1.18.0 or later</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>
@ -43,10 +45,16 @@ If this policy is disabled or not configured, the default is No.</string>
If "Application GPO Blacklist/Whitelist" is set in this GPO the Path can be: GPO
If this policy is disabled or not configured, the default ListPath is used (WAU InstallLocation).</string>
<string id="ModsPath_Name">Get Mods from external Path (URL/UNC/Local)</string>
<string id="ModsPath_Explain">If this policy is enabled, you can set a (URL/UNC/Local) Path to external mods other than the default.
<string id="ModsPath_Name">Get Mods from external Path (URL/UNC/Local/AzureBlob)</string>
<string id="ModsPath_Explain">If this policy is enabled, you can set a (URL/UNC/Local/AzureBlob) Path to external mods other than the default.
If this policy is disabled or not configured, the default ModsPath is used (WAU InstallLocation).</string>
If this policy is disabled or not configured, the default ModsPath is used (WAU InstallLocation).
Note: When set to 'AzureBlob', ensure you also configure 'Set Azure Blob URL with SAS token'.</string>
<string id="BlobURL_Name">Set Azure Blob URL with SAS Token</string>
<string id="BlobURL_Explain">If this policy is enabled, you can set an Azure Storage Blob URL with SAS token for use with the 'Mods' feature. The URL must include the SAS token and have 'read' and 'list' permissions.
If this policy is disabled or not configured, the value is blank and Azure Blob storage will NOT work.</string>
<string id="NotificationLevel_Name">Notification Level</string>
<string id="NotificationLevel_Explain">If this policy is enabled, you can configure the Notification Level:
1. Full (Default)
@ -133,6 +141,10 @@ 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="UserApproval_Name">Specify if user approval is needed before updating apps</string>
<string id="UserApproval_Explain">This policy setting specifies whether to require user approval before updatings available application updates .
If this policy is disabled or not configured, the default is No.</string>
</stringTable>
<presentationTable>
<presentation id="BlackList">
@ -148,7 +160,12 @@ If this policy is disabled or not configured, the default size is used.</string>
</presentation>
<presentation id="ModsPath">
<textBox refId="ModsPath">
<label>(URL/UNC/Local) Path:</label>
<label>(URL/UNC/Local/AzureBlob) Path:</label>
</textBox>
</presentation>
<presentation id="BlobURL">
<textBox refId="BlobURL">
<label>Azure Storage URL with SAS token:</label>
</textBox>
</presentation>
<presentation id="NotificationLevel">

117
README.md
View File

@ -4,7 +4,7 @@ This project uses the Winget tool to daily update apps (with system context) and
![image](https://user-images.githubusercontent.com/96626929/150645599-9460def4-0818-4fe9-819c-dd7081ff8447.png)
## Intallation
Just [download latest release (source code)](https://github.com/Romanitho/Winget-AutoUpdate/releases), unzip, run "install.bat" as admin to install by default.
Just [download latest release (WAU.zip)](https://github.com/Romanitho/Winget-AutoUpdate/releases/latest/download/WAU.zip), unzip, run "install.bat" as admin to install by default.
## Configurations
### Keep some apps out of Winget-AutoUpdate
@ -29,7 +29,9 @@ By default, scripts and components will be placed in ProgramData location (insid
From version 1.9.0 (on new installations) WAU runs everyday at 6AM. You can now configure the frequency with `-UpdatesInterval` option (Daily, BiDaily, Weekly, BiWeekly or Monthly). You can also add `-UpdatesAtLogon` parameter to run at user logon and keep this option activated like previous versions (recommanded).
### Log location
You can find logs in install location, in logs folder.
You can find logs in install location, in logs folder.<br>
If **Intune Management Extension** is installed, a **SymLink** (WAU-updates.log) is created under **C:\ProgramData\Microsoft\IntuneManagementExtension\Logs**<br>
If you are deploying winget Apps with [Winget-Install](https://github.com/Romanitho/Winget-Install) a **SymLink** (WAU-install.log) is also created under **C:\ProgramData\Microsoft\IntuneManagementExtension\Logs**
### "Unknown" App version
As explained in this [post](https://github.com/microsoft/winget-cli/issues/1255), Winget cannot detect the current version of some installed apps. We decided to skip managing these apps with WAU to avoid retries each time WAU runs:
@ -70,38 +72,40 @@ Simply uninstall it from your programs:
## Advanced installation
You can run the `Winget-AutoUpdate-Install.ps1` script with parameters :
**-Silent**
**-Silent**<br>
Install Winget-AutoUpdate and prerequisites silently.
**-MaxLogFiles**
Specify number of allowed log files.
Default is 3 out of 0-99:
Setting MaxLogFiles to 0 don't delete any old archived log files.
**-MaxLogFiles**<br>
Specify number of allowed log files.<br>
Default is 3 out of 0-99:<br>
Setting MaxLogFiles to 0 don't delete any old archived log files.<br>
Setting it to 1 keeps the original one and just let it grow.
**-MaxLogSize**
Specify the size of the log file in bytes before rotating.
**-MaxLogSize**<br>
Specify the size of the log file in bytes before rotating.<br>
Default is 1048576 = 1 MB (ca. 7500 lines)
**-WingetUpdatePath**
**-WingetUpdatePath**<br>
Specify Winget-AutoUpdate installation location. Default: `C:\ProgramData\Winget-AutoUpdate` (Recommended to leave default).
**-DoNotUpdate**
**-DoNotUpdate**<br>
Do not run Winget-AutoUpdate after installation. By default, Winget-AutoUpdate is run just after installation.
**-DisableWAUAutoUpdate**
**-DisableWAUAutoUpdate**<br>
Disable Winget-AutoUpdate update checking. By default, WAU auto updates if new version is available on Github.
**-UseWhiteList**
**-UseWhiteList**<br>
Use White List instead of Black List. This setting will not create the "excluded_apps.txt" but "included_apps.txt".
**-ListPath**
Get Black/White List from external Path (**URL/UNC/GPO/Local**) - download/copy to Winget-AutoUpdate installation location if external list is newer.
If `-ListPath` is set to **GPO** the Black/White List can be managed from within the GPO itself under **Application GPO Blacklist**/**Application GPO Whitelist**.
Thanks to [Weatherlights](https://github.com/Weatherlights) in [#256 (reply in thread)](https://github.com/Romanitho/Winget-AutoUpdate/discussions/256#discussioncomment-4710599)!
**-ListPath**<br>
Get Black/White List from external Path (**URL/UNC/Local/GPO**) - download/copy to Winget-AutoUpdate installation location if external list is newer.<br>
**PATH** must end with a Directory, not a File...<br>
...if the external Path is an **URL** and the web host doesn't respond with a date/time header for the file (i.e **GitHub**) then the file is always downloaded!
**-ModsPath**
Get Mods from external Path (**URL/UNC/Local**) - download/copy to `mods` in Winget-AutoUpdate installation location if external mods are newer.
If `-ListPath` is set to **GPO** the Black/White List can be managed from within the GPO itself under **Application GPO Blacklist**/**Application GPO Whitelist**. Thanks to [Weatherlights](https://github.com/Weatherlights) in [#256 (reply in thread)](https://github.com/Romanitho/Winget-AutoUpdate/discussions/256#discussioncomment-4710599)!
**-ModsPath**<br>
Get Mods from external Path (**URL/UNC/Local/AzureBlob**) - download/copy to `mods` in Winget-AutoUpdate installation location if external mods are newer.<br>
For **URL**: This requires a site directory with **Directory Listing Enabled** and no index page overriding the listing of files (or an index page with href listing of all the **Mods** to be downloaded):
```
@ -114,41 +118,50 @@ For **URL**: This requires a site directory with **Directory Listing Enabled** a
```
Validated on **IIS/Apache**.
**Nota bene IIS** :
- The extension **.ps1** must be added as **MIME Types** (text/powershell-script) otherwise it's displayed in the listing but can't be opened
- Files with special characters in the filename can't be opened by default from an IIS server - config must be administrated: **Enable Allow double escaping** in '**Request Filtering**'
>**Nota bene IIS** :
>- The extension **.ps1** must be added as **MIME Types** (text/powershell-script) otherwise it's displayed in the listing but can't be opened
>- Files with special characters in the filename can't be opened by default from an IIS server - config must be administrated: **Enable Allow double escaping** in '**Request Filtering**'
**-InstallUserContext**
Install WAU with system and **user** context executions (From version 1.15.3).
For **AzureBlob**: This requires the parameter **-AzureBlobURL** to be set with an appropriate Azure Blob Storage URL including the SAS token. See **-AzureBlobURL** for more information.
**-BypassListForUsers**
**-AzureBlobURL**<br>
Used in conjunction with the **-ModsPath** parameter to provide the Azure Storage Blob URL with SAS token. The SAS token must, at a minimum, have 'Read' and 'List' permissions. It is recommended to set the permisions at the container level and rotate the SAS token on a regular basis. Ensure the container reflects the same structure as found under the initial `mods` folder. (From version 1.16.4).
**-InstallUserContext**<br>
Install WAU with system and **user** context executions (From version 1.15.3).<br>
Applications installed in system context will be ignored under user context.
**-BypassListForUsers**<br>
Bypass Black/White list when run in user context (From version 1.15.0).
**-NoClean**
**-NoClean**<br>
Keep critical files when installing/uninstalling. This setting will keep "excluded_apps.txt", "included_apps.txt", "mods" and "logs" as they were.
**-DesktopShortcut**
**-DesktopShortcut**<br>
Create a shortcut for user interaction on the Desktop to run task `Winget-AutoUpdate` (From version 1.15.0).
**-StartMenuShortcut**
**-StartMenuShortcut**<br>
Create shortcuts for user interaction in the Start Menu to run task `Winget-AutoUpdate`, open Logs and Web Help (From version 1.15.0).
**-NotificationLevel**
**-NotificationLevel**<br>
Specify the Notification level: Full (Default, displays all notification), SuccessOnly (Only displays notification for success) or None (Does not show any popup).
**-UpdatesAtLogon**
**-UpdatesAtLogon**<br>
Set WAU to run at user logon.
**-UpdatesInterval**
**-UpdatesInterval**<br>
Specify the update frequency: Daily (Default), BiDaily, Weekly, BiWeekly, Monthly or Never. Can be set to 'Never' in combination with '-UpdatesAtLogon' for instance.
**-UpdatesAtTime**
**-UpdatesAtTime**<br>
Specify the time of the update interval execution time. Default 6AM. (From version 1.15.0).
**-RunOnMetered**
**-UserApproval**<br>
Specify if user approval is needed before updating apps
**-RunOnMetered**<br>
Run WAU on metered connection. Default No.
**-Uninstall**
**-Uninstall**<br>
Remove scheduled tasks and scripts.
## Intune/SCCM use
@ -157,37 +170,37 @@ See https://github.com/Romanitho/Winget-AutoUpdate/discussions/88
## Custom scripts (Mods feature)
From version 1.8.0, 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` or `-installed` suffix in the **mods** folder.
> Runs before upgrade/install: `AppID-preinstall.ps1`
> Runs during upgrade/install (before install check): `AppID-upgrade.ps1`/`AppID-install.ps1`
> Runs after upgrade/install has been confirmed: `AppID-installed.ps1`
The **-install** mod will be used for upgrades too if **-upgrade** doesn't exist (**WAU** first tries `& $Winget upgrade --id` and if the app isn't detected after that `& $Winget install --id` is tried).
>- Runs before upgrade/install: `AppID-preinstall.ps1`<br>
>- Runs during upgrade/install (before install check): `AppID-upgrade.ps1`/`AppID-install.ps1`<br>
>- Runs after upgrade/install has been confirmed: `AppID-installed.ps1`
The **-install** mod will be used for upgrades too if **-upgrade** doesn't exist (**WAU** first tries `& $Winget upgrade --id` and if the app isn't detected after that `& $Winget install --id` is tried).<br>
`AppID-install.ps1` is recommended because it's used in **both** scenarios.
> Example:
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.
> 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-Install#custom-mods), as it's a related feature.
You can find more information on [Winget-Install Repo](https://github.com/Romanitho/Winget-Install#custom-mods), as it's a related feature.<br>
Read more in the `README.md` under the directory **mods**.
Share your mods with the community:
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:
> **Canneverbe.CDBurnerXP-override.txt** with the content `ADDLOCAL=All REMOVE=Desktop_Shortcut /qn`
> Example:<br>
**Canneverbe.CDBurnerXP-override.txt** with the content `ADDLOCAL=All REMOVE=Desktop_Shortcut /qn`
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)).
## GPO Management
In an enterprise environment it's crucial that different groups can have different settings in applications etc. or to implement other mandatory settings, i.e for security/management reasons.
**WAU** doesn't have any setting that can be changed except for when installing (or editing the registry/the task `Winget-AutoUpdate` as **Admin**).
With the use of **ADML/ADMX** files you can manage every **WAU** setting from within **GPO**.
They will be detected/evaluated during the next run of **WAU** (taking effect before any actions).
The **GPO ADMX/ADML** validated with:
[Windows 10 - Validate ADMX for Ingestion](https://developer.vmware.com/samples/7115/windows-10---validate-admx-for-ingestion)
In an enterprise environment it's crucial that different groups can have different settings in applications etc. or to implement other mandatory settings, i.e for security/management reasons.<br>
**WAU** doesn't have any setting that can be changed except for when installing (or editing the registry/the task `Winget-AutoUpdate` as **Admin**).<br>
With the use of **ADML/ADMX** files you can manage every **WAU** setting from within **GPO**.<br>
They will be detected/evaluated during the next run of **WAU** (taking effect before any actions).<br>
The **GPO ADMX/ADML** validated with: [Windows 10 - Validate ADMX for Ingestion](https://developer.vmware.com/samples/7115/windows-10---validate-admx-for-ingestion)<br>
Read more in the `README.md` under the directory **Policies**.
![image](https://user-images.githubusercontent.com/102996177/213920242-7ff8e2b4-d926-4407-b860-1e5922e29c3e.png)
@ -199,4 +212,4 @@ In some cases, you need to "unblock" the `install.bat` file (Windows Defender Sm
* 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
## Optimization
Feel free to give us any suggestions or optimizations in code and support us by adding a star :).
Feel free to give us any suggestions or optimizations in code and support us by adding a star :)

View File

@ -4,7 +4,7 @@ Configure Winget to daily update installed apps.
.DESCRIPTION
Install powershell scripts and scheduled task to daily run Winget upgrade and notify connected users.
Possible to exclude apps from auto-update
Posibility to exclude apps from auto-update
https://github.com/Romanitho/Winget-AutoUpdate
.PARAMETER Silent
@ -29,10 +29,13 @@ Disable Winget-AutoUpdate update checking. By default, WAU auto update if new ve
Use White List instead of Black List. This setting will not create the "exclude_apps.txt" but "include_apps.txt"
.PARAMETER ListPath
Get Black/White List from Path (URL/UNC/Local)
Get Black/White List from Path (URL/UNC/GPO/Local)
.PARAMETER ModsPath
Get mods from Path (URL/UNC/Local)
Get mods from Path (URL/UNC/Local/AzureBlob)
.PARAMETER AzureBlobURL
Set the Azure Storage Blob URL including the SAS token. The token requires at a minimum 'Read' and 'List' permissions. It is recommended to set this at the container level
.PARAMETER Uninstall
Remove scheduled tasks and scripts.
@ -64,8 +67,11 @@ Run WAU on metered connection. Default No.
.PARAMETER InstallUserContext
Install WAU with system and user context executions
.PARAMETER UserApproval
Specify if user approval is needed before updating apps
.PARAMETER BypassListForUsers
Configure WAU to bypass the Black/White list when run in user context
Configure WAU to bypass the Black/White list when run in user context. Applications installed in system context will be ignored under user context.
.EXAMPLE
.\Winget-AutoUpdate-Install.ps1 -Silent -DoNotUpdate -MaxLogFiles 4 -MaxLogSize 2097152
@ -93,6 +99,7 @@ param(
[Parameter(Mandatory = $False)] [Alias('Path')] [String] $WingetUpdatePath = "$env:ProgramData\Winget-AutoUpdate",
[Parameter(Mandatory = $False)] [Alias('List')] [String] $ListPath,
[Parameter(Mandatory = $False)] [Alias('Mods')] [String] $ModsPath,
[Parameter(Mandatory = $False)] [Alias('AzureBlobURL')] [String] $AzureBlobSASURL,
[Parameter(Mandatory = $False)] [Switch] $DoNotUpdate = $false,
[Parameter(Mandatory = $False)] [Switch] $DisableWAUAutoUpdate = $false,
[Parameter(Mandatory = $False)] [Switch] $RunOnMetered = $false,
@ -107,13 +114,11 @@ param(
[Parameter(Mandatory = $False)] [DateTime] $UpdatesAtTime = ("06am"),
[Parameter(Mandatory = $False)] [Switch] $BypassListForUsers = $false,
[Parameter(Mandatory = $False)] [Switch] $InstallUserContext = $false,
[Parameter(Mandatory = $False)] [ValidateRange(0,99)] [int32] $MaxLogFiles = 3,
[Parameter(Mandatory = $False)] [Switch] $UserApproval= $false,
[Parameter(Mandatory = $False)] [ValidateRange(0, 99)] [int32] $MaxLogFiles = 3,
[Parameter(Mandatory = $False)] [int64] $MaxLogSize = 1048576 # in bytes, default is 1048576 = 1 MB
)
<# APP INFO #>
$WAUVersion = "1.15.3"
<# FUNCTIONS #>
@ -158,7 +163,7 @@ function Install-Prerequisites {
$SourceURL = "https://aka.ms/vs/17/release/VC_redist.$OSArch.exe"
$Installer = $WingetUpdatePath + "\VC_redist.$OSArch.exe"
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest $SourceURL -OutFile (New-Item -Path $Installer -Force)
Invoke-WebRequest $SourceURL -UseBasicParsing -OutFile (New-Item -Path $Installer -Force)
Write-host "-> Installing VC_redist.$OSArch.exe..."
Start-Process -FilePath $Installer -Args "/quiet /norestart" -Wait
Remove-Item $Installer -ErrorAction Ignore
@ -344,8 +349,6 @@ function Install-WingetAutoUpdate {
New-ItemProperty $regPath -Name QuietUninstallString -Value "powershell.exe -noprofile -executionpolicy bypass -file `"$WingetUpdatePath\WAU-Uninstall.ps1`"" -Force | Out-Null
New-ItemProperty $regPath -Name NoModify -Value 1 -Force | Out-Null
New-ItemProperty $regPath -Name NoRepair -Value 1 -Force | Out-Null
New-ItemProperty $regPath -Name VersionMajor -Value ([version]$WAUVersion).Major -Force | Out-Null
New-ItemProperty $regPath -Name VersionMinor -Value ([version]$WAUVersion).Minor -Force | Out-Null
New-ItemProperty $regPath -Name Publisher -Value "Romanitho" -Force | Out-Null
New-ItemProperty $regPath -Name URLInfoAbout -Value "https://github.com/Romanitho/Winget-AutoUpdate" -Force | Out-Null
New-ItemProperty $regPath -Name WAU_NotificationLevel -Value $NotificationLevel -Force | Out-Null
@ -368,21 +371,32 @@ function Install-WingetAutoUpdate {
if ($ModsPath) {
New-ItemProperty $regPath -Name WAU_ModsPath -Value $ModsPath -Force | Out-Null
}
if ($AzureBlobSASURL) {
New-ItemProperty $regPath -Name WAU_AzureBlobSASURL -Value $AzureBlobSASURL -Force | Out-Null
}
if ($BypassListForUsers) {
New-ItemProperty $regPath -Name WAU_BypassListForUsers -Value 1 -PropertyType DWord -Force | Out-Null
}
if ($UserApproval) {
New-ItemProperty $regPath -Name WAU_UserApproval -Value 1 -PropertyType DWord -Force | Out-Null
}
#Set ACL for users on logfile
$LogFile = "$WingetUpdatePath\logs\updates.log"
if (test-path $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
#Log file and symlink initialization
. "$WingetUpdatePath\functions\Start-Init.ps1"
Start-Init
#Security check
Write-host "`nChecking Mods Directory:" -ForegroundColor Yellow
. "$WingetUpdatePath\functions\Invoke-ModsProtect.ps1"
$Protected = Invoke-ModsProtect "$WingetUpdatePath\mods"
if ($Protected -eq $True) {
Write-Host "The mods directory is now secured!`n" -ForegroundColor Green
}
elseif ($Protected -eq $False) {
Write-Host "The mods directory was already secured!`n" -ForegroundColor Green
}
else {
Write-Host "Error: The mods directory couldn't be verified as secured!`n" -ForegroundColor Red
}
#Create Shortcuts
@ -425,6 +439,12 @@ function Uninstall-WingetAutoUpdate {
if (!$NoClean) {
Remove-Item $InstallLocation -Force -Recurse
if (Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log") {
Remove-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log" -Force -ErrorAction SilentlyContinue | Out-Null
}
if (Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log") {
Remove-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log" -Force -ErrorAction SilentlyContinue | Out-Null
}
}
else {
#Keep critical files
@ -506,6 +526,12 @@ function Add-Shortcut ($Target, $Shortcut, $Arguments, $Icon, $Description) {
$Shortcut.Save()
}
<# APP INFO #>
$WAUVersion = Get-Content "$PSScriptRoot\Winget-AutoUpdate\Version.txt" -ErrorAction SilentlyContinue
<# MAIN #>
#If running as a 32-bit process on an x64 system, re-launch as a 64-bit process
@ -540,5 +566,6 @@ else {
Uninstall-WingetAutoUpdate
}
Remove-Item "$WingetUpdatePath\Version.txt" -Force
Write-host "`nEnd of process." -ForegroundColor Cyan
Start-Sleep 3

View File

@ -21,8 +21,7 @@ https://github.com/Romanitho/Winget-AutoUpdate
param(
[Parameter(Mandatory = $False)] [Switch] $Logs = $false,
[Parameter(Mandatory = $False)] [Switch] $Help = $false,
[Parameter(Mandatory = $False)] [Switch] $NotifApprovedAsSystem = $false,
[Parameter(Mandatory = $False)] [Switch] $NotifApprovedAsUser = $false
[Parameter(Mandatory = $False)] [String] $NotifApproved
)
function Test-WAUisRunning {
@ -55,23 +54,42 @@ if ($Logs) {
#Not available yet
$Message = $NotifLocale.local.outputs.output[5].message
$MessageType = "warning"
Start-NotifTask -Message $Message -MessageType $MessageType
Start-NotifTask -Message $Message -MessageType $MessageType -UserRun
}
}
elseif ($Help) {
Start-Process "https://github.com/Romanitho/Winget-AutoUpdate"
}
elseif ($NotifApprovedAsUser){
elseif ($NotifApproved){
$MessageBody = "Do you want to update these apps ?`n`n"
$MessageBody += Get-Content "$WorkingDir/config/NotifContent.txt" -Raw
$Title = "Winget-AutoUpdate"
if ($NotifApproved -eq "wau:systemDialogBox"){
Add-Type -AssemblyName PresentationCore,PresentationFramework
$Result = [System.Windows.MessageBox]::Show($MessageBody,$Title,4,32)
if ($Result -eq "Yes") {
$NotifApproved = "wau:system"
}
}
if ($NotifApproved -eq "wau:userDialogBox"){
Add-Type -AssemblyName PresentationCore,PresentationFramework
$Result = [System.Windows.MessageBox]::Show($MessageBody,$Title,4,32)
if ($Result -eq "Yes") {
$NotifApproved = "wau:user"
}
}
if ($NotifApproved -eq "wau:system"){
#Create tag if user approve notif for requested updates
$WAUNotifApprovedPath = "$WingetUpdatePath\config\NotifApproved.txt"
$WAUNotifApprovedPath = "$WorkingDir\config\NotifApproved.txt"
New-Item $WAUNotifApprovedPath -Force
Get-ScheduledTask -TaskName "Winget-AutoUpdate-UserContext" -ErrorAction SilentlyContinue | Start-ScheduledTask -ErrorAction SilentlyContinue
}
elseif ($NotifApprovedAsSystem){
Get-ScheduledTask -TaskName "Winget-AutoUpdate" -ErrorAction Stop | Start-ScheduledTask -ErrorAction Stop
}
if ($NotifApproved -eq "wau:user"){
#Create tag if user approve notif for requested updates
$WAUNotifApprovedPath = "$WingetUpdatePath\config\NotifApproved.txt"
$WAUNotifApprovedPath = "$WorkingDir\config\NotifApproved.txt"
New-Item $WAUNotifApprovedPath -Force
Get-ScheduledTask -TaskName "Winget-AutoUpdate" -ErrorAction SilentlyContinue | Start-ScheduledTask -ErrorAction SilentlyContinue
Get-ScheduledTask -TaskName "Winget-AutoUpdate-UserContext" -ErrorAction Stop | Start-ScheduledTask -ErrorAction Stop
}
}
else {
try {
@ -79,7 +97,7 @@ else {
if (Test-WAUisRunning) {
$Message = $NotifLocale.local.outputs.output[8].message
$MessageType = "warning"
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -ButtonDismiss
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -UserRun
break
}
#Run scheduled task
@ -87,7 +105,7 @@ else {
#Starting check - Send notification
$Message = $NotifLocale.local.outputs.output[6].message
$MessageType = "info"
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -ButtonDismiss
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -UserRun
#Sleep until the task is done
While (Test-WAUisRunning) {
Start-Sleep 3
@ -105,12 +123,15 @@ else {
$MessageType = "success"
$Message = $NotifLocale.local.outputs.output[9].message
}
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -ButtonDismiss
$IsUserApprovalEnable = (Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate\" -Name WAU_UserApproval -ErrorAction SilentlyContinue).WAU_UserApproval
if ($IsUserApprovalEnable -ne "1"){
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -UserRun
}
}
catch {
#Check failed - Just send notification
$Message = $NotifLocale.local.outputs.output[7].message
$MessageType = "error"
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -ButtonDismiss
Start-NotifTask -Message $Message -MessageType $MessageType -Button1Text $Button1Text -Button1Action $OnClickAction -UserRun
}
}

View File

@ -0,0 +1 @@
1.17.5-1

View File

@ -3,7 +3,7 @@
Uninstall Winget-AutoUpdate
.DESCRIPTION
Uninstall Winget-AutoUpdate (DEFAULT: clean old install)
Uninstalls Winget-AutoUpdate (DEFAULT: clean old install)
https://github.com/Romanitho/Winget-AutoUpdate
.PARAMETER NoClean
@ -65,6 +65,14 @@ try {
Remove-Item -Path "${env:Public}\Desktop\WAU - Check for updated Apps.lnk" -Force | Out-Null
}
#Remove Intune Logs if they are existing
if (Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log") {
Remove-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log" -Force -ErrorAction SilentlyContinue | Out-Null
}
if (Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log") {
Remove-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log" -Force -ErrorAction SilentlyContinue | Out-Null
}
Write-host "Uninstallation succeeded!" -ForegroundColor Green
}
else {

View File

@ -1,4 +1,4 @@
#Send Notif Script
#Send Notify Script
#get xml notif config
$WAUinstalledPath = Get-ItemPropertyValue -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate\" -Name InstallLocation

View File

@ -1,6 +1,6 @@
<# LOAD FUNCTIONS #>
#Get Working Dir
#Get the Working Dir
$Script:WorkingDir = $PSScriptRoot
#Get Functions
Get-ChildItem "$WorkingDir\functions" | ForEach-Object { . $_.FullName }
@ -19,17 +19,17 @@ $Script:WAUConfig = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\Cur
#Log running context and more...
if ($IsSystem) {
Write-Log "Running in System context"
Write-ToLog "Running in System context"
#Get and set Domain/Local Policies (GPO)
$ActivateGPOManagement, $ChangedSettings = Get-Policies
if ($ActivateGPOManagement) {
Write-Log "Activated WAU GPO Management detected, comparing..."
Write-ToLog "Activated WAU GPO Management detected, comparing..."
if ($null -ne $ChangedSettings -and $ChangedSettings -ne 0) {
Write-Log "Changed settings detected and applied" "Yellow"
Write-ToLog "Changed settings detected and applied" "Yellow"
}
else {
Write-Log "No Changed settings detected" "Yellow"
Write-ToLog "No Changed settings detected" "Yellow"
}
}
@ -54,7 +54,7 @@ if ($IsSystem) {
#LogRotation if System
$LogRotate = Invoke-LogRotation $LogFile $MaxLogFiles $MaxLogSize
if ($LogRotate -eq $False) {
Write-Log "An Exception occured during Log Rotation..."
Write-ToLog "An Exception occured during Log Rotation..."
}
#Run post update actions if necessary if run as System
@ -66,12 +66,12 @@ if ($IsSystem) {
Add-ScopeMachine $SettingsPath
}
else {
Write-Log "Running in User context"
Write-ToLog "Running in User context"
}
#Get Notif Locale function
$LocaleDisplayName = Get-NotifLocale
Write-Log "Notification Level: $($WAUConfig.WAU_NotificationLevel). Notification Language: $LocaleDisplayName" "Cyan"
Write-ToLog "Notification Level: $($WAUConfig.WAU_NotificationLevel). Notification Language: $LocaleDisplayName" "Cyan"
#Check network connectivity
if (Test-Network) {
@ -81,26 +81,26 @@ if (Test-Network) {
if ($TestWinget) {
#Get Current Version
$WAUCurrentVersion = $WAUConfig.DisplayVersion
Write-Log "WAU current version: $WAUCurrentVersion"
Write-ToLog "WAU current version: $WAUCurrentVersion"
if ($IsSystem) {
#Check if WAU update feature is enabled or not if run as System
$WAUDisableAutoUpdate = $WAUConfig.WAU_DisableAutoUpdate
#If yes then check WAU update if run as System
if ($WAUDisableAutoUpdate -eq 1) {
Write-Log "WAU AutoUpdate is Disabled." "Grey"
Write-ToLog "WAU AutoUpdate is Disabled." "Gray"
}
else {
Write-Log "WAU AutoUpdate is Enabled." "Green"
Write-ToLog "WAU AutoUpdate is Enabled." "Green"
#Get Available Version
$WAUAvailableVersion = Get-WAUAvailableVersion
$Script:WAUAvailableVersion = Get-WAUAvailableVersion
#Compare
if ([version]$WAUAvailableVersion -gt [version]$WAUCurrentVersion) {
if ([version]$WAUAvailableVersion.Replace("-", ".") -ne [version]$WAUCurrentVersion.Replace("-", ".")) {
#If new version is available, update it
Write-Log "WAU Available version: $WAUAvailableVersion" "Yellow"
Write-ToLog "WAU Available version: $WAUAvailableVersion" "Yellow"
Update-WAU
}
else {
Write-Log "WAU is up to date." "Green"
Write-ToLog "WAU is up to date." "Green"
}
}
@ -111,25 +111,36 @@ if (Test-Network) {
#Get External ListPath if run as System
if ($WAUConfig.WAU_ListPath) {
Write-Log "WAU uses External Lists from: $($WAUConfig.WAU_ListPath.TrimEnd(" ", "\", "/"))"
if ($($WAUConfig.WAU_ListPath) -ne "GPO") {
$NewList = Test-ListPath $WAUConfig.WAU_ListPath.TrimEnd(" ", "\", "/") $WAUConfig.WAU_UseWhiteList $WAUConfig.InstallLocation.TrimEnd(" ", "\")
$ListPathClean = $($WAUConfig.WAU_ListPath.TrimEnd(" ", "\", "/"))
Write-ToLog "WAU uses External Lists from: $ListPathClean"
if ($ListPathClean -ne "GPO") {
$NewList = Test-ListPath $ListPathClean $WAUConfig.WAU_UseWhiteList $WAUConfig.InstallLocation.TrimEnd(" ", "\")
if ($ReachNoPath) {
Write-Log "Couldn't reach/find/compare/copy from $($WAUConfig.WAU_ListPath.TrimEnd(" ", "\", "/"))..." "Red"
Write-ToLog "Couldn't reach/find/compare/copy from $ListPathClean..." "Red"
if ($ListPathClean -notlike "http*") {
if (Test-Path -Path "$ListPathClean" -PathType Leaf) {
Write-ToLog "PATH must end with a Directory, not a File..." "Red"
}
}
else {
if ($ListPathClean -match "_apps.txt") {
Write-ToLog "PATH must end with a Directory, not a File..." "Red"
}
}
$Script:ReachNoPath = $False
}
if ($NewList) {
Write-Log "Newer List downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))" "Yellow"
Write-ToLog "Newer List downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))" "Yellow"
}
else {
if ($WAUConfig.WAU_UseWhiteList -and (Test-Path "$WorkingDir\included_apps.txt")) {
Write-Log "List (white) is up to date." "Green"
Write-ToLog "List (white) is up to date." "Green"
}
elseif (!$WAUConfig.WAU_UseWhiteList -and (Test-Path "$WorkingDir\excluded_apps.txt")) {
Write-Log "List (black) is up to date." "Green"
Write-ToLog "List (black) is up to date." "Green"
}
else {
Write-Log "Critical: White/Black List doesn't exist, exiting..." "Red"
Write-ToLog "Critical: White/Black List doesn't exist, exiting..." "Red"
New-Item "$WorkingDir\logs\error.txt" -Value "White/Black List doesn't exist" -Force
Exit 1
}
@ -139,25 +150,31 @@ if (Test-Network) {
#Get External ModsPath if run as System
if ($WAUConfig.WAU_ModsPath) {
Write-Log "WAU uses External Mods from: $($WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/"))"
$NewMods, $DeletedMods = Test-ModsPath $WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/") $WAUConfig.InstallLocation.TrimEnd(" ", "\")
$ModsPathClean = $($WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/"))
Write-ToLog "WAU uses External Mods from: $ModsPathClean"
if ($WAUConfig.WAU_AzureBlobSASURL) {
$NewMods, $DeletedMods = Test-ModsPath $ModsPathClean $WAUConfig.InstallLocation.TrimEnd(" ", "\") $WAUConfig.WAU_AzureBlobSASURL.TrimEnd(" ")
}
else {
$NewMods, $DeletedMods = Test-ModsPath $ModsPathClean $WAUConfig.InstallLocation.TrimEnd(" ", "\")
}
if ($ReachNoPath) {
Write-Log "Couldn't reach/find/compare/copy from $($WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/"))..." "Red"
Write-ToLog "Couldn't reach/find/compare/copy from $ModsPathClean..." "Red"
$Script:ReachNoPath = $False
}
if ($NewMods -gt 0) {
Write-Log "$NewMods newer Mods downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))\mods" "Yellow"
Write-ToLog "$NewMods newer Mods downloaded/copied to local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))\mods" "Yellow"
}
else {
if (Test-Path "$WorkingDir\mods\*.ps1") {
Write-Log "Mods are up to date." "Green"
Write-ToLog "Mods are up to date." "Green"
}
else {
Write-Log "No Mods are implemented..." "Yellow"
Write-ToLog "No Mods are implemented..." "Yellow"
}
}
if ($DeletedMods -gt 0) {
Write-Log "$DeletedMods Mods deleted (not externally managed) from local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))\mods" "Red"
Write-ToLog "$DeletedMods Mods deleted (not externally managed) from local path: $($WAUConfig.InstallLocation.TrimEnd(" ", "\"))\mods" "Red"
}
}
}
@ -168,12 +185,12 @@ if (Test-Network) {
#Get White or Black list
if ($WAUConfig.WAU_UseWhiteList -eq 1) {
Write-Log "WAU uses White List config"
Write-ToLog "WAU uses White List config"
$toUpdate = Get-IncludedApps
$UseWhiteList = $true
}
else {
Write-Log "WAU uses Black List config"
Write-ToLog "WAU uses Black List config"
$toSkip = Get-ExcludedApps
}
@ -182,7 +199,7 @@ if (Test-Network) {
if ($UseWhiteList) {
$WhiteList = $toUpdate.GetUpperBound(0)
if ($null -eq $WhiteList) {
Write-Log "Critical: Whitelist doesn't exist in GPO, exiting..." "Red"
Write-ToLog "Critical: Whitelist doesn't exist in GPO, exiting..." "Red"
New-Item "$WorkingDir\logs\error.txt" -Value "Whitelist doesn't exist in GPO" -Force
Exit 1
}
@ -191,7 +208,7 @@ if (Test-Network) {
else {
$BlackList = $toSkip.GetUpperBound(0)
if ($null -eq $BlackList) {
Write-Log "Critical: Blacklist doesn't exist in GPO, exiting..." "Red"
Write-ToLog "Critical: Blacklist doesn't exist in GPO, exiting..." "Red"
New-Item "$WorkingDir\logs\error.txt" -Value "Blacklist doesn't exist in GPO" -Force
Exit 1
}
@ -200,17 +217,17 @@ if (Test-Network) {
}
#Get outdated Winget packages
Write-Log "Checking application updates on Winget Repository..." "yellow"
Write-ToLog "Checking application updates on Winget Repository..." "yellow"
$outdated = Get-WingetOutdatedApps
#If something is wrong with the winget source, exit
if ($outdated -like "Problem:*") {
Write-Log "Critical: An error occured, exiting..." "red"
Write-Log "$outdated" "red"
New-Item "$WorkingDir\logs\error.txt" -Value "$outdated" -Force
Exit 1
#If something unusual happened
if ($outdated -like "An unusual*") {
Write-ToLog "$outdated" "cyan"
$outdated = $False
}
#Run only if $outdated is populated!
if ($outdated) {
#Log list of app to update
foreach ($app in $outdated) {
#List available updates
@ -219,54 +236,35 @@ if (Test-Network) {
$Log | out-file -filepath $LogFile -Append
}
#Ask for user if configured
#Ask user to approve, if configured
if ($WAUConfig.WAU_UserApproval -eq 1){
Write-Log "User Approval feature enabled."
Write-ToLog "User Approval feature enabled."
#Check for approved tag
$WAUNotifApproved = "$WorkingDir/Config/NotifApproved.txt"
if (!(Test-Path $WAUNotifApproved)) {
if (Test-Path $WAUNotifApproved) {
Write-ToLog "-> User approved update notification."
Remove-Item $WAUNotifApproved -Force -Confirm:$false
}
else {
$UserApprovalReturn = Invoke-UserApproval $outdated
if ($UserApprovalReturn -eq 0){
Write-Log "-> User approval requested. Waiting for user to approve available updates..."
Write-ToLog "-> User approval requested. Waiting for user to approve available updates... Closing for now."
#Closing job, waiting for user approval
Exit 0
}
else{
Write-log "-> No update to request to user."
Write-ToLog "-> No update to request to user."
}
}
else {
Write-Log "-> User approved notification."
}
} #Ask for user if configured
if ($WAUConfig.WAU_UserApproval -eq 1){
Write-Log "User Approval feature enabled."
#Check for approved tag
$WAUNotifApproved = "$WorkingDir/Config/NotifApproved.txt"
if (!(Test-Path $WAUNotifApproved)) {
$UserApprovalReturn = Invoke-UserApproval $outdated
if ($UserApprovalReturn -eq 0){
Write-Log "-> User approval requested. Waiting for user to approve available updates..."
#Closing job, waiting for user approval
Exit 0
}
else{
Write-log "-> No update to request to user."
}
}
else {
Write-Log "-> User approved notification."
}
}
#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."
if ($IsSystem -eq $false -and $WAUConfig.WAU_BypassListForUsers -eq 1) {
Write-ToLog "Bypass system list in user context is Enabled."
$UseWhiteList = $false
$toSkip = $null
}
@ -280,11 +278,11 @@ if (Test-Network) {
}
#if current app version is unknown
elseif ($($app.Version) -eq "Unknown") {
Write-Log "$($app.Name) : Skipped upgrade because current version is 'Unknown'" "Gray"
Write-ToLog "$($app.Name) : Skipped upgrade because current version is 'Unknown'" "Gray"
}
#if app is in "excluded list"
else {
Write-Log "$($app.Name) : Skipped upgrade because it is not in the included app list" "Gray"
Write-ToLog "$($app.Name) : Skipped upgrade because it is not in the included app list" "Gray"
}
}
}
@ -297,20 +295,22 @@ if (Test-Network) {
}
#if current app version is unknown
elseif ($($app.Version) -eq "Unknown") {
Write-Log "$($app.Name) : Skipped upgrade because current version is 'Unknown'" "Gray"
Write-ToLog "$($app.Name) : Skipped upgrade because current version is 'Unknown'" "Gray"
}
#if app is in "excluded list"
else {
Write-Log "$($app.Name) : Skipped upgrade because it is in the excluded app list" "Gray"
Write-ToLog "$($app.Name) : Skipped upgrade because it is in the excluded app list" "Gray"
}
}
}
if ($InstallOK -gt 0) {
Write-Log "$InstallOK apps updated ! No more update." "Green"
Write-ToLog "$InstallOK apps updated ! No more update." "Green"
}
if ($InstallOK -eq 0) {
Write-Log "No new update." "Green"
}
if ($InstallOK -eq 0 -or !$InstallOK) {
Write-ToLog "No new update." "Green"
}
#Check if any user is logged on if System and run User task (if installed)
@ -318,7 +318,7 @@ if (Test-Network) {
#User check routine from: https://stackoverflow.com/questions/23219718/powershell-script-to-see-currently-logged-in-users-domain-and-machine-status
$explorerprocesses = @(Get-WmiObject -Query "Select * FROM Win32_Process WHERE Name='explorer.exe'" -ErrorAction SilentlyContinue)
If ($explorerprocesses.Count -eq 0) {
Write-Log "No explorer process found / Nobody interactively logged on..."
Write-ToLog "No explorer process found / Nobody interactively logged on..."
}
Else {
#Run WAU in user context if the user task exist
@ -326,28 +326,28 @@ if (Test-Network) {
if ($UserScheduledTask) {
#Get Winget system apps to excape them befor running user context
Write-Log "User logged on, get a list of installed Winget apps in System context..."
Write-ToLog "User logged on, get a list of installed Winget apps in System context..."
Get-WingetSystemApps
#Run user context scheduled task
Write-Log "Starting WAU in User context"
Write-ToLog "Starting WAU in User context"
Start-ScheduledTask $UserScheduledTask.TaskName -ErrorAction SilentlyContinue
Exit 0
}
elseif (!$UserScheduledTask) {
Write-Log "User context execution not installed..."
Write-ToLog "User context execution not installed..."
}
}
}
}
else {
Write-Log "Critical: Winget not installed or detected, exiting..." "red"
Write-ToLog "Critical: Winget not installed or detected, exiting..." "red"
New-Item "$WorkingDir\logs\error.txt" -Value "Winget not installed or detected" -Force
Write-Log "End of process!" "Cyan"
Write-ToLog "End of process!" "Cyan"
Exit 1
}
}
#End
Write-Log "End of process!" "Cyan"
Write-ToLog "End of process!" "Cyan"
Start-Sleep 3

View File

@ -1,4 +1,4 @@
#Function to configure prefered scope option as Machine
#Function to configure the prefered scope option as Machine
function Add-ScopeMachine ($SettingsPath) {
if (Test-Path $SettingsPath) {

View File

@ -1,4 +1,4 @@
#Function for creating shortcuts
#Function to create shortcuts
function Add-Shortcut ($Target, $Shortcut, $Arguments, $Icon, $Description) {
$WScriptShell = New-Object -ComObject WScript.Shell
$Shortcut = $WScriptShell.CreateShortcut($Shortcut)

View File

@ -0,0 +1,50 @@
#Function to get AZCopy, if it doesn't exist and update it, if it does
Function Get-AZCopy ($WingetUpdatePath) {
$AZCopyLink = (Invoke-WebRequest -Uri https://aka.ms/downloadazcopy-v10-windows -UseBasicParsing -MaximumRedirection 0 -ErrorAction SilentlyContinue).headers.location
$AZCopyVersionRegex = [regex]::new("(\d+\.\d+\.\d+)")
$AZCopyLatestVersion = $AZCopyVersionRegex.Match($AZCopyLink).Value
if ($null -eq $AZCopyLatestVersion -or "" -eq $AZCopyLatestVersion) {
$AZCopyLatestVersion = "0.0.0"
}
if (Test-Path -Path "$WingetUpdatePath\azcopy.exe" -PathType Leaf) {
$AZCopyCurrentVersion = & "$WingetUpdatePath\azcopy.exe" -v
$AZCopyCurrentVersion = $AZCopyVersionRegex.Match($AZCopyCurrentVersion).Value
Write-ToLog "AZCopy version $AZCopyCurrentVersion found"
}
else {
Write-ToLog "AZCopy not already installed"
$AZCopyCurrentVersion = "0.0.0"
}
if (([version] $AZCopyCurrentVersion) -lt ([version] $AZCopyLatestVersion)) {
Write-ToLog "Installing version $AZCopyLatestVersion of AZCopy"
Invoke-WebRequest -Uri $AZCopyLink -UseBasicParsing -OutFile "$WingetUpdatePath\azcopyv10.zip"
Write-ToLog "Extracting AZCopy zip file"
Expand-archive -Path "$WingetUpdatePath\azcopyv10.zip" -Destinationpath "$WingetUpdatePath" -Force
$AZCopyPathSearch = Resolve-Path -path "$WingetUpdatePath\azcopy_*"
if ($AZCopyPathSearch -is [array]) {
$AZCopyEXEPath = $AZCopyPathSearch[$AZCopyPathSearch.Length - 1]
}
else {
$AZCopyEXEPath = $AZCopyPathSearch
}
Write-ToLog "Copying 'azcopy.exe' to main folder"
Copy-Item "$AZCopyEXEPath\azcopy.exe" -Destination "$WingetUpdatePath\"
Write-ToLog "Removing temporary AZCopy files"
Remove-Item -Path $AZCopyEXEPath -Recurse
Remove-Item -Path "$WingetUpdatePath\azcopyv10.zip"
$AZCopyCurrentVersion = & "$WingetUpdatePath\azcopy.exe" -v
$AZCopyCurrentVersion = $AZCopyVersionRegex.Match($AZCopyCurrentVersion).Value
Write-ToLog "AZCopy version $AZCopyCurrentVersion installed"
}
}

View File

@ -1,4 +1,4 @@
#Get App Info
#Get the winget App Information
Function Get-AppInfo ($AppID) {
#Get AppID Info

View File

@ -1,4 +1,4 @@
#Function to get Black List apps
#Function to get the Block List apps
function Get-ExcludedApps {

View File

@ -1,4 +1,4 @@
#Function to get White List apps
#Function to get the allow List apps
function Get-IncludedApps {

View File

@ -1,9 +1,9 @@
#Function to get locale file for Notification.
#Function to get the locale file for notifications
Function Get-NotifLocale {
#Get OS locale
$OSLocale = (Get-Culture).Parent
$OSLocale = (Get-UICulture).Parent
#Test if OS locale notif file exists
$TestOSLocalPath = "$WorkingDir\locale\$($OSLocale.Name).xml"

View File

@ -1,4 +1,4 @@
#Function to get Domain/Local Policies (GPO)
#Function to get the Domain/Local Policies (GPO)
Function Get-Policies {
#Get WAU Policies and set the Configurations Registry Accordingly
@ -69,6 +69,14 @@ Function Get-Policies {
Remove-ItemProperty $regPath -Name WAU_ModsPath -Force -ErrorAction SilentlyContinue | Out-Null
$ChangedSettings++
}
if ($null -ne $($WAUPolicies.WAU_AzureBlobSASURL) -and ($($WAUPolicies.WAU_AzureBlobSASURL) -ne $($WAUConfig.WAU_AzureBlobSASURL))) {
New-ItemProperty $regPath -Name WAU_AzureBlobSASURL -Value $($WAUPolicies.WAU_AzureBlobSASURL.TrimEnd(" ", "\", "/")) -Force | Out-Null
$ChangedSettings++
}
elseif ($null -eq $($WAUPolicies.WAU_AzureBlobSASURL) -and $($WAUConfig.WAU_AzureBlobSASURL)) {
Remove-ItemProperty $regPath -Name WAU_AzureBlobSASURL -Force -ErrorAction SilentlyContinue | Out-Null
$ChangedSettings++
}
if ($null -ne $($WAUPolicies.WAU_NotificationLevel) -and ($($WAUPolicies.WAU_NotificationLevel) -ne $($WAUConfig.WAU_NotificationLevel))) {
New-ItemProperty $regPath -Name WAU_NotificationLevel -Value $($WAUPolicies.WAU_NotificationLevel) -Force | Out-Null
@ -87,14 +95,14 @@ Function Get-Policies {
$folder = $service.GetFolder('\')
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
for($triggerId=1; $triggerId -le $definition.Triggers.Count; $triggerId++){
if(($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")){
$PreStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(0,11)
$PostStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(19,6)
for ($triggerId = 1; $triggerId -le $definition.Triggers.Count; $triggerId++) {
if (($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")) {
$PreStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(0, 11)
$PostStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(19, 6)
$Boundary = $PreStartBoundary + $($WAUPolicies.WAU_UpdatesAtTime) + $PostStartBoundary
$definition.Triggers.Item($triggerId).StartBoundary = $Boundary
break
$triggerId-=1
$triggerId -= 1
}
}
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null) | Out-Null
@ -108,14 +116,14 @@ Function Get-Policies {
$folder = $service.GetFolder('\')
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
for($triggerId=1; $triggerId -le $definition.Triggers.Count; $triggerId++){
if(($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")){
$PreStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(0,11)
$PostStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(19,6)
for ($triggerId = 1; $triggerId -le $definition.Triggers.Count; $triggerId++) {
if (($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")) {
$PreStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(0, 11)
$PostStartBoundary = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(19, 6)
$Boundary = $PreStartBoundary + "06:00:00" + $PostStartBoundary
$definition.Triggers.Item($triggerId).StartBoundary = $Boundary
break
$triggerId-=1
$triggerId -= 1
}
}
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null) | Out-Null
@ -129,11 +137,11 @@ Function Get-Policies {
$folder = $service.GetFolder('\')
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
for($triggerId=1; $triggerId -le $definition.Triggers.Count; $triggerId++){
if(($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")){
$UpdatesAtTime = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(11,8)
for ($triggerId = 1; $triggerId -le $definition.Triggers.Count; $triggerId++) {
if (($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")) {
$UpdatesAtTime = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(11, 8)
$definition.Triggers.Remove($triggerId)
$triggerId-=1
$triggerId -= 1
}
}
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null) | Out-Null
@ -152,11 +160,11 @@ Function Get-Policies {
$definition = $task.Definition
$definition.Triggers.Count | Out-Null
switch ($($WAUPolicies.WAU_UpdatesInterval)) {
"Daily" {$tasktrigger = New-ScheduledTaskTrigger -Daily -At $($WAUConfig.WAU_UpdatesAtTime); break}
"BiDaily" {$tasktrigger = New-ScheduledTaskTrigger -Daily -At $($WAUConfig.WAU_UpdatesAtTime) -DaysInterval 2; break}
"Weekly" {$tasktrigger = New-ScheduledTaskTrigger -Weekly -At $($WAUConfig.WAU_UpdatesAtTime) -DaysOfWeek 2; break}
"BiWeekly" {$tasktrigger = New-ScheduledTaskTrigger -Weekly -At $($WAUConfig.WAU_UpdatesAtTime) -DaysOfWeek 2 -WeeksInterval 2; break}
"Monthly" {$tasktrigger = New-ScheduledTaskTrigger -Weekly -At $($WAUConfig.WAU_UpdatesAtTime) -DaysOfWeek 2 -WeeksInterval 4; break}
"Daily" { $tasktrigger = New-ScheduledTaskTrigger -Daily -At $($WAUConfig.WAU_UpdatesAtTime); break }
"BiDaily" { $tasktrigger = New-ScheduledTaskTrigger -Daily -At $($WAUConfig.WAU_UpdatesAtTime) -DaysInterval 2; break }
"Weekly" { $tasktrigger = New-ScheduledTaskTrigger -Weekly -At $($WAUConfig.WAU_UpdatesAtTime) -DaysOfWeek 2; break }
"BiWeekly" { $tasktrigger = New-ScheduledTaskTrigger -Weekly -At $($WAUConfig.WAU_UpdatesAtTime) -DaysOfWeek 2 -WeeksInterval 2; break }
"Monthly" { $tasktrigger = New-ScheduledTaskTrigger -Weekly -At $($WAUConfig.WAU_UpdatesAtTime) -DaysOfWeek 2 -WeeksInterval 4; break }
}
if ($definition.Triggers.Count -gt 0) {
$triggers = @()
@ -177,11 +185,11 @@ Function Get-Policies {
$folder = $service.GetFolder('\')
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
for($triggerId=1; $triggerId -le $definition.Triggers.Count; $triggerId++){
if(($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")){
$UpdatesAtTime = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(11,8)
for ($triggerId = 1; $triggerId -le $definition.Triggers.Count; $triggerId++) {
if (($definition.Triggers.Item($triggerId).Type -eq "2") -or ($definition.Triggers.Item($triggerId).Type -eq "3")) {
$UpdatesAtTime = ($definition.Triggers.Item($triggerId).StartBoundary).Substring(11, 8)
$definition.Triggers.Remove($triggerId)
$triggerId-=1
$triggerId -= 1
}
}
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null) | Out-Null
@ -223,15 +231,17 @@ Function Get-Policies {
$folder = $service.GetFolder('\')
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
$definition.Triggers.Count | Out-Null
if ($definition.Triggers.Count -gt 0) {
$triggerLogon = $false
foreach ($trigger in $definition.Triggers) {
if ($trigger.Type -eq "9") {
$triggerLogon = $true
break
}
}
if (!$triggerLogon) {
$triggers += New-ScheduledTaskTrigger -AtLogon
Set-ScheduledTask -TaskName "Winget-AutoUpdate" -Trigger $triggers
}
else {
$tasktrigger = New-ScheduledTaskTrigger -AtLogon
Set-ScheduledTask -TaskName "Winget-AutoUpdate" -Trigger $tasktrigger
}
}
else {
New-ItemProperty $regPath -Name WAU_UpdatesAtLogon -Value $($WAUPolicies.WAU_UpdatesAtLogon) -PropertyType DWord -Force | Out-Null
@ -241,10 +251,10 @@ Function Get-Policies {
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
$definition.Triggers.Count | Out-Null
for($triggerId=1; $triggerId -le $definition.Triggers.Count; $triggerId++){
if($definition.Triggers.Item($triggerId).Type -eq "9"){
for ($triggerId = 1; $triggerId -le $definition.Triggers.Count; $triggerId++) {
if ($definition.Triggers.Item($triggerId).Type -eq "9") {
$definition.Triggers.Remove($triggerId)
$triggerId-=1
$triggerId -= 1
}
}
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null) | Out-Null
@ -258,10 +268,10 @@ Function Get-Policies {
$folder = $service.GetFolder('\')
$task = $folder.GetTask("Winget-AutoUpdate")
$definition = $task.Definition
for($triggerId=1; $triggerId -le $definition.Triggers.Count; $triggerId++){
if($definition.Triggers.Item($triggerId).Type -eq "9"){
for ($triggerId = 1; $triggerId -le $definition.Triggers.Count; $triggerId++) {
if ($definition.Triggers.Item($triggerId).Type -eq "9") {
$definition.Triggers.Remove($triggerId)
$triggerId-=1
$triggerId -= 1
}
}
$folder.RegisterTaskDefinition($task.Name, $definition, 4, $null, $null, $null) | Out-Null
@ -346,6 +356,15 @@ Function Get-Policies {
$ChangedSettings++
}
if ($null -ne $($WAUPolicies.WAU_UserApproval) -and ($($WAUPolicies.WAU_UserApproval) -ne $($WAUConfig.WAU_UserApproval))) {
New-ItemProperty $regPath -Name WAU_UserApproval -Value $($WAUPolicies.WAU_UserApproval) -PropertyType DWord -Force | Out-Null
$ChangedSettings++
}
elseif ($null -eq $($WAUPolicies.WAU_UserApproval) -and ($($WAUConfig.WAU_UserApproval) -or $($WAUConfig.WAU_UserApproval) -eq 0)) {
Remove-ItemProperty $regPath -Name WAU_UserApproval -Force -ErrorAction SilentlyContinue | Out-Null
$ChangedSettings++
}
#Get WAU Configurations after Policies change
$Script:WAUConfig = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate"
}

View File

@ -1,4 +1,4 @@
#Function to get latest WAU available version on Github
#Function to get the latest WAU available version on Github
function Get-WAUAvailableVersion {
@ -6,7 +6,7 @@ function Get-WAUAvailableVersion {
if ($WAUConfig.WAU_UpdatePrerelease -eq 1) {
#Log
Write-log "WAU AutoUpdate Pre-release versions is Enabled" "Cyan"
Write-ToLog "WAU AutoUpdate Pre-release versions is Enabled" "Cyan"
#Get latest pre-release info
$WAUurl = 'https://api.github.com/repos/Romanitho/Winget-AutoUpdate/releases'
@ -19,6 +19,7 @@ function Get-WAUAvailableVersion {
}
#Return version
return ((Invoke-WebRequest $WAUurl -UseBasicParsing | ConvertFrom-Json)[0].tag_name).Replace("v", "")
}

View File

@ -1,4 +1,4 @@
#Function to get Winget Command regarding execution context (User, System...)
#Function to get the winget command regarding execution context (User, System...)
Function Get-WingetCmd {
@ -21,7 +21,7 @@ Function Get-WingetCmd {
$Script:Winget = "$WingetPath\winget.exe"
}
else {
Write-Log "Winget not installed or detected !" "Red"
Write-ToLog "Winget not installed or detected !" "Red"
return $false
}
@ -30,7 +30,7 @@ Function Get-WingetCmd {
#Log Winget installed version
$WingetVer = & $Winget --version
Write-Log "Winget Version: $WingetVer"
Write-ToLog "Winget Version: $WingetVer"
return $true

View File

@ -1,4 +1,4 @@
#Function to get outdated app list, in formatted array
#Function to get the outdated app list, in formatted array
function Get-WingetOutdatedApps {
class Software {
@ -13,11 +13,11 @@ function Get-WingetOutdatedApps {
#Start Convertion of winget format to an array. Check if "-----" exists (Winget Error Handling)
if (!($upgradeResult -match "-----")) {
return "Problem:`n$upgradeResult"
return "An unusual thing happened (maybe all apps are upgraded):`n$upgradeResult"
}
#Split winget output to lines
$lines = $upgradeResult.Split([Environment]::NewLine) | Where-Object { $_ -and $_ -notmatch "--include-unknown" }
$lines = $upgradeResult.Split([Environment]::NewLine) | Where-Object { $_ }
# Find the line that starts with "------"
$fl = 0
@ -38,9 +38,22 @@ function Get-WingetOutdatedApps {
# Now cycle in real package and split accordingly
$upgradeList = @()
For ($i = $fl + 2; $i -lt $lines.Length - 1; $i++) {
For ($i = $fl + 2; $i -lt $lines.Length; $i++) {
$line = $lines[$i]
if ($line) {
if ($line.StartsWith("-----")) {
#Get header line
$fl = $i - 1
#Get header titles
$index = $lines[$fl] -split '\s+'
# Line $fl has the header, we can find char where we find ID and Version
$idStart = $lines[$fl].IndexOf($index[1])
$versionStart = $lines[$fl].IndexOf($index[2])
$availableStart = $lines[$fl].IndexOf($index[3])
}
#(Alphanumeric | Literal . | Alphanumeric) - the only unique thing in common for lines with applications
if ($line -match "\w\.\w") {
$software = [Software]::new()
$software.Name = $line.Substring(0, $idStart).TrimEnd()
$software.Id = $line.Substring($idStart, $versionStart - $idStart).TrimEnd()

View File

@ -1,6 +1,6 @@
function Get-WingetSystemApps {
#Json File where to export system installed apps
#Json File, where to export system installed apps
$jsonFile = "$WorkingDir\winget_system_apps.txt"
#Get list of installed Winget apps to json file

View File

@ -1,4 +1,4 @@
#Function rotate the logs
#Function to rotate the logs
function Invoke-LogRotation ($LogFile, $MaxLogFiles, $MaxLogSize) {
<#
@ -73,17 +73,17 @@ function Invoke-LogRotation ($LogFile, $MaxLogFiles, $MaxLogSize) {
#Log Header
$Log = "##################################################`n# CHECK FOR APP UPDATES - $(Get-Date -Format (Get-culture).DateTimeFormat.ShortDatePattern)`n##################################################"
$Log | out-file -filepath $LogFile -Append
Write-Log "Running in System context"
Write-ToLog "Running in System context"
if ($ActivateGPOManagement) {
Write-Log "Activated WAU GPO Management detected, comparing..."
Write-ToLog "Activated WAU GPO Management detected, comparing..."
if ($null -ne $ChangedSettings -and $ChangedSettings -ne 0) {
Write-Log "Changed settings detected and applied" "Yellow"
Write-ToLog "Changed settings detected and applied" "Yellow"
}
else {
Write-Log "No Changed settings detected" "Yellow"
Write-ToLog "No Changed settings detected" "Yellow"
}
}
Write-Log "Max Log Size reached: $MaxLogSize bytes - Rotated Logs"
Write-ToLog "Max Log Size reached: $MaxLogSize bytes - Rotated Logs"
Return $True
}

View File

@ -0,0 +1,65 @@
#Function to check if the mods directory is secured.
#Security: Mods directory must be protected (Users could create scripts of their own - then they'll run in System Context)!
#Check if Local Users have write rights in Mods directory or not (and take action if necessary):
function Invoke-ModsProtect ($ModsPath) {
try {
$directory = Get-Item -Path $ModsPath -ErrorAction SilentlyContinue
$acl = Get-Acl -Path $directory.FullName
#Local Users - S-1-5-32-545
$userSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-545")
#Translate SID to Locale Name
$ntAccount = $userSID.Translate([System.Security.Principal.NTAccount])
$userName = $ntAccount.Value
$userRights = [System.Security.AccessControl.FileSystemRights]"Write"
$hasWriteAccess = $False
foreach ($access in $acl.Access) {
if ($access.IdentityReference.Value -eq $userName -and $access.FileSystemRights -eq $userRights) {
$hasWriteAccess = $True
break
}
}
if ($hasWriteAccess) {
#Disable inheritance
$acl.SetAccessRuleProtection($True, $True)
# Remove any existing rules
$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) }
#SYSTEM Full - S-1-5-18
$userSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-18")
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($userSID, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
# Save the updated ACL
Set-Acl -Path $directory.FullName -AclObject $acl
#Administrators Full - S-1-5-32-544
$acl = Get-Acl -Path $directory.FullName
$userSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-544")
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($userSID, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
Set-Acl -Path $directory.FullName -AclObject $acl
#Local Users ReadAndExecute - S-1-5-32-545 S-1-5-11
$acl = Get-Acl -Path $directory.FullName
$userSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-32-545")
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($userSID, "ReadAndExecute", "ContainerInherit,ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
Set-Acl -Path $directory.FullName -AclObject $acl
#Authenticated Users ReadAndExecute - S-1-5-11
$acl = Get-Acl -Path $directory.FullName
$userSID = New-Object System.Security.Principal.SecurityIdentifier("S-1-5-11")
$rule = New-Object System.Security.AccessControl.FileSystemAccessRule($userSID, "ReadAndExecute", "ContainerInherit,ObjectInherit", "None", "Allow")
$acl.SetAccessRule($rule)
Set-Acl -Path $directory.FullName -AclObject $acl
return $True
}
return $False
}
catch {
return "Error"
}
}

View File

@ -1,9 +1,87 @@
#Function to make actions post WAU update
#Function to make actions after WAU update
function Invoke-PostUpdateActions {
#log
Write-Log "Running Post Update actions..." "yellow"
Write-ToLog "Running Post Update actions:" "yellow"
#Check if Intune Management Extension Logs folder and WAU-updates.log exists, make symlink
if ((Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs") -and !(Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log")) {
Write-ToLog "-> Creating SymLink for log file in Intune Management Extension log folder" "yellow"
New-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log" -ItemType SymbolicLink -Value $LogFile -Force -ErrorAction SilentlyContinue | Out-Null
}
#Check if Intune Management Extension Logs folder and WAU-install.log exists, make symlink
if ((Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs") -and (Test-Path "$WorkingDir\logs\install.log") -and !(Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log")) {
Write-host "`nCreating SymLink for log file (WAU-install) in Intune Management Extension log folder" -ForegroundColor Yellow
New-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log" -ItemType SymbolicLink -Value "$WorkingDir\logs\install.log" -Force -ErrorAction SilentlyContinue | Out-Null
}
Write-ToLog "-> Checking prerequisites..." "yellow"
#Check if Visual C++ 2019 or 2022 installed
$Visual2019 = "Microsoft Visual C++ 2015-2019 Redistributable*"
$Visual2022 = "Microsoft Visual C++ 2015-2022 Redistributable*"
$path = Get-Item HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*, HKLM:\SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\* | Where-Object { $_.GetValue("DisplayName") -like $Visual2019 -or $_.GetValue("DisplayName") -like $Visual2022 }
#If not installed, install
if (!($path)) {
try {
if ((Get-CimInStance Win32_OperatingSystem).OSArchitecture -like "*64*") {
$OSArch = "x64"
}
else {
$OSArch = "x86"
}
Write-ToLog "-> Downloading VC_redist.$OSArch.exe..."
$SourceURL = "https://aka.ms/vs/17/release/VC_redist.$OSArch.exe"
$Installer = "$($WAUConfig.InstallLocation)\VC_redist.$OSArch.exe"
$ProgressPreference = 'SilentlyContinue'
Invoke-WebRequest $SourceURL -UseBasicParsing -OutFile (New-Item -Path $Installer -Force)
Write-ToLog "-> Installing VC_redist.$OSArch.exe..."
Start-Process -FilePath $Installer -Args "/quiet /norestart" -Wait
Remove-Item $Installer -ErrorAction Ignore
Write-ToLog "-> MS Visual C++ 2015-2022 installed successfully" "green"
}
catch {
Write-ToLog "-> MS Visual C++ 2015-2022 installation failed." "red"
}
}
else {
Write-ToLog "-> Prerequisites checked. OK" "green"
}
#Check Package Install
Write-ToLog "-> Checking if Winget is installed/up to date" "yellow"
$TestWinGet = Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -eq "Microsoft.DesktopAppInstaller" }
#Current: v1.4.10173 = 1.19.10173.0 = 2023.118.406.0
If ([Version]$TestWinGet.Version -ge "2023.118.406.0") {
Write-ToLog "-> WinGet is Installed/up to date" "green"
}
Else {
#Download WinGet MSIXBundle
Write-ToLog "-> Not installed/up to date. Downloading WinGet..."
$WinGetURL = "https://github.com/microsoft/winget-cli/releases/download/v1.4.10173/Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle"
$WebClient = New-Object System.Net.WebClient
$WebClient.DownloadFile($WinGetURL, "$($WAUConfig.InstallLocation)\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle")
#Install WinGet MSIXBundle
try {
Write-ToLog "-> Installing Winget MSIXBundle for App Installer..."
Add-AppxProvisionedPackage -Online -PackagePath "$($WAUConfig.InstallLocation)\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -SkipLicense | Out-Null
Write-ToLog "-> Installed Winget MSIXBundle for App Installer" "green"
}
catch {
Write-ToLog "-> Failed to intall Winget MSIXBundle for App Installer..." "red"
}
#Remove WinGet MSIXBundle
Remove-Item -Path "$($WAUConfig.InstallLocation)\Microsoft.DesktopAppInstaller_8wekyb3d8bbwe.msixbundle" -Force -ErrorAction Continue
}
#Reset Winget Sources
$ResolveWingetPath = Resolve-Path "$env:programfiles\WindowsApps\Microsoft.DesktopAppInstaller_*_*__8wekyb3d8bbwe\winget.exe" | Sort-Object { [version]($_.Path -replace '^[^\d]+_((\d+\.)*\d+)_.*', '$1') }
@ -13,7 +91,7 @@ function Invoke-PostUpdateActions {
& $WingetPath source reset --force
#log
Write-Log "-> Winget sources reseted." "green"
Write-ToLog "-> Winget sources reseted." "green"
}
#Create WAU Regkey if not present
@ -32,7 +110,7 @@ function Invoke-PostUpdateActions {
New-ItemProperty $regPath -Name WAU_UpdatePrerelease -Value 0 -PropertyType DWord -Force
#log
Write-Log "-> $regPath created." "green"
Write-ToLog "-> $regPath created." "green"
}
#Fix Notif where WAU_NotificationLevel is not set
$regNotif = Get-ItemProperty $regPath -Name WAU_NotificationLevel -ErrorAction SilentlyContinue
@ -40,7 +118,7 @@ function Invoke-PostUpdateActions {
New-ItemProperty $regPath -Name WAU_NotificationLevel -Value Full -Force
#log
Write-Log "-> Notification level setting was missing. Fixed with 'Full' option."
Write-ToLog "-> Notification level setting was missing. Fixed with 'Full' option."
}
#Set WAU_MaxLogFiles/WAU_MaxLogSize if not set
@ -50,22 +128,51 @@ function Invoke-PostUpdateActions {
New-ItemProperty $regPath -Name WAU_MaxLogSize -Value 1048576 -PropertyType DWord -Force | Out-Null
#log
Write-Log "-> MaxLogFiles/MaxLogSize setting was missing. Fixed with 3/1048576 (in bytes, default is 1048576 = 1 MB)."
Write-ToLog "-> MaxLogFiles/MaxLogSize setting was missing. Fixed with 3/1048576 (in bytes, default is 1048576 = 1 MB)."
}
#Convert about.xml if exists (previous WAU versions) to reg
#Set WAU_ListPath if not set
$ListPath = Get-ItemProperty $regPath -Name WAU_ListPath -ErrorAction SilentlyContinue
if (!$ListPath) {
New-ItemProperty $regPath -Name WAU_ListPath -Force | Out-Null
#log
Write-ToLog "-> ListPath setting was missing. Fixed with empty string."
}
#Set WAU_ModsPath if not set
$ModsPath = Get-ItemProperty $regPath -Name WAU_ModsPath -ErrorAction SilentlyContinue
if (!$ModsPath) {
New-ItemProperty $regPath -Name WAU_ModsPath -Force | Out-Null
#log
Write-ToLog "-> ModsPath setting was missing. Fixed with empty string."
}
#Security check
Write-ToLog "-> Checking Mods Directory:" "yellow"
$Protected = Invoke-ModsProtect "$($WAUConfig.InstallLocation)\mods"
if ($Protected -eq $True) {
Write-ToLog "-> The mods directory is now secured!" "green"
}
elseif ($Protected -eq $False) {
Write-ToLog "-> The mods directory was already secured!" "green"
}
else {
Write-ToLog "-> Error: The mods directory couldn't be verified as secured!" "red"
}
#Convert about.xml if exists (old WAU versions) to reg
$WAUAboutPath = "$WorkingDir\config\about.xml"
if (test-path $WAUAboutPath) {
[xml]$About = Get-Content $WAUAboutPath -Encoding UTF8 -ErrorAction SilentlyContinue
New-ItemProperty $regPath -Name DisplayVersion -Value $About.app.version -Force
New-ItemProperty $regPath -Name VersionMajor -Value ([version]$About.app.version).Major -Force
New-ItemProperty $regPath -Name VersionMinor -Value ([version]$About.app.version).Minor -Force
#Remove file once converted
Remove-Item $WAUAboutPath -Force -Confirm:$false
#log
Write-Log "-> $WAUAboutPath converted." "green"
Write-ToLog "-> $WAUAboutPath converted." "green"
}
#Convert config.xml if exists (previous WAU versions) to reg
@ -81,21 +188,34 @@ function Invoke-PostUpdateActions {
Remove-Item $WAUConfigPath -Force -Confirm:$false
#log
Write-Log "-> $WAUConfigPath converted." "green"
Write-ToLog "-> $WAUConfigPath converted." "green"
}
#Remove old functions
#Remove old functions / files
$FileNames = @(
"$WorkingDir\functions\Get-WAUConfig.ps1",
"$WorkingDir\functions\Get-WAUCurrentVersion.ps1",
"$WorkingDir\functions\Get-WAUUpdateStatus.ps1"
"$WorkingDir\functions\Get-WAUUpdateStatus.ps1",
"$WorkingDir\functions\Write-Log.ps1",
"$WorkingDir\Version.txt"
)
foreach ($FileName in $FileNames) {
if (Test-Path $FileName) {
Remove-Item $FileName -Force -Confirm:$false
#log
Write-Log "-> $FileName removed." "green"
Write-ToLog "-> $FileName removed." "green"
}
}
#Remove old registry key
$RegistryKeys = @(
"VersionMajor",
"VersionMinor"
)
foreach ($RegistryKey in $RegistryKeys) {
if (Get-ItemProperty -Path $regPath -Name $RegistryKey -ErrorAction SilentlyContinue) {
Remove-ItemProperty -Path $regPath -Name $RegistryKey
}
}
@ -120,6 +240,6 @@ function Invoke-PostUpdateActions {
$Script:WAUConfig = Get-ItemProperty -Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\Winget-AutoUpdate"
#log
Write-Log "Post Update actions finished" "green"
Write-ToLog "Post Update actions finished" "green"
}

View File

@ -3,19 +3,22 @@
function Invoke-UserApproval ($outdated){
#Create / Update WAU Class for notification action
if ($IsSystem) {
$WAUClass = "HKLM:\Software\Classes\WAU"
$WAUClassCmd = "$WAUClass\shell\open\command"
if ($IsSystem){
$WAUClassRun = "Wscript.exe ""$WingetUpdatePath\Invisible.vbs"" ""powershell.exe -NoProfile -ExecutionPolicy Bypass -File '$WingetUpdatePath\User-Run.ps1' -NotifApprovedAsSystem"
}
else{
$WAUClassRun = "Wscript.exe ""$WingetUpdatePath\Invisible.vbs"" ""powershell.exe -NoProfile -ExecutionPolicy Bypass -File '$WingetUpdatePath\User-Run.ps1' -NotifApprovedAsUser"
}
$WAUClassRun = "Wscript.exe ""$WorkingDir\Invisible.vbs"" ""powershell.exe -NoProfile -ExecutionPolicy Bypass -Command & '$WorkingDir\User-Run.ps1' -NotifApproved %1"""
New-Item $WAUClassCmd -Force -ErrorAction SilentlyContinue | Out-Null
New-ItemProperty -LiteralPath $WAUClass -Name 'URL Protocol' -Value '' -PropertyType String -Force -ErrorAction SilentlyContinue | Out-Null
New-ItemProperty -LiteralPath $WAUClass -Name '(default)' -Value "URL:$($ActionType)" -PropertyType String -Force -ErrorAction SilentlyContinue | Out-Null
New-ItemProperty -LiteralPath $WAUClass -Name '(default)' -Value "URL:WAU" -PropertyType String -Force -ErrorAction SilentlyContinue | Out-Null
New-ItemProperty -LiteralPath $WAUClass -Name 'EditFlags' -Value '2162688' -PropertyType DWord -Force -ErrorAction SilentlyContinue | Out-Null
New-ItemProperty -LiteralPath $WAUClassCmd -Name '(default)' -Value $WAUClassRun -PropertyType String -Force -ErrorAction SilentlyContinue | Out-Null
$Button1Action = "wau:system"
$OnClickAction = "wau:systemDialogBox"
}
else{
$Button1Action = "wau:user"
$OnClickAction = "wau:userDialogBox"
}
$OutdatedApps = @()
#If White List
@ -23,7 +26,7 @@ function Invoke-UserApproval ($outdated){
$toUpdate = Get-IncludedApps
foreach ($app in $Outdated) {
if (($toUpdate -contains $app.Id) -and $($app.Version) -ne "Unknown") {
$OutdatedApps += $app.Name
$OutdatedApps += "- $($app.Name)"
}
}
}
@ -32,7 +35,7 @@ function Invoke-UserApproval ($outdated){
$toSkip = Get-ExcludedApps
foreach ($app in $Outdated) {
if (-not ($toSkip -contains $app.Id) -and $($app.Version) -ne "Unknown") {
$OutdatedApps += $app.Name
$OutdatedApps += "- $($app.Name)"
}
}
}
@ -40,7 +43,12 @@ function Invoke-UserApproval ($outdated){
$body = $OutdatedApps | Out-String
if ($body) {
#Ask user to update apps
Start-NotifTask -Title "New available updates" -Message "Do you want to update these apps ?" -Body $body -ButtonDismiss -Button1Text "Yes" -Button1Action "wau:1" -MessageType "info"
$Message = "Do you want to update these apps ?"
$body += "`nPlease save your work and close theses apps"
$WAUNotifContent = "$WorkingDir\config\NotifContent.txt"
New-Item -Path $WAUNotifContent -ItemType File -Force | Out-Null
Set-Content -Path $WAUNotifContent -Value $body
Start-NotifTask -Title "New available updates" -Message $Message -Body $body -ButtonDismiss -Button1Text "Yes" -Button1Action $Button1Action -OnClickAction $OnClickAction -MessageType "info"
Return 0
}
else {

View File

@ -1,20 +1,25 @@
#Initialisation
# Initialisation
function Start-Init {
#Config console output encoding
[Console]::OutputEncoding = [System.Text.Encoding]::UTF8
$caller = Get-ChildItem $MyInvocation.PSCommandPath | Select-Object -Expand Name
if ($caller -eq "Winget-Upgrade.ps1") {
#Log Header
$Log = "`n##################################################`n# CHECK FOR APP UPDATES - $(Get-Date -Format (Get-culture).DateTimeFormat.ShortDatePattern)`n##################################################"
$Log | Write-host
#Logs initialisation
$Script:LogFile = "$WorkingDir\logs\updates.log"
}
elseif ($caller -eq "Winget-AutoUpdate-Install.ps1") {
$Script:LogFile = "$WingetUpdatePath\logs\updates.log"
}
if (!(Test-Path $LogFile)) {
#Create file if doesn't exist
New-Item -ItemType File -Path $LogFile -Force
New-Item -ItemType File -Path $LogFile -Force | Out-Null
#Set ACL for users on logfile
$NewAcl = Get-Acl -Path $LogFile
@ -26,8 +31,32 @@ function Start-Init {
$NewAcl.SetAccessRule($fileSystemAccessRule)
Set-Acl -Path $LogFile -AclObject $NewAcl
}
elseif ((Test-Path $LogFile) -and ($caller -eq "Winget-AutoUpdate-Install.ps1")) {
#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
}
#Check if Intune Management Extension Logs folder and WAU-updates.log exists, make symlink
if ((Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs") -and !(Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log")) {
Write-host "`nCreating SymLink for log file (WAU-updates) in Intune Management Extension log folder" -ForegroundColor Yellow
New-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-updates.log" -ItemType SymbolicLink -Value $LogFile -Force -ErrorAction SilentlyContinue | Out-Null
}
#Check if Intune Management Extension Logs folder and WAU-install.log exists, make symlink
if ((Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs") -and (Test-Path "$WorkingDir\logs\install.log") -and !(Test-Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log")) {
Write-host "`nCreating SymLink for log file (WAU-install) in Intune Management Extension log folder" -ForegroundColor Yellow
New-Item -Path "${env:ProgramData}\Microsoft\IntuneManagementExtension\Logs\WAU-install.log" -ItemType SymbolicLink -Value "$WorkingDir\logs\install.log" -Force -ErrorAction SilentlyContinue | Out-Null
}
if ($caller -eq "Winget-Upgrade.ps1") {
#Log file
$Log | out-file -filepath $LogFile -Append
}
}

View File

@ -1,4 +1,4 @@
#Function to send notifications to user
#Function to send the notifications to user
function Start-NotifTask {
@ -11,10 +11,11 @@ function Start-NotifTask {
[String]$Body,
[String]$Button1Text,
[String]$Button1Action,
[Switch]$ButtonDismiss = $false
[Switch]$ButtonDismiss = $false,
[Switch]$UserRun = $false
)
if (($WAUConfig.WAU_NotificationLevel -eq "Full") -or ($WAUConfig.WAU_NotificationLevel -eq "SuccessOnly" -and $MessageType -eq "Success") -or (!$IsSystem)) {
if (($WAUConfig.WAU_NotificationLevel -eq "Full") -or ($WAUConfig.WAU_NotificationLevel -eq "SuccessOnly" -and $MessageType -eq "Success") -or ($UserRun)) {
# XML Toast template creation
[xml]$ToastTemplate = New-Object system.Xml.XmlDocument
@ -31,7 +32,7 @@ function Start-NotifTask {
$XMLbinding.Attributes.Append($XMLbindingAtt1) | Out-Null
$XMLimagepath = "$WorkingDir\icons\$MessageType.png"
if (Test-Path $XMLimagepath){
if (Test-Path $XMLimagepath) {
# Creation of a image node
$XMLimage = $ToastTemplate.CreateElement("image")
$XMLbinding.AppendChild($XMLimage) | Out-Null
@ -43,7 +44,7 @@ function Start-NotifTask {
$XMLimage.Attributes.Append($XMLimageAtt2) | Out-Null
}
if ($Title){
if ($Title) {
# Creation of a text node
$XMLtitle = $ToastTemplate.CreateElement("text")
$XMLtitleText = $ToastTemplate.CreateTextNode($Title)
@ -51,7 +52,7 @@ function Start-NotifTask {
$XMLbinding.AppendChild($XMLtitle) | Out-Null
}
if ($Message){
if ($Message) {
# Creation of a text node
$XMLtext = $ToastTemplate.CreateElement("text")
$XMLtextText = $ToastTemplate.CreateTextNode($Message)
@ -59,7 +60,7 @@ function Start-NotifTask {
$XMLbinding.AppendChild($XMLtext) | Out-Null
}
if ($Body){
if ($Body) {
# Creation of a group node
$XMLgroup = $ToastTemplate.CreateElement("group")
$XMLbinding.AppendChild($XMLgroup) | Out-Null
@ -91,7 +92,7 @@ function Start-NotifTask {
$XMLactionAtt1 = $ToastTemplate.CreateAttribute("content")
$XMLactionAtt1.Value = $Button1Text
$XMLaction.Attributes.Append($XMLactionAtt1) | Out-Null
if ($Button1Action){
if ($Button1Action) {
$XMLactionAtt2 = $ToastTemplate.CreateAttribute("arguments")
$XMLactionAtt2.Value = $Button1Action
$XMLaction.Attributes.Append($XMLactionAtt2) | Out-Null
@ -126,7 +127,7 @@ function Start-NotifTask {
$ToastTemplate.LastChild.AppendChild($XMLactions) | Out-Null
$ToastTemplate.LastChild.AppendChild($XMLtag) | Out-Null
if ($OnClickAction){
if ($OnClickAction) {
$ToastTemplate.toast.SetAttribute("activationType", "Protocol") | Out-Null
$ToastTemplate.toast.SetAttribute("launch", $OnClickAction) | Out-Null
}

View File

@ -1,4 +1,4 @@
#Function to check Black/White List External Path
#Function to check Block/Allow List External Path
function Test-ListPath ($ListPath, $UseWhiteList, $WingetUpdatePath) {
# URL, UNC or Local Path
@ -37,10 +37,23 @@ function Test-ListPath ($ListPath, $UseWhiteList, $WingetUpdatePath) {
}
}
catch {
try {
$content = $wc.DownloadString("$ExternalList")
if ($null -ne $content -and $content -match "\w\.\w") {
$wc.DownloadFile($ExternalList, $LocalList)
return $true
}
else {
$Script:ReachNoPath = $True
return $False
}
}
catch {
$Script:ReachNoPath = $True
return $False
}
}
}
# If path is UNC or local
else {
if (Test-Path -Path $ExternalList) {

View File

@ -1,4 +1,4 @@
#Function to check if modification exists in 'mods' directory
#Function to check if modification exists within 'mods' directory
function Test-Mods ($app) {

View File

@ -1,6 +1,6 @@
#Function to check Mods External Path
#Function to check mods External Path
function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
function Test-ModsPath ($ModsPath, $WingetUpdatePath, $AzureBlobSASURL) {
# URL, UNC or Local Path
# Get local and external Mods paths
$LocalMods = -join ($WingetUpdatePath, "\", "mods")
@ -30,7 +30,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
# Collect the external list of href links
$BinLinks = $BinResponse.Links | Select-Object -ExpandProperty HREF
#If there's a directory path in the HREF:s, delete it (IIS)
$CleanBinLinks = $BinLinks -replace "/.*/",""
$CleanBinLinks = $BinLinks -replace "/.*/", ""
#Modify strings to HREF:s
$index = 0
foreach ($Bin in $CleanBinLinks) {
@ -41,14 +41,14 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
}
#Delete Local Bins that don't exist Externally
$index = 0
$CleanLinks = $BinLinks -replace "/.*/",""
$CleanLinks = $BinLinks -replace "/.*/", ""
foreach ($Bin in $InternalBinsNames) {
If ($CleanLinks -notcontains "$Bin") {
Remove-Item $LocalMods\bins\$Bin -Force -ErrorAction SilentlyContinue | Out-Null
}
$index++
}
$CleanBinLinks = $BinLinks -replace "/.*/",""
$CleanBinLinks = $BinLinks -replace "/.*/", ""
$Bin = ""
#Loop through all links
$wc = New-Object System.Net.WebClient
@ -56,7 +56,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
#Check for .exe in listing/HREF:s in an index page pointing to .exe
if ($_ -like "*.exe") {
$dateExternalBin = ""
$dateLocalBin =""
$dateLocalBin = ""
$wc.OpenRead("$ExternalBins/$_").Close() | Out-Null
$dateExternalBin = ([DateTime]$wc.ResponseHeaders['Last-Modified']).ToString("yyyy-MM-dd HH:mm:ss")
if (Test-Path -Path $LocalMods"\bins\"$_) {
@ -64,7 +64,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
}
if ($dateExternalBin -gt $dateLocalBin) {
$SaveBin = Join-Path -Path "$LocalMods\bins" -ChildPath $_
Invoke-WebRequest -Uri "$ExternalBins/$_" -OutFile $SaveBin.Replace("%20"," ") -UseBasicParsing
Invoke-WebRequest -Uri "$ExternalBins/$_" -OutFile $SaveBin.Replace("%20", " ") -UseBasicParsing
}
}
}
@ -74,7 +74,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
$ModLinks = $WebResponse.Links | Select-Object -ExpandProperty HREF
#If there's a directory path in the HREF:s, delete it (IIS)
$CleanLinks = $ModLinks -replace "/.*/",""
$CleanLinks = $ModLinks -replace "/.*/", ""
#Modify strings to HREF:s
$index = 0
@ -88,7 +88,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
#Delete Local Mods that don't exist Externally
$DeletedMods = 0
$index = 0
$CleanLinks = $ModLinks -replace "/.*/",""
$CleanLinks = $ModLinks -replace "/.*/", ""
foreach ($Mod in $InternalModsNames) {
If ($CleanLinks -notcontains "$Mod") {
Remove-Item $LocalMods\$Mod -Force -ErrorAction SilentlyContinue | Out-Null
@ -97,7 +97,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
$index++
}
$CleanLinks = $ModLinks -replace "/.*/",""
$CleanLinks = $ModLinks -replace "/.*/", ""
#Loop through all links
$wc = New-Object System.Net.WebClient
@ -106,7 +106,7 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
if (($_ -like "*.ps1") -or ($_ -like "*.txt")) {
try {
$dateExternalMod = ""
$dateLocalMod =""
$dateLocalMod = ""
$wc.OpenRead("$ExternalMods/$_").Close() | Out-Null
$dateExternalMod = ([DateTime]$wc.ResponseHeaders['Last-Modified']).ToString("yyyy-MM-dd HH:mm:ss")
if (Test-Path -Path $LocalMods"\"$_) {
@ -134,21 +134,60 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
}
return $ModsUpdated, $DeletedMods
}
# If Path is Azure Blob
elseif ($ExternalMods -like "AzureBlob") {
Write-ToLog "Azure Blob Storage set as mod source"
Write-ToLog "Checking AZCopy"
Get-AZCopy $WingetUpdatePath
#Safety check to make sure we really do have azcopy.exe and a Blob URL
if ((Test-Path -Path "$WingetUpdatePath\azcopy.exe" -PathType Leaf) -and ($null -ne $AzureBlobSASURL)) {
Write-ToLog "Syncing Blob storage with local storage"
$AZCopySyncOutput = & $WingetUpdatePath\azcopy.exe sync "$AzureBlobSASURL" "$LocalMods" --from-to BlobLocal --delete-destination=true
$AZCopyOutputLines = $AZCopySyncOutput.Split([Environment]::NewLine)
foreach ( $_ in $AZCopyOutputLines) {
$AZCopySyncAdditionsRegex = [regex]::new("(?<=Number of Copy Transfers Completed:\s+)\d+")
$AZCopySyncDeletionsRegex = [regex]::new("(?<=Number of Deletions at Destination:\s+)\d+")
$AZCopySyncErrorRegex = [regex]::new("^Cannot perform sync due to error:")
$AZCopyAdditions = [int] $AZCopySyncAdditionsRegex.Match($_).Value
$AZCopyDeletions = [int] $AZCopySyncDeletionsRegex.Match($_).Value
if ($AZCopyAdditions -ne 0) {
$ModsUpdated = $AZCopyAdditions
}
if ($AZCopyDeletions -ne 0) {
$DeletedMods = $AZCopyDeletions
}
if ($AZCopySyncErrorRegex.Match($_).Value) {
Write-ToLog "AZCopy Sync Error! $_"
}
}
}
else {
Write-ToLog "Error 'azcopy.exe' or SAS Token not found!"
}
return $ModsUpdated, $DeletedMods
}
# If path is UNC or local
else {
$ExternalBins = "$ModsPath\bins"
if (Test-Path -Path $ExternalBins"\*.exe") {
$ExternalBinsNames = Get-ChildItem -Path $ExternalBins -Name -Recurse -Include *.exe
#Delete Local Bins that don't exist Externally
foreach ($Bin in $InternalBinsNames){
If ($Bin -notin $ExternalBinsNames ){
foreach ($Bin in $InternalBinsNames) {
If ($Bin -notin $ExternalBinsNames ) {
Remove-Item $LocalMods\bins\$Bin -Force -ErrorAction SilentlyContinue | Out-Null
}
}
#Copy newer external bins
foreach ($Bin in $ExternalBinsNames){
foreach ($Bin in $ExternalBinsNames) {
$dateExternalBin = ""
$dateLocalBin =""
$dateLocalBin = ""
if (Test-Path -Path $LocalMods"\bins\"$Bin) {
$dateLocalBin = (Get-Item "$LocalMods\bins\$Bin").LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
}
@ -165,17 +204,17 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
#Delete Local Mods that don't exist Externally
$DeletedMods = 0
foreach ($Mod in $InternalModsNames){
If ($Mod -notin $ExternalModsNames ){
foreach ($Mod in $InternalModsNames) {
If ($Mod -notin $ExternalModsNames ) {
Remove-Item $LocalMods\$Mod -Force -ErrorAction SilentlyContinue | Out-Null
$DeletedMods++
}
}
#Copy newer external mods
foreach ($Mod in $ExternalModsNames){
foreach ($Mod in $ExternalModsNames) {
$dateExternalMod = ""
$dateLocalMod =""
$dateLocalMod = ""
if (Test-Path -Path $LocalMods"\"$Mod) {
$dateLocalMod = (Get-Item "$LocalMods\$Mod").LastWriteTime.ToString("yyyy-MM-dd HH:mm:ss")
}

View File

@ -1,4 +1,4 @@
#Function to check connectivity
#Function to check the connectivity
function Test-Network {
@ -9,7 +9,7 @@ function Test-Network {
$ProgressPreference = 'SilentlyContinue'
#Test connectivity during 30 min then timeout
Write-Log "Checking internet connection..." "Yellow"
Write-ToLog "Checking internet connection..." "Yellow"
While ($timeout -lt 1800) {
$URLtoTest = "https://raw.githubusercontent.com/Romanitho/Winget-AutoUpdate/main/LICENSE"
@ -17,7 +17,7 @@ function Test-Network {
if ($URLcontent -like "*MIT License*") {
Write-Log "Connected !" "Green"
Write-ToLog "Connected !" "Green"
#Check for metered connection
[void][Windows.Networking.Connectivity.NetworkInformation, Windows, ContentType = WindowsRuntime]
@ -25,17 +25,17 @@ function Test-Network {
if ($cost.ApproachingDataLimit -or $cost.OverDataLimit -or $cost.Roaming -or $cost.BackgroundDataUsageRestricted -or ($cost.NetworkCostType -ne "Unrestricted")) {
Write-Log "Metered connection detected." "Yellow"
Write-ToLog "Metered connection detected." "Yellow"
if ($WAUConfig.WAU_DoNotRunOnMetered -eq 1) {
Write-Log "WAU is configured to bypass update checking on metered connection"
Write-ToLog "WAU is configured to bypass update checking on metered connection"
return $false
}
else {
Write-Log "WAU is configured to force update checking on metered connection"
Write-ToLog "WAU is configured to force update checking on metered connection"
return $true
}
@ -56,7 +56,7 @@ function Test-Network {
#Send Warning Notif if no connection for 5 min
if ($timeout -eq 300) {
#Log
Write-Log "Notify 'No connection' sent." "Yellow"
Write-ToLog "Notify 'No connection' sent." "Yellow"
#Notif
$Title = $NotifLocale.local.outputs.output[0].title
@ -71,7 +71,7 @@ function Test-Network {
}
#Send Timeout Notif if no connection for 30 min
Write-Log "Timeout. No internet connection !" "Red"
Write-ToLog "Timeout. No internet connection !" "Red"
#Notif
$Title = $NotifLocale.local.outputs.output[1].title

View File

@ -1,4 +1,4 @@
#Function to check if there's a Pending Reboot
#Function to check if there is a Pending Reboot
function Test-PendingReboot {

View File

@ -1,15 +1,15 @@
#Function to Update an App
#Function to update an App
Function Update-App ($app) {
#Get App Info
$ReleaseNoteURL = Get-AppInfo $app.Id
if ($ReleaseNoteURL){
if ($ReleaseNoteURL) {
$Button1Text = $NotifLocale.local.outputs.output[10].message
}
#Send available update notification
Write-Log "Updating $($app.Name) from $($app.Version) to $($app.AvailableVersion)..." "Cyan"
Write-ToLog "Updating $($app.Name) from $($app.Version) to $($app.AvailableVersion)..." "Cyan"
$Title = $NotifLocale.local.outputs.output[2].title -f $($app.Name)
$Message = $NotifLocale.local.outputs.output[2].message -f $($app.Version), $($app.AvailableVersion)
$MessageType = "info"
@ -20,26 +20,26 @@ Function Update-App ($app) {
$ModsPreInstall, $ModsOverride, $ModsUpgrade, $ModsInstall, $ModsInstalled = Test-Mods $($app.Id)
#Winget upgrade
Write-Log "########## WINGET UPGRADE PROCESS STARTS FOR APPLICATION ID '$($App.Id)' ##########" "Gray"
Write-ToLog "########## WINGET UPGRADE PROCESS STARTS FOR APPLICATION ID '$($App.Id)' ##########" "Gray"
#If PreInstall script exist
if ($ModsPreInstall) {
Write-Log "Modifications for $($app.Id) before upgrade are being applied..." "Yellow"
Write-ToLog "Modifications for $($app.Id) before upgrade are being applied..." "Yellow"
& "$ModsPreInstall"
}
#Run Winget Upgrade command
if ($ModsOverride) {
Write-Log "-> Running (overriding default): Winget upgrade --id $($app.Id) --accept-package-agreements --accept-source-agreements --override $ModsOverride"
Write-ToLog "-> Running (overriding default): Winget upgrade --id $($app.Id) --accept-package-agreements --accept-source-agreements --override $ModsOverride"
& $Winget upgrade --id $($app.Id) --accept-package-agreements --accept-source-agreements --override $ModsOverride | Tee-Object -file $LogFile -Append
}
else {
Write-Log "-> Running: Winget upgrade --id $($app.Id) --accept-package-agreements --accept-source-agreements -h"
Write-ToLog "-> Running: Winget upgrade --id $($app.Id) --accept-package-agreements --accept-source-agreements -h"
& $Winget upgrade --id $($app.Id) --accept-package-agreements --accept-source-agreements -h | Tee-Object -file $LogFile -Append
}
if ($ModsUpgrade) {
Write-Log "Modifications for $($app.Id) during upgrade are being applied..." "Yellow"
Write-ToLog "Modifications for $($app.Id) during upgrade are being applied..." "Yellow"
& "$ModsUpgrade"
}
@ -53,25 +53,25 @@ Function Update-App ($app) {
#Test for a Pending Reboot (Component Based Servicing/WindowsUpdate/CCM_ClientUtilities)
$PendingReboot = Test-PendingReboot
if ($PendingReboot -eq $true) {
Write-Log "-> A Pending Reboot lingers and probably prohibited $($app.Name) from upgrading...`n-> ...an install for $($app.Name) is NOT executed!" "Red"
Write-ToLog "-> A Pending Reboot lingers and probably prohibited $($app.Name) from upgrading...`n-> ...an install for $($app.Name) is NOT executed!" "Red"
$FailedToUpgrade = $true
break
}
#If app failed to upgrade, run Install command
Write-Log "-> An upgrade for $($app.Name) failed, now trying an install instead..." "Yellow"
Write-ToLog "-> An upgrade for $($app.Name) failed, now trying an install instead..." "Yellow"
if ($ModsOverride) {
Write-Log "-> Running (overriding default): Winget install --id $($app.Id) --accept-package-agreements --accept-source-agreements --override $ModsOverride"
Write-ToLog "-> Running (overriding default): Winget install --id $($app.Id) --accept-package-agreements --accept-source-agreements --override $ModsOverride"
& $Winget install --id $($app.Id) --accept-package-agreements --accept-source-agreements --override $ModsOverride | Tee-Object -file $LogFile -Append
}
else {
Write-Log "-> Running: Winget install --id $($app.Id) --accept-package-agreements --accept-source-agreements -h"
Write-ToLog "-> Running: Winget install --id $($app.Id) --accept-package-agreements --accept-source-agreements -h"
& $Winget install --id $($app.Id) --accept-package-agreements --accept-source-agreements -h | Tee-Object -file $LogFile -Append
}
if ($ModsInstall) {
Write-Log "Modifications for $($app.Id) during install are being applied..." "Yellow"
Write-ToLog "Modifications for $($app.Id) during install are being applied..." "Yellow"
& "$ModsInstall"
}
@ -87,18 +87,18 @@ Function Update-App ($app) {
if ($FailedToUpgrade -eq $false) {
if ($ModsInstalled) {
Write-Log "Modifications for $($app.Id) after upgrade/install are being applied..." "Yellow"
Write-ToLog "Modifications for $($app.Id) after upgrade/install are being applied..." "Yellow"
& "$ModsInstalled"
}
}
Write-Log "########## WINGET UPGRADE PROCESS FINISHED FOR APPLICATION ID '$($App.Id)' ##########" "Gray"
Write-ToLog "########## WINGET UPGRADE PROCESS FINISHED FOR APPLICATION ID '$($App.Id)' ##########" "Gray"
#Notify installation
if ($FailedToUpgrade -eq $false) {
#Send success updated app notification
Write-Log "$($app.Name) updated to $($app.AvailableVersion) !" "Green"
Write-ToLog "$($app.Name) updated to $($app.AvailableVersion) !" "Green"
#Send Notif
$Title = $NotifLocale.local.outputs.output[3].title -f $($app.Name)
@ -113,7 +113,7 @@ Function Update-App ($app) {
else {
#Send failed updated app notification
Write-Log "$($app.Name) update failed." "Red"
Write-ToLog "$($app.Name) update failed." "Red"
#Send Notif
$Title = $NotifLocale.local.outputs.output[4].title -f $($app.Name)

View File

@ -1,4 +1,4 @@
#Function to Update WAU
#Function to update WAU
function Update-WAU {
@ -19,44 +19,44 @@ function Update-WAU {
New-Item $ZipFile -ItemType File -Force | Out-Null
#Download the zip
Write-Log "Downloading the GitHub Repository version $WAUAvailableVersion" "Cyan"
Invoke-RestMethod -Uri "https://github.com/Romanitho/Winget-AutoUpdate/archive/refs/tags/v$($WAUAvailableVersion).zip/" -OutFile $ZipFile
Write-ToLog "Downloading the GitHub Repository version $WAUAvailableVersion" "Cyan"
Invoke-RestMethod -Uri "https://github.com/Romanitho/Winget-AutoUpdate/releases/download/v$($WAUAvailableVersion)/WAU.zip" -OutFile $ZipFile
#Extract Zip File
Write-Log "Unzipping the WAU GitHub Repository" "Cyan"
Write-ToLog "Unzipping the WAU Update package" "Cyan"
$location = "$WorkingDir\WAU_update"
Expand-Archive -Path $ZipFile -DestinationPath $location -Force
Get-ChildItem -Path $location -Recurse | Unblock-File
#Update scritps
Write-Log "Updating WAU" "Yellow"
$TempPath = (Resolve-Path "$location\*\Winget-AutoUpdate\")[0].Path
Write-ToLog "Updating WAU..." "Yellow"
$TempPath = (Resolve-Path "$location\Winget-AutoUpdate\")[0].Path
if ($TempPath) {
Copy-Item -Path "$TempPath\*" -Destination "$WorkingDir\" -Exclude "icons" -Recurse -Force
}
#Remove update zip file and update temp folder
Write-Log "Done. Cleaning temp files" "Cyan"
Write-ToLog "Done. Cleaning temp files..." "Cyan"
Remove-Item -Path $ZipFile -Force -ErrorAction SilentlyContinue
Remove-Item -Path $location -Recurse -Force -ErrorAction SilentlyContinue
#Set new version to registry
$WAUConfig | New-ItemProperty -Name DisplayVersion -Value $WAUAvailableVersion -Force
$WAUConfig | New-ItemProperty -Name VersionMajor -Value ([version]$WAUAvailableVersion).Major -Force
$WAUConfig | New-ItemProperty -Name VersionMinor -Value ([version]$WAUAvailableVersion).Minor -Force
$WAUConfig | New-ItemProperty -Name VersionMajor -Value ([version]$WAUAvailableVersion.Replace("-", ".")).Major -Force
$WAUConfig | New-ItemProperty -Name VersionMinor -Value ([version]$WAUAvailableVersion.Replace("-", ".")).Minor -Force
#Set Post Update actions to 1
$WAUConfig | New-ItemProperty -Name WAU_PostUpdateActions -Value 1 -Force
#Send success Notif
Write-Log "WAU Update completed." "Green"
Write-ToLog "WAU Update completed." "Green"
$Title = $NotifLocale.local.outputs.output[3].title -f "Winget-AutoUpdate"
$Message = $NotifLocale.local.outputs.output[3].message -f $WAUAvailableVersion
$MessageType = "success"
Start-NotifTask -Title $Title -Message $Message -MessageType $MessageType -Button1Action $OnClickAction -Button1Text $Button1Text
#Rerun with newer version
Write-Log "Re-run WAU"
Write-ToLog "Re-run WAU"
Start-Process powershell -ArgumentList "-NoProfile -ExecutionPolicy Bypass -Command `"$WorkingDir\winget-upgrade.ps1`""
exit
@ -70,7 +70,7 @@ function Update-WAU {
$Message = $NotifLocale.local.outputs.output[4].message
$MessageType = "error"
Start-NotifTask -Title $Title -Message $Message -MessageType $MessageType -Button1Action $OnClickAction -Button1Text $Button1Text
Write-Log "WAU Update failed" "Red"
Write-ToLog "WAU Update failed" "Red"
}

View File

@ -1,6 +1,6 @@
#Write Log Function
#Write to Log Function
function Write-Log ($LogMsg, $LogColor = "White") {
function Write-ToLog ($LogMsg, $LogColor = "White") {
#Get log
$Log = "$(Get-Date -UFormat "%T") - $LogMsg"

View File

@ -49,6 +49,7 @@
<output id="9">
<!--Manual check for updated apps completed-->
<message>Die manuelle suche nach Updates wurde abgeschlossen.</message>
</output>
<output id="10">
<!--See changelog-->
<message>See changelog</message>

View File

@ -43,8 +43,8 @@
<message>Couldn't start a manual check for updated apps!</message>
</output>
<output id="8">
<!--Check for updated apps already running-->
<message>Check for updated apps already running...</message>
<!--A check for updated apps already running-->
<message>A check for updated apps already running...</message>
</output>
<output id="9">
<!--Manual check for updated apps completed-->

View File

@ -0,0 +1,62 @@
<local>
<outputs>
<output id="0">
<!--Check network connection-->
<title>Sjekk nettverkstilkoblingen.</title>
<!--Unable to check for software updates at this time!-->
<message>Kan ikke se etter programvareoppdateringer for øyeblikket!</message>
</output>
<output id="1">
<!--No internet connection-->
<title>Ingen internettforbindelse.</title>
<!--Updates could not be verified-->
<message>Oppdateringer kunne ikke bekreftes.</message>
</output>
<output id="2">
<!--{App} will be updated-->
<title>{0} vil bli oppdatert!</title>
<!--{v1.0} to {v2.0}-->
<message>{0} til {1}</message>
</output>
<output id="3">
<!--{App} updated-->
<title>{0} oppdatert.</title>
<!--Installed version: {v1.0}-->
<message>Installert versjon: {0}</message>
</output>
<output id="4">
<!--{App} could not be updated-->
<title>{0} kunne ikke oppdateres!</title>
<!--Please contact support-->
<message>Vennligst kontakt support.</message>
</output>
<output id="5">
<!--Logs are not available yet-->
<message>Logger er ikke tilgjengelig ennå!</message>
</output>
<output id="6">
<!--Starting a manual check for updated apps-->
<message>Starter en manuell sjekk for oppdaterte apper...</message>
</output>
<output id="7">
<!--Couldn't start a manual check for updated apps-->
<message>Kunne ikke starte en manuell sjekk for oppdaterte apper!</message>
</output>
<output id="8">
<!--Check for updated apps already running-->
<message>Se etter oppdaterte apper kjører allerede...</message>
</output>
<output id="9">
<!--Manual check for updated apps completed-->
<message>Manuell sjekk for oppdaterte apper fullført...</message>
</output>
<output id="10">
<!--See changelog-->
<message>Se endringslogg</message>
</output>
<output id="11">
<!--Open log file-->
<message>Åpne loggfilen</message>
</output>
</outputs>
</local>

View File

@ -4,59 +4,59 @@
<!--Check network connection-->
<title>Controleer de netwerkverbinding.</title>
<!--Unable to check for software updates at this time!-->
<message>Er kan op dit moment niet gecontroleerd worden op software-updates!</message>
<message>Er kan op dit moment niet gecontroleerd worden op software updates!</message>
</output>
<output id="1">
<!--No internet connction-->
<title>Geen internetverbinding.</title>
<!--Updates could not be verified-->
<message>Updates kon niet worden gecontroleerd.</message>
<message>Updates konden niet worden gecontroleerd.</message>
</output>
<output id="2">
<!--{App} will be updated-->
<title>{0} wordt geupdate!</title>
<title>{0} zal geüpdatet worden !</title>
<!--{v1.0} to {v2.0}-->
<message>{0} to {1}</message>
</output>
<output id="3">
<!--{App} updated-->
<title>{0} geupdate.</title>
<title>{0} is geüpdatet.</title>
<!--Installed version: {v1.0}-->
<message>Geinstalleerde versie: {0}</message>
<message>Geïnstalleerde versie: {0}</message>
</output>
<output id="4">
<!--{App} could not be updated-->
<title>{0} kan niet worden geupdate!</title>
<title>{0} kan niet worden geüpdatet!</title>
<!--Please contact support-->
<message>Neem contact op met support.</message>
</output>
<output id="5">
<!--Logs are not available yet-->
<message>Logs are not available yet!</message>
<message>Logs zijn nog niet beschikbaar !</message>
</output>
<output id="6">
<!--Starting a manual check for updated apps-->
<message>Starting a manual check for updated apps...</message>
<message>Start een manuele controle op software updates...</message>
</output>
<output id="7">
<!--Couldn't start a manual check for updated apps-->
<message>Couldn't start a manual check for updated apps!</message>
<message>Kon geen manuele controle op software updates starten!</message>
</output>
<output id="8">
<!--Check for updated apps already running-->
<message>Check for updated apps already running...</message>
<message>Er wordt al naar software updates gezocht...</message>
</output>
<output id="9">
<!--Manual check for updated apps completed-->
<message>Manual check for updated apps completed...</message>
<message>Manuele controle op software updates voltooid...</message>
</output>
<output id="10">
<!--See changelog-->
<message>See changelog</message>
<message>Zie changelog</message>
</output>
<output id="11">
<!--Open log file-->
<message>Open log file</message>
<message>Open logbestand</message>
</output>
</outputs>
</local>

View File

@ -43,7 +43,7 @@
<message>Kunde inte starta en manuell koll efter uppdaterade appar!</message>
</output>
<output id="8">
<!--Check for updated apps already running-->
<!--A check for updated apps already running-->
<message>En koll efter uppdaterade appar körs redan...</message>
</output>
<output id="9">

View File

@ -1,6 +1,6 @@
<# ARRAYS/VARIABLES #>
#App to Run (as SYSTEM)
#$RunWait = $False if it shouldn't be waited for completion. Example:
#$RunWait = $False if it shouldn't be waited for completion. For example:
#$RunSystem = "$PSScriptRoot\bins\MsiZap.exe"
#$RunSwitch = "tw! {GUID}"
$RunSystem = ""
@ -13,9 +13,18 @@ $Proc = @("")
#Beginning of Process Name to Wait for to End - optional wildcard (*) after, without .exe, multiple: "proc1","proc2"
$Wait = @("")
#Install App from Winget Repo, multiple: "appID1","appID2". Example:
#$WingetIDInst = @("Microsoft.PowerToys")
$WingetIDInst = @("")
#WingetID to uninstall in default manifest mode (silent if supported)
#Multiple: "ID1","ID2". Example:
#$WingetIDUninst = @("Microsoft.PowerToys")
$WingetIDUninst = @("")
#Beginning of App Name string to Silently Uninstall (MSI/NSIS/INNO/EXE with defined silent uninstall in registry)
#Multiple: "app1*","app2*", required wildcard (*) after; search is done with "-like"!
$App = @("")
$AppUninst = @("")
#Beginning of Desktop Link Name to Remove - optional wildcard (*) after, without .lnk, multiple: "lnk1","lnk2"
$Lnk = @("")
@ -37,18 +46,23 @@ $AddType = ""
$DelKey = ""
$DelValue = ""
#Remove file/directory, multiple: "file1","file2"
#Remove file/directory, multiple: "file1","file2" Example:
#$DelFile = @("${env:ProgramFiles}\PowerToys\PowerToys.Update.exe")
$DelFile = @("")
#Copy file/directory
#Example:
#Rename file/directory. Example:
#$RenFile = "${env:ProgramFiles}\PowerToys\PowerToys.Update.exe"
#$NewName = "PowerToys.Update.org"
$RenFile = ""
$NewName = ""
#Copy file/directory. Example:
#$CopyFile = "C:\Logfiles"
#$CopyTo = "C:\Drawings\Logs"
$CopyFile = ""
$CopyTo = ""
#Find/Replace text in file
#Example:
#Find/Replace text in file. Example:
#$File = "C:\dummy.txt"
#$FindText = 'brown fox'
#$ReplaceText = 'white fox'
@ -59,10 +73,6 @@ $ReplaceText = ''
#Grant "Modify" for directory/file to "Authenticated Users" - multiple: "dir1","dir2"
$GrantPath = @("")
#Install App from Winget Repo, multiple: "appID1","appID2". Example:
#$AppID = @("Microsoft.PowerToys")
$AppID = @("")
#App to Run (as current logged-on user)
$RunUser = ""
$User = $True
@ -80,8 +90,14 @@ if ($Proc) {
if ($Wait) {
Wait-ModsProc $Wait
}
if ($App) {
Uninstall-ModsApp $App
if ($WingetIDInst) {
Install-WingetID $WingetIDInst
}
if ($WingetIDUninst) {
Uninstall-WingetID $WingetIDUninst
}
if ($AppUninst) {
Uninstall-ModsApp $AppUninst
}
if ($Lnk) {
Remove-ModsLnk $Lnk
@ -95,6 +111,9 @@ if ($DelKey) {
if ($DelFile) {
Remove-ModsFile $DelFile
}
if ($RenFile -and $NewName) {
Rename-ModsFile $RenFile $NewName
}
if ($CopyFile -and $CopyTo) {
Copy-ModsFile $CopyFile $CopyTo
}
@ -104,9 +123,6 @@ if ($File -and $FindText -and $ReplaceText) {
if ($GrantPath) {
Grant-ModsPath $GrantPath
}
if ($AppID) {
Install-ModsApp $AppID
}
if ($RunUser) {
Invoke-ModsApp $RunUser "" "" $User
}

View File

@ -1,8 +1,8 @@
#Common shared functions for mods handling
#Common shared functions to handle the mods
function Invoke-ModsApp ($Run, $RunSwitch, $RunWait, $User) {
if (Test-Path "$Run") {
if (!$RunSwitch) {$RunSwitch = " "}
if (!$RunSwitch) { $RunSwitch = " " }
if (!$User) {
if (!$RunWait) {
Start-Process $Run -ArgumentList $RunSwitch
@ -20,26 +20,37 @@ function Invoke-ModsApp ($Run, $RunSwitch, $RunWait, $User) {
function Stop-ModsProc ($Proc) {
foreach ($process in $Proc)
{
foreach ($process in $Proc) {
Stop-Process -Name $process -Force -ErrorAction SilentlyContinue | Out-Null
}
Return
}
function Wait-ModsProc ($Wait) {
foreach ($process in $Wait)
{
foreach ($process in $Wait) {
Get-Process $process -ErrorAction SilentlyContinue | Foreach-Object { $_.WaitForExit() }
}
Return
}
function Uninstall-ModsApp ($App) {
foreach ($app in $App)
{
function Install-WingetID ($WingetIDInst) {
foreach ($app in $WingetIDInst) {
& $Winget install --id $app --accept-package-agreements --accept-source-agreements -h
}
Return
}
function Uninstall-WingetID ($WingetIDUninst) {
foreach ($app in $WingetIDUninst) {
& $Winget uninstall --id $app -e --accept-source-agreements -h
}
Return
}
function Uninstall-ModsApp ($AppUninst) {
foreach ($app in $AppUninst) {
$InstalledSoftware = Get-ChildItem "HKLM:\Software\Microsoft\Windows\CurrentVersion\Uninstall"
foreach ($obj in $InstalledSoftware){
foreach ($obj in $InstalledSoftware) {
if ($obj.GetValue('DisplayName') -like $App) {
$UninstallString = $obj.GetValue('UninstallString')
$CleanedUninstallString = $UninstallString.Trim([char]0x0022)
@ -95,7 +106,7 @@ function Uninstall-ModsApp ($App) {
}
if (!$x64) {
$InstalledSoftware = Get-ChildItem "HKLM:\Software\WOW6432Node\Microsoft\Windows\CurrentVersion\Uninstall"
foreach ($obj in $InstalledSoftware){
foreach ($obj in $InstalledSoftware) {
if ($obj.GetValue('DisplayName') -like $App) {
$UninstallString = $obj.GetValue('UninstallString')
$CleanedUninstallString = $UninstallString.Trim([char]0x0022)
@ -153,8 +164,7 @@ function Uninstall-ModsApp ($App) {
Return
}
function Remove-ModsLnk ($Lnk) {
foreach ($link in $Lnk)
{
foreach ($link in $Lnk) {
Remove-Item -Path "${env:Public}\Desktop\$link.lnk" -Force -ErrorAction SilentlyContinue | Out-Null
}
Return
@ -162,7 +172,7 @@ function Remove-ModsLnk ($Lnk) {
function Add-ModsReg ($AddKey, $AddValue, $AddTypeData, $AddType) {
if ($AddKey -like "HKEY_LOCAL_MACHINE*") {
$AddKey = $AddKey.replace("HKEY_LOCAL_MACHINE","HKLM:")
$AddKey = $AddKey.replace("HKEY_LOCAL_MACHINE", "HKLM:")
}
if (!(Test-Path "$AddKey")) {
New-Item $AddKey -Force -ErrorAction SilentlyContinue | Out-Null
@ -173,7 +183,7 @@ function Add-ModsReg ($AddKey, $AddValue, $AddTypeData, $AddType) {
function Remove-ModsReg ($DelKey, $DelValue) {
if ($DelKey -like "HKEY_LOCAL_MACHINE*") {
$DelKey = $DelKey.replace("HKEY_LOCAL_MACHINE","HKLM:")
$DelKey = $DelKey.replace("HKEY_LOCAL_MACHINE", "HKLM:")
}
if (Test-Path "$DelKey") {
if (!$DelValue) {
@ -187,8 +197,7 @@ function Remove-ModsReg ($DelKey, $DelValue) {
}
function Remove-ModsFile ($DelFile) {
foreach ($file in $DelFile)
{
foreach ($file in $DelFile) {
if (Test-Path "$file") {
Remove-Item -Path $file -Force -Recurse -ErrorAction SilentlyContinue | Out-Null
}
@ -196,6 +205,13 @@ function Remove-ModsFile ($DelFile) {
Return
}
function Rename-ModsFile ($RenFile, $NewName) {
if (Test-Path "$RenFile") {
Rename-Item -Path $RenFile -NewName $NewName -Force -ErrorAction SilentlyContinue | Out-Null
}
Return
}
function Copy-ModsFile ($CopyFile, $CopyTo) {
if (Test-Path "$CopyFile") {
Copy-Item -Path $CopyFile -Destination $CopyTo -Recurse -Force -ErrorAction SilentlyContinue | Out-Null
@ -205,14 +221,13 @@ function Copy-ModsFile ($CopyFile, $CopyTo) {
function Edit-ModsFile ($File, $FindText, $ReplaceText) {
if (Test-Path "$File") {
((Get-Content -path $File -Raw) -replace "$FindText","$ReplaceText") | Set-Content -Path $File -Force -ErrorAction SilentlyContinue | Out-Null
((Get-Content -path $File -Raw) -replace "$FindText", "$ReplaceText") | Set-Content -Path $File -Force -ErrorAction SilentlyContinue | Out-Null
}
Return
}
function Grant-ModsPath ($GrantPath) {
foreach ($path in $GrantPath)
{
foreach ($path in $GrantPath) {
if (Test-Path "$path") {
$NewAcl = Get-Acl -Path $path
$identity = New-Object System.Security.Principal.SecurityIdentifier S-1-5-11
@ -229,11 +244,3 @@ function Grant-ModsPath ($GrantPath) {
}
Return
}
function Install-ModsApp ($AppID) {
foreach ($app in $AppID)
{
& $Winget install --id $app --accept-package-agreements --accept-source-agreements -h
}
Return
}