Automate the installation of applications using Winget
My current Windows 11 setup on a home PC has become a bit unstable and slow. Originally, I upgraded Windows 10 to 11 immediately when it was available. I think it was four years ago.
I handled Windows operating system, files, and programs on a single SSD disk for quite a long time. A year ago I needed to purchase an additional SSD to get more disk space. This impacted the setup so that I now have files here and there, some programs are installed on the C: drive and some on the D: drive. It's getting messy. I want to have more organized structures for my files and programs. Besides that, I also have many unnecessary programs installed, and some background services are running that are not really needed.
This is now a good opportunity to clean the table, so to speak. I think formatting the C: drive and reinstalling Windows 11 is a good approach now. Practically, this means that I need to reinstall all programs and do the necessary configurations after the Windows installation. That will be a big job to do.
Back in the day, I used to use the disk image creation tool called Norton Ghost. Ghost enabled saving the state of the system as an image file. Practically, this meant configuring Windows as I wanted and installing all necessary programs, and after that, creating the image. Whenever I needed to start everything over, I just restored everything using the disk image. The downside of this approach is that it installs outdated software versions since the image is a snapshot from a specific time.
This time, I want to do things a bit differently. I want to achieve a similar kind of result, but with scripting and installing the latest versions of programs. I'm aiming to have one script which installs the necessary programs on Windows, making future reinstalls easier and less time-consuming.
Package Managers for Windows
There are multiple solutions available for managing and automating application installation, scripting, and configuration in Windows. The most famous package managers are Winget and Chocolatey. Both of these are CLI (command-line interface) tools that allow you to search, install, remove, and update applications.
Winget is a free and open-source package manager originally developed by Microsoft. Winget is also pre-installed within Windows 11. Chocolatey provides an open-source version for individuals and a commercial Chocolatey for Business version for complex environments.
There are other tools also available, and one interesting one is AME Wizard. This tool is designed to modify and customize the Windows operating system using YAML-based Playbooks. Within Playbooks you have a wide range of possibilities to modify system components and install packages. Currently (03/25), this tool is in beta phase.
Benefits of using Package Manager
- A cohesive and streamlined experience for program installation. No need to manually download and run installers.
- Enables automation and scripting.
- Reusability: You can easily share your configuration/script with your friends or colleagues.
- Unified way to update all programs with a single command.
- Enables an easy way to restore your application after operating system installation when automation is utilized.
How do I automate this?
I decided to use Winget as a foundation for the automation. I created a PowerShell script which utilizes Winget and Winget YAML templates to install and configure all necessary programs. I prepared four separate YAML templates for different application categories. One for AI, Developer, Gaming, Productivity tooling.
Templates
Winget.run website is a convenient site to find applications available in the Winget repository. Of course, you can also use the winget search command.
AI-setup template (ai-setup.yaml)
properties:
configurationVersion: 0.2.2
resources:
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Ollama.Ollama
allowPrerelease: false
securityContext: current
settings:
id: "Ollama.Ollama"
source: winget
id: Ollama.Ollama
Developer-setup template (developer-setup.yaml)
properties:
configurationVersion: 0.2.1
resources:
- resource: Microsoft.Windows.Developer/DeveloperMode
directives:
description: Enable Developer Mode
allowPrerelease: false
settings:
Ensure: Present
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.VisualStudio.2022.Community
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.VisualStudio.2022.Community"
source: winget
id: Microsoft.VisualStudio.2022.Community
- resource: Microsoft.VisualStudio.DSC/VSComponents
dependsOn:
- Microsoft.VisualStudio.2022.Community
directives:
description: Install required VS workloads
allowPrerelease: false
settings:
productId: Microsoft.VisualStudio.Product.Community
channelId: VisualStudio.17.Release
components:
- Microsoft.VisualStudio.Workload.Azure
- Microsoft.VisualStudio.Workload.Aspire
- resource: Microsoft.WinGet.DSC/WinGetPackage
id: Microsoft.VisualStudioCode
directives:
description: Installing Microsoft.VisualStudioCode
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.VisualStudioCode"
source: winget
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.DotNet.SDK.9
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.DotNet.SDK.9"
source: winget
id: Microsoft.DotNet.SDK.9
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.WSL
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.WSL"
source: winget
id: Microsoft.WSL
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.WindowsTerminal
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.WindowsTerminal"
source: winget
id: Microsoft.WindowsTerminal
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing GitHub.GitHubDesktop
allowPrerelease: false
securityContext: current
settings:
id: "GitHub.GitHubDesktop"
source: winget
id: GitHub.GitHubDesktop
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Docker.DockerDesktop
allowPrerelease: false
securityContext: current
settings:
id: "Docker.DockerDesktop"
source: winget
id: Docker.DockerDesktop
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.Bicep
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.Bicep"
source: winget
id: Microsoft.Bicep
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.Azd
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.Azd"
source: winget
id: Microsoft.Azd
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Microsoft.AzureCLI
allowPrerelease: false
securityContext: current
settings:
id: "Microsoft.AzureCLI"
source: winget
id: Microsoft.AzureCLI
Gaming-setup template (gaming-setup.yaml)
properties:
configurationVersion: 0.2.2
resources:
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing EpicGames.EpicGamesLauncher
allowPrerelease: false
securityContext: current
settings:
id: "EpicGames.EpicGamesLauncher"
source: winget
id: EpicGames.EpicGamesLauncher
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Valve.Steam
allowPrerelease: false
securityContext: current
settings:
id: "Valve.Steam"
source: winget
id: Valve.Steam
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Discord.Discord
allowPrerelease: false
securityContext: current
settings:
id: "Discord.Discord"
source: winget
id: Discord.Discord
Productivity-setup template
properties:
configurationVersion: 0.2.2
resources:
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Synology.DriveClient
allowPrerelease: false
securityContext: current
settings:
id: "Synology.DriveClient"
source: winget
id: Synology.DriveClient
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Obsidian.Obsidian
allowPrerelease: false
securityContext: current
settings:
id: "Obsidian.Obsidian"
source: winget
id: Obsidian.Obsidian
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing Mozilla.Firefox
allowPrerelease: false
securityContext: current
settings:
id: "Mozilla.Firefox"
source: winget
id: Mozilla.Firefox
Package sources
By default, there are two sources available: the Winget repository and the Microsoft Store. You can check available sources and add new ones using the source command.
winget source
Adding applications from the Microsoft Store to a YAML template requires some additional work. Change the source to "msstore" and set the ID field to the Store Product identifier, not the name.
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Installing iCloud
allowPrerelease: false
securityContext: current
settings:
id: "9PKTQ5699M62"
source: msstore
id: "iCloud"
Easiest way is to use winget show command, which reveals the Store Product ID.
winget show iCloud -s msstore

Powershell script
Script itself is super simple. Basically, it just calls the winget configure command, passing the specific template file as a parameter. Configuration also uses the "accept-configuration-agreements" parameter to skip agreement/terms prompting.
function WriteText {
param (
$text
)
Write-Host "`n"
$text | Write-Ascii -ForegroundColor Green -Compress
Write-Host "`n"
}
function RunWingetConfigure {
param (
$templates
)
foreach ($template in $templates.GetEnumerator()) {
WriteText($template.Name)
winget configure $template.Value --accept-configuration-agreements --verbose-logs;
}
}
$templates = @{
'AI' = 'winget/ai-setup.yaml'
'GAMING' = 'winget/gaming-setup.yaml'
'PRODUCTIVITY' = 'winget/productivity-setup.yaml'
'DEVELOPER' = 'winget/developer-setup.yaml'
}
RunWingetConfigure($templates)
Running the script loops through all templates and installs all necessary applications. Now I will keep these templates up-to-date, and the next installation will be much easier.

Later, I will investigate extending this PowerShell script to modify also Windows settings. There are multiple PowerShell modules available that enable this.
# Enabling Windows Feature
Enable-WindowsOptionalFeature -FeatureName "Containers-DisposableClientVM" -All -Online
# Disabling Windows Feature
Disable-WindowsOptionalFeature -Online -FeatureName WindowsMediaPlayer
# Remove application
Remove-AppxPackage Clipchamp.Clipchamp_3.0.10220.0_neutral__yxz26nhyzhsrt
Comments