Quick tip: What new products and classifications have been added in the past 30 days to WSUS?

Two days ago a PM.org list member asked the following question:

When you see the notice “X new products and Y new classifications have been added in the past 30 days”, how do you know which ones are new when you click on the link.

The only answer was a piece of PowerShell code 😀 that another list member pointed (here)

# Get new classifications
(Get-WsusServer).GetUpdateClassifications(
 "$((Get-Date).AddDays(-31))",
 "$(Get-Date)"
) | Select Title,Description, Releasenotes, arrivaldate

# Get what new products were added over the month
(Get-WsusServer).GetUpdateCategories(
 "$((Get-Date).AddDays(-31))",
 "$(Get-Date)"
) |  
Select Title,Id,arrivaldate | 
ft -AutoSize

Enjoy!

Advertisements

About updating inbox PowerShell modules

I’ve started testing Windows 10 1803 branch and got surprised by a few things.

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

I wanted to get the latest version of Pester and naïvely ran:

Update-Module -Name Pester -Verbose

Ok, I hardly remember other MVPs talking about this problem…
To fix it ASAP, I did:

# Step 1: Save locally
Find-Module -Name Pester -Repository PSGallery -Verbose | 
Save-Module -Path  ~/Downloads -Verbose

# Step 2: remove alternate stream if any
dir ~/Downloads/Pester/* -rec -for -ea 0 | 
Unblock-File -Verbose

# Step 3: move to Programfiles
gi ~/Downloads/Pester/* | 
Copy-Item -Destination "C:\Program Files\WindowsPowerShell\Modules\Pester" -Recurse

NB: I moved it to programfiles because the Get-Module uses the PSModulePath environment variable to find and enumerate available modules. Keep that in mind. I’ll come back later on this.

The above longer way will actually prevent you from hitting a second road block if you try to take a shortcut.
Note that it’s also a best practice to review downloaded code before installing and trusting it.

Second issue:
PackageManagement\Install-Package : The version ‘4.3.1’ of the module ‘Pester’ being installed is not catalog signed.
Ensure that the version ‘4.3.1’ 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.3.1’ 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

Updating the module doesn’t work because it’s not installed from the PSGallery and is instead shipped inbox.
Let’s install it using Install-Module and not Update-Module. Right?

Find-Module -Name Pester -Repository PSGallery -Verbose | 
Install-Module -Verbose


Notice the above warning about the untrusted source.

Ok, don’t give up or be irritated, the solution and the shortcut is in the red error message 😛

Install-Module -Name Pester -Repository PSGallery -SkipPublisherCheck

One last step, you’re almost there. This time the fix is in the warning stream. You need a -Force.

Install-Module -Name Pester -SkipPublisherCheck -Force -Repository PSGallery 

With the 2nd issue illustrated, you probably understand why I go my way (using the 3 steps shown in issue #1 above)

Third issue: The installed module doesn’t show up!

No matter what I do, the installed module isn’t discovered by the Get-Module cmdlet although it’s located in one of the locations stored in the $env:PSModulePath variable:

Get-Module -Name Pester -ListAvailable
Get-Module -Name Pester -ListAvailable -Refresh
$env:PSModulePath -split ';'

The PowerShell prompt is elevated and running in constrained mode.

$ExecutionContext.SessionState.LanguageMode


Applocker Allow mode (no default rules!) is preventing the new module from being discovered.
Why?
Because of the digital signature. The 3.4.0 is signed by Microsoft and the 4.3.1 isn’t signed at all

Get-AuthenticodeSignature 'C:\Program Files\WindowsPowerShell\Modules\Pester\*\*.ps?1'

How to fix this?
If you can, the best solution is to use an internal PKI and/or a code signing certificate to sign the 4.3.1 files. Then you just add a single Applocker rule to trust that Publisher.
There’s a second solution.

Fourth issue: an Applocker cmdlet shortcoming…
When you use the -Directory parameter, it doesn’t pick .psd1 and .psm1 files 😦

Get-AppLockerFileInformation -Directory 'C:\Program Files\WindowsPowerShell\Modules\Pester\4.3.1' -Recurse -FileType Script


You can for sure use the Get-AppLockerFileInformation cmdlet on PSD1 and PSM1 files

# Check psd1 and psm1 files
Get-AppLockerFileInformation 'C:\Program Files\WindowsPowerShell\Modules\Pester\4.3.1\*.ps?1'

# Try to create a policy
Get-AppLockerFileInformation 'C:\Program Files\WindowsPowerShell\Modules\Pester\4.3.1\*.ps?1' |
New-AppLockerPolicy -User EveryOne


You can pipe the two cmdlets Get-AppLockerFileInformation and New-AppLockerPolicy but it creates an empty Applocker policy object 😦

Here’s my solution:

# Copy psd1 & psm1 files as ps1 files
dir 'C:\Program Files\WINDOWSPOWERSHELL\MODULES\PESTER\4.3.1\*.ps?1' -Recurse -Force | 
Foreach-Object { 
 $_ | Copy-Item -Destination "$($_.FullName).ps1"  
}

# Create a local policy using these 2 files
Get-AppLockerFileInformation -Directory 'C:\Program Files\WindowsPowerShell\Modules\Pester\4.3.1' -Recurse -FileType Script | 
New-AppLockerPolicy -User EveryOne -RuleNamePrefix 'Allow Pester 4.3.1' | 
Set-AppLockerPolicy -Merge -Verbose

Last but not least. Refresh the group policies.

Now, Pester 4.3.1 can be imported and used even in ConstrainedLanguage mode 😎