OneNote Page Count Per Section

Keystrokes

Alt + F, P, R, C, Shift + Tab, Shift + Tab, P

Commands

  • File
  • Print
  • Print Preview
  • Page Range: Current Section
  • Print

The Page Range field contains the number of pages in the section.

For example, if the page range is 1-134, the number of pages in the section is 134.

Press Esc to close this window

Invoke-WebReqest/Invoke-RestMethod slower in PowerShell Core

Symptoms

Script using multiple Invoke-WebRequest or Invoke-RestMethod requests takes 3-4 times longer in Core (e.g. 7.4.5) than it did in Desktop, aka Windows PowerShell (e.g. 5.1)

Cause

In PS Core, if the parameters of subsequent requests change (e.g. header, URI, etc…), a new web session is created. In Windows PowerShell (Desktop edition, ver. 5.1) they used the same web session for each request. If you use many requests in a loop this can result in a significant degradation in performance. What took a few minutes in 5.1 could take 10-20 minutes in 7.

Solution

Create a WebRequestSession object and use the -WebSession parameter at the end of the line to force PS to use the same web session:

Snippet

$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
$response = Invoke-WebRequest -Uri https://www.example.com -WebSession $session

Any subsequent requests need to use the -WebSession

Sample

$max = 10
$start = Get-Date -Format "HH:mm:ss"
foreach ($i in 1..$max) {
    Invoke-RestMethod "https://postman-echo.com/get?i=$i"
}
$end = Get-Date -Format "HH:mm:ss"
write-host "started at" $start
write-host "  ended at" $end

If you run the above code in 5.1, it should take a few seconds but run in the same code in 7x and you’ll see it take 9-10 seconds. Each iteration creates a new web request session. To really see the performance hit, increase the $max value and try running in 7x.

Sample Fixed

$max = 10
$start = Get-Date -Format "HH:mm:ss"
$session = New-Object Microsoft.PowerShell.Commands.WebRequestSession
foreach ($i in 1..$max) {
    Invoke-RestMethod "https://postman-echo.com/get?i=$i" -WebSession $session
}
$end = Get-Date -Format "HH:mm:ss"
write-host "started at" $start
write-host "  ended at" $end

More Information

PS 6/7 are 4-5x slower than PS 5 due to not using web connection pool · Issue #12764 · PowerShell/PowerShell · GitHub

Reproducing the Replacement Character (U+FFFD) � in a Webpage from Scratch

  1. Open Notepad and type the following text into a new file:

Note the inverted exclamation mark ¡ in the <p></p> tags. You can insert this special character by holding down the Alt key and typing 0161 on the numeric keypad or by using the Character Map application included with Windows.

  1. From the File menu click Save. In the Save as type drop-down list select All files (*.*) and in the Encoding drop-down list select ANSI. Name the file charencoding.html and click Save.
  1. From File Explorer double click charencoding.html to open in the default browser.

Instead of ¡ displaying on the page, the Replacement Character (U+FFFD) is shown in its place.

Enlarged

This is because the file was saved with ANSI encoding in Notepad, but UTF-8 was declared as the charset in the HTML code, forcing the browser to render the webpage as UTF-8.

Fixes

  1. Open charencoding.html in Notepad. Change line 3 to:
<meta charset="Windows-1252">

Save file and reload webpage. It should now correctly render as ¡.

  1. Back in Notepad, change line 3 back to <meta charset=”UTF-8″> and save. Under the File menu select Save as, change the Save as type drop-down list to All files (*.*), select charencoding.html and change the Encoding drop-down list to UTF-8 and click the Save button. Click Yes to overwrite the existing file.

After reloading, the webpage will again correctly render the character as ¡.

Character Encoding Demo

1. Open Notepad

2. Hold down Alt key, on numeric keypad (Num Lock on) type 0174. This will insert the Registered Sign ® into Notepad. (If you don’t have a numpad type 00AE and type Alt+x, or use Character Map to copy/paste into Notepad)

3. From the File menu click Save. In the Save as type drop-down select All files (.) and in the File name box type registeredsign.csv, make sure the encoding is UTF-8 and click Save.

4. From Windows Explorer double-click on registeredsign.csv to open in Excel.

Assuming your file association for *.csv files is set to open with Excel, you should see this:

What’s this character before the Registered Sign? With the help of Character Map, it looks like U+00C2 – Latin Capital Letter A With Circumflex

To run Character Map, type it in the Windows Search box or open the Run window (Windows logo key + R) and type charmap

Why is this  character there? The simple answer is that Excel doesn’t know the file is UTF-8 and assumes it’s Windows (ANSI) encoding. However, if you open Excel first and then open the file registeredsign.csv using File/Open it will trigger the Text Import Wizard:

Make sure to set the file type filter to All Files (*.*) so that you see csv files in the File/Open dialog.

The File origin drop down should default to 65001: Unicode (UTF-8) and show the Registered Sign ® correctly in the preview and if you click Finish it will display properly in the worksheet. But before clicking Finish click on the File origin drop down and scroll all the way to the top of the list and select Windows (ANSI):

Notice that  character’s there before the registered sign:

