• 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
  • Aborting the PowerShell Pipeline (Part 2: Manual Abort)

    In the previous tip you learned how to abort the PowerShell pipeline once the required number of results is in, potentially saving a lot of time:

    $fileToSearch = 'ngen.log'
    Get-ChildItem -Path c:\Windows -Recurse -ErrorAction SilentlyContinue -Filter $fileToSearch |
    Select-Object -First 1
    

    Apparently, Select-Object can send a secret message to the upstream pipeline cmdlets, telling them to stop when the number…

    • 20 Dec 2019
  • Aborting the PowerShell Pipeline (Part 1: Select-Object)

    Sometimes it can save a lot of time to manually abort a PowerShell pipeline. For example, if you don’t know exactly where a file is located and start a recursive search, the search could be aborted once you found your file. There is no reason why it should continue to search the rest of the directories.

    Here is a scenario illustrating the problem: let’s assume you are searching for a file called “ngen.log” somewhere…

    • 18 Dec 2019
  • Using a StopWatch to Measure Execution Times

    There are situations when you’d like to know how long some code took to execute, for example to return statistics or compare code, and there are plenty of ways to measure commands, including the Measure-Command cmdlet:

    $duration = Measure-Command -Expression {
      $result = Get-Hotfix
    }
    
    $time = $duration.TotalMilliseconds
    
    '{0} results in {1:n1} milliseconds' -f $result.Count, $time
    

    Measure-Command has some…

    • 16 Dec 2019
  • Foreach -parallel (Part 3: Mass Ping)

    In PowerShell 7, there is a new parallel ForEach-Object that can execute code in parallel and speed up things considerably. The same technique can be used in Windows PowerShell via modules like this one:

    Install-Module -Name PSParallel -Scope CurrentUser -Force 
    

    Let’s take a look at interesting use cases. For example, if you’d like to get a list of computers that respond to ping (ICMP), this typically can take a long…

    • 12 Dec 2019
  • Foreach -parallel (Part 2: Windows PowerShell)

    PowerShell 7 comes with a new ForEach-Object that supports parallel execution:

    1..100 | ForEach-Object -ThrottleLimit 20 -Parallel { Start-Sleep -Seconds 1; $_ }
    
    

    If you use Windows PowerShell, you can use the same parallelization techniques. For example, download and install this free module:

    Install-Module -Name PSParallel -Scope CurrentUser -Force 
    

    It comes with a single command: Invoke-Parallel. You would use it…

    • 10 Dec 2019
  • Foreach -parallel (Part 1: PowerShell 7)

    PowerShell 7 comes with a built-in parameter to run different tasks in parallel. Here is a simple example:

    1..100 | ForEach-Object -ThrottleLimit 20 -Parallel { Start-Sleep -Seconds 1; $_ }
    

    In a normal ForEach-Object loop, this would take 100 seconds to execute. Thanks to -parallel, the code is executed in parallel. -ThrottleLimit defines the “chunks”, so in this example, there are 20 threads running in parallel, reducing…

    • 6 Dec 2019
  • -RepeatHeader Parameter

    Here is a somewhat unknown parameter: -RepeatHeader! What does it do?

    Let’s assume you want to see results page by page (which only works in a console, not the PowerShell ISE):

     
    PS> Get-Process | Out-Host -Paging 
     

    The output now is paused per page until you press SPACE. However, the column headers are displayed only on the first page.

    A better output can be produced like this:

     
    PS> Get-Process | Format…
    • 4 Dec 2019
  • PowerShell 7 Ternary Operator

    With PowerShell 7, the language gets a new operator that created a lot of debate. Basically, you don’t have to use it, but users with a developer background will welcome it.

    Until now, to create a condition you’d always have to write a whole lot of code. For example, to find out whether your script runs in a 32-bit or 64-bit environment, you could query the length of a pointer like this:

    [IntPtr]::Size -e…
    • 2 Dec 2019
  • Get-ComputerInfo vs. systeminfo.exe (Part 2)

    In PowerShell 5, a new cmdlet called Get-ComputerInfo was introduced which does what systeminfo.exe did in the past, yet Get-ComputerInfo is object-oriented right away. There are no localization issues:

    $infos = Get-ComputerInfo
    

    You can now query individual details about your computer:

    $infos.OsInstallDate
    $infos.OsFreePhysicalMemory
    $infos.BiosBIOSVersion
    

    Or use Select-Object to select all properties that interest…

    • 28 Nov 2019
  • Get-ComputerInfo vs. systeminfo.exe (Part 1)

    For a long time, the command-line utility systeminfo.exe provides a wealth of information about a computer and can return object-oriented results with a little trick:

    $objects = systeminfo.exe /FO CSV |
      ConvertFrom-Csv
    
    $objects.'Available Physical Memory'
    

    On the pros side, systeminfo.exe is available on almost all Windows systems. On the cons side, the results are localized which can be a problem with the…

    • 26 Nov 2019
  • Safely Using WMI in PowerShell (Part 4)

    In this mini-series, we are looking at the differences between Get-WmiObject and Get-CimInstance. Future PowerShell versions no longer support Get-WmiObject, so it is time to switch to Get-CimInstance if you haven’t already.

    In the previous part you learned that there are considerable differences when you query information across a network, and that Get-CimInstance can use fully configurable and reusable session…

    • 22 Nov 2019
  • Safely Using WMI in PowerShell (Part 3)

    In this mini-series, we are looking at the differences between Get-WmiObject and Get-CimInstance. Future PowerShell versions no longer support Get-WmiObject, so it is time to switch to Get-CimInstance if you haven’t already.

    In the previous part you learned that both cmdlets return the same basic information for WMI classes, but the metadata properties added by both cmdlets differ considerably, and occasionally…

    • 20 Nov 2019
  • Safely Using WMI in PowerShell (Part 2)

    In this mini-series, we are looking at the differences between Get-WmiObject and Get-CimInstance. Future PowerShell versions no longer support Get-WmiObject, so it is time to switch to Get-CimInstance if you haven’t already.

    In the previous part you learned that both cmdlets return the same basic information for WMI classes, but the metadata properties added by both cmdlets differ considerably. Now let’s take a…

    • 18 Nov 2019