Inside the Nuget bootstraping process

A few days ago the PowerShell Team announced on their blog that PowerShellGet has been open-sourced. Both PowerShellGet and PackageManagement modules are now available on the PowerShell Gallery to more easily consume/update these modules and on github to contribute to these projects:

The article says

PowerShellGet has a dependency on PackageManagement.

That’s true.
I’d add that you cannot use the Find-Module cmdlet from the PowerShellGet module before the PackagementManagement module installed the Nuget provider.

Do I have Nuget listed as a provider?

# You can either do
# and see if Nuget is in the list
# or
Get-PackageProvider | Where Name -eq 'NuGet'


But, as soon as you do

Get-PackageProvider -Name NuGet -ErrorAction SilentlyContinue


…or if you use the Find-Module cmdlet, you’ll be asked to complete the Nuget provider installation.

Find-Module -Name Pester -Repository PSGallery


Did you notice that the messages don’t say exactly the same thing and that one proposes to install a minimum version and the other
The Get-PackageProvider from the PackageManagement module seems more accurate than the Find-Module cmdlet from the PowerShellGet module.
Well, because the PowerShellGet module hardcodes the version

…whereas the PackageManagement module built the version on the fly:

After opening the PSModule.psm1 file located in C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\, I can notice that many functions inside that module call either:

# the BootstrapNuGetExe switch 
# used by the Publish-Module function
Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet `


Install-NuGetClientBinaries -CallerPSCmdlet $PSCmdlet

The reason is explained on this page: What’s the difference between nuget-anycpu.exe, Microsoft.PackageManagement.NuGetProvider.dll and nuget.exe?

nuget.exe is used by PowerShellGet to publish packages
Microsoft.PackageManagement.NuGetProvider.dll is used by OneGet and PowerShellGet to discover and install packages.
Only the Publish-Module cmdlet of PowerShellGet will require nuget.exe.

So far, we’ve seen that there are two components that can be downloaded and installed.
According to the content of the PSModule.psm1 file, Nuget.exe is downloaded by the PowerShellGet module and uses the following URL to get it:

# go fwlink for ''
$script:NuGetClientSourceURL = 

Where does Microsoft.PackageManagement.NuGetProvider.dll come from?

Microsoft proposes in their recent blog post to do the following to install the Nuget provider:

Install-PackageProvider -Name Nuget –Force –Verbose

The same piece of information is also mentioned in the FAQ of the PackagementManagement module on github: How do I install a package provider such as NuGet provider if I do not have Internet connection on my box?

Again inside the the PSModule.psm1 file (the PowerShellGet module), its internal Install-NuGetClientBinaries function actually launches the following to install the Nuget provider:

PackageManagement\Install-PackageProvider -Name 'Nuget' `
-MinimumVersion ([Version]'')  `
-Scope $scope -Force


Instead of the above command, I propose to do directly the following and add the Debug switch to uncover what happens behind the scene:

Get-PackageProvider -Name NuGet `
-ErrorAction SilentlyContinue -Verbose -Debug

The following hardcoded URL is immediately used:


Let’s examine this URL and set the MaximumRedirection to 0 to avoid any redirection.

$HT = @{
 Uri = ''
 MaximumRedirection = 0
 ErrorAction = 'SilentlyContinue'
$req = Invoke-WebRequest @HT
# the page has moved
# to this location

We can see the page is redirected to another URL:

The file downloaded from is a swidtag file (Software Identiy Tag) written in XML:

Now, to get the latest version of the Microsoft.PackageManagement.NuGetProvider.dll file, I need to read the content of the providers.masterList.feed.swidtag XML file:

# set a variable
$MasterSwidTagURI = ''

# Get the link of the Nuget provider
(Invoke-WebRequest -Uri $MasterSwidTagURI -MaximumRedirection 0 -ErrorAction SilentlyContinue).Content
))).SoftwareIdentity.Link | Where {
    $_.rel -eq 'package' -and
    $_.latest -eq 'true' -and
    $ -eq 'nuget'
} | Select -expand href

