WinGet on Windows Server 2025

Pratheep Sinnathurai
7 min readFeb 29, 2024

--

Software Installation on Windows Server was mainly a manual Task. If you want to automate Software Installation, you either need to use Configuration Manager or similar Solutions. If we look on Linux we see that they have those cool fancy Package Manager for installing, upgrading, configuring, and removing software. In 2020 Microsoft finally released their own Package Manager but first only on Windows Clients and now four Years later on Windows Server Preview Build 26063 we can use WinGet.

In this Blog Article I want to automate the Software Installation on a Windows Server 2025 using WinGet.

Installing Windows Server 2025

Before we can automate anything, we need to have a Windows Server 2025 on the latest Preview Build. First we need to download the latest ISO from Windows Server 2025.

The next step is to install the new Windows Server 2025.

I experienced some Issues on either upgrading a previous Windows Server Insider Version to the latest Version or creating a new Server using the latest ISO. Those two Issues are known Issues. I ended up using Configuration Manager to stage my Windows Server 2025 with the install.wim File.

It’s important to mention that we are on a Insider Preview, so therefore we can expect some unexpected Error Messages.

Using WinGet on Windows Server

WinGet — the usual way

I would like to install PowerShell 7 on my Windows Server using WinGet.

The next step is to open a PowerShell Window. Let’s search for PowerShell in WinGet. For this I can use the following command.

winget search PowerShell

The Package identifier are dotted. This is the “ID” Column in the middle. To identify the Package we need to know that every Package from Microsoft starts in the ID Column with “Microsoft.” Only the latest Version of PowerShell is available. Let’s search of PowerShell Package from Microsoft.

winget search - name PowerShell - id Microsoft.

We still see some Packages from the Microsoft Store with a unknown Version but I think we can ignore those Packages. So we end up with the PowerShell Preview or productive PowerShell .

Let’s try to install the Microsoft PowerShell Package.

winget install Microsoft.PowerShell

As we can see we are able to use WinGet to install PowerShell.

As this is a server without any network restrictions it’s easy to use it but I would helpful to have a list of network endpoints which needs to be open up for WinGet. I didn’t found any documentation related to network endpoints for WinGet.

This was the manual way to install a package, by searching and installing it. But is there already some automation available?

Winget Configure

The Winget configure command let us automate the installation and set up the needed requirements. Let’s see how this is working.

For a WinGet Configuration File I could use Dev Home App but I don’t see any Use Cases to install the Dev Home App on a Windows Server.

Dev Home App (preview)

The other method is to use the command winget configure.

The WinGet Configuration File is written in YAML and define how the device should look like. The same approach which we know from PowerShell DSC.

You can find some examples in the following URL: https://aka.ms/dsc.yaml

For my further testing I use the following .YAML File.

# yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/0.2
properties:
assertions:
- resource: Microsoft.Windows.Developer/OsVersion
directives:
description: Verify min OS version requirement
allowPrerelease: true
settings:
MinVersion: '10.0.26063'
resources:
- resource: Microsoft.WinGet.DSC/WinGetPackage
directives:
description: Install PowerShell 7
allowPrerelease: true
settings:
id: Microsoft.PowerShell
source: winget
InstallMode: Silent
configurationVersion: 0.2.0

Explanation of the structure:

  • The first line in your configuration file should contain the following comment: # yaml-language-server: $schema=https://aka.ms/configuration-dsc-schema/<most recent schema version #>.
  • Under Properties we can either add a resource node or an assertions node.
  • An assertions is a list of prerequisites which required on the endpoint for the configuration. In my example I want to make sure that the OS Version is correct.
  • To identify what type of resource I can use or how they are called I need to identify the PowerShell DSC Resource. What we will do in the following steps.
  • Under the directives we can add a description to make it readable and understandable for the next maintainer and we set allowPrelease to “true” to make sure that the Module from the Gallery can be downloaded, as the modules are still in Prelease State.

In my case I use the Microsoft.Winget.DSC Module which is available in the PowerShell Gallery.

Now let’s install the Module.

Install-Module -Name Microsoft.WinGet.DSC -AllowPrerelease

Using the following Command I can identify which DSC Resources are available and which Settings I can use.

Get-DScResource -Module Microsoft.Winget.DSC

To identify the WinGetPackage DSC Resource we can use the following Command.

