Skip to content

Commit 08baf0e

Browse files
authored
Prototype creating a WinGet Configuration DSC file in PowerShell (#462)
1 parent acee5ea commit 08baf0e

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed

Tools/WingetCreateMakeDSC.ps1

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
# This script is a prototype for quickly creating DSC files.
2+
3+
#Powershell 7 Required
4+
if ($(Get-Host).version.major -lt 7) {
5+
Write-Host 'This script requires powershell 7. You can update powershell by typing winget install Microsoft.Powershell.' -ForegroundColor red
6+
Exit(1)
7+
}
8+
9+
# Create a custom exception type for our dependency management
10+
class UnmetDependencyException : Exception {
11+
UnmetDependencyException([string] $message) : base($message) {}
12+
UnmetDependencyException([string] $message, [Exception] $exception) : base($message, $exception) {}
13+
}
14+
15+
# Ensure the Winget PowerShell modules are installed
16+
if (-not(Get-Module -ListAvailable -Name Microsoft.Winget.Client)) {
17+
try {
18+
Install-Module Microsoft.Winget.Client
19+
} catch {
20+
# If there was an exception while installing, pass it as an InternalException for further debugging
21+
throw [UnmetDependencyException]::new("'Microsoft.Winget.Client' was not installed successfully", $_.Exception)
22+
} finally {
23+
# Check to be sure it acutally installed
24+
if (-not(Get-Module -ListAvailable -Name Microsoft.Winget.Client)) {
25+
throw [UnmetDependencyException]::new("`Microsoft.Winget.Client` was not found. Check that you have installed the Windows Package Manager modules correctly.")
26+
}
27+
}
28+
}
29+
30+
# Ensure the powershell-yaml module is installed
31+
if (-not(Get-Module -ListAvailable -Name powershell-yaml)) {
32+
try {
33+
Install-PackageProvider -Name NuGet -MinimumVersion 2.8.5.201 -Force
34+
Install-Module -Name powershell-yaml -Force -Repository PSGallery -Scope CurrentUser
35+
} catch {
36+
# If there was an exception while installing, pass it as an InternalException for further debugging
37+
throw [UnmetDependencyException]::new("'powershell-yaml' was not installed successfully", $_.Exception)
38+
} finally {
39+
# Check to be sure it acutally installed
40+
if (-not(Get-Module -ListAvailable -Name powershell-yaml)) {
41+
throw [UnmetDependencyException]::new("`powershell-yaml` was not found. Check that you have installed the module correctly.")
42+
}
43+
}
44+
}
45+
46+
[System.Collections.ArrayList]$finalPackages = @()
47+
$configurationVersion = '0.2.0'
48+
$Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False
49+
$DSCHeader = "# yaml-language-server: `$schema=https://aka.ms/configuration-dsc-schema/$($configurationVersion -Replace '\.0$','')"
50+
51+
do {
52+
$findResult = Find-WinGetPackage $(Read-Host 'What is the Winget ID, or name of the package you want to add to the configuration file?')
53+
54+
if ($findResult.count -ne 0) {
55+
# Assign an index to each package
56+
$findResult | ForEach-Object { $script:i = 1 } { Add-Member -InputObject $_ -NotePropertyName Index -NotePropertyValue $i; $i++ }
57+
$findResult | Select-Object -Property Index, Name, Id, Version | Format-Table | Out-Host
58+
59+
$packageSelected = $false
60+
while (-not($packageSelected)) {
61+
Write-Host
62+
# Prompt user for selection string
63+
$selection = (Read-Host 'Select a package by Index, Name, or Id. Press enter to continue or skip')
64+
$selectedPackage = $null
65+
# If user didn't enter any selection string, set no package as selected and continue
66+
if ( [string]::IsNullOrWhiteSpace($selection) ) {
67+
$packageSelected = $true
68+
} elseif ( $selection -in $findResult.Id ) {
69+
# If the user entered a string which matches the Id, select that package
70+
$selectedPackage = $findResult.Where({ $_.Id -eq $selection })
71+
$packageSelected = $true
72+
} elseif ( $selection -in $findResult.Name ) {
73+
# If the user entered a string which matches the Name, select that package
74+
# Because names could conflict, take the first item in the list to avoid error
75+
$selectedPackage = $findResult.Where({ $_.Name -eq $selection }) | Select-Object -First 1
76+
$packageSelected = $true
77+
} else {
78+
# If the name and ID didn't match, try selecting by index
79+
# This needs to be a try-catch to handle converting strings to integers
80+
try {
81+
$selectedPackage = $findResult.Where({ $_.Index -eq [int]$selection })
82+
# If the user selects an index out of range, don't set no package as selected. Instead, allow for correcting the index
83+
# If the intent is to select no package, the user will be able to skip after being notified the index is out of range
84+
if ($selectedPackage) {
85+
$packageSelected = $true
86+
} else {
87+
Write-Host 'Index out of range, please try again'
88+
}
89+
} catch {
90+
Write-Host 'Invalid entry, please try again'
91+
}
92+
}
93+
}
94+
95+
# If a package was selected, add it to the package list; Otherwise, continue
96+
if ($selectedPackage) {
97+
$unit = @{'resource' = 'Microsoft.WinGet.DSC/WinGetPackage'; 'directives' = @{'description' = $selectedPackage.Name; 'allowPrerelease' = $true; }; 'settings' = @{'id' = $selectedPackage.Id; 'source' = $selectedPackage.Source } }
98+
[void]$finalPackages.Add($unit)
99+
Write-Host "Added $($selectedPackage.Name)" -ForegroundColor Blue
100+
}
101+
102+
} else {
103+
Write-Host 'No package found matching input criteria.' -ForegroundColor DarkYellow
104+
}
105+
} while ($(Read-Host 'Would you like to add another package? [y/n]') -eq 'y')
106+
107+
Write-Host
108+
$fileName = Read-Host 'Name of the configuration file (without extension)'
109+
$filePath = Join-Path -Path (Get-Location) -ChildPath "$($fileName).winget"
110+
111+
$rawYaml = ConvertTo-Yaml @{'properties' = @{'resources' = $finalPackages; 'configurationVersion' = $configurationVersion } }
112+
[System.IO.File]::WriteAllLines($filePath, @($DSCHeader, '', $rawYaml.trim()), $Utf8NoBomEncoding)
113+
114+
Write-Host
115+
Write-Host 'Testing resulting file...' -ForegroundColor yellow
116+
(&winget configure --help) > $null
117+
118+
if ($LASTEXITCODE -eq 0) {
119+
winget configure validate --file $filePath
120+
} else {
121+
Write-Host "'winget configure' is not available, skipping validation." -ForegroundColor Yellow
122+
}
123+
124+
Write-Host "Configuration file created at: $($filePath)" -ForegroundColor Green

0 commit comments

Comments
 (0)