Now click the file origin dropdown again and scroll all the way down and select 1252 : Western European (Windows):

 is still there. That’s because 1252 : Western European (Windows) is basically the same thing as Windows (ANSI). Scroll up a little bit and select 65001 : Unicode (UTF-8) and click Finish

This demonstration was to show you a simple encoding issue that can occur on a Windows PC and how to resolve it. Next, I’ll explain why this happened and how you can avoid this type of issue.

Root Cause

Here’s why that extra  character is there when opening in Excel through Explorer. UTF-8 is a variable byte encoding. 0-4 bytes depending on the range the character is in. In this case, it’s using two bytes to store the Registered Sign ® character. C2 for the first byte and AE for the second byte. Opening the file in a hex editor shows this:

Screenshot of file in WinHex: C2 is byte 0 and AE is byte 1

If I type C2 into Go to Unicode box in Character Map and hit Enter, it brings up Â

Since Excel assumes the file is ANSI (single byte) encoding, it treats each byte as a character. C2 for  and AE for ®.

The Wikipedia article for UTF-8 explains the extra byte well in the Encoding process section. The pound sign £, for example, uses C2 for the first byte and A3 for the second byte.

If the Registered Sign ® is encoded as ANSI instead of UTF-8, then it will only take one byte, AE. Therefore, if you saved the csv file in Notepad with ® using ANSI encoding and opened the csv file using Explorer it would open correctly in Excel without the  in front of it.

The registered sign ® character is in the extended ASCII range that allows you to save as both ANSI or Unicode (UTF-8) encoding.

Extended ASCII range 128-255 highlighted in red, registered sign ® highlighted in black

Only characters in the 0-255 range can be saved as both ANSI or UTF-8. For example, if you tried to save a character above this range as ANSI encoding, such as Ā (U+0100), using Notepad you’ll get a prompt:

Getting back to the Registered Sign ® in the UTF-8 file. The character in UTF-8 is encoded using two bytes (C2 AE) and ANSI encoding uses only one byte (AE).

The only thing I can’t explain here is why Excel assumes the csv file is ANSI when it is encoded as UTF-8 when opening it from Explorer. But there is a way to tell Excel the file is UTF-8 without going through the workaround of opening Excel first.

Solution

There is a definite way to tell Excel to open the file as UTF-8 and that’s to save the file as UTF-8 with BOM:

BOM is a three-byte marker (EF BB BF) at the beginning of the raw file that identifies the file as UTF-8. Saving a CSV file from Notepad as UTF-8 with BOM encoding is the equivalent of saving a CSV file from Excel as CSV UTF-8 (Comma delimited) (*.csv)

There’s one pitfall to this solution: If you intend on opening the CSV file in another application that doesn’t support opening files encoded as UTF-8 with BOM.

MS Edge History DB file

%LOCALAPPDATA%\Microsoft\Edge\User Data\Default

It’s stored in a file called History (no file extension)

The file’s locked by Edge so you need to copy it.

Copy the History file to another directory. For example C:\temp\edgehist.

Download and install DB Browser for SQLite and run it.

File > Open Database

Select the History file you just copied

Browse Data tab

Table: urls

PowerShell 7.2+ Color Coding in Get-ChildItem Output

I noticed in PowerShell Core (pwsh.exe), JavaScript file names are green

According to the online help for Format-Table:

PowerShell 7.2 introduced new features to colorize output. The colors can be managed using the $PSStyle automatic variable. The $PSStyle.Formatting.TableHeader property defines the color used for the header of the table displayed by Format-Table.

Output of $PSStyle automatic variable

Notice the FileInfo.Extension values aren’t color coding. To get them run $PSStyle.FileInfo

Apps & Features PowerShell Script

Link to Script

AppsAndFeatures.ps1

Download and Run

  1. Click on the link to download zip
  2. Extract zip file, right-click on AppsAndFeatures.ps1, click Properties, check Unblock, OK
  3. Launch PowerShell, navigate to the directory the script is in, type .\AppsAndFeatures.ps1 and press Enter

For more information see How to run a script.

Description

This script outputs the list of programs in Apps & features on Windows 10 and 11.

Screenshot of default output

Tagging

There’s a Type column that tags the program as either Modern (Metro/UWP) or Desktop (classic/Win32).

Filter by Modern or Desktop

.\AppsAndFeatures.ps1 | Where Type -eq "Modern" | Select Name,Publisher
Modern (metro) apps
.\AppsAndFeatures.ps1 | Where Type -eq "Desktop" | Select Name,Publisher
Desktop apps

Export to CSV

.\AppsAndFeatures.ps1 | Export-CSV AppsAndFeatures.csv -NoTypeInformation
Opened exported AppsAndFeatures.csv in Excel: AutoFit Columns and (CTRL+T) converted to Table with headers

Code Summary

Desktop

Pulls data from Uninstall reg keys using Get-ItemProperty piped to Where-Object filter

  • SystemComponent not 1
  • DisplayName not null
  • ReleaseType is null

Wrapped code inside function for code reuse and tagged as Desktop.

Modern

