From ec1ceebab05ccd45c62487b0a6bf6afe867b1d14 Mon Sep 17 00:00:00 2001 From: Aaron Parker Date: Fri, 27 Sep 2024 10:14:09 +1000 Subject: [PATCH 1/2] Add MicrosoftWindowsApp --- Evergreen/Apps/Get-MicrosoftWindowsApp.ps1 | 45 ++++++++++++++++++++ Evergreen/Manifests/MicrosoftWindowsApp.json | 33 ++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 Evergreen/Apps/Get-MicrosoftWindowsApp.ps1 create mode 100644 Evergreen/Manifests/MicrosoftWindowsApp.json diff --git a/Evergreen/Apps/Get-MicrosoftWindowsApp.ps1 b/Evergreen/Apps/Get-MicrosoftWindowsApp.ps1 new file mode 100644 index 00000000..9812d9d0 --- /dev/null +++ b/Evergreen/Apps/Get-MicrosoftWindowsApp.ps1 @@ -0,0 +1,45 @@ +function Get-MicrosoftWindowsApp { + <# + .NOTES + Site: https://stealthpuppy.com + Author: Aaron Parker + Twitter: @stealthpuppy + #> + [OutputType([System.Management.Automation.PSObject])] + [CmdletBinding(SupportsShouldProcess = $false)] + param ( + [Parameter(Mandatory = $false, Position = 0)] + [ValidateNotNull()] + [System.Management.Automation.PSObject] + $res = (Get-FunctionResource -AppName ("$($MyInvocation.MyCommand)".Split("-"))[1]) + ) + + foreach ($Url in $res.Get.Download.Uri) { + # Grab the download link headers to find the file name + $params = @{ + Uri = $Url + Method = "Head" + ReturnObject = "Headers" + } + $Headers = Invoke-EvergreenWebRequest @params + if ($null -ne $Headers) { + + # Match filename + $Filename = [RegEx]::Match($Headers['Content-Disposition'], $res.Get.Download.MatchFilename).Captures.Groups[1].Value + + # Match version + $Version = [RegEx]::Match($Headers['Content-Disposition'], $res.Get.Download.MatchVersion).Captures.Value + if ($Version.Length -eq 0) { $Version = "Unknown" } + + # Construct the output; Return the custom object to the pipeline + $PSObject = [PSCustomObject] @{ + Version = $Version + Date = $Headers['Last-Modified'] | Select-Object -First 1 + Architecture = Get-Architecture -String $Filename + Filename = $Filename + URI = $Url + } + Write-Output -InputObject $PSObject + } + } +} diff --git a/Evergreen/Manifests/MicrosoftWindowsApp.json b/Evergreen/Manifests/MicrosoftWindowsApp.json new file mode 100644 index 00000000..9c73323d --- /dev/null +++ b/Evergreen/Manifests/MicrosoftWindowsApp.json @@ -0,0 +1,33 @@ +{ + "Name": "Microsoft Windows App", + "Source": "https://learn.microsoft.com/en-us/windows-app/whats-new", + "Get": { + "Update": {}, + "Download": { + "Uri": [ + "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RW1pC6G", + "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RW1pHol", + "https://query.prod.cms.rt.microsoft.com/cms/api/am/binary/RW1pJV5" + ], + "ApiUri": "https://query.prod.cms.rt.microsoft.com/cms/api", + "ApiHeader1": "X-CMS-Tenant", + "ApiHeader2": "X-CMS-Type", + "ApiHeader3": "X-CMS-DocumentId", + "MatchFilename": "(WindowsApp_.*_Release_.*.msix)", + "MatchVersion": "(\\d+(\\.\\d+){1,4})", + "SplitText": "filename=", + "DatePattern": "ddd, dd MMM yyyy HH:mm:ss GMT" + } + }, + "Install": { + "Setup": "", + "Physical": { + "Arguments": "", + "PostInstall": [] + }, + "Virtual": { + "Arguments": "", + "PostInstall": [] + } + } +} \ No newline at end of file From 86d1c04fc97b63d1dfc4987538d18df0b67238c7 Mon Sep 17 00:00:00 2001 From: Aaron Parker Date: Sat, 28 Sep 2024 17:52:42 +1000 Subject: [PATCH 2/2] Update docs --- docs/{invoke.md => api.md} | 8 +++--- docs/getlibraryapp.md | 14 +++++----- ...yApp.md => Get-EvergreenAppFromLibrary.md} | 0 docs/index.md | 28 +++++++++++++------ docs/under.md | 8 ++++-- docs/updatelibrary.md | 8 +++--- docs/why.md | 15 ---------- mkdocs.yml | 14 +++++----- 8 files changed, 47 insertions(+), 48 deletions(-) rename docs/{invoke.md => api.md} (86%) rename docs/help/en-US/{Get-EvergreenLibraryApp.md => Get-EvergreenAppFromLibrary.md} (100%) delete mode 100644 docs/why.md diff --git a/docs/invoke.md b/docs/api.md similarity index 86% rename from docs/invoke.md rename to docs/api.md index b3fc8b31..efe344b9 100644 --- a/docs/invoke.md +++ b/docs/api.md @@ -41,12 +41,12 @@ PS C:\> Invoke-RestMethod -Uri "https://evergreen-api.stealthpuppy.com/app/Unsup Invoke-RestMethod: {message: "Application not found. List all apps for valid application names. Application names are case sensitive.} ``` -## Invoke-EvergreenApp +## Get-EvergreenAppFromApi -Evergreen includes the `Invoke-EvergreenApp` function that is used in much the same way as `Get-EvergreenApp`. This function is simpler than using `Invoke-RestMethod`, and it automatically filters for available applications. For example, to query the API for application data for Microsoft Edge, use: +Evergreen includes the `Get-EvergreenAppFromApi` function that is used in much the same way as `Get-EvergreenApp`. This function is simpler than using `Invoke-RestMethod`, and it automatically filters for available applications. For example, to query the API for application data for Microsoft Edge, use: ```powershell -PS C:\> Invoke-EvergreenApp -Name "MicrosoftEdge" +PS C:\> Get-EvergreenAppFromApi -Name "MicrosoftEdge" Version : 89.0.774.76 Platform : Windows @@ -63,5 +63,5 @@ This returns the current version and download URLs for Microsoft Edge using the Just as with `Get-EvergreenApp`, the output can be filtered for the specific application installer with `Where-Object`. The example below returns the current version and download URL for the Stable channel of the 64-bit Enterprise ring of Microsoft Edge. ```powershell -Invoke-EvergreenApp -Name "MicrosoftEdge" | Where-Object { $_.Architecture -eq "x64" -and $_.Channel -eq "Stable" -and $_.Release -eq "Enterprise" } +Get-EvergreenAppFromApi -Name "MicrosoftEdge" | Where-Object { $_.Architecture -eq "x64" -and $_.Channel -eq "Stable" -and $_.Release -eq "Enterprise" } ``` diff --git a/docs/getlibraryapp.md b/docs/getlibraryapp.md index 2e27ce26..181782f6 100644 --- a/docs/getlibraryapp.md +++ b/docs/getlibraryapp.md @@ -1,16 +1,16 @@ # Install an application from a library -Once an Evergreen library is populated with application downloads, it can be queried for a specific application for the available versions of that application with `Get-EvergreenLibraryApp`. Details of the Evergreen library must be passed to `Get-EvergreenLibraryApp` from `Get-EvergreenLibrary`. +Once an Evergreen library is populated with application downloads, it can be queried for a specific application for the available versions of that application with `Get-EvergreenAppFromLibrary`. Details of the Evergreen library must be passed to `Get-EvergreenAppFromLibrary` from `Get-EvergreenLibrary`. The application details that are returned will include the version and path to the installer binaries for installing the target application. Application details are returned in descending order of version, thus the latest available version can be used or the details filtered for a specific version. ## Examples -In this example, details of the target library at `\\server\EvergreenLibrary` are returned with `Get-EvergreenLibrary` and placed into a variable `$Library`. `Get-EvergreenLibraryApp` is then used to search for Microsoft Visual Studio Code in the library. +In this example, details of the target library at `\\server\EvergreenLibrary` are returned with `Get-EvergreenLibrary` and placed into a variable `$Library`. `Get-EvergreenAppFromLibrary` is then used to search for Microsoft Visual Studio Code in the library. ```powershell PS C:\> $Library = Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" -PS C:\> Get-EvergreenLibraryApp -Inventory $Library -Name "MicrosoftVisualStudioCode" +PS C:\> Get-EvergreenAppFromLibrary -Inventory $Library -Name "MicrosoftVisualStudioCode" Version : 1.74.3 URI : https://az764295.vo.msecnd.net/stable/97dec172d3256f8ca4bfb2143f3f76b503ca0534/VSCodeSetup-x64-1.74.3.exe @@ -29,10 +29,10 @@ Channel : Stable Architecture : x64 ``` -This syntax can be simplified by passing details of the Evergreen library at `\\server\EvergreenLibrary` to `Get-EvergreenLibraryApp` via the pipeline to return details for Microsoft Visual Studio Code. +This syntax can be simplified by passing details of the Evergreen library at `\\server\EvergreenLibrary` to `Get-EvergreenAppFromLibrary` via the pipeline to return details for Microsoft Visual Studio Code. ```powershell -PS C:\> Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" | Get-EvergreenLibraryApp -Name "MicrosoftVisualStudioCode" +PS C:\> Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" | Get-EvergreenAppFromLibrary -Name "MicrosoftVisualStudioCode" Version : 1.74.3 URI : https://az764295.vo.msecnd.net/stable/97dec172d3256f8ca4bfb2143f3f76b503ca0534/VSCodeSetup-x64-1.74.3.exe @@ -54,7 +54,7 @@ Architecture : x64 Application information returned from an Evergreen library can be used in a script to install the latest available version (in this case) of Microsoft Visual Studio Code: ```powershell -$App = Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" | Get-EvergreenLibraryApp -Name "MicrosoftVisualStudioCode" | Select-Object -First 1 +$App = Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" | Get-EvergreenAppFromLibrary -Name "MicrosoftVisualStudioCode" | Select-Object -First 1 $params = @{ FilePath = $App.Path ArgumentList = "/VERYSILENT /NOCLOSEAPPLICATIONS /NORESTARTAPPLICATIONS /NORESTART /SP- /SUPPRESSMSGBOXES /MERGETASKS=!runcode" @@ -69,7 +69,7 @@ Start-Process @params Where a specific version of Visual Studio Code needs to be installed instead of the latest version, the specific version can be selected before installing: ```powershell -$App = Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" | Get-EvergreenLibraryApp -Name "MicrosoftVisualStudioCode" | Where-Object { $_.Version -eq "1.74.0" } +$App = Get-EvergreenLibrary -Path "\\server\EvergreenLibrary" | Get-EvergreenAppFromLibrary -Name "MicrosoftVisualStudioCode" | Where-Object { $_.Version -eq "1.74.0" } $params = @{ FilePath = $App.Path ArgumentList = "/VERYSILENT /NOCLOSEAPPLICATIONS /NORESTARTAPPLICATIONS /NORESTART /SP- /SUPPRESSMSGBOXES /MERGETASKS=!runcode" diff --git a/docs/help/en-US/Get-EvergreenLibraryApp.md b/docs/help/en-US/Get-EvergreenAppFromLibrary.md similarity index 100% rename from docs/help/en-US/Get-EvergreenLibraryApp.md rename to docs/help/en-US/Get-EvergreenAppFromLibrary.md diff --git a/docs/index.md b/docs/index.md index 897e260e..bfa56928 100644 --- a/docs/index.md +++ b/docs/index.md @@ -1,25 +1,35 @@ # Evergreen -Evergreen is a PowerShell module that returns the latest version and download URLs for a set of common Windows applications. The module consists of simple functions to use in scripts when performing several tasks including: +Evergreen is a PowerShell module that returns the latest version and download links for a set of common Windows applications. -* Retrieve the latest version of an application to compare against a version already installed or downloaded -* Return the URL for the latest version of the application to download it for local installation or deployment to target machines +## Trust -Evergreen is intended for use with solutions used to automate software deployments. These solutions could be: +The goal of this project is to provide trust. Evergreen executes in your environment and queries application vendor sources only. To find application versions, Evergreen queries the same update APIs used by the application to find new updates or a source owned by the vendor. This means that you can trust what Evergreen returns because there is no middle man. -* Image creation with Hashicorp Packer - images can be created with the latest version of a set of applications -* Import applications into Configuration Manager or [Microsoft Intune](https://github.com/aaronparker/packagefactory) - keep up to date with the latest versions of applications -* Validating or auditing a desktop image to ensure the current version of an application is installed -* Create a [library of application installers](https://stealthpuppy.com/apptracker) - by regularly running Evergreen functions, you can retrieve and download the current version of an application and store it in an application directory structure for later use +## Why + +Evergreen helps solve several challenges including: + +* Finding the latest version of an application to compare against a version already installed or downloaded +* Finding the URL for the latest application installer to download it for local installation (via scripted install or in a gold image) or deployment to target machines (e.g. Intune or ConfigMgr) + +Evergreen helps to automate software deployments. These could be: + +* Gold image creation with Hashicorp Packer - images can be created with the latest version of a set of applications +* Import applications into the Microsoft Deployment Toolkit, Configuration Manager or [Microsoft Intune](https://github.com/aaronparker/packagefactory) - stay current with the latest versions of applications +* Validating or auditing a Windows image or machine for installed application versions +* Create a [library of application installers](https://stealthpuppy.com/apptracker) - by regularly running Evergreen functions, you can retrieve and download the current version of an application and store it for later use * Submitting manifests to `Winget` or `Chocolatey` or similar - Evergreen can return an object with a version number and download URL that can be used to construct manifests for the most recent versions +There are several community and commercial solutions that manage application deployment and updates already. This module isn't intended to compete against those, and Evergreen isn't intended to be a fully featured package manager for Windows. Evergreen can be complementary to 3rd party solutions + ## Functions Primary functions in Evergreen are: * `Get-EvergreenApp` - returns details of the latest release of an application including the version number and download URL for supported applications. Runs in your environment +* `Save-EvergreenApp` - simplifies downloading application installers returned from `Get-EvergreenApp` * `Get-EvergreenEndpointFromApi` - returns details of the latest release of an application including the version number and download URL from the Evergreen API -* `Save-EvergreenApp` - simplifies downloading application URLs returned from `Get-EvergreenApp` * `Find-EvergreenApp` - lists applications supported by the module * `Test-EvergreenApp` - tests that the URIs returned by `Get-EvergreenApp` are valid * `New-EvergreenLibrary` - creates a new Evergreen library for downloading and maintaining multiple versions of application installers diff --git a/docs/under.md b/docs/under.md index ab521647..353a27dc 100644 --- a/docs/under.md +++ b/docs/under.md @@ -10,6 +10,7 @@ Evergreen includes the following directory structure: * `/Public` - public functions including `Get-EvergreenApp`, `Find-EvergreenApp` and `Save-EvergreenApp` * `/Apps` - internal per-application functions that contain the logic for retrieving application details. These are often unique for each application +* `/Shared` - internal functions used by specific apps to reduce repeated code * `/Manifests` - each application includes a manifest in JSON format that includes application specific details used by the per-application functions. These describe details of the application including URLs used to determine the latest version of the application * `/Private` - internal functions containing reusable code @@ -17,15 +18,18 @@ Evergreen includes the following directory structure: The `Public` folder includes all functions exported from Evergreen: +* `ConvertTo-DotNetVersionClass.ps1` * `Export-EvergreenApp.ps1` * `Export-EvergreenManifest.ps1` * `Find-EvergreenApp.ps1` * `Get-EvergreenApp.ps1` +* `Get-EvergreenAppFromApi.ps1` +* `Get-EvergreenAppFromLibrary.ps1` +* `Get-EvergreenEndpointFromApi.ps1` * `Get-EvergreenLibrary.ps1` -* `Invoke-EvergreenApp.ps1` -* `Invoke-EvergreenLibraryUpdate.ps1` * `New-EvergreenLibrary.ps1` * `Save-EvergreenApp.ps1` +* `Start-EvergreenLibraryUpdate.ps1` * `Test-EvergreenApp.ps1` ### Apps diff --git a/docs/updatelibrary.md b/docs/updatelibrary.md index 2eadb7f9..003b17e1 100644 --- a/docs/updatelibrary.md +++ b/docs/updatelibrary.md @@ -1,6 +1,6 @@ # Update an Evergreen Library -To update a library, use `Invoke-EvergreenLibraryUpdate` - this function will read the `EvergreenLibrary.json` file and use `Get-EvergreenApp` and `Save-EvergreenApp` to populate the library with the application installers and maintain a manifest of the application version information for later reference. +To update a library, use `Start-EvergreenLibraryUpdate` - this function will read the `EvergreenLibrary.json` file and use `Get-EvergreenApp` and `Save-EvergreenApp` to populate the library with the application installers and maintain a manifest of the application version information for later reference. Here's an example - `EvergreenLibrary.json` contains the following entry for Microsoft Teams: @@ -33,12 +33,12 @@ Each time a new version of Team installer is downloaded, `MicrosoftTeams.json` i ## How to update a library -`Invoke-EvergreenLibraryUpdate` has a single parameter - `-Path`, which should be the path to the Evergreen library: +`Start-EvergreenLibraryUpdate` has a single parameter - `-Path`, which should be the path to the Evergreen library: ```powershell -Invoke-EvergreenLibraryUpdate -Path "\\server\EvergreenLibrary" +Start-EvergreenLibraryUpdate -Path "\\server\EvergreenLibrary" ``` If a path is specified that does not contain `EvergreenLibrary.json` and error will be thrown. -To download new application installers when a new version is detected, `Invoke-EvergreenLibraryUpdate` can be run via a scheduled task or other automation tools. This provides a simple method to update the library and make new application available for install or packaging. +To download new application installers when a new version is detected, `Start-EvergreenLibraryUpdate` can be run via a scheduled task or other automation tools. This provides a simple method to update the library and make new application available for install or packaging. diff --git a/docs/why.md b/docs/why.md deleted file mode 100644 index 11a0dfd1..00000000 --- a/docs/why.md +++ /dev/null @@ -1,15 +0,0 @@ -# Why - -Evergreen's focus is on integration with PowerShell as a simple solution to provide application version numbers and download URLs. This has many use cases, including: - -* Integration with [Azure DevOps](https://stealthpuppy.com/packer/) or [Packer](https://www.packer.io/) to create evergreen machine images on-premises, in Azure, AWS, or other cloud platforms -* Import applications into Microsoft Endpoint Manager - keep the Microsoft Deployment Toolkit, Configuration Manager or [Microsoft Intune](https://github.com/aaronparker/packagefactory) up to date with the latest versions of applications -* Validating or [auditing a desktop image](https://github.com/aaronparker/w365) to ensure the current version of an application is installed -* Audit installed application versions in an image or a Windows desktop -* Create a [library of application installers](https://stealthpuppy.com/evergreen/newlibrary/) - by regularly running Evergreen functions, you can retrieve and download the current version of an application and store it in an application directory structure for later use -* [Track application updates](https://github.com/aaronparker/apptracker) to stay on top of new releases -* Submitting manifests to `Winget` or `Chocolatey` or similar - Evergreen can return an object with a version number and download URL that can be used to construct manifests for the most recent versions - -There are several community and commercial solutions that manage application deployment and updates already. This module isn't intended to compete against those, and Evergreen isn't intended to be a fully featured package manager for Windows. - -Evergreen can be complementary to 3rd party solutions - for example, Evergreen can be used with the [Chocolatey Automatic Package Updater Module](https://www.powershellgallery.com/packages/AU/) to find the latest version of an application and then create and submit a Chocolatey package, or it can be used to create a [Windows Package Manager](https://github.com/microsoft/winget-cli) manifest (see a sample script here: [New-WinGetManifest.ps1](https://github.com/aaronparker/Evergreen/blob/main/tools/New-WinGetManifest.ps1)). diff --git a/mkdocs.yml b/mkdocs.yml index 0b819db8..ac457e19 100644 --- a/mkdocs.yml +++ b/mkdocs.yml @@ -126,8 +126,7 @@ extra: # Page tree nav: - Home: - - Introduction: index.md - - Why Evergreen: why.md + - About: index.md - How Evergreen works: how.md - Supported apps: apps.md - Getting started: @@ -145,7 +144,7 @@ nav: - Retrieve details from a library: getlibrary.md - Install an application from a library: getlibraryapp.md - Evergreen API: - - How to use the Evergreen API: invoke.md + - How to use the Evergreen API: api.md - List endpoints used by Evergreen: endpoints.md - Resources: - Troubleshooting: troubleshoot.md @@ -159,12 +158,13 @@ nav: - Save-EvergreenApp: help/en-US/Save-EvergreenApp.md - Test-EvergreenApp: help/en-US/Test-EvergreenApp.md - New-EvergreenLibrary: help/en-US/New-EvergreenLibrary.md - - Invoke-EvergreenApp: help/en-US/Invoke-EvergreenApp.md - - Invoke-EvergreenLibraryUpdate: help/en-US/Invoke-EvergreenLibraryUpdate.md + - Start-EvergreenLibraryUpdate: help/en-US/Start-EvergreenLibraryUpdate.md - Get-EvergreenLibrary: help/en-US/Get-EvergreenLibrary.md - - Get-EvergreenLibraryApp: help/en-US/Get-EvergreenLibraryApp.md + - Get-EvergreenAppFromLibrary: help/en-US/Get-EvergreenAppFromLibrary.md - Export-EvergreenApp: help/en-US/Export-EvergreenApp.md - Export-EvergreenManifest: help/en-US/Export-EvergreenManifest.md - - Get-EvergreenEndpoint: help/en-US/Get-EvergreenEndpoint.md + - Get-EvergreenAppFromApi: help/en-US/Get-EvergreenAppFromApi.md + - Get-EvergreenEndpointFromApi: help/en-US/Get-EvergreenEndpointFromApi.md + - ConvertTo-DotNetVersionClass: help/en-US/ConvertTo-DotNetVersionClass.md - App Tracker: https://stealthpuppy.com/apptracker/ - PSPackageFactory: https://stealthpuppy.com/packagefactory/