# or more simply using the Invoke-RestMethod cmdlet
(Invoke-RestMethod $MasterSwidTagURI).SoftwareIdentity.Link | 
Where {
    $_.rel -eq 'package' -and
    $_.latest -eq 'true' -and
    $ -eq 'nuget'
} | Select -expand href


To get the latest version of the dll, there’s a specific swidtag file to read from the following URL:

Let’s examine the content of this new XML file:

$dllURI = ''
# Get the version
(Invoke-RestMethod -Uri $dllURI).SoftwareIdentity.version
# Get the source (dll download location)
(Invoke-RestMethod -Uri $dllURI).SoftwareIdentity.Link.href
# New info about the file to download
(Invoke-RestMethod -Uri $dllURI).SoftwareIdentity.Payload.File


Now, we know how and from where the file is being downloaded.

As of version, there’s a hash being used by the Install-PackageProvider cmdlet to check the integrity of the downloaded Microsoft.PackageManagement.NuGetProvider.dll file.
If the Install-PackageProvider is invoked with the Debug switch, I can see at the end of the debug stream the following line: DEBUG: 00:02:07.7019092 BoostrapRequest::ValidateFileHash

The above hash that appears inside the swidtag file doesn’t look standard.

Here’s how it can be verified:

# Download the dll
Invoke-WebRequest -Uri $((Invoke-RestMethod -Uri $dllURI).SoftwareIdentity.Link.href) -OutFile ~/downloads/$((Invoke-RestMethod -Uri $dllURI).SoftwareIdentity.Payload.File.Name) -Verbose

# Get its SHA512 hash
(Get-FileHash ~/downloads/Microsoft.PackageManagement.NuGetProvider.dll -Algorithm SHA512 | Select -Expand Hash).ToLower()

# Check it matches the one specified in the swidtag file
   (Invoke-RestMethod -Uri '').SoftwareIdentity.Payload.File.hash
 ) -replace '-',''


Retours sur le 1er #FRPSUG

