• Redirecting Streams

    PowerShell writes output information to six different streams, and only the output stream is assigned to variables:

    function Invoke-Test
    {
      "Regular Output"
      Write-Host "You always see me!"
      Write-Information "Info"
      Write-Warning "Warning"
      Write-Error "Error"
      Write-Debug "Debug"
      Write-Verbose "Verbose"
      Write-Output "Output"
    }…
    • 17 Jul 2020
  • Silencing Write-Host Statements

    Write-Host is an extremely useful cmdlet to output information to a user because this output cannot be discarded:

    function Invoke-Test
    {
      "Regular Output"
      Write-Host "You always see me!"
    }
    
    # both show
    Invoke-Test
    
    # Write-Host still shows
    $result = Invoke-Test
    

    Beginning in PowerShell 5, there was a silent change in the engine though. Output emitted from Write-Host is now also controlled by the…

    • 15 Jul 2020
  • Discarding Streams

    PowerShell outputs information via different streams. Warnings are written to a different stream than output, and errors again go to a different stream. Each stream has a unique numeric identifier:

    ID Stream
    1 Output
    2 Error
    3 Warning
    4 Verbose
    5 Debug
    6 Information

    If you want to silence a stream, you can use the redirection operator (“>”) and redirect the stream(s) to $null. This line would discard…

    • 13 Jul 2020
  • Discarding (Any) Output

    There are (a few) commands in PowerShell that output information to the console no matter what you do. Neither redirection of streams nor assigning to $null will silence such commands, for example:

     
    PS> $null = Get-WindowsUpdateLog *>&1  
     

    Even though all output streams are discarded, the Get-WindowsUpdateLog cmdlet still writes extensive information to the console.

    If you come across such a situation, a last…

    • 9 Jul 2020
  • Identifying Operating System Details

    WMI returns a cryptic number when you ask for operating system details:

     
    PS> Get-CimInstance -ClassName Win32_OperatingSystem | 
          Select-Object -ExpandProperty SuiteMask
    272 
     

    SuiteMask really is a bitmask where each bit stands for a specific detail. To turn this into readable text, use a flag enumeration:

    $SuiteMask = @{
      Name = 'SuiteMaskText'
      Expression = {
        [Flags()] Enum EnumSuiteMask
       
    • 7 Jul 2020
  • Identifying Windows Type

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

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

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

    $OperatingSystemSKU = @{
      Name = 'OperatingSystemSKUText'
      Expression = {
        $value = $_.OperatingSystemSKU
        
        switch([int]$va…
    • 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
    {
      param
      (
        # one or more MAC addresses
        [Parameter(Mandatory,ValueFromPipeline,ValueFromPipelineByPropertyName)]
        # MAC address must be a following…
    • 17 Jun 2020
  • Converting Hex Numbers

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

     
    PS> 0xAB0f
    43791 
     

    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"
    43791 
     



    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
    {
      param
      (
        # suggest country names
        [ValidateSet('USA','Germany','Norway','Sweden','Austria','YouNameIt')]
        [string]
        $Name
      )
    
      # return parameter
      $PSBoundParameters
    } 
    

    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
    {
      [CmdletBinding()]
      param
      (
        [Parameter(Mand…
    • 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\*',
                        'HKLM:\SOFTWARE\WOW6432Node…
    • 12 May 2020