Get-DScResource -Module Microsoft.Winget.DSC -Name WinGetPackage | Select-Object -ExpandProperty Properties

As I want to install the Application Silent I have added the Install Mode in my YAML File.

As soon as I run the command we can see that it works as expected.

winget configure powershell.yaml

Now we installed the PowerShell Package in a pre-configured way on one Server, but how do I manage this on multiple Servers?

WinGet Machine Configuration

As we learned before, there is a PowerShell DSC Module for WinGet, but can we create a Machine Configuration using the PowerShell DSC Module?

Before we can use Machine Configuration we need to onboard our Server to Azure Arc. I have used the Built-In functionality to onboard a Server to Azure Arc which is pretty straight forward.

I have prepared the following PowerShell File for the DSC Configuration.

Configuration PowerShell7
{
Import-DscResource -ModuleName Microsoft.WinGet.DSC

node localhost
{
WinGetPackage PowerShell7
{
Id = 'Microsoft.PowerShell'
source = 'winget'
InstallMode = 'silent'
}
}
}

PowerShell7

Save this file as PowerShell File (.ps1) and run it. Now we will have a new .MOF File which we can use to convert it to a Machine Configuration.

For a detailed explanation on how to convert a .MOF File to a Machine Configuration File you can check my previous post: Security Baseline on Azure Arc-Enabled Servers using Machine Configuration | by Pratheep Sinnathurai | Jan, 2024 | Medium

I used the following PowerShell Commands to convert the .MOF File to an Azure Policy using an existing Storage Account.

New-GuestConfigurationPackage -Configuration powershell7\localhost.mof -Name WinGet_PowerShell7 -Type AuditAndSet 

$existingAccountParams = @{
ResourceGroupname = 'rg-machineconfiguration-mgt-dev-szn-01'
Name = 'stsimgtdevsznmachineconf'
}

$container = Get-AzStorageAccount @existingAccountParams |
Get-AzStorageContainer -Name machineconfiguration

$setParams = @{
Container = 'machineconfiguration'
File = '.\WinGet_PowerShell7.zip'
Context = $container.Context
}

$blob = Set-AzStorageBlobContent @setParams
$contentUri = $blob.ICloudBlob.Uri.AbsoluteUri

$PolicyConfig = @{
PolicyId = (New-Guid)
ContentUri = $contentUri
DisplayName = 'WinGet_PowerShell7'
Description = 'Install PowerShell 7 using WinGet'
Path = './WinGet_PowerShell7.json'
Platform = 'Windows'
PolicyVersion = '1.0.0'
Mode = 'ApplyAndAutoCorrect'
}

New-GuestConfigurationPolicy @PolicyConfig

New-AzPolicyDefinition -Name 'Winget_PowerShell7' -Policy WinGet_PowerShell7.json\WinGet_PowerShell7_DeployIfNotExists.json

The next step is to deploy the Azure Policy to the Resource Group in which the Azure Arc Resource of our Windows Server 2025 is located.

As soon as the Policy is deployed on that Resource we can find it under C:\Programdata\GuestConfig\Configuration

Checking the File “C:\ProgramData\GuestConfig\arc_policy_logs\gc_worker.log” we can identify that our Machine Configuration is applied on our Azure Arc Enabled Server.

At this point I identified an Issue that the Machine Configuration don’t want to apply on my Azure Arc Enabled Server.

The Machine Configuration Package seems to work.

I have created a new PowerShell DSC for Visual Studio Code and this time it shows up as compliant even if Visual Studio Code is not installed on my Azure Arc Enabled Server.

I am currently created an Issue on the PowerShell DSC Module and will update this Post as soon as I know more.

Conclusion

WinGet on Windows Server is still in preview but more and more we see that Microsoft is going into a Configuration as Code Environment with Windows Server am I really looking forward this.

Looking ahead, WinGet has the potential to make server management simpler and more flexible. As it gets better and more widely used, it will help administrators do their jobs more efficiently and keep up with the changing demands of technology.

By leveraging WinGet alongside PowerShell DSC and Azure Arc, administrators can establish robust automation frameworks, ensuring consistent software deployments across their server environments. The exploration of WinGet’s capabilities underscores Microsoft’s commitment to embracing configuration as code principles, offering administrators greater flexibility and efficiency in managing Windows Server instances.

--

--

Pratheep Sinnathurai

Senior Azure Engineer and Microsoft MVP in Azure Hybrid & Migration