• 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
  • Using Custom Validation Attributes

    Beginning in PowerShell 5, you can create your own attributes, i.e. custom validators. They can be applied to variables (and parameters), and once a value is assigned that does not match the validator, an exception is raised.

    Here is an example for a path validator. When you apply it to a variable, only valid file paths can be applied to the variable:

    class ValidatePathExistsAttribute : System.Management.Automation.V…
    • 24 Apr 2020
  • Testing for Metered WLAN

    Ever needed to know whether you are currently connected to a metered (costly) network? Here is a quick way to check:

    function Test-WlanMetered
    {
      [void][Windows.Networking.Connectivity.NetworkInformation, Windows, ContentType = WindowsRuntime]
      $cost = [Windows.Networking.Connectivity.NetworkInformation]::GetInternetConnectionProfile().GetConnectionCost()
      $cost.ApproachingDataLimit -or $cost.OverDataLimit -or $co…
    • 22 Apr 2020
  • Using WMI Instance Paths (Part 2)

    In the previous tip we showed that the new Get-CimInstance command is missing the important “__Path” property that was returned by Get-WmiObject. Let’s add this property back to Get-CimInstance.

    Every instance returned by Get-CimInstance is of type [Microsoft.Management.Infrastructure.CimInstance], so Update-TypeData can be used to add a new property to this type:

    $code = {
     # get key properties
     $k…
    • 20 Apr 2020
  • Using WMI Instance Paths (Part 1)

    Generally, it is the best to move away from the old and deprecated Get-WmiObject command and instead use the modern and faster CIM cmdlets like Get-CimInstance. In most scenarios, they almost work the same.

    In a few areas, though, the new CIM cmdlets lack information. One of the most important areas is the property “__Path” that was available with any object returned by Get-WmiObject. With Get-CimInstance, it is missing…

    • 16 Apr 2020
  • Installing PowerShell 7

    PowerShell 7 is a portable app and can run side-by-side with Windows PowerShell. You just need to download and install it.

    This part is easy because the PowerShell team provides an automatic installation script. With a little trick, you can download this code and tie it to a fresh new PowerShell function, making it super easy to install PowerShell 7 from the existing Windows PowerShell:

    # Download installation script…
    • 14 Apr 2020
  • Enabling Clickable PowerPoint Actions

    Using clickable actions in PowerPoint presentations can be super useful to launch Visual Studio Code or PowerShell ISE, and seamlessly open and demo PowerShell code.

    However, for security reasons, launching programs via inserted “Action” items is prohibited by default, and there is no easy way to enable it. What’s more, even when you do enable this feature, PowerPoint will revert it back to protected mode after a short…

    • 10 Apr 2020
  • Manage Automatic Disk Checks

    Whenever Windows detects irregularities with storage drives, it enables an automatic integrity check. For system partitions, on next boot, Windows shows a user prompt and asks for permission to perform the check.

    To find out all drives that are enabled for this kind of check, run this:

     
    PS> Get-CimInstance -ClassName Win32_AutochkSetting | Select-Object -Property SettingID, UserInputDelay
    
    SettingID                …
    • 8 Apr 2020
  • Getting Available Video Resolutions

    WMI can return a list of available video resolutions for your video adapter:

     
    PS> Get-CimInstance -ClassName CIM_VideoControllerResolution |
     Select-Object -Property SettingID
    
    SettingID                                              
    ---------                                              
    640 x 480 x 4294967296 colors @ 60 Hertz               
    640 x 480 x 4294967296 colors @ 67 Hertz               
    640 x 480 x 4294967296…
    • 6 Apr 2020
  • Be Careful with Some Commands

    Here are three commands often found in PowerShell scripts that you should be careful about because they can have severe side effects:

    exit
    “exit” is not really a command but rather part of the language. It exits PowerShell immediately, and optionally you can submit a number which will be the “error level” that callers can query.

    Use “exit” only when you really want to exit PowerShell. Do not use…

    • 2 Apr 2020
  • Dealing with Out-GridView Bug

    Out-GridView can serve as a universal selection dialog when you add the -PassThru parameter. The one-liner below stops all services you select in the grid view window (well, not really; you can play safely until you remove -WhatIf):

     
    Get-Service | Out-GridView -Title 'Select Service' -PassThru | Stop-Service -WhatIf  
     

    However, there is a long-standing bug in Out-GridView: while information is pumped into the…

    • 31 Mar 2020
  • Exploring WMI with PowerShell

    The Win32_LogicalDevice WMI class represents all logic devices available in a computer, and by querying this “superclass”, you get back all the specialized individual classes. This is a simple way of finding out what kind of information WMI can get you, and what the names of WMI classes are:

    Get-CimInstance -ClassName CIM_LogicalDevice | 
        Select-Object -Property Name, CreationClassName, DeviceID, Syst…
    • 27 Mar 2020
  • Adding New PowerShell Commands with Carbon

    Carbon is one of the most popular free PowerShell modules available from the PowerShell Gallery. Similar to a swiss army knife, it comes with a variety of helper functions. To install it, run this:

     
    PS> Install-Module -Name Carbon -Scope CurrentUser -Force
     

    Apparently, the owner of this module has added useful functionality whenever it was needed. This is all you need to test whether your PowerShell currently is…

    • 25 Mar 2020
  • Managing Updates with PSWindowsUpdate

    There are many useful PowerShell modules available from the PowerShell Gallery. One helps you managing updates. To download and install it, run:

     
    PS> Install-Module -Name PSWindowsUpdate -Scope CurrentUser -Force
     

    It adds a list of new commands related to Windows Update:

     
    PS> Get-Command -Module PSWindowsUpdate 
    
    CommandType Name                    Version Source         
    ----------- ----                    ---…
    • 23 Mar 2020
  • Dynamic Argument Completion (Part 5)

    In our previous tip we looked at sophisticated completion code that completed application paths. Collecting the completion values could take some time and had the potential of timing out IntelliSense. For completion values that are unlikely to change, it is much better to calculate the values once and then use cached values.

    This way, installing the completers will cost a second or two, but after that you enjoy rapid…

    • 19 Mar 2020
  • Dynamic Argument Completion (Part 4)

    In the previous tip we explained how you can use [ArgumentCompleter] to add powerful argument completers for parameters. There are limitations though:

    • When the completion code becomes complex, your code becomes hard to read
    • You cannot add argument completion to existing commands. The [ArgumentCompleter] attribute only works with your own functions

    In reality, though, the attribute is just one of two ways to add argument…

    • 17 Mar 2020
  • Dynamic Argument Completion (Part 3)

    With the discoveries in our past tips, let’s compose a useful completion code that suggests all available programs you can launch:

    function Start-Software {
        param(
            [Parameter(Mandatory)]
            [ArgumentCompleter({
            
           
    # get registered applications from registry     
    $key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*", 
        "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion…
    • 13 Mar 2020
  • Dynamic Argument Completion (Part 2)

    In our previous tip we looked at [ArgumentCompleter] and how this attribute can add clever code to parameters that provides auto-completion values for your arguments. AutoCompletion can do even more: you can submit different values for the IntelliSense menu, and for the actual completion.

    Check this code:

    function Get-OU {
        param(
            [Parameter(Mandatory)]
            [ArgumentCompleter({
            
            [Management…
    • 11 Mar 2020
  • Dynamic Argument Completion (Part 1)

    In previous tips we explained various ways of adding argument completers to your parameters. One approach used the [ArgumentCompleter] attribute and looked like this: As you can see, it’s solely a matter of refining the completion code: when the file name contains a space, the expression is placed inside quotes, else it isn’t. If you wanted the completer to only return files and omit folders, add the -File parameter to…

    • 9 Mar 2020
  • Listing Installed Applications (Part 2)

    In the previous tip we read the registry to find out paths to applications you can launch. This approach worked well but had two flaws: first, the list did not include the friendly names for the applications, and second, the list was not complete. Only programs who chose to register themselves were listed.

    Let’s get a complete list of applications and use three tricks to overcome the limitations:

    • Use a generic…
    • 5 Mar 2020
  • Listing Installed Applications (Part 1)

    Ever wondered what the path is to launch a given application? The Windows registry has a key that stores such information:

      $key = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*", 
            "HKCU:\SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths\*"
    
     $lookup = Get-ItemProperty -Path $key | 
     Select-Object -ExpandProperty '(Default)' -ErrorAction Ignore |
     Where-Object { $_
    • 3 Mar 2020
  • Secret Dynamic Argument Completer

    In the previous tip we introduced the lesser-known “ArgumentCompletion” attribute that can provide IntelliSense-like autocompletion to parameters. This attribute can do way more than that, though. Previously, we introduced this code:

    function Get-Vendor {
        param(
            [Parameter(Mandatory)]
            [ArgumentCompleter({'Microsoft','Amazon','Google'})]
            [string]
            $Vendor
        )
    
        "Chosen…
    • 28 Feb 2020