• 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
  • Creating Colorful Console Hardcopies

    If you’d like to hardcopy the content of a PowerShell console, you can copy and select the text, but this messes up colors and formatting.

    A better way is reading the console screen buffer, and composing HTML documents. These HTML documents can then be copied and pasted into Word and other targets, and keep formatting and colors

    The code below is certainly not yet perfect but illustrates the path to take:

    funct…
    • 26 Feb 2020
  • Understanding $ErrorView

    When PowerShell encounters a problem, it displays a rather lengthy error message:

     
    PS> 1/0
    Attempted to divide by zero.
    At line:1 char:1
    + 1/0
    + ~~~
        + CategoryInfo          : NotSpecified: (:) [], RuntimeException
        + FullyQualifiedErrorId : RuntimeException
     

    In real life, you often just need the first line, and as early as in 2006, the PowerShell team added a preference variable called $ErrorView that can…

    • 24 Feb 2020
  • IntelliSense for Parameters (Part 4)

    Wouldn’t it be nice if parameters would suggest valid arguments for the user? Sometimes they do. When you type below command and press a SPACE after -LogName, PowerShell ISE and Visual Studio Code pop up an IntelliSense menu with all log files you can dump:

     
    PS> Get-EventLog -LogName   
     

    If no automatic Intellisense pops up (i.e. in the PowerShell console), you can press TAB for auto completion, or CTRL+SPACE…

    • 20 Feb 2020
  • IntelliSense for Parameters (Part 3)

    Wouldn’t it be nice if parameters would suggest valid arguments for the user? Sometimes they do. When you type below command and press a SPACE after -LogName, PowerShell ISE and Visual Studio Code pop up an IntelliSense menu with all log files you can dump:

     
    PS> Get-EventLog -LogName  
     

    If no automatic IntelliSense pops up (i.e. in the PowerShell console), you can press TAB for auto completion, or CTRL+SPACE…

    • 18 Feb 2020
  • IntelliSense for Parameters (Part 2)

    Wouldn’t it be nice if parameters would suggest valid arguments for the user? Sometimes they do. When you type below command and press a SPACE after -LogName, PowerShell ISE and Visual Studio Code pop up an IntelliSense menu with all log files you can dump:

     
     PS> Get-EventLog -LogName
     

    If no automatic IntelliSense pops up (i.e. in the PowerShell console), you can press TAB for auto completion, or CTRL+SPACE…

    • 14 Feb 2020
  • IntelliSense for Parameters (Part 1)

    Wouldn’t it be nice if parameters would suggest valid arguments for the user? Sometimes they do. When you type below command and press a SPACE after -LogName, PowerShell ISE and Visual Studio Code pop up an IntelliSense menu with all log files you can dump:

     
    PS> Get-EventLog -LogName 
     

    If no automatic IntelliSense pops up (i.e. in the PowerShell console), you can press TAB for auto completion, or CTRL+SPACE…

    • 12 Feb 2020
  • Separating IPv4 and IPv6

    Let’s assume you want to return IP addresses from all network cards but separate them by address type. Here is an approach that uses solely Select-Object:

    function Get-IPAddress
    {
      Get-CimInstance -ClassName Win32_NetworkAdapterConfiguration |
      Where-Object { $_.IPEnabled -eq $true } |
      # add two new properties for IPv4 and IPv6 at the end
      Select-Object -Property Description, MacAddress, IPAddress, IPAddre…
    • 10 Feb 2020
  • Installing and Test-Driving Windows Terminal

    Windows Terminal is a new multi-tabbed tool for console-based shells. It is officially available via the Microsoft Store and currently requires Windows 10 1903 or better.

    To install it from the Microsoft Store, you need to register yourself which is frustrating. If you want to install Windows Terminal anonymously (and have installed Chocolatey in the previous tip), simply run this line from an elevated PowerShell:

    # download…
    • 6 Feb 2020
  • Installing Free Chocolatey Package Management

    Chocolatey is a package management system that helps you download and install software packages. Unlike the PowerShell Gallery, Chocolatey is not limited to PowerShell modules and scripts and can install a wide variety of software including tools like Notepad++, Acrobat Reader, or the Chrome browser.

    Using Chocolatey is trivial if you are prepared to run it in an elevated shell with full Administrator privileges. While…

    • 4 Feb 2020
  • Grab Original PowerShell Language Specification

    The PowerShell team has once published the rich and detailed PowerShell 3 language reference, and since the core language never changed, this document is still extremely valuable and full of hidden treasures.

    Grab the free documentation as long as it's still available: https://www.microsoft.com/en-us/download/confirmation.aspx?id=36389



    You are a PowerShell Professional, passionate about improving your code and…

    • 31 Jan 2020
  • Downloading PowerShell Language Reference (or any file)

    Invoke-WebRequest can easily download files for you. The code below downloads the PowerShell Language Reference published by PowerShell Magazine, and opens it with the associated program:

    $url = "https://download.microsoft.com/download/4/3/1/43113f44-548b-4dea-b471-0c2c8578fbf8/powershell_langref_v4.pdf"
    
    # get desktop path
    $desktop = [Environment]::GetFolderPath('Desktop')
    $destination = "$desktop…
    • 29 Jan 2020
  • Sharing Modules in Windows PowerShell and PowerShell Core

    Many PowerShell users start to take a look at PowerShell 7, and run it side-by-side to the built-in Windows PowerShell.

    Both PowerShell versions maintain their own locations for PowerShell modules, so when you add new modules (i.e. via Install-Module), you need to do this for both PowerShell versions separately.

    There is one folder path though that is shared by both Windows PowerShell and PowerShell 7: although introduced…

    • 27 Jan 2020
  • Installing ActiveDirectory Module

    Good news for any PowerShell users dealing with Active Directory: in recent Windows 10 builds (Enterprise, Professional), Microsoft included the RSAT tools so there is no additional download required. To use PowerShell commands for AD, simply enable the RSAT features (see below).

    Plus, finally the Active Directory PowerShell module is natively supported in PowerShell 7! If you started to use the new PowerShell side-by…

    • 23 Jan 2020
  • Testing for Pending Reboots

    When Windows installed updates or made related changes to the operating system, changes may become effective only after a reboot. While a reboot is pending, the operating system may not yet be fully protected, and you may not be able to install additional software.

    Whether a reboot is pending can be determined by testing for a special registry key:

    $rebootRequired = Test-Path "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion…
    • 21 Jan 2020
  • Launching PowerShell Scripts Invisibly

    There is no a built-in way to launch a PowerShell script hidden: even if you run powershell.exe and specify -WindowStyle Hidden, the PowerShell console will still be visible for a fraction of a second.

    To launch PowerShell scripts hidden, you can use a VBScript, though:

    Set objShell = CreateObject("WScript.Shell")
    path = WScript.Arguments(0)
    
    command = "powershell -noprofile -windowstyle hidden -executionpolicy…
    • 17 Jan 2020
  • Killing Non-Responding Processes

    Process objects returned by Get-Process can tell whether the process is currently responding to window messages and thus to user requests. This line takes the current PowerShell process to expose its property “Responding”:

     
    PS> Get-Process -Id $Pid | Select-Object *respond*
    
    Responding
    ----------
          True
     

    It is common for a process to occasionally become unresponsive, i.e. because of a high load and…

    • 15 Jan 2020
  • Testing Network Connections (Part 2)

    If you’d like to test whether a specific computer or URL is online, for decades ping requests (ICMP) have been used. In recent times, many servers and firewalls turn off ICMP to reduce attack surfaces. Test-NetConnection by default uses ICMP, so it fails on computers that do not respond to ICMP:

     
    PS> Test-NetConnection -ComputerName microsoft.com 
    WARNING: Ping to 40.76.4.15 failed with status: TimedOut
    WARNING…
    • 13 Jan 2020
  • Testing Network Connections (Part 1)

    PowerShell comes with Test-NetConnection which works like a sophisticated ping tool. In its default, you can ping computers:

     
    PS> Test-NetConnection -ComputerName powershell.one 
    
    
    ComputerName           : powershell.one
    RemoteAddress          : 104.18.46.88
    InterfaceAlias         : Ethernet 4
    SourceAddress          : 192.168.2.108
    PingSucceeded          : True
    PingReplyDetails (RTT) : 26 ms  
     

    Using -TraceRoute…

    • 9 Jan 2020
  • Exploring Plug&Play Devices (Part 4)

    In the previous tips we investigated the UPnP.UPnPDeviceFinder and how to identify devices in your network. Let’s look at some use cases. Obviously, these use cases are meant to be your source of inspiration because what you can do depends entirely on the actual devices connected to your network.

    My first use case is managing a NAS device, namely my Synology Disk Station. It can be managed via a web interface but…

    • 7 Jan 2020
  • Exploring Plug&Play Devices (Part 3)

    In the previous tip we illustrated how to use the UPnP.UPnPDeviceFinder to find devices on your network. You already learned how to enumerate all root devices (“upnp:rootdevice”), and how to directly access a device via its unique device identifier.

    $UPnPFinder = New-Object -ComObject UPnP.UPnPDeviceFinder
    $UPnPFinder.FindByType("upnp:rootdevice", 0) | Out-GridView 
    

    In this part, let’s complete…

    • 3 Jan 2020
  • Exploring Plug&Play Devices (Part 2)

    In the previous tip, we used the UPnP.UPnPDeviceFinder to discover smart devices hooked up to your network. Today, let’s take a closer look at the objects returned.

    $UPnPFinder = New-Object -ComObject UPnP.UPnPDeviceFinder
    $result = $UPnPFinder.FindByType("upnp:rootdevice", 0)
    

    When you run a search (which can take some time to complete), you get back a lot of information, but some properties return just…

    • 1 Jan 2020
  • Exploring Plug&Play Devices (Part 1)

    You are probably living already in a connected smart home with many devices hooked up to your network. PowerShell can help you find your devices with just a few lines of code:

    $UPnPFinder = New-Object -ComObject UPnP.UPnPDeviceFinder
    $UPnPFinder.FindByType("upnp:rootdevice", 0)
    

    Note that the UPnP finder component takes some time to detect your devices. The result looks like this:

     
    IsRootDevice     : True
    RootDevice…
    • 30 Dec 2019
  • Listing Installed Updates (Part 2)

    In the previous tip we looked at how to retrieve the list of currently installed updates from the Windows Update Client.

    This list can be polished, and for example you can use hash tables to create calculated properties that extract information such as the KB article number that are by default part of other properties such as the title:

    $severity = @{
      Name = 'Severity'
      Expression = { if ([string]::IsNullO…
    • 26 Dec 2019
  • Listing Installed Updates (Part 1)

    Get-Hotfix only lists operating-system-related hotfixes:

    Get-HotFix 
    

    In reality, it is just a thin wrapper around a WMI query which produces identical results:

    Get-CimInstance -ClassName Win32_QuickFixEngineering 
    

    A quick and more complete way of dumping all installed updates is querying the System event log:

    Get-WinEvent @{
      Logname='System'
      ID=19
      ProviderName='Microsoft-Windows-WindowsUpdateClien…
    • 24 Dec 2019