• Major Update for PowerShell Extensions

    If you have tried VS Code in the past but were disappointed because of speed and stability, you may want to have a second look now. On May 3, Sydney Smith from the PowerShell team has announced a major overhaul and rewrite of the PowerShell extensions.

    Specifically, the core pipeline execution has been reinvented, and editor services such as IntelliSense and suggestions now run in a separate synchronous thread for more…

  • Careful with Arrays

    With PowerShell you never know whether a cmdlet returns an array or a single object. That’s because PowerShell automatically wraps results in an array once a command returns more than one item:

    # no array:
    $test = Get-Service -Name Spooler
    $test -is [Array]
    # array:
    $test = Get-Service -Name S*
    $test -is [Array]

    It’s critical to understand this because it means that runtime conditions can determine the nature…

  • Identifying Multi-Language Online Documents (Part 2)

    How can you automatically check the supported languages for an online document?

    Provided the URL uses a language ID, it’s easy to create a list of URLs with all available language IDs. This is what we have done in part 1 so far:

    $list = RL -f

    In this second part we now identify the URLs in the list that actually exist. Just trying to contact the URL via Invoke-WebRequest isn’t sufficient, though:

    $list =
  • Identifying Multi-Language Online Documents (Part 1)

    In the previous tip we pointed you to the official PowerShell Language Definition which is available online in many different languages. Which raises the question about the supported languages.

    Typically, multi-language online documents use the same URL and just change the language ID. For example, the English and the German edition just differ in their language ID:


  • Worth a Read: PowerShell Language Definition

    Today I like to point you to the official Microsoft PowerShell Language Definition. As a seasoned PowerShell scripter, you can gain a lot of inside knowledge by looking at the formal definition of the PowerShell language itself.

    The language definition explains a zillion of practically relevant details such as a comprehensive list of predefined variables, built-in keywords, operator precedence, and so much more. You can…

  • Resolving URLs

    URLs aren’t always (directly) pointing to a resource. Often, URL act as shortcuts or static addresses that always point to latest versions. PowerShell can reveal the true URL of a resource, and you can use this for a number of cases.

    Here’s an example how to resolve a shortcut link:

    # this is the URL we got:
    $URLRaw = 'http://go.microsoft.com/fwlink/?LinkID=135173'
    # we do not allow automatic redirection…
  • Simple Text-Based Filtering a la grep (Part 1)

    PowerShell is object-oriented so there’s not much text filtering and regex magic required compared to Linux and grep. Yet occasionally, it would be efficient and comfortable to filter command object by simple text patterns.

    And it works -kinda. PowerShell does come with a grep-like command, the cmdlet Select-String. While it excels at filtering file content, it isn’t useful at first when trying to filter command…

  • Reading Windows 10 Product Key

    There are plenty of scripts available that promise to read the original Windows 10 product key from the registry by converting a series of binary values.

    Unfortunately, most of the algorithms found in these scripts are deprecated, and the calculated product key is wrong. If you planned to reinstall the operating system, you may find out only after you erased your original installation.

    A better and simpler way may be…

  • Creating sudo for PowerShell (Part 2)

    In our effort to create a sudo command for PowerShell – to elevate individual commands – in part 1 we created the sudo function body:

    function sudo 

    Now let’s replace $PSBoundParameters with the actual…

  • Creating sudo for PowerShell (Part 1)

    In Linux shells, there’s a command called “sudo” that lets you run a command with elevated privileges. In PowerShell, you’d have to open a completely new shell with elevated privileges.

    Let’s try and add a sudo command to PowerShell. We want a new command called ‘sudo’, and it should require at least a command name, but then also a variable number of white-space separated arguments. Here is how…

  • Code-Signing PowerShell Scripts (Part 3)

    In the previous parts, we created a code signing certificate and used it to add a digital signature to a PowerShell script file. Yet what good can a digital signature do that was added to a PowerShell script file?

    Use Get-AuthenticodeSignature to reveal the secrets found in the digital signature. Just make sure you adjust $Path to point to a file with a digital signature:

    # path to a digitally signed file (adjust path…
  • Code-Signing PowerShell Scripts (Part 2)

    In our previous tip we explained how you can use New-SelfSignedCert to create a self-signed code signing certificate. Today, we’ll use a self-signed or corporate code signing certificate to actually start and digitally sign a Powershell script.

    For this, take any PowerShell script file you want. All you need is its path. Also, you need the path to a valid code signing certificate stored in any of Windows certificate…

  • Code-Signing PowerShell Scripts (Part 1)

    Adding a digital signature to a PowerShell script is no black magic anymore these days, and while you ideally need an official “trusted” code signing certificate from your corporate IT or trusted authority, even this is not mandatory anymore these days.

    Before we proceed with code signing, why would you want to code sign a PowerShell script in the first place?

    A digital signature is a hash of your script code…

  • Professional Error Handling

    Often PowerShell scripts use a very simple form of error reporting that is structured like this:

    # clearing global error list:
    # hiding errors:
    $ErrorActionPreference = 'SilentlyContinue'
    # do stuff:
    Stop-Service -Name Spooler
    dir c:\gibtsnichtabc
    # check errors at end:
    $error | Out-GridView

    While there is nothing wrong with this, you should understand that $error is a global variable…

  • Cleaning Hard Drive (Part 2)

    In the previous post we introduced the Windows tool cleanmgr and its parameters /sageset and /sagerun that you can use to define and run automated hard disk cleanups.

    Today we’ll be looking into how you can customize the actual cleanup tasks performed by cleanmgr.exe.

    This tool stores all configuration in the Windows Registry at this location: HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer…

  • Cleaning Hard Drive (Part 1)

    Part of Windows is an ancient tool that can clean your hard drive: cleanmgr.exe.

    This tool can remove a variety of data garbage and at times removes many gigabytes of space. What makes it interesting for PowerShell is its support for automation.

    To automate hard drive cleanup, first you need to launch PowerShell with Admin privileges (without them, no error is raised but your cleanup choices won’t be saved correctly)…

  • Managing Bluetooth Devices (Part 3)

    If you’d like to programmatically unpair a paired Bluetooth device, then there is no built-in cmdlet available. Still PowerShell can do the trick, and it often can even unpair Bluetooth devices that won’t remove via the UI or keeps coming back.

    What you need first to remove a Bluetooth device is its hardware address. Here is an example on how to list all Bluetooth devices and return their hardware address…

  • Managing Bluetooth Devices (Part 2)

    If you’re just looking for a quick way in Windows to pair and unpair Bluetooth devices, try this command:

    PS> explorer.exe ms-settings-connectabledevices:devicediscovery   

    It immediately pops up a dialog showing all Bluetooth devices. Just add a function to PowerShell so you don’t have to remember the command, and place it in your profile script:

    PS> function Show-Bluetooth { explorer.exe ms-settings…
  • Managing Bluetooth Devices (Part 1)

    Identifying Bluetooth devices that your computer has connected to is as easy as a one-liner:

    PS> Get-PnpDevice -Class Bluetooth 
    Status Class     FriendlyName                           InstanceId             
    ------ -----     ------------                           ----------             
    OK     Bluetooth Bose QC35 II Avrcp Transport           BTHENUM\{0000110C-00...
    OK     Bluetooth Generic Attribute Profile      …
  • PowerShell Plans for 2022

    The Microsoft PowerShell Team has just released its plans and investments for the year 2022: https://devblogs.microsoft.com/powershell/powershell-and-openssh-team-investments-for-2022/

    In short, these investments circle around even more security. In addition, custom remoting connections may become an interesting addition: code you write to access remote systems can then be used by other cmdlets, essentially opening up…

  • Leveraging WMI (Part 5)

    WMI classes are organized in so-called namespaces that start at “root” and work like a directory structure. The default namespace is root\cimv2, and when you do not specify a namespace, you can only see the WMI classes located in the default namespace. This is what we have been using in the past parts of this series.

    There are many more namespaces with many additional WMI classes, some of which can be highly…

  • Leveraging WMI (Part 4)

    The secret to successfully leveraging WMI is knowing the class names that represent what you are after. In the previous tip we explained how to use IntelliSense to ask Get-CimInstance for available class names. You can do the same programmatically, too, though. Below is code that dumps all valid WMI class names for the default namespace root\cimv2:

    Get-CimClass | Select-Object -ExpandProperty CimClassName | Sort-Obje…
  • Leveraging WMI (Part 3)

    The new Get-CimInstance cmdlet lets you query WMI locally, and there is (limited) support for remote queries: you can specify the -ComputerName parameter, but you cannot use alternative credentials.

    That’s because Get-CimInstance uses separate network sessions for remote access which provide you with many more options. For example, once you establish a network session, you can use it for multiple queries. Here is how…

  • Leveraging WMI (Part 2)

    When you query WMI classes, you may not get back all information at first:

    PS> Get-CimInstance -ClassName Win32_LogicalDisk
    DeviceID DriveType ProviderName   VolumeName Size          FreeSpace   
    -------- --------- ------------   ---------- ----          ---------   
    C:       3                        OS         1007210721280 227106992128
    Z:       4         \\\c$ OS         1007210721280 227106988032

  • Leveraging WMI (Part 1)

    WMI is a Windows technology to query computer details. If you are still using the deprecated Get-WmiObject cmdlet, you should rethink:

    PS> Get-WmiObject -Class Win32_BIOS
    SMBIOSBIOSVersion : 1.9.1
    Manufacturer      : Dell Inc.
    Name              : 1.9.1
    SerialNumber      : 4ZKM0Z2
    Version           : DELL   - 20170001  

    Switch to the new Get-CimInstance cmdlet which works very similar:

    PS> Get-CimInstance -ClassName…