Merge pull request #294 from RedEchidnaUK/main

Added Azure Blob Storage for 'Mods'
pull/299/head
Romain 2023-03-14 11:47:45 +01:00 committed by GitHub
commit 3cf93a5661
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
8 changed files with 143 additions and 14 deletions

View File

@ -1,12 +1,13 @@
<?xml version="1.0" encoding="utf-8"?> <?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.8" xsi:schemaLocation="" schemaVersion="1.0" xmlns="http://www.microsoft.com/GroupPolicy/PolicyDefinitions">
<policyNamespaces> <policyNamespaces>
<target prefix="WAU" namespace="Romanitho.Policies.WAU"/> <target prefix="WAU" namespace="Romanitho.Policies.WAU"/>
</policyNamespaces> </policyNamespaces>
<resources minRequiredRevision="4.7" fallbackCulture="en-us"/> <resources minRequiredRevision="4.8" fallbackCulture="en-us"/>
<supportedOn> <supportedOn>
<definitions> <definitions>
<definition name="SUPPORTED_WAU_1_16_0" displayName="$(string.SUPPORTED_WAU_1_16_0)"/> <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)"/>
</definitions> </definitions>
</supportedOn> </supportedOn>
<categories><category displayName="$(string.WAU)" name="WAU"/></categories> <categories><category displayName="$(string.WAU)" name="WAU"/></categories>
@ -99,6 +100,13 @@
<text id="ModsPath" valueName="WAU_ModsPath" /> <text id="ModsPath" valueName="WAU_ModsPath" />
</elements> </elements>
</policy> </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)"> <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"/> <parentCategory ref="WAU"/>
<supportedOn ref="WAU:SUPPORTED_WAU_1_16_0"/> <supportedOn ref="WAU:SUPPORTED_WAU_1_16_0"/>

View File

@ -1,11 +1,12 @@
<?xml version="1.0" encoding="utf-8"?> <?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.8" schemaVersion="1.0" xmlns="http://schemas.microsoft.com/GroupPolicy/2006/07/PolicyDefinitions">
<displayName>WinGet-AutoUpdate</displayName> <displayName>WinGet-AutoUpdate</displayName>
<description>WinGet-AutoUpdate GPO Management</description> <description>WinGet-AutoUpdate GPO Management</description>
<resources > <resources >
<stringTable > <stringTable >
<string id="WAU">Winget-AutoUpdate</string> <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_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="ActivateGPOManagement_Name">Activate WAU GPO Management</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="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> <string id="BypassListForUsers_Name">Bypass Black/White list for User</string>
@ -43,10 +44,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 "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> 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_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) Path to external mods other than the default. <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_Name">Notification Level</string>
<string id="NotificationLevel_Explain">If this policy is enabled, you can configure the Notification Level: <string id="NotificationLevel_Explain">If this policy is enabled, you can configure the Notification Level:
1. Full (Default) 1. Full (Default)
@ -148,7 +155,12 @@ If this policy is disabled or not configured, the default size is used.</string>
</presentation> </presentation>
<presentation id="ModsPath"> <presentation id="ModsPath">
<textBox refId="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> </textBox>
</presentation> </presentation>
<presentation id="NotificationLevel"> <presentation id="NotificationLevel">

View File

@ -104,7 +104,7 @@ If `-ListPath` is set to **GPO** the Black/White List can be managed from within
Thanks to [Weatherlights](https://github.com/Weatherlights) in [#256 (reply in thread)](https://github.com/Romanitho/Winget-AutoUpdate/discussions/256#discussioncomment-4710599)! Thanks to [Weatherlights](https://github.com/Weatherlights) in [#256 (reply in thread)](https://github.com/Romanitho/Winget-AutoUpdate/discussions/256#discussioncomment-4710599)!
**-ModsPath** **-ModsPath**
Get Mods from external Path (**URL/UNC/Local**) - download/copy to `mods` in Winget-AutoUpdate installation location if external mods are newer. Get Mods from external Path (**URL/UNC/Local/AzureBlob**) - download/copy to `mods` in Winget-AutoUpdate installation location if external mods are newer.
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): 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):
``` ```
@ -121,6 +121,11 @@ Validated on **IIS/Apache**.
- The extension **.ps1** must be added as **MIME Types** (text/powershell-script) otherwise it's displayed in the listing but can't be opened - 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**' - 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**'
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.
**-AzureBlobURL**
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** **-InstallUserContext**
Install WAU with system and **user** context executions (From version 1.15.3). Install WAU with system and **user** context executions (From version 1.15.3).

View File

@ -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" Use White List instead of Black List. This setting will not create the "exclude_apps.txt" but "include_apps.txt"
.PARAMETER ListPath .PARAMETER ListPath
Get Black/White List from Path (URL/UNC/Local) Get Black/White List from Path (URL/UNC/GPO/Local)
.PARAMETER ModsPath .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 .PARAMETER Uninstall
Remove scheduled tasks and scripts. Remove scheduled tasks and scripts.
@ -93,6 +96,7 @@ param(
[Parameter(Mandatory = $False)] [Alias('Path')] [String] $WingetUpdatePath = "$env:ProgramData\Winget-AutoUpdate", [Parameter(Mandatory = $False)] [Alias('Path')] [String] $WingetUpdatePath = "$env:ProgramData\Winget-AutoUpdate",
[Parameter(Mandatory = $False)] [Alias('List')] [String] $ListPath, [Parameter(Mandatory = $False)] [Alias('List')] [String] $ListPath,
[Parameter(Mandatory = $False)] [Alias('Mods')] [String] $ModsPath, [Parameter(Mandatory = $False)] [Alias('Mods')] [String] $ModsPath,
[Parameter(Mandatory = $False)] [Alias('AzureBlobURL')] [String] $AzureBlobSASURL,
[Parameter(Mandatory = $False)] [Switch] $DoNotUpdate = $false, [Parameter(Mandatory = $False)] [Switch] $DoNotUpdate = $false,
[Parameter(Mandatory = $False)] [Switch] $DisableWAUAutoUpdate = $false, [Parameter(Mandatory = $False)] [Switch] $DisableWAUAutoUpdate = $false,
[Parameter(Mandatory = $False)] [Switch] $RunOnMetered = $false, [Parameter(Mandatory = $False)] [Switch] $RunOnMetered = $false,
@ -113,7 +117,7 @@ param(
<# APP INFO #> <# APP INFO #>
$WAUVersion = "1.16.4" $WAUVersion = "1.16.5"
<# FUNCTIONS #> <# FUNCTIONS #>
@ -363,6 +367,9 @@ function Install-WingetAutoUpdate {
if ($ModsPath) { if ($ModsPath) {
New-ItemProperty $regPath -Name WAU_ModsPath -Value $ModsPath -Force | Out-Null 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) { if ($BypassListForUsers) {
New-ItemProperty $regPath -Name WAU_BypassListForUsers -Value 1 -PropertyType DWord -Force | Out-Null New-ItemProperty $regPath -Name WAU_BypassListForUsers -Value 1 -PropertyType DWord -Force | Out-Null
} }

View File

@ -87,7 +87,7 @@ if (Test-Network) {
$WAUDisableAutoUpdate = $WAUConfig.WAU_DisableAutoUpdate $WAUDisableAutoUpdate = $WAUConfig.WAU_DisableAutoUpdate
#If yes then check WAU update if run as System #If yes then check WAU update if run as System
if ($WAUDisableAutoUpdate -eq 1) { if ($WAUDisableAutoUpdate -eq 1) {
Write-Log "WAU AutoUpdate is Disabled." "Grey" Write-Log "WAU AutoUpdate is Disabled." "Gray"
} }
else { else {
Write-Log "WAU AutoUpdate is Enabled." "Green" Write-Log "WAU AutoUpdate is Enabled." "Green"
@ -152,7 +152,7 @@ if (Test-Network) {
if ($WAUConfig.WAU_ModsPath) { if ($WAUConfig.WAU_ModsPath) {
$ModsPathClean = $($WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/")) $ModsPathClean = $($WAUConfig.WAU_ModsPath.TrimEnd(" ", "\", "/"))
Write-Log "WAU uses External Mods from: $ModsPathClean" Write-Log "WAU uses External Mods from: $ModsPathClean"
$NewMods, $DeletedMods = Test-ModsPath $ModsPathClean $WAUConfig.InstallLocation.TrimEnd(" ", "\") $NewMods, $DeletedMods = Test-ModsPath $ModsPathClean $WAUConfig.InstallLocation.TrimEnd(" ", "\") $WAUConfig.WAU_AzureBlobSASURL.TrimEnd(" ")
if ($ReachNoPath) { if ($ReachNoPath) {
Write-Log "Couldn't reach/find/compare/copy from $ModsPathClean..." "Red" Write-Log "Couldn't reach/find/compare/copy from $ModsPathClean..." "Red"
$Script:ReachNoPath = $False $Script:ReachNoPath = $False

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 -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-Log "AZCopy version $AZCopyCurrentVersion found"
}
else {
Write-Log "AZCopy not already installed"
$AZCopyCurrentVersion = "0.0.0"
}
if (([version] $AZCopyCurrentVersion) -lt ([version] $AZCopyLatestVersion)) {
Write-Log "Installing version $AZCopyLatestVersion of AZCopy"
Invoke-WebRequest -Uri $AZCopyLink -OutFile "$WingetUpdatePath\azcopyv10.zip"
Write-Log "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-Log "Copying 'azcopy.exe' to main folder"
Copy-Item "$AZCopyEXEPath\azcopy.exe" -Destination "$WingetUpdatePath\"
Write-Log "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-Log "AZCopy version $AZCopyCurrentVersion installed"
}
}

View File

@ -69,6 +69,14 @@ Function Get-Policies {
Remove-ItemProperty $regPath -Name WAU_ModsPath -Force -ErrorAction SilentlyContinue | Out-Null Remove-ItemProperty $regPath -Name WAU_ModsPath -Force -ErrorAction SilentlyContinue | Out-Null
$ChangedSettings++ $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))) { 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 New-ItemProperty $regPath -Name WAU_NotificationLevel -Value $($WAUPolicies.WAU_NotificationLevel) -Force | Out-Null

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 # URL, UNC or Local Path
# Get local and external Mods paths # Get local and external Mods paths
$LocalMods = -join ($WingetUpdatePath, "\", "mods") $LocalMods = -join ($WingetUpdatePath, "\", "mods")
@ -134,6 +134,45 @@ function Test-ModsPath ($ModsPath, $WingetUpdatePath) {
} }
return $ModsUpdated, $DeletedMods return $ModsUpdated, $DeletedMods
} }
# If Path is Azure Blob
elseif ($ExternalMods -like "AzureBlob") {
Write-Log "Azure Blob Storage set as mod source"
Write-Log "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-Log "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-Log "AZCopy Sync Error! $_"
}
}
}
else {
Write-Log "Error 'azcopy.exe' or SAS Token not found!"
}
return $ModsUpdated, $DeletedMods
}
# If path is UNC or local # If path is UNC or local
else { else {
$ExternalBins = "$ModsPath\bins" $ExternalBins = "$ModsPath\bins"