Uses the Get-AppxPackage and Get-AppxPackageManifest cmdlets from Appx module, decoding obfuscated display names (ms-resource) using Expand-IndirectString script found online. Some apps aren’t listed in Apps & features (e.g. HEIF Image Extensions on Windows 11) so I diff them with a blacklist for either Windows 10 or 11. Once you have the list of packages, loop through each package, get the package manifest. Packages containing more than one app use the package display name, packages with only one app use the app display name. Remove duplicates for those packages containing more than one app. Finally, add the publisher from the package manifest and tagged as Modern.

Package Filter

Get just the Main packages and filter out packages with no InstallLocation and System signatures.

$allpackages = Get-AppxPackage -PackageTypeFilter Main | 
Where-Object {($_.InstallLocation -ne $null) -and ($_.SignatureKind -ne "System")} | 
Select-Object -ExpandProperty Name

Blacklists

These are apps that show in above Get-AppxPackage command output but aren’t in Apps & features. So I need to remove them using Compare-Object (diff).

$whitelist = Compare-Object $allpackages $blacklist | 
Select-Object -ExpandProperty InputObject
$packages = $whitelist | 
ForEach-Object {Get-AppxPackage $_}
Windows 11

Microsoft.DesktopAppInstaller
Microsoft.HEIFImageExtension
Microsoft.StorePurchaseApp
Microsoft.VP9VideoExtensions
Microsoft.WebMediaExtensions
Microsoft.WebpImageExtension
Microsoft.XboxGameOverlay
Microsoft.XboxIdentityProvider
Microsoft.XboxSpeechToTextOverlay
MicrosoftWindows.Client.WebExperience
Microsoft.MicrosoftEdge.Stable
Microsoft.OneDriveSync

Windows 10

Microsoft.StorePurchaseApp
Microsoft.VP9VideoExtensions
Microsoft.Wallet
Microsoft.XboxGameOverlay
Microsoft.XboxIdentityProvider
Microsoft.XboxSpeechToTextOverlay
Microsoft.MicrosoftEdge.Stable

Loop Through Each Package

Package -> Manifest -> Package Properties/App Properties

foreach ($pkg in $packages) {
 $manifest = $pkg | Get-AppxPackageManifest
 $apps = $manifest.package.Applications.Application
 ...

Package or App display name?

If there’s more than one app in the package, use the package’s display name. Otherwise, use the app’s display name:

    if ($apps.Count -gt 1) {
        $DisplayName = $manifest.Package.Properties.DisplayName
    } else {
        $DisplayName = $manifest.Package.Applications.Application.VisualElements.DisplayName
    }

Convert Indirect Strings

Any DisplayName containing ms-resource: needs to be transposed to the proper Indirect String format Package name and resource ID “` syntax @{PackageFullName?resource} “` and converted using the Expand-IndirectString function:

if ($DisplayName -match "ms-resource:") {
        if (($DisplayName -notmatch "Resources/") -and ($DisplayName -notmatch "ms-resource://")) {
            $DisplayName = $DisplayName.Insert(12,"Resources/")
        }
        $DisplayName = Expand-IndirectString "@{$($pkg.PackageFullName)?$DisplayName}"
    }

To show an example of how this works, I’ll walkthrough a manual conversion using Microsoft.WindowsCalculator as an example:

1. Get the PackageFullName
(Get-AppxPackage Microsoft.WindowsCalculator).PackageFullName
Microsoft.WindowsCalculator_11.2205.9.0_x64__8wekyb3d8bbwe

2. Get the app DisplayName
(Get-AppxPackage Microsoft.WindowsCalculator | Get-AppxPackageManifest).Package.Applications.Application.VisualElements.DisplayName
ms-resource:AppName
*Since there's only one result (one app in the package) we'll use the app display name. If there was more than one result we'd get the package display name.
**If there's no Resources/ in the name and there's no // after ms-resource: then we need to inject Resources/ into the name, like this:
ms-resource:Resources/AppName

3. Transpose this to an indirect string using the syntax @{PackageFullName?resource}
@{Microsoft.WindowsCalculator_11.2205.9.0_x64__8wekyb3d8bbwe?ms-resource:Resources/AppName}

4. Pass this indirect string to Expand-IndirectString
.\Expand-IndirectString.ps1 "@{Microsoft.WindowsCalculator_11.2205.9.0_x64__8wekyb3d8bbwe?ms-resource:Resources/AppName}"
Calculator
*In this example I'm using Expand-IndirectString in its own separate script.
manual conversion of an indirect string

YouTube Freezes Transitioning to Next Video in Playlist

Problem started May 11, 2022. When YouTube switches to the next video in one of my playlists the webpage freezes for about 25-40 seconds. It doesn’t freeze the whole browser, just that tab. YouTube tab process spikes in Task Manager. It happens in both MS Edge and Google Chrome on multiple machines running Windows 10 and 11. Tried hard refreshing page (CTRL+F5); cleared browser cache; tested on another machine; disabled shuffle, nothing worked. The only workaround I’ve found is to hide the playlist pane on the right.

Playlist pane highlighted in red
Click on the carat, circled in red, to hide the playlist pane
Playlist pane is now hidden

As soon as I un-hid the playlist pane the problem came back. Re-hide it goes away.