From feba2b1b04ec9c1ba01f04a483ec88d1eb6b2261 Mon Sep 17 00:00:00 2001 From: Noah Dressler Date: Fri, 13 Feb 2026 00:15:20 +0100 Subject: [PATCH 1/4] Add DATEV.Belegtransfer task --- Tasks/DATEV.Belegtransfer/Config.yaml | 4 ++++ 1 file changed, 4 insertions(+) create mode 100644 Tasks/DATEV.Belegtransfer/Config.yaml diff --git a/Tasks/DATEV.Belegtransfer/Config.yaml b/Tasks/DATEV.Belegtransfer/Config.yaml new file mode 100644 index 0000000000..e50ce14608 --- /dev/null +++ b/Tasks/DATEV.Belegtransfer/Config.yaml @@ -0,0 +1,4 @@ +Type: PackageTask +WinGetIdentifier: DATEV.Belegtransfer +Skip: false +RemoveLastVersion: false From d9abcbb99ae9088a8d6353d29367e09d83d78e06 Mon Sep 17 00:00:00 2001 From: Noah Dressler Date: Fri, 13 Feb 2026 00:16:54 +0100 Subject: [PATCH 2/4] Add DATEV.Belegtransfer script --- Tasks/DATEV.Belegtransfer/Script.ps1 | 115 +++++++++++++++++++++++++++ 1 file changed, 115 insertions(+) create mode 100644 Tasks/DATEV.Belegtransfer/Script.ps1 diff --git a/Tasks/DATEV.Belegtransfer/Script.ps1 b/Tasks/DATEV.Belegtransfer/Script.ps1 new file mode 100644 index 0000000000..fe2338a31d --- /dev/null +++ b/Tasks/DATEV.Belegtransfer/Script.ps1 @@ -0,0 +1,115 @@ +$ProductId = 'ddc1adec-4b1e-4581-b5b0-504fe0d68fd2' +$PortalUrl = "https://apps.datev.de/myupdates/download/products/${ProductId}" + +function Read-Installer { + $InstallerFile = Get-TempFile -Uri $this.CurrentState.Installer[0].InstallerUrl + # Version + $this.CurrentState.Version = $InstallerFile | Read-ProductVersionFromExe + # InstallerSha256 + $this.CurrentState.Installer[0]['InstallerSha256'] = (Get-FileHash -Path $InstallerFile -Algorithm SHA256).Hash + # ProductCode + $this.CurrentState.Installer[0]['ProductCode'] = $InstallerFile | Read-ProductCodeFromBurn + # AppsAndFeaturesEntries + $this.CurrentState.Installer[0]['AppsAndFeaturesEntries'] = @( + [ordered]@{ + UpgradeCode = $InstallerFile | Read-UpgradeCodeFromBurn + } + ) + Remove-Item -Path $InstallerFile -Recurse -Force -ErrorAction 'Continue' -ProgressAction 'SilentlyContinue' +} + +# Discover version from the MyUpdates page title (e.g. "Download Detail - Belegtransfer 5.49 - DATEV MyUpdates") +$EdgeDriver = Get-EdgeDriver -Headless +$EdgeDriver.Navigate().GoToUrl($PortalUrl) +Start-Sleep -Seconds 15 + +$PageTitle = $EdgeDriver.Title +if ($PageTitle -notmatch 'Belegtransfer\s+([\d.]+)') { + throw "Failed to extract version from page title: ${PageTitle}" +} + +$ShortVersion = $Matches[1] +$VersionSlug = $ShortVersion -replace '\.', '' + +$this.CurrentState.Installer += [ordered]@{ + InstallerUrl = "https://download.datev.de/download/bedi/belegtransfer${VersionSlug}.exe" +} + +$Object1 = Invoke-WebRequest -Uri $this.CurrentState.Installer[0].InstallerUrl -Method Head +$ETag = $Object1.Headers.ETag[0] + +# Case 0: Force submit the manifest +if ($Global:DumplingsPreference.Contains('Force')) { + $this.Log('Skip checking states', 'Info') + + # ETag + $this.CurrentState.ETag = @($ETag) + + Read-Installer + + $this.Print() + $this.Write() + $this.Message() + $this.Submit() + return +} + +# Case 1: The task is new +if ($this.Status.Contains('New')) { + $this.Log('New task', 'Info') + + # ETag + $this.CurrentState.ETag = @($ETag) + + Read-Installer + + $this.Print() + $this.Write() + return +} + +# Case 2: The ETag is unchanged +if ($ETag -in $this.LastState.ETag) { + $this.Log("The version $($this.LastState.Version) from the last state is the latest (Global)", 'Info') + return +} + +Read-Installer + +# Case 3: The current state has an invalid version +if ([string]::IsNullOrWhiteSpace($this.CurrentState.Version)) { + throw 'The current state has an invalid version' +} + +# Case 4: The ETag has changed, but the SHA256 is not +if ($this.CurrentState.Installer[0].InstallerSha256 -eq $this.LastState.Installer[0].InstallerSha256) { + $this.Log('The ETag has changed, but the SHA256 is not', 'Info') + + # ETag + $this.CurrentState.ETag = $this.LastState.ETag + $ETag + + $this.Write() + return +} + +# ETag +$this.CurrentState.ETag = @($ETag) + +switch -Regex ($this.Check()) { + # Case 6: The ETag, the SHA256 and the version have changed + 'Updated|Rollbacked' { + $this.Print() + $this.Write() + $this.Message() + $this.Submit() + } + # Case 5: The ETag and the SHA256 have changed, but the version is not + Default { + $this.Log('The ETag and the SHA256 have changed, but the version is not', 'Info') + $this.Config.IgnorePRCheck = $true + $this.Print() + $this.Write() + $this.Message() + $this.Submit() + } +} From 696830c73f9186169663c53a9d5d2bc42fa0eebe Mon Sep 17 00:00:00 2001 From: Charlie Chen <56779163+SpecterShell@users.noreply.github.com> Date: Sun, 15 Feb 2026 17:42:40 +0800 Subject: [PATCH 3/4] Remove RemoveLastVersion property --- Tasks/DATEV.Belegtransfer/Config.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/Tasks/DATEV.Belegtransfer/Config.yaml b/Tasks/DATEV.Belegtransfer/Config.yaml index e50ce14608..50d1bb86b8 100644 --- a/Tasks/DATEV.Belegtransfer/Config.yaml +++ b/Tasks/DATEV.Belegtransfer/Config.yaml @@ -1,4 +1,3 @@ Type: PackageTask WinGetIdentifier: DATEV.Belegtransfer Skip: false -RemoveLastVersion: false From 2983f6b78ed5724c8b343f765cb58f7e4fa2bd2d Mon Sep 17 00:00:00 2001 From: Charlie Chen <56779163+SpecterShell@users.noreply.github.com> Date: Sun, 15 Feb 2026 17:42:56 +0800 Subject: [PATCH 4/4] Rewrite script --- Tasks/DATEV.Belegtransfer/Script.ps1 | 122 +++++---------------------- 1 file changed, 20 insertions(+), 102 deletions(-) diff --git a/Tasks/DATEV.Belegtransfer/Script.ps1 b/Tasks/DATEV.Belegtransfer/Script.ps1 index fe2338a31d..d71429a1c6 100644 --- a/Tasks/DATEV.Belegtransfer/Script.ps1 +++ b/Tasks/DATEV.Belegtransfer/Script.ps1 @@ -1,115 +1,33 @@ -$ProductId = 'ddc1adec-4b1e-4581-b5b0-504fe0d68fd2' -$PortalUrl = "https://apps.datev.de/myupdates/download/products/${ProductId}" +$Session = [Microsoft.PowerShell.Commands.WebRequestSession]::new() +$null = Invoke-RestMethod -Uri 'https://apps.datev.de/myupdates/api/login/status' -WebSession $Session +$Session.Headers.Add('X-Requested-With', 'dcal') +$Session.Headers.Add('X-XSRF-TOKEN', $Session.Cookies.GetAllCookies().Where({ $_.Name -eq 'XSRF-TOKEN' }, 'First')[0].Value) -function Read-Installer { - $InstallerFile = Get-TempFile -Uri $this.CurrentState.Installer[0].InstallerUrl - # Version - $this.CurrentState.Version = $InstallerFile | Read-ProductVersionFromExe - # InstallerSha256 - $this.CurrentState.Installer[0]['InstallerSha256'] = (Get-FileHash -Path $InstallerFile -Algorithm SHA256).Hash - # ProductCode - $this.CurrentState.Installer[0]['ProductCode'] = $InstallerFile | Read-ProductCodeFromBurn - # AppsAndFeaturesEntries - $this.CurrentState.Installer[0]['AppsAndFeaturesEntries'] = @( - [ordered]@{ - UpgradeCode = $InstallerFile | Read-UpgradeCodeFromBurn - } - ) - Remove-Item -Path $InstallerFile -Recurse -Force -ErrorAction 'Continue' -ProgressAction 'SilentlyContinue' -} - -# Discover version from the MyUpdates page title (e.g. "Download Detail - Belegtransfer 5.49 - DATEV MyUpdates") -$EdgeDriver = Get-EdgeDriver -Headless -$EdgeDriver.Navigate().GoToUrl($PortalUrl) -Start-Sleep -Seconds 15 +$Object2 = Invoke-RestMethod -Uri 'https://apps.datev.de/myupdates/api/amr/download-portal-api/v1/additional-software/ddc1adec-4b1e-4581-b5b0-504fe0d68fd2' -WebSession $Session -$PageTitle = $EdgeDriver.Title -if ($PageTitle -notmatch 'Belegtransfer\s+([\d.]+)') { - throw "Failed to extract version from page title: ${PageTitle}" -} +# Version +$this.CurrentState.Version = $Object2.version -$ShortVersion = $Matches[1] -$VersionSlug = $ShortVersion -replace '\.', '' +$Object3 = Invoke-RestMethod -Uri 'https://apps.datev.de/myupdates/api/amr/download-portal-api/v1/download/ddc1adec-4b1e-4581-b5b0-504fe0d68fd2/download-link' -WebSession $Session +# Installer $this.CurrentState.Installer += [ordered]@{ - InstallerUrl = "https://download.datev.de/download/bedi/belegtransfer${VersionSlug}.exe" + InstallerUrl = $Object3.url } -$Object1 = Invoke-WebRequest -Uri $this.CurrentState.Installer[0].InstallerUrl -Method Head -$ETag = $Object1.Headers.ETag[0] - -# Case 0: Force submit the manifest -if ($Global:DumplingsPreference.Contains('Force')) { - $this.Log('Skip checking states', 'Info') - - # ETag - $this.CurrentState.ETag = @($ETag) - - Read-Installer +switch -Regex ($this.Check()) { + 'New|Changed|Updated' { + $this.InstallerFiles[$this.CurrentState.Installer[0].InstallerUrl] = $InstallerFile = Get-TempFile -Uri $this.CurrentState.Installer[0].InstallerUrl + # RealVersion + $this.CurrentState.RealVersion = $InstallerFile | Read-ProductVersionFromExe $this.Print() $this.Write() + } + 'Changed|Updated' { $this.Message() + } + 'Updated' { $this.Submit() - return -} - -# Case 1: The task is new -if ($this.Status.Contains('New')) { - $this.Log('New task', 'Info') - - # ETag - $this.CurrentState.ETag = @($ETag) - - Read-Installer - - $this.Print() - $this.Write() - return -} - -# Case 2: The ETag is unchanged -if ($ETag -in $this.LastState.ETag) { - $this.Log("The version $($this.LastState.Version) from the last state is the latest (Global)", 'Info') - return -} - -Read-Installer - -# Case 3: The current state has an invalid version -if ([string]::IsNullOrWhiteSpace($this.CurrentState.Version)) { - throw 'The current state has an invalid version' -} - -# Case 4: The ETag has changed, but the SHA256 is not -if ($this.CurrentState.Installer[0].InstallerSha256 -eq $this.LastState.Installer[0].InstallerSha256) { - $this.Log('The ETag has changed, but the SHA256 is not', 'Info') - - # ETag - $this.CurrentState.ETag = $this.LastState.ETag + $ETag - - $this.Write() - return -} - -# ETag -$this.CurrentState.ETag = @($ETag) - -switch -Regex ($this.Check()) { - # Case 6: The ETag, the SHA256 and the version have changed - 'Updated|Rollbacked' { - $this.Print() - $this.Write() - $this.Message() - $this.Submit() - } - # Case 5: The ETag and the SHA256 have changed, but the version is not - Default { - $this.Log('The ETag and the SHA256 have changed, but the version is not', 'Info') - $this.Config.IgnorePRCheck = $true - $this.Print() - $this.Write() - $this.Message() - $this.Submit() - } + } }