Wednesday, June 7, 2023

PowerShell: Installing the latest version of Pester

Before installing the latest version of Pester, uninstall the legacy version of Pester (Pester 3.x) which is installed with most modern versions of Windows (see PowerShell: Uninstalling Pester 3.0). On a machine with PowerShell 5.0 or later install, the latest version of Pester can be installed as follows without running as administrator:

Install-Module -Name Pester

Once install verify that version of Pester is the most recent:

(Get-Module -ListAvailable Pester).Version

An example of installing Pester is as follows (not that a user is prompted to accept the modules being installed):

E:\Users\Jann\PowerShellRepos> Install-Module -Name Pester

Untrusted repository

You are installing the modules from an untrusted repository. If you trust this repository, change its InstallationPolicy value by running the Set-PSRepository

cmdlet. Are you sure you want to install the modules from 'PSGallery'?

[Y] Yes  [A] Yes to All  [N] No  [L] No to All  [S] Suspend  [?] Help (default is "N"): A

Tuesday, June 6, 2023

PowerShell: Uninstalling Pester 3.0

Microsoft by default installs an obsolete version of Pester on Windows (Pester 3.x). For example on one of my machines (Windows 11) the version of Pester installed is 3.4.0 (2016 Pester). In fact, Pester 3.4.0 is installed for x64 and x86 (32-bit) versions of PowerShell. To uninstall Pester 3.4.0 means that the x64 and x86 installs have to be uninstalled.

Detecting the Available Versions of Pester Installed

The following PowerShell displays available versions of Pester installed:

(Get-Module -ListAvailable Pester).Version

The default version of Pester installed on my Windows 11 host is as follows:

Uninstalling Pester 3.x

The problem with Pester 3.x is that it installed as part the O.S. and it cannot be uninstalled with Uninstall-Module (this won't work: Uninstall-Module -Name Pester). The following script will understand all 3.x versions of Pester on a machine:

#Requires -RunAsAdministrator

function Uninstall-PesterInstance {
        [string] $pesterFolderPath

    takeown /F $pesterFolderPath /A /R
    icacls $pesterFolderPath /reset
    # Grant permissions to group, Administrators, via SID.
    # This handles localiztion on non-U.S. Windows installations
    icacls $pesterFolderPath /grant "*S-1-5-32-544:F" /inheritance:d /T
    Remove-Item -Path $pesterFolderPath -Recurse -Force -Confirm:$false    

[string] $bitness32ProgramFiles = ${env:ProgramFiles(x86)}
[string] $bitness64ProgramFiles = $env:ProgramFiles
[string[]] $programFilePaths = $bitness32ProgramFiles, $bitness64ProgramFiles

foreach ($programFilePath in $programFilePaths) {
    [string] $pester3xFolderPath = "$programFilePath\WindowsPowerShell\Modules\Pester"

    if (Test-Path -Path $pester3xFolderPath -PathType Container) {        
        [System.IO.DirectoryInfo[]] $pesterDirectories =
           Get-ChildItem -Path $pester3xFolderPath -Filter '3.*'

        foreach ($pesterDirectory in $pesterDirectories) {
            Uninstall-PesterInstance $pesterDirectory.FullName

The first line of the above script uses "#Requires -RunAsAdministrator" to mandate the script runs with administrator credentials. Pester 3.x is installed for Windows and can only be uninstalled by an administrator (see PowerShell: Requiring a Script to Run as Administrator).

The code above is broken into a loop the iterate through all Pester 3.x version found in program files targeting x86 and x64 bit PowerShell:

For each instance of Pester 3.x install the Uninstall-PesterIntance method is invoked to physically delete the Pester 3.x folders recursively:

Monday, June 5, 2023

PowerShell: Requiring a Script to Run as Administrator

Placing the following at the top of a PowerShell script requires that said script to run as administrator:

#Requires -RunAsAdministrator

For example, Pester 3.x is installed with modern versions of Windows and only an administrator can uninstall this O.S. integrated version of Pester hence "#Requires -RunAsAdministrator" comes in handy.

The #Requires statement is documented by Microsoft at about_Requires and the comprehensive overview of #Requires provided by Microsoft's documentation is as follows: