Recently, I reloaded my computer and noticed a problem when I tried to install the latest version of the Pester PowerShell module using PowerShellGet. I loaded Windows 10 version 1703 (the creators update) which has PowerShell version 5.1 installed by default:

Get-CimInstance -ClassName Win32_OperatingSystem -Property Caption, BuildNumber, OSArchitecture | Select-Object -Property @{label='Operating System';expression={$_.Caption}}, @{label='Version';expression={Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseId}}, BuildNumber, OSArchitecture $PSVersionTable.PSVersion 1 2 3 4 5 6 7 Get-CimInstance -ClassName Win32_OperatingSystem -Property Caption , BuildNumber , OSArchitecture | Select-Object -Property @ { label = 'Operating System' ; expression = { $_ . Caption } } , @ { label = 'Version' ; expression = { Get-ItemPropertyValue -Path 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion' -Name ReleaseId } } , BuildNumber , OSArchitecture $PSVersionTable . PSVersion

Pester version 3.4.0 ships with both Windows 10 version 1607 and 1703. Both of these versions of Windows and/or PowerShell seem to work differently than previous versions when updating and/or installing modules using PowerShellGet as shown in this blog article. I wouldn’t necessarily call this a problem, it seems more like increased security, but it negates the effectiveness of the Force parameter in some cases.

The first error when I tried to run Update-Module to update the Pester module is expected since it wasn’t originally installed using Install-Module, although it would have been nice of Microsoft to install it that way so updating would have been a little easier.

With Windows 10 version 1511, running Install-Module with the -Force parameter installs the updated module without a problem, but beginning with Windows 10 1607, it generates an error because Pester version 3.4.0 is signed by Microsoft and the versions in the PowerShell Gallery are either not signed or are signed by a different publisher.

Get-Module -Name Pester -ListAvailable Update-Module -Name Pester -Force Install-Module -Name Pester -Force Install-Module -Name Pester -Force -SkipPublisherCheck Get-Module -Name Pester -ListAvailable 1 2 3 4 5 6 7 8 9 Get-Module -Name Pester -ListAvailable Update-Module -Name Pester -Force Install-Module -Name Pester -Force Install-Module -Name Pester -Force -SkipPublisherCheck Get-Module -Name Pester -ListAvailable

“PackageManagement\Install-Package : The version ‘4.0.5’ of the module ‘Pester’ being installed is not catalog signed.

Ensure that the version ‘4.0.5’ of the module ‘Pester’ has the catalog file ‘Pester.cat’ and signed with the same

publisher ‘CN=Microsoft Root Certificate Authority 2010, O=Microsoft Corporation, L=Redmond, S=Washington, C=US’ as

the previously-installed module ‘4.0.5’ with version ‘3.4.0’ under the directory ‘C:\Program

Files\WindowsPowerShell\Modules\Pester\3.4.0′. If you still want to install or update, use -SkipPublisherCheck parameter.

At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:1809 char:21

+ … $null = PackageManagement\Install-Package @PSBoundParameters

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (Microsoft.Power….InstallPackage:InstallPackage) [Install-Package], Exception

+ FullyQualifiedErrorId : ModuleIsNotCatalogSigned,Validate-ModuleAuthenticodeSignature,Microsoft.PowerShell.PackageManagement.Cmdlets.InstallPackage”

Let’s see who signed the modules to verify the previous errors are valid:

Get-Module -Name Pester -ListAvailable -PipelineVariable Module | Select-Object -Property @{label='FilePath';expression={$_.Path}} | Get-AuthenticodeSignature | Format-Table -AutoSize -Wrap -Property @{label='Name';expression={$Module.Name}}, @{label='Version';expression={$Module.Version}}, Status, @{label='SignedBy';expression={$_.SignerCertificate.Issuer -replace '^.*O=|,.*$'}} 1 2 3 4 5 6 7 Get-Module -Name Pester -ListAvailable -PipelineVariable Module | Select-Object -Property @ { label = 'FilePath' ; expression = { $_ . Path } } | Get-AuthenticodeSignature | Format-Table -AutoSize -Wrap -Property @ { label = 'Name' ; expression = { $Module . Name } } , @ { label = 'Version' ; expression = { $Module . Version } } , Status , @ { label = 'SignedBy' ; expression = { $_ . SignerCertificate . Issuer -replace '^.*O=|,.*$' } }

Now to show the behavior in Windows 10 version 1511 which has PowerShell version 5.0 installed by default:

As you can see, the SkipPublisherCheck parameter wasn’t previously required:

“Update-Module : Module ‘Pester’ was not installed by using Install-Module, so it cannot be updated.

At line:1 char:1

+ Update-Module -Name Pester -Force

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (Pester:String) [Write-Error], WriteErrorException

+ FullyQualifiedErrorId : ModuleNotInstalledUsingInstallModuleCmdlet,Update-Module”

Pester version 3.3.5 instead of version 3.4.0 ships with Windows 10 version 1511 so I thought there might be some differences with the signatures, but they’re the same:

I originally thought that maybe the PackageManagement or PowerShellGet module had changed, but both of those are at version 1.0.0.1 on Windows 10 version 1511, 1607, and 1703. Be sure to read the update at the end of this blog article.

I’m also seeing subtle differences when trying to install a module that includes commands that already exist on your system. On Windows 10 version 1511 with PowerShell 5.0, the PowerShell Community Extensions module installs with no problem:

Get-Command -Name GCB Install-Module -Name Pscx -Force 1 2 3 Get-Command -Name GCB Install-Module -Name Pscx -Force

On Windows 10 version 1607 or 1703, it complains about needing to use the AllowClobber parameter because a command in the Pscx module already exists on the system (That same command also existed in version 1511).

Get-Command -Name GCB Install-Module -Name Pscx -Force Install-Module -Name Pscx -Force -AllowClobber 1 2 3 4 5 Get-Command -Name GCB Install-Module -Name Pscx -Force Install-Module -Name Pscx -Force -AllowClobber

“PackageManagement\Install-Package : A command with name ‘gcb’ is already available on this system. This module ‘Pscx’

may override the existing commands. If you still want to install this module ‘Pscx’, use -AllowClobber parameter.

At C:\Program Files\WindowsPowerShell\Modules\PowerShellGet\1.0.0.1\PSModule.psm1:1661 char:21

+ … $null = PackageManagement\Install-Package @PSBoundParameters

+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

+ CategoryInfo : InvalidOperation: (Microsoft.Power….InstallPackage:InstallPackage) [Install-Package], Exception

+ FullyQualifiedErrorId : CommandAlreadyAvailable,Validate-ModuleCommandAlreadyAvailable,Microsoft.PowerShell.Pack

ageManagement.Cmdlets.InstallPackage”

I don’t have a problem with the increased security, but my complaint is that whatever changes Microsoft has made, while great for security are breaking changes and has effectively rendered the Force parameter useless for the cmdlets shown in this blog article. When Force is specified, it means remove all safeties because I know what I’m doing and I don’t care if you have to burn my system to the ground if that’s what it takes to make it so. In other words, the Force parameter should override the need for the SkipPublisherCheck and/or the AllowClobber parameter in the scenarios shown in this blog article. I decided to perform a little more testing after noticing the line numbers in the error messages shown in this blog article were different depending on whether or not the command was run on Windows 10 version 1607 or 1703. I also decided to republish this blog article with different title to reflect the results of this further testing.

It appears what has happened to cause these differences, is that the PackageManagement and PowerShellGet modules have indeed been changed between Windows 10 versions and their module version numbers haven’t been updated which made tracking down the source of the differences a little more difficult.

Windows 10 version 1511:

Get-ChildItem -Path (Get-Module -Name PowerShellGet, PackageManagement -ListAvailable).ModuleBase 1 Get-ChildItem -Path ( Get-Module -Name PowerShellGet , PackageManagement -ListAvailable ) . ModuleBase

Windows 10 version 1607:

Windows 10 version 1703:

The file dates could be different and still be the same file, but the sizes are different which is a dead giveaway that something somewhere has changed.

µ

Share this: Twitter

Reddit

LinkedIn

Facebook

Pocket

Print