Le 1er RDV gratuit et 100% virtuel du French PowerShell User Group (#FRPSUG) a bien eu lieu et a été un franc succès🙂

Si vous l’avez râté, vous pouvez revoir l’enregistrement sur cette page, vous y trouverez également la présentation et le code présentés.

Comment rejoindre la communauté?

Get the TLS ciphers suite order

Last year, Microsoft published an advisory about a vulnerability in Schannel where weak/insecure ciphers were used in TLS sessions. More recently Microsoft also published an Update to add new cipher suites to Internet Explorer and Microsoft Edge in Windows.

In the above advisory, they introduced a GPO setting where you can set a new ciphers suite order. Nice, I love it.
But wait, without that GPO setting,…

  • How do I know what is the order of ciphers being used?

The question was answered on this forum page
Unfortunately it doesn’t work with PowerShell 2.0 (default version) on Windows 7 and I get the following error

  • What about newer systems?

The code proposed on the forum page works in Windows 8.1 and PowerShell 4.0. There’s also a module called TLS but it doesn’t have the Get-TlsCipherSuite cmdlet😦

On Window 10, you’ve got more in the TLS module and the Get- TlsCipherSuite is available🙂

On Windows 10 to get the order of ciphers, you simply do

  • How can I get the order of ciphers whatever the operating system and its version of PowerShell?

I’ve slightly changed the code proposed on the forum page : line 49 replaced by 48😎

Additional links
Documented ciphers suites per OS
Update to enable TLS 1.1 and TLS 1.2 as a default secure protocols in WinHTTP in Windows
BCryptEnumContextFunctions function
BCryptFreeBuffer function

Testing WSUS server operational status

During the summer, someone asked the following questionwsus-monitoring-question on the WSUS mailing list.

I replied and immediately thought that Pester would do the job and quickly showed how he could test if he can connect to the console.

I’ve actually more than a WSUS server to manage. So, I started separating the environmental configuration data from the pester tests code almost the same way Mike F. Robbins did in his recent post where he goes far beyond to what I did.

I think it’s a great idea and here’s what I did in my case to monitor my WSUS server operational status.

To get started, I copied the Pester module on my WSUS server, imported the module and did in the ISE:

# helper to create the required files and folder if not present
New-Fixture -Path  ~/Documents/Pester -Name Test-WSUS
# Put the config data into that file:
psEdit ~/Documents/Pester/Test-WSUS.ps1
# Put the pester code into that file:
psEdit ~/Documents/Pester/Test-WSUS.Tests.ps1

After the first 3 commands, here’s what the ISE console looked liked

The first file Test-WSUS.ps1 looks like this by default.
It will be used to store my configuration data.

The second file Test-WSUS.Tests.ps1 is where I’ll write the pester tests code

After editing the 1rst file Test-WSUS.ps1 like this:
pester-test-wsus-file (fake data in this case)

…and the 2nd file Test-WSUS.Tests.ps1 like this:

…I’m actually ready to assess the operational readiness of my WSUS configuration by using the following cmdlet:

Invoke-Pester -Script ~/Documents/Pester/Test-WSUS.Tests.ps1


I still feel like a Pester newbie but no doubt that Pester rocks 😎

Communauté PowerShell francophone, à vos calendriers

Une avalanche de bonnes nouvelles pour la rentrée, c’est pas génial ? : PowerShell open-source, dispo sur Linux et MacOS,…et la création du 1er FRPSUG pour pouvoir discuter PowerShell dans la langue de Molière😀

Plusieurs MVP francophones passionnés par PowerShell ont créé ce ‘User Group’ et vous proposent 1x par mois un RDV en ligne.

C’est gratuit et 100% virtuel (diffusé et enregistré sur YouTube) parce que notre répartition géographique est très loin de se limiter à l’hexagone. Je pense à nos amis québécois, belges, suisses etc. qui sont de la partie.

J’aime PowerShell et lis ces quelques lignes > je veux pas râter ça, que dois-je faire ?

Qu’est-ce qu’il y a au menu ?



… la suite sur:

PowerShell is all about the Community

PowerShell just reached a huge milestone since Jeffrey Snover wrote the Monad Manifesto more than 10 years ago.

PowerShell is now Open-source Software (OSS) under the MIT license and available on GitHub.

  • Why so excited about this?

We’ve been waiting for it for a long time. It was made possible since Microsoft also Open sourced .Net Core and refactored PowerShell to run on top of .Net Core (aka PowerShell Core and running in Nano server).

This means that it’s more and more mature and just started to become a cross-platform community-driven configuration and automation framework able to manage both API oriented operating system (Windows) and document oriented operating systems (Linux) from anywhere. It clearly aims at providing a consistent and sustainable experience for IT pros and developers for everybody.

  • What else does that mean?

Well, if it’s open sourced, it’s about the community. Microsoft embraced the heterogeneity of both the community and the ecosystem and allows its partners and any customer anybody to be successful.
You, actually anybody running on any operating system (Linux, Microsoft and MacOS) can use these ALPHA versions of PowerShell, submit issues and participate in its development.

Friday Fun: capture pokemon using PowerShell

A few years ago, I wrote a quick function to download all the pokemon pictures from for my kids to create the equivalent of the pokedex:


Beyond that, I don’t know anything about Pokemon, so don’t ask me anything about them😛

Due to the recent success of Pokémon Go, I thought that I should extend the function, make it more friendly, accessible,… and share it, of course😀

If you like Pokemon and PowerShell, this page is for you. You’ll discover, get to know Pokemon and have them all at your finger tips in your favorite console:

The first thing to do is to capture all the pictures from the main site:

The function aims to download all the files. You can launch it, interrupt it, relaunch it. It’ll restart where it left till the end. You’ve got to have at least 720 (the current total of pokemon) jpeg files in the Pokedex folder so that the other functions work.
The Build-Pokedex function will always end by displaying how many Pokemon exist.


Now, to use the Find-Pokemon and Show-Pokemon, it’s pretty straightforward


If you just pipe the two cmdlets together, the picture will be shown:

Find-Pokemon -Name Kyurem | Show-Pokemon 


If you use the -Online switch, the default browser should open the web page corresponding to the pokemon you looked for

Find-Pokemon -Name Kyurem | Show-Pokemon -Online


To discover a new Pokemon more randomly, you can do

0..720 | Get-Random | Find-Pokemon | Show-Pokemon -Online

Enjoy and have fun😎