Tuesday, July 4, 2023

Docker/Windows: Installation Requirement "BIOS-level Hardware Virtualization"

Installing/running Docker on Windows requires that WSL be installed (see Install Docker Desktop on Windows). According the aforementioned write up, WSL has the following hardware requirements:


While running Windows it is possible to check if hardware virtualization is enabled at the BIOS level. To check if this is enabled, launch Task Manager (Ctrl-Alt-Delete) and from Task Manager select the Performance blade:


Notice in the lower right corner there is a box high added to the screenshot showing Virtualization Enabled.

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 {
    param(
        [Parameter(mandatory=$true)]
        [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:






Sunday, May 28, 2023

PowerShell: StringBuild AppendLine lessons from C

Two years ago I wrote a post, PowerShell: Inadvertently Returning Multiple Values from a Function and low and behold I found a found a common C# data type that is a common culprit of this issue, StringBuilder. I have coded C# for twenty-tree years and I did not realize the each Append* method of StringBuilder returns a reference to the StringBuilder.

To demonstrate consider this C# snippet:

var builder = new StringBuilder();

builder.AppendLine("Environment Properties:");
builder.AppendLine($"MachineName: {Environment.MachineName}");
builder.AppendLine($"UserName: {Environment.UserName}");
builder.AppendLine($"UserDomainName: {Environment.UserDomainName}");
builder.AppendLine($"OSVersion: {Environment.OSVersion}");
builder.AppendLine($"ProcessorCount: {Environment.ProcessorCount}");
builder.AppendLine(
  $"Is64BitOperatingSystem: {Environment.Is64BitOperatingSystem}");
builder.AppendLine(
  $"SystemDirectory: {Environment.SystemDirectory}");
builder.AppendLine($"CurrentDirectory: {Environment.CurrentDirectory}");

Console.Write(builder.ToString());

In the documentation for the AppendLine method, AppendLine(String), the return value of AppendLine and each Append* method of StringBuilder is defined as follows:


A clearer way to write the above code in C# would be acknowledge the return value and to ignore it:

var builder = new StringBuilder();

_ = builder.AppendLine("Environment Properties:");
_ = builder.AppendLine($"MachineName: {Environment.MachineName}");
_ = builder.AppendLine($"UserName: {Environment.UserName}");
_ = builder.AppendLine(
      $"UserDomainName: {Environment.UserDomainName}");
_ = builder.AppendLine($"OSVersion: {Environment.OSVersion}");
_ = builder.AppendLine(
      $"ProcessorCount: {Environment.ProcessorCount}");
_ = builder.AppendLine(
      $"Is64BitOperatingSystem: {Environment.Is64BitOperatingSystem}");
_ = builder.AppendLine(
      $"SystemDirectory: {Environment.SystemDirectory}");
_ = builder.AppendLine($"CurrentDirectory: {Environment.CurrentDirectory}");

Console.Write(builder.ToString());

The following code shows PowerShell invoking AppendLine multiple times:

function Get-EnvironmentProperties {
    [System.Text.StringBuilder] $builder = [System.Text.StringBuilder]::new()

    $builder.AppendLine("Environment Properties:")
    $builder.AppendLine("MachineName: " + [Environment]::MachineName)
    $builder.AppendLine("UserName: " + [Environment]::UserName)
    $builder.AppendLine("UserDomainName: " + [Environment]::UserDomainName)
    $builder.AppendLine("OSVersion: " + [Environment]::OSVersion)
    $builder.AppendLine("ProcessorCount: " + [Environment]::ProcessorCount)
    $builder.AppendLine("Is64BitOperatingSystem: " + [Environment]::Is64BitOperatingSystem)
    $builder.AppendLine("SystemDirectory: " + [Environment]::SystemDirectory)
    $builder.AppendLine("CurrentDirectory: " + [Environment]::CurrentDirectory)

    return $builder.ToString()
}

$result = Get-EnvironmentProperties

Although it appears that the PowerShell function, Get-EnvironmentProperties, returns a string. Result (the return value from Get-EnvironmentProperties) in an array of 10 elements:


The method AppendLine is invoked nine times so the first nine elements of the array. The tenth element of the array (index of 9) is the string return in the last line of function, Get-EnvironmentProperties.


Below show a variant of the EnvironmentProperties function suppresses the return value from StringBuilder's AppendLine:

function Get-EnvironmentProperties {
    [System.Text.StringBuilder] $builder = `
          [System.Text.StringBuilder]::new()

    $builder.AppendLine("Environment Properties:") | Out-Null
    [void]$builder.AppendLine("MachineName: " + 
              [Environment]::MachineName)
    $builder.AppendLine("UserName: " + 
              [Environment]::UserName) > $null
    $null = $builder.AppendLine("UserDomainName: " + 
              [Environment]::UserDomainName)

    return $builder.ToString()
}

Suppressing the StringBuilder returned by AppendLine results in the the correct behavior, the lone return value is as string as is show below:


A variety of mechanism were show to suppress return value of AppendLine. From the performance stand point, Out-Null is the slowest but from a readability stand point, it is the most readable for all levels of PowerShell developer.

In my code I used the following approach as I learned C as my first programming language:

    [void]$builder.AppendLine("MachineName: " + 
              [Environment]::MachineName)

With regard to performance and suppressing the result of a method/expression StackOverflow has an excellent post on the topic What's the better (cleaner) way to ignore output in PowerShell? A response by JasonMArcher demonstrates and Out-Null has the worst performance.



Monday, May 8, 2023

Visual Studio Code: Disable Format on Save per-File (including wildcards)

In this post, we'll explore how to disable the formatOnSave option for specific files, multiple files, using wild cards, and files with certain extensions.


Disabling formatOnSave for a specific file

To disable formatOnSave for a specific file, you can add the following setting to your settings.json file:

"[file path/filename.ext]": {
    "editor.formatOnSave": false
}

Replace file path/filename.ext (noted in boldface) with the path and filename of the file for which you want to disable formatOnSave.


Disabling formatOnSave for multiple files

To disable formatOnSave for multiple files, you can add the following setting to your settings.json file:

"editor.formatOnSave": true,
"[file path/filename1.ext]": {
    "editor.formatOnSave": false
},
"[file path/filename2.ext]": {
    "editor.formatOnSave": false
}

Replace file path/filename1.ext and file path/filename2.ext  (noted in boldface) with the path and filenames of the files for which you want to disable formatOnSave.


Disabling formatOnSave using wildcards

You can also disable formatOnSave for files that match a specific pattern using wildcards. For example, to disable formatOnSave for files that have a specific prefix, you can add the following setting to your settings.json file:

"editor.formatOnSave": true,
"[prefix]*.ext": {
    "editor.formatOnSave": false
}

Replace prefix  (noted in boldface) with the desired prefix for the files you want to exclude from formatOnSave.

Similarly, to disable formatOnSave for files that have multiple possible extensions, you can use a wildcard to match the extensions. For example:

"editor.formatOnSave": true,
"[file path/*.ext1, *.ext2]": {
    "editor.formatOnSave": false
}

Replace file path with the path to the directory containing the files you want to exclude from formatOnSave. Replace ext1 and ext2 with the extensions of the files you want to exclude from formatOnSave.

Conclusion

And that's it! With these settings, you can easily disable the formatOnSave option for specific files, multiple files, or using wildcards.

Sunday, May 7, 2023

Visual Studio Code: Disable Format on Save (settings.json: formatOnSave=true) per-File-Extension

I worked with two good engineers who loved auto format code (PowerShell) using Visual Studio Code's settings.json attribute. So I asked ChatGPT how to ignore the formatOnSave feature (trying out ChatGPT). Here is how to ignore Visual Studio Code's formatOnSave for a specific file extension. The steps to achieve presented.

If you want to exclude specific file types from being formatted on save, you need to configure Visual Studio Code to ignore those file extensions.

Step 1: Open the User Settings in VS Code

To configure the Format on Save feature, you need to edit the user settings in VS Code. To do this, open the Command Palette by pressing Ctrl+Shift+P (Windows) or Command+Shift+P (macOS), and type "Open User Settings". You should see "Preferences: Open User Settings" in the list of suggestions. Select it, and the settings.json file will open.

Step 2: Add the File Extensions to Ignore

In the settings.json file, you need to add the file extensions you want to exclude from the Format on Save feature. To do this, add the following code snippet:

"editor.formatOnSave": true,
"[md]": {
    "editor.formatOnSave": false
}

The code in boldface was added to the standard settings.json to ignore Markdown files. In this example, we're telling VS Code to enable the Format on Save feature globally ("editor.formatOnSave": true) and then disabling it for Markdown files ("[md]": {"editor.formatOnSave": false}).

Step 3: Save the User Settings

Once you've added the code snippet to the settings.json file, save the file, and you're done. The Format on Save feature will now be disabled for the file extension specified (the markdown extension, md).

Conclusion

In this blog post, we've seen how to configure Visual Studio Code to ignore specific file extensions when using the Format on Save feature. This can be useful if you want to exclude certain files from being automatically formatted when you save them. With just a few simple steps, you can customize this feature to suit your coding needs. 

Acknowledgments

I'd like to thank my high school typing teacher, Miss Joyce. I took one year of secretarial typing (on an IBM Selectric) and I type 120 WPM. I would like to think my mother for giving me the ability to write which I inherited from her. I would like that thank ChatGPT which wrote most of this blog. This is an experiment but ChatGPT is scary useful.