• Sophisticated Battery Report

    If your laptop battery is going low too soon, or you’d like to investigate related issues, there is a simple way to generate an extensive battery charging report. It shows exactly when your battery was charged, what its capacity is, and how long it took to deplete.

    Here is the code to create a 14-day report:

    $path = "$env:temp/battery_report2.html"
    powercfg /batteryreport /output $Path /duration 14
    Start…
    • 4 Aug 2020
  • Adding PowerShell commands for SharePoint

    The PowerShell Gallery provides easy access to additional PowerShell commands. For example, you can download and install the command extension for SharePoint and use PowerShell to automate your SharePoint sites:

    Install-Module -Name Microsoft.Online.SharePoint.PowerShell -Scope CurrentUser -Force 
    
    # listing all new SharePoint commands
    Get-Command -Module Microsoft.Online.SharePoint.PowerShell
    

    There are many more PowerShell…

    • 31 Jul 2020
  • Adding PowerShell commands for Azure

    To manage and automate your assets in the Azure cloud, you can easily install a free PowerShell module which comes with a wealth of new PowerShell commands:

    if ($PSVersionTable.PSEdition -eq 'Desktop' -and (Get-Module -Name AzureRM -ListAvailable)) {
        Write-Warning 'AzureRM and Az modules installed at the same time is not supported.')
    } else {
        Install-Module -Name Az -AllowClobber -Scope Curren…
    • 29 Jul 2020
  • Showing Wi-Fi SSIDs

    In the previous tip we illustrated how you can dump all Wi-Fi profile names using netsh.exe. Typically, profile names and SSIDs are identical. However, if you are interested in the true Wi-Fi SSID names, you can query these directly by dumping individual profiles and using a wildcard for the profile name:

     
    PS> netsh wlan show profile name="*" key=clear |
     Where-Object { $_ -match "SSID name\s*:\s(.*)$"…
    • 27 Jul 2020
  • Dumping Wi-Fi Passwords

    In the previous tip we used netsh.exe to dump Wi-Fi profiles. Let’s take it a step further and expose the cached passwords:

     # get cleartext password for each profile
     Foreach ($profile in $profiles)
     {
           $password = (@(netsh wlan show profile name="$profile" key=clear) -like '*Key Content*' -split ': ')[-1]
           [PSCustomObject]@{
                 Profile = $profile
                 Pa…
    • 23 Jul 2020
  • Showing Wi-Fi Profiles

    PowerShell is not limited to cmdlets and can run executables. For example, there is no built-in cmdlet to list the existing Wi-Fi profiles, but netsh.exe can provide the information:

     
    PS> netsh wlan show profiles
     

    Use Select-String to identify only output lines that match the pattern (a colon with following text), then use the -split operator to separate the strings at “: “, and get just the profile names by returning…

    • 21 Jul 2020
  • 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