• Identifying Windows Type

    WMI returns a cryptic code number of every distinct Windows SKU:

    PS> Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -ExpandProperty OperatingSystemSKU

    To translate this number into a meaningful text, for example for reporting purposes, try this:

    $OperatingSystemSKU = @{
      Name = 'OperatingSystemSKUText'
      Expression = {
        $value = $_.OperatingSystemSKU
    • 3 Jul 2020
  • Boot and Install Time for Operating System

    The WMI class Win32_OperatingSystem provides rich information about a number of datetime information, including the date of last boot-up and the installation time:

    $dateTimeProps = 'InstallDate', 'LastBootupTime', 'LocalDateTime', 'CurrentTimeZone', 'CountryCode'
    Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property $dateTimeProps

    The result looks similar…

    • 1 Jul 2020
  • Changing Operating System Description

    Each Windows operating system has a description, and you can view (and change) this description with the following command:

    PS> control sysdm.cpl

    To do the same in an automated way via PowerShell, use this:

    # change operating system description
    # (requires admin privileges)
    $values = @{
        Description = 'My Computer'
    Set-CimInstance -Query 'Select * from Win32_OperatingSystem' -Property $val…
    • 29 Jun 2020
  • Showing Object Data as Table in a Grid View Window

    Typically, when you output a single object to Out-GridView, you get one line, and every property surfaces as a column:

    Get-ComputerInfo | Select-Object -Property * | Out-GridView

    This makes it hard to view and filter for specific information. Simply convert an object to an ordered hash table to show it as a table inside a grid view window. As a side effect, you can now also eliminate empty properties and make sure properties…

    • 25 Jun 2020
  • Removing Empty Properties

    WMI and Get-CimInstance can provide you with a lot of useful information but the returned objects often contain a number of empty properties:

    PS> Get-CimInstance -ClassName Win32_OperatingSystem | Select-Object -Property 

    Also, properties aren’t necessarily sorted. You can fix both by identifying and sorting the properties that are not empty:

    # get all WMI information
    $os = Get-CimInstance -ClassName Wi…
    • 23 Jun 2020
  • Using Assertions

    Often, your code needs to assert certain prerequisites. For example, you may want to ensure that a given folder exists, and use code like this:

    # path to download files to
    $OutPath = "$env:temp\SampleData"
    # does it already exist?
    $exists = Test-Path -Path $OutPath -PathType Container
    # no, create it
    if (!$exists)
      $null = New-Item -Path $OutPath -ItemType Directory

    Instead of coding this over and over…

    • 19 Jun 2020
  • Wake On LAN

    There is no need for external “Wake On LAN” tools. If you want to wake up a network machine, simply tell PowerShell the MAC address of the target machine. Here is a function that composes the magic packet and wakes the machine(s):

    function Invoke-WakeOnLan
        # one or more MAC addresses
        # MAC address must be a following…
    • 17 Jun 2020
  • Converting Hex Numbers

    PowerShell can interactively convert hexadecimal numbers when you prefix “0x”:

    PS> 0xAB0f

    If the hex number is stored in a string, you can invoke the conversion by applying a type to the expression:

    PS> $a = 'ab0f'
    PS> [int]"0x$a"

    Twitter This Tip! ReTweet this Tip!

    • 15 Jun 2020
  • Auto-Learning Argument Completion

    Argument completion is awesome for a user because valid arguments are always suggested. Many built-in PowerShell commands come with argument completion. You can see this in action when you enter:

    PS> Get-EventLog -LogName  

    Enter a space after -LogName to trigger automatic argument completion in the PowerShell ISE editor. In the PowerShell console, press TAB. And in Visual Studio Code, press CTRL+SPACE. Get-EventLog…

    • 11 Jun 2020
  • Adding Argument Completion (Part 2)

    In the previous tip we talked about the new [ArgumentCompletions()] attribute that was added to PowerShell 7, and how you can use it to add sophisticated argument completion to your function parameters.

    Unfortunately, this attribute isn’t available in Windows PowerShell, so by using it, your code is no longer compatible with Windows PowerShell.

    Unless you add the attribute to Windows PowerShell, of course. When…

    • 9 Jun 2020
  • Adding Argument Completion (Part 1)

    Adding argument completion to your PowerShell function parameters can improve the usability of your functions tremendously. A common approach is adding the [ValidateSet()] attribute to your parameter:

    function Get-Country
        # suggest country names
      # return parameter

    When a user…

    • 5 Jun 2020
  • Decoding Windows Product Key (Part 2)

    In the previous tip we explained how you can ask WMI for a partial Windows product key. If you have lost your original product key, here is a way to restore the full key:

    function Get-WindowsProductKey
      # test whether this is Windows 7 or older
      function Test-Win7
        $OSVersion = [System.Environment]::OSVersion.Version
        ($OSVersion.Major -eq 6 -and $OSVersion.Minor -lt 2) -or
        $OSVersion.Major -le 6
    • 3 Jun 2020
  • Decoding Windows Product Key (Part 1)

    There are a lot of script examples out there and even key recovery tools that promise to return the full product key, but in many cases, the returned key is not your windows product key.

    When you resort to key recovery tools, you typically lost your product key, so there is no easy way for you to check whether the promised key returned by key recovery scripts or tools is correct or not.

    Fortunately, WMI can at least return…

    • 1 Jun 2020
  • Reading Operating System Details

    PowerShell can easily retrieve important operating system details such as the build number and version by reading the appropriate registry values:

    # read operating system info
    Get-ItemProperty -Path 'Registry::HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion' |
    # pick selected properties
    Select-Object -Property CurrentBuild,CurrentVersion,ProductId, ReleaseID, UBR

    Some of these values use crypting…

    • 28 May 2020
  • Prompting for Credentials in Console

    When you run Get-Credential or are otherwise prompted for a username and password, Windows PowerShell (powershell.exe) always opens a separate credentials dialog. The new PowerShell 7 (pwsh.exe) prompts inside the console:

    PS> Get-Credential 
    PowerShell credential request
    Enter your credentials.
    User: Tobias
    Password for user Tobias: ******
    UserName                     Password
    --------                     -----…
    • 26 May 2020
  • Searching PowerShell Gallery for New Modules

    The official PowerShell Gallery is a public repository with thousands of free PowerShell modules. Instead of reinventing the wheel, it makes total sense to browse the gallery for reusable code that you can use as-is or as a starting point for your own projects. Let’s take a look at how you can discover and download PowerShell code from the PowerShell Gallery.

    You can use its graphical frontend at https://powershellgallery…

    • 22 May 2020
  • Managing SharePoint Online

    If you use SharePoint Online and would like to manage it via PowerShell, download and install the Microsoft.Online.SharePoint.PowerShell module from the PowerShell Gallery:

    # search for the module in PowerShell Gallery (optional)
    PS> Find-Module -Name Microsoft.Online.SharePoint.PowerShell
    Version              Name                                Repository           Description 
    -------              ----          …
    • 20 May 2020
  • Identifying Compromised Passwords (Part 2)

    When you want to submit sensitive information to a PowerShell function, you typically use the SecureString type. This type makes sure a user gets prompted with a masked dialog box, and the input is protected from anyone “looking over the shoulder”.

    Since SecureString can always be decrypted to plain text by the person who created the SecureString, you can take advantage of masked input boxes but still work…

    • 18 May 2020
  • Identifying Compromised Passwords (Part 1)

    Passwords are no longer considered safe when they are complex. Instead, you need to ensure that passwords have not been compromised and are not part of default attacker dictionaries. Even the most complex password is unsafe if it is routinely checked by automated attacks.

    To find out whether a password is compromised, use the function below:

    function Test-Password
    • 14 May 2020
  • Create Software Inventories

    The Windows registry stores the names and details of all software that you installed. PowerShell can read this information and provide you with a complete software inventory:

    # read all child keys (*) from all four locations and do not emit
    # errors if one of these keys does not exist
    Get-ItemProperty -Path 'HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*',
    • 12 May 2020
  • Keep PowerShell Modules Up-To-Date

    It’s important to check every now and then that your PowerShell modules are up-to-date. If you are using old and outdated modules, you can run into issues, just like using old and outdated software in general.

    For example, the PowerShellGet module provides cmdlets like Install-Module that let you easily download and install additional PowerShell modules, extending your PowerShell with new commands and capabilities…

    • 8 May 2020
  • Adding New PowerShell Commands

    PowerShell is just a scripting platform and can be extended with new commands. A great source for new commands is the public PowerShell Gallery. You can visit the graphical front-end at https://powershellgallery.com and search for modules.

    PowerShell comes with a module called PowerShellGet which in turn provides the commands to download and install extensions from the PowerShell Gallery. Let’s download and install a…

    • 6 May 2020
  • Getting Help for WMI Objects

    WMI is extremely powerful but a little underdocumented. To change this, a group has formed and is creating a PowerShell-specific WMI reference: https://powershell.one/wmi

    To easily look up help, you can add the Help() method to all of your WMI and CIM instance objects. Simply run this code:

    $codeCim = {
     $url = 'https://powershell.one/wmi/{0}/{1}' -f $this.CimSystemProperties.Namespace.Replace("/","…
    • 4 May 2020
  • Reading Chassis SKU

    In Windows 10 and Server 2016, WMI added a new property that simplifies collecting chassis or enclosure SKUs. This one-liner reads the SKU for you:

    PS> Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property Name, ChassisSKUNumber
    Name            ChassisSKUNumber
    ----            ----------------
    DESKTOP-8DVNI43 Convertible  

    Whether or not the SKU number is just a generic “Convertible” (for notebooks…

    • 30 Apr 2020
  • Managing Automatic Reset

    When a Windows system crashes, it typically reboots immediately. This is called “Automatic Reset Capability”, and with this one-liner you can check whether your machine supports it:

    Get-CimInstance -ClassName Win32_ComputerSystem | Select-Object -Property Name, AutomaticResetCapability   

    Whether or not the system actually performs an automatic reboot is controlled by “AutomaticResetBootOption”:…

    • 28 Apr 2020