The future of PSResourceGet: Three features that change how you manage PowerShell packages

And the ones you want to keep using in your automation flows

The future of PSResourceGet: Three features that change how you manage PowerShell packages

If you have ever waited for Install-PSResource to trudge through a long list of modules, for example, the Az one, and thought it felt no faster than the Install-Module days it was meant to replace, in the new preview release something changed.

But there are two other features that also change how the future of PSResourceGet is going to look.

The release dropped last week, including a post from Sydney Smith. With a couple of bug fixes included, three features stood out both in the release and the blog post. PSResourceGet is maturing and focusing more on becoming an enterprise tool.

In this blog post, we'll take a further look at how parallel execution makes bulk installation faster. How Microsoft Artifact Registry (MAR) becomes the default trusted repository. And how a Microsoft DSC resource is shipped with PSResourceGet.

Installing the preview

Each section of this post will contain code snippets that you can follow along with. If you want to test them out yourself, you can use the following command if you're running PowerShell 7.6+:

Install-PSResource -Name Microsoft.PowerShell.PSResourceGet `
  -Version '1.3.0-preview1' `
  -Prerelease
ℹ️
This preview drops Windows PowerShell support.

Execute module installation in parallel

I'm not going to lie, as I was already (pretty) satisfied with the result of Install-PSResource vs Install-Module on performance. But with the ever-growing number of modules being published to the gallery, there are scenarios in which it is still labeled as slow. One of those scenarios is whenever Install-PSResource needs to resolve ten or twenty dependencies.

Each dependency has to go through finding, then downloading, and after all, installing it. In DevOps pipelines or if you want to install them on a bunch of servers at a time, this can come at a cost. So what has changed in the preview release?

In the following PR, a rewrite happened on the internals of finding and installing packages. Both use async and concurrent execution. What this means is that instead of waiting for each package to finish before starting the next one, PSResourceGet now kicks off multiple find and install operations at the same time.

So, if we look at it in practice, we can do a measuring exercise even though the Install-PSResource command doesn't need any additional parameters or switches added. The following script was used to measure the performance:

# Clean slate before each run (run this before both benchmarks)
Uninstall-PSResource -Name 'Az' -ErrorAction SilentlyContinue -Scope AllUsers

# Benchmark — run this once in a session with v1.2.0, once with v1.3.0-preview1
$time = Measure-Command {
    Install-PSResource -Name 'Az' -Scope AllUsers
}

"Elapsed: {0:N2}s" -f $time.TotalSeconds

The first run when running Microsoft.PowerShell.PSResourceGet v1.2.0:

Figure 1: First run on v1.2.0

Second run for the preview version:

Figure 2: Second run v1.3.0-preview1

You can see there's a slight difference there, but the work is still in progress. Expect future updates that will further improve the performance.

The native Microsoft DSC resource for PSResourceGet

It gets easier and easier to declaratively define your system out of the box. That's because, before this release, you still would have required some external system to download and install either a native command-based DSC resource, or use Install-PSResource for it.

With the preview release, this resource is natively baked in. Yes, you heard that right. If you inspect the contents that get shipped with, you notice three files have been silently added:

Figure 3: Microsoft DSC files for PSResourceGet

These files combined make a DSC resource natively discoverable through DSC's engine. And with natively, I mean the following. Even that the psresourceget.ps1 is a PowerShell script, the engine sees it as a command-based resource because of the shipped resource manifest + logic inside the script. This resource basically doesn't have to go through an adapter.

Take a look when you run the following command:

# Install community module
Install-PSResource -Name PSDSC

# Install the latest stable version of dsc.exe
Install-DscExe

dsc resource list | 
  ConvertFrom-Json | 
  Where-Object -Property type -Like Microsoft.PowerShell.PSResourceGet*
Figure 4: Microsoft DSC PSResourceGet resource

You can see in the above image that there's nothing set for requireAdapter, thus meaning it doesn't have to go through it.

Let's see an example and add two modules from the previous section declaratively:

# psresourceList.dsc.config.yaml
$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
  - name: Install required modules
    type: Microsoft.PowerShell.PSResourceGet/PSResourceList
    properties:
      repositoryName: PSGallery
      trustedRepository: true
      resources:
        - name: Pester
          version: 5.7.1
        - name: PSScriptAnalyzer
          version: 1.25.0

First, let's run a get to see if they're installed:

dsc config get --file psresourceList.dsc.config.yaml
Figure 5: Check current state

The modules have not been installed. Time to run set:

dsc config set --file psresourceList.dsc.config.yaml
Figure 6: Set the state
ℹ️
Because scope wasn't declared in the document, the default will be CurrentUser.

If you want to trust the PowerShell Gallery by default (which you shouldn't), you can use the Repository resource and remove the trustedRepository: true property:

$schema: https://aka.ms/dsc/schemas/v3/bundled/config/document.json
resources:
  - name: Ensure PSGallery is registered
    type: Microsoft.PowerShell.PSResourceGet/Repository
    properties:
      name: PSGallery
      uri: https://www.powershellgallery.com/api/v2
      trusted: true
      priority: 50

Those are the current DSC resources that got shipped. That brings us to the latest feature added: the default MAR repository.

Safety by default with Microsoft Artifact Registry

Slowly, behind the scenes, Microsoft has already started migrating a bunch of its own PowerShell modules to MAR. But why is this an important feature?

Well, I have already mentioned it, and Sydney Smith also did in the blog post. You shouldn't be trusting the PowerShell Gallery by default. Whereas MAR can be trusted:

Microsoft Artifact Registry (also known as Microsoft Container Registry or MCR) is the primary registry for all Microsoft published artifacts (such as container images) that offers a reliable and trustworthy delivery of artifacts with a syndicated catalog, while maintaining the quality that customers expect from a Microsoft product offering.

MAR also offers a Service Level Agreement (SLA). And with the latest issues happening on the Gallery, you can be certain that you can install your PowerShell modules that you need.

Now, because it's a Microsoft offering, you will not find all the community-based PowerShell modules, but only those that are officially published by Microsoft itself. And with the preview release, MAR is the default trusted repository.

Figure 7: Default trusted repository (MAR)

So, what does this, in essence, mean in practice? If you now install PowerShell modules that come from Microsoft, say Az.Accounts, it will automatically resolve from MAR first (as it is a higher priority) if the module is published there. It's not going to the PowerShell Gallery untrusted repository (unless you trusted it). For enterprises, this can become useful.

How the three features connect

On the surface, these three features look like separate improvements. Faster installs, a DSC resource, and a new default repository. But if you step back, they all pull in the same direction.

Parallel execution matters more as organizations adopt stricter intake workflows. From private feeds, pinned versions, to audited dependencies, the numbers keep increasing. That's where the performance improvement becomes relevant at exactly the point where PSResourceGet is getting serious.

Then, the Microsoft DSC resource makes scenarios more declarative. Even better is the fact that during the community call, it was announced that Windows Server vNext is going to ship PowerShell 7 by default, removing one step further into bootstrapping it from the ground up. You don't need to call Install-PSResource anymore. Instead, you can orchestrate it with the declarativeness you need.

And MAR being the default for trusted Microsoft PowerShell modules brings in another layer of trust. That's important for enterprises. Plus, the fact that it has an SLA, and now PSResourceGet points to it automatically, is definitely a good bonus.

These three features together push PSResourceGet from being a package management tool to something that an enterprise can automate on. Faster, declarative, and with a clearer trust model built in.

Wrapping up

It looked like PSResourceGet's preview version was a short changelog. But it represented a meaningful shift happening underneath. Each of the three features resolves a friction point.

Sydney's roadmap post draws the bigger picture. PSResourceGet is molded towards an enterprise-grade tool. Not just something that replaced PowerShellGet. This preview is the first concrete delivery against that roadmap. And it landed quite well.