• Hiding Progress Bars

    Sometimes, cmdlets automatically display a progress bar. Here is an example of such a progress bar:

    $url = "http://www.powertheshell.com/reference/wmireference/root/cimv2/"
    $page = Invoke-WebRequest -URI $url
    

    Invoke-WebRequest retrieves the raw content for a web page, and if retrieving the content takes a while, a progress bar is shown.

    Whenever you run a cmdlet that shows a progress bar, you can hide the progress…

    • 9 Nov 2018
  • Analyzing Web Page Content

    PowerShell comes with a built-in web client which can retrieve HTML content for you. For a simple web page analysis, use the -UseBasicParsing parameter. This gets you the raw HTML content as well as, for example, a list of all embedded links and images:

    $url = "http://powershellmagazine.com"
    $page = Invoke-WebRequest -URI $url -UseBasicParsing
    
    $page.Content | Out-GridView -Title Content
    $page.Links | Select…
    • 8 Nov 2018
  • Adding Extra Safety Net

    If you are writing PowerShell functions, and you know a particular function has the potential to cause a lot of harm, there is an easy way of adding an extra safety net. Below are two functions, one without safety net, and one with a safety net:

    function NoSafety
    {
        param
        (
            [Parameter(Mandatory)]
            $Something
        )
        "HARM DONE with $Something!"
    }
    
    function Safety
    {
        # step 1: add …
    • 7 Nov 2018
  • Hiding Common Parameters

    In our last tip we explained how you can hide parameters from IntelliSense. This has a cool side effect that we’d like to point you to today!

    PowerShell supports two different types of functions: simple functions and advanced functions. A simple function just exposes the parameters you define. An advanced function also adds all the common parameters. Here are two sample functions:

    function Simple
    {
        param
      
    • 6 Nov 2018
  • Turning Objects into Hash Tables

    In one of the previous tips we examined how Get-Member can retrieve the property names for an object. Here is another use case that takes any object, turns it into a hash table with sorted properties, and excludes empty properties.

    # take an object...
    $process = Get-Process -id $pid 
    
    # ...and turn it into a hash table
    $hashtable = $process | ForEach-Object {
    
      $object = $_
    
      # determine the property names in this object…
    • 5 Nov 2018
  • Hiding Parameters

    In the previous tip we explained how you can dump all the legal values for a PowerShell attribute. Today we’ll take a look at the [Parameter()] attribute and its value DontShow. Take a look at this function:

    function Test-Something
    {
        param
        (
            [string]
            [Parameter(Mandatory)]
            $Name,
            
            [Parameter(DontShow)]
            [Switch]
            $Internal
        )
    
        "You entered: $name…
    • 2 Nov 2018
  • Exploring PowerShell Attribute Values

    As you might know, you can add attributes to variables and parameters to more specifically define them. For example, the line below defines a function with a parameter that accepts only three distinct string values and is mandatory:

    function Test-Attribute
    {
        [CmdletBinding()] 
        param
        (
            [string]
            [Parameter(Mandatory)]
            [ValidateSet("A","B","C")]
            $Choice
        )
    
        "Choice: $Choice…
    • 1 Nov 2018
  • Using Dynamic Parameters

    Most PowerShell functions use static parameters. They are defined in a param() block and are always present. A little-known fact is that you can also add dynamic parameters programmatically on the fly. The big advantage of dynamic parameters is that you are completely free as to when they should appear, and what kind of values they should accept. The drawback is that you need to use a lot of low level code to “program…

    • 31 Oct 2018
  • Accessing Website Content

    Typically, it is trivial for PowerShell to retrieve raw HTML website content by using Invoke-WebRequest. A script can then take the HTML content and do whatever it wants with it, for example scrape information from it using regular expressions:

    $url = "www.tagesschau.de"
    $w = Invoke-WebRequest -Uri $url -UseBasicParsing
    $w.Content
    

    However, sometimes a website content is created dynamically using client-side…

    • 30 Oct 2018
  • Accepting Different Parameter Types

    Occasionally, you might want to create a function that accepts different parameter types. Let’s say you want the user to be able to either submit an employee name, or an Active Directory object.

    There is one fixed rule in PowerShell: variables cannot have multiple data types at the same time. Since parameters are variables, a given parameter can only have one distinct type.

    However, you can use parameter sets to…

    • 29 Oct 2018
  • Translating VBScript to PowerShell

    Most old VBS scripts can be easily translated to PowerShell. The key command in VBS is “CreateObject” which lets you access system libraries. PowerShell translates “CreateObject” to “New-Object -ComObject”, yet the object model and member names stay the same:

    This VBS script talks to you when you save it to a text file with “.vbs” extension:

    Set obj = CreateObject("Sapi…

    • 26 Oct 2018
  • Invoking Excel Macros from PowerShell

    PowerShell can invoke Microsoft Excel sheets and start contained macros. While this would work with an invisible Excel application window, it is a wise idea to keep Excel open (as shown below) to spot warning messages that might appear when you try and run security sensitive things like macros:

    # file path to your XLA file with macros
    $FilePath = "c:\test\file.xla"
    # macro name to run
    $Macro = "AddData"…
    • 25 Oct 2018
  • Programmatically listing any Cmdlet or Function Parameters

    Ever wondered how you can list all properties exposed by a function or cmdlet? Here is how:

    Get-Help Get-Service -Parameter * | Select-Object -ExpandProperty name
    

    Get-Help provides a lot of helpful information and meta data about parameters as well. If you’d like to dump only parameters that support pipeline input, here is how:

    Get-Help Get-Service -Parameter * | 
    Where-Object { $_.pipelineInput.Length -gt 10 
    • 24 Oct 2018
  • Examining Object Properties Programmatically

    Whether you import a CSV list into PowerShell using Import-Csv, or deal with any other type of objects: how can you automatically determine the object properties? Here is a simple approach:

    # take any object, and dump a list of its properties
    Get-Process -Id $pid | 
      Get-Member -MemberType *property | 
      Select-Object -ExpandProperty Name | 
      Sort-Object 
    

    Why would this be useful? There are many use cases. For example…

    • 23 Oct 2018
  • Accessing Hidden (Private) Member

    Objects and types have members such as methods and properties, but only a fraction is publicly visible and usable. There are numerous hidden (private) members. While it is not wise to use these in production code as they can change without notice with new versions, it is a highly interesting playground for advanced PowerShellers.

    There is a free PowerShell module called ImpliedReflection which makes private members visible…

    • 22 Oct 2018
  • Performance (Part 3): Faster Pipeline Functions

    In previous tips we illustrated how you can improve loops and especially pipeline operations. To transfer this knowledge to functions, take a look at a simple pipeline-aware function which counts the number of piped elements:

    function Count-Stuff
    {
        param
        (
            # pipeline-aware input parameter
            [Parameter(ValueFromPipeline)]
            $InputElement
        )
    
        begin 
        {
            # initialize counter
    
    • 19 Oct 2018
  • Performance (Part 2): From 2 sec to 200ms

    In the previous tip we added considerable speed to a common script pattern. Now, let’s squeeze out even more performance with a pretty unusual trick. Here is how far we got in the last tip:

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

    We managed to get down from 6+ minutes to only 46 seconds on PowerShell 5.1 and 1.46 seconds on PowerShell…

    • 18 Oct 2018
  • 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 $_"
    }
    
    $bucket.Count
    
    (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}}, * |
      Out-GridView
    

    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