• Performance (Part 1): From 6 min to 2 sec

    Here is a common mistake found in many PowerShell scripts:

    $start = Get-Date
    $bucket = @()
    1..100000 | ForEach-Object {
        $bucket += "I am adding $_"
    (Get-Date) - $start

    In this design, scripts are using an empty array, then employ some sort of loop to add items to the array. When you run it, you’ll notice that it takes forever. In fact, it took more than 6 minutes on our test system and…

    • 17 Oct 2018
  • Keeping Track of Script Execution

    Here is a chunk of code that demonstrates how you can store private settings in the Windows Registry:

    # store settings here
    $Path = "HKCU:\software\powertips\settings"
    # check whether key exists
    $exists = Test-Path -Path $Path
    if ($exists -eq $false)
        # if this is first run, initialize registry key
        $null = New-Item -Path $Path -Force
    # read existing value
    $currentValue = Get-ItemProperty -Path 
    • 16 Oct 2018
  • Retrieving Outlook Calendar Entries

    If you use Outlook to organize your calendar events, here is a useful PowerShell function that connects to Outlook and dumps your calendar entries:

    Function Get-OutlookCalendar
        # load the required .NET types
        Add-Type -AssemblyName 'Microsoft.Office.Interop.Outlook'
        # access Outlook object model
        $outlook = New-Object -ComObject outlook.application
        # connect to the appropriate location…
    • 15 Oct 2018
  • Getting AD Users with Selected First Letters

    How would you query for all AD users with names that start with a “e”-“g”? You shouldn’t use a client-side filter such as Where-Object. One thing you can do is use the -Filter parameter with logical operators such as -and and -or:

    Get-ADUser -filter {(name -lt 'E') -or (name -gt 'G')} |
      Select-Object -ExpandProperty Name

    this example requires the free RSAT tools from Microsoft…

    • 12 Oct 2018
  • Adding New Incrementing Number Column in a Grid View Window

    Maybe you’d like to add a column with incrementing indices to your objects. Try this:

    $startcount = 0
    Get-Service |
      Select-Object -Property @{N='ID#';E={$script:startcount++;$startcount}}, * |

    When you run this chunk of code, you get a list of services in a grid view window, and the first column “ID#” is added with incrementing ID numbers.

    The technique can be used to add arbitrary…

    • 11 Oct 2018
  • Improving Group-Object

    In the previous tip we explained what Group-Object can do for you, and how awesome it is. Unfortunately, Group-Object does not scale well. When you try and group a large number of objects, the cmdlet may take a very long time.

    Here is a line that groups all files in your user profile by size. This could be an important prerequisite when you want to check for duplicate files. While this line will eventually yield results…

    • 10 Oct 2018
  • Discover Group-Object

    Group-Object is an awesome cmdlet: it can easily visualize distributions. Check out the examples below:

    Get-Process | Group-Object -Property Company
    Get-Eventlog -LogName System -EntryType Error | Group-Object -Property Source
    Get-ChildItem -Path c:\windows -File | Group-Object -Property Extension

    Basically, the cmdlet builds groups based on the content of a given property. You can also omit the group, and just look…

    • 9 Oct 2018
  • Automating “Live” Websites

    Occasionally, there is the need to automate tasks on websites that have been opened manually. Maybe you need to log into internal web pages first using some web forms. Provided the website is hosted in Internet Explorer (not Edge or any 3rd-party browser), you can use a COM interface to access the live browser content.

    This can even be valuable for plain “HTML-scraping” when you visit dynamic web pages. A pure WebClient…

    • 8 Oct 2018
  • Installing Printers

    Starting with Windows 8 and Server 2012 R2, these operating systems ship a PowerShell module called PrintManagement. The cmdlets found in this module can be helpful to script printer installations and configuration. Here is a simple chunk of code to get you started:

    $PrinterName = "MyPrint"
    $ShareName = "MyShare"
    $DriverName = 'HP Designjet Z Series PS Class Driver'
    $portname = "${PrinterName…
    • 5 Oct 2018
  • Using CSV to Create Objects

    Sometimes it may be clever to use simple text-based CSV format internally to bulk-create objects, especially if the original data is already text-based and may need just a little reformatting.

    Here is a simple example that takes information and creates a list of custom objects this way:

    $text = 'Name,FirstName,Location
    • 4 Oct 2018
  • Finding Active Directory Group Members Efficiently

    Often, AD Administrators need to find all members of a given AD group, including nested members. Here is a code snippet that frequently surfaces in examples to solve this puzzle:

    $groupname = 'External_Consultants'
    $group = Get-ADGroup -Identity $groupname
    $dn = $group.DistinguishedName
    $all = Get-ADUser -filter {memberof -recursivematch $dn}
    $all | Out-GridView

    (note that you need the free RSAT tools from Microsoft…

    • 3 Oct 2018
  • Using Artificial Intelligence with Azure Cognitive Services

    The cloud these days not only offers virtual machines and storage, but also brand new and exciting services such as the cognitive services. You need an Azure subscription key (which you can get for free on the website mentioned below) if you want to directly access these services. Else, you would need to resort to the free interactive demos found here:


    • 2 Oct 2018
  • Backing Up All Scripts to ZIP

    PowerShell 5 finally includes support for ZIP files, so if you want to backup all of your PowerShell scripts into one ZIP file, here is a one-liner:

    Get-ChildItem -Path $Home -Filter *.ps1 -Recurse -ErrorAction SilentlyContinue |
      Compress-Archive -DestinationPath "$home\desktop\backupAllScripts.zip" -CompressionLevel Optimal

    Note that on Windows 10, all files are passed through your AV engine before they…

    • 1 Oct 2018
  • Running PowerShell Code as Someone Else

    Local admin privileges are extremely powerful, and you should use techniques such as JEA to minimize the number of local Admins as much as you can. Why? Take a look at the example below. If you have local Admin privileges on a machine, and PowerShell remoting is active, then you can send arbitrary PowerShell code to that machine, and have it execute in the context of the user that is logged on to that machine.

    If an Enterprise…

    • 28 Sep 2018
  • Hardening Script Block Logging

    By default, script block logging data is open to anyone, not just Administrators. When script block logging is enabled, any user can access the log and read its content. The easiest way would probably be to download tools and use a one-liner:

    Install-Module -Name scriptblocklogginganalyzer -Scope CurrentUser
    Get-SBLEvent | Out-GridView

    There are ways to harden the script block log, and make sure only Administrators can…

    • 27 Sep 2018
  • Enabling Script Block Logging

    In the previous tips, we took a deep look at how PowerShell 5 script block logging works: in a nutshell, when enabled, all PowerShell code that executes on a machine is logged so you can browse through the source code and see what PowerShell code is used on your machine(s).

    We baked this into a free PowerShell module that is available from the PowerShell Gallery, so to enable script block logging, all you need is a PowerShell…

    • 26 Sep 2018
  • Finding Secret Passwords in Memory

    Some scripts may leave variables with sensitive information behind. This can happen by accident, when the global scope is used, or when users call functions and commands “dot-sourced”. Some of these variables may contain data such as user accounts and passwords that are highly attractive to hackers.

    Here is a quick test that examines all variables in memory to find credentials, then returns the variable plus…

    • 25 Sep 2018
  • Outputting Data to HTML Reports

    Here is a super easy and useful PowerShell function called Out-HTML:

    function Out-HTML
            $Path = "$env:temp\report$(Get-Date -format yyyy-MM-dd-HH-mm-ss).html",
            $Title = "PowerShell Output",
        $headContent = @"
    building { background-color…
    • 24 Sep 2018
  • Stealing Sensitive Data from PowerShell Functions

    Frequently, PowerShell functions work with sensitive information, i.e. log-on information including passwords, and store this information in variables. Let’s assume a function like this to play with:

    function Connect-Server
        "You entered a credential for {0…
    • 21 Sep 2018
  • Handling Credentials as Parameters

    Credentials are objects that contain a user name and an encrypted password. If your PowerShell functions should be able to accept credentials, assign the PSCredential type:

    function Connect-Server
        "You entered a credential for {0}." -f $Credential.UserName
        # now you could do something with $Credential…
    • 20 Sep 2018
  • Resolving Mapped Drive

    Ever wanted to know the original URL behind network drives? Here is an easy PowerShell way:

    # make sure the below drive is a mapped network drive
    # on your computer
    $mappedDrive = 'z'
    $result = Get-PSDrive -Name $mappedDrive | 
        Select-Object -ExpandProperty DisplayRoot
    "$mappedDrive -> $result"

    Twitter This Tip! ReTweet this Tip!

    • 19 Sep 2018
  • Downloading Data with BitsTransfer in the Background

    Downloading very large files can be a challenge because the download process may take longer than a machine is turned on. With BitsTransfer, you can download files in the background, and even if the computer is turned off or rebooted, the download will resume and eventually complete.

    The code below downloads a NASA video for you. However, the download occurs in the background, and you can immediately continue. In fact…

    • 18 Sep 2018
  • Downloading Data via SSL and BitsTransfer (Sync)

    A very convenient built-in way to download files, even with SSL connections, is Start-BitsTransfer. It also sports a progress bar that shows the actual download status. Here is a working sample:

    $url = 'https://mars.nasa.gov/system/downloadable_items/41764_20180703_marsreport-1920.mp4'
    $OutFile = "$home\desktop\videoNasa2.mp4"
    Start-BitsTransfer -Source $url -Destination $OutFile -Priority Normal 
    • 17 Sep 2018
  • Downloading Data via SSL and Invoke-WebRequest

    Invoke-WebRequest can download files for you but may struggle with HTTPS URLs. To use SSL connections, you may have to change a default setting. Here is a working example:

    $url = 'https://mars.nasa.gov/system/downloadable_items/41764_20180703_marsreport-1920.mp4'
    $OutFile = "$home\desktop\video.mp4"
    $AllProtocols = [Net.SecurityProtocolType]'Ssl3,Tls,Tls11,Tls12'
    • 14 Sep 2018
  • Finding Disabled GPOs

    Here is a quick one-liner that dumps all Group Policy objects that have all settings disabled:

    Get-Gpo -All | Where-Object GpoStatus -eq AllSettingsDisabled

    This sample requires the free RSAT tools from Microsoft.

    Twitter This Tip! ReTweet this Tip!

    • 14 Sep 2018