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.

💡
By Default applications are installed to C:\Program Files or C:\Program Files (x86) folders.
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