Book Image

Windows Server Automation with PowerShell Cookbook - Fourth Edition

By : Thomas Lee
Book Image

Windows Server Automation with PowerShell Cookbook - Fourth Edition

By: Thomas Lee

Overview of this book

With a foreword from PowerShell creator Jeffrey Snover, this heavily updated edition is designed to help you learn how to use PowerShell 7.1 effectively and manage the core roles, features, and services of Windows Server in an enterprise setting. All scripts are compatible with both Window Server 2022 and 2019. This latest edition equips you with over 100 recipes you'll need in day-to-day work, covering a wide range of fundamental and more advanced use cases. We look at how to install and configure PowerShell 7.1, along with useful new features and optimizations, and how the PowerShell compatibility solution bridges the gap to older versions of PowerShell. Topics include using PowerShell to manage networking and DHCP in Windows Server, objects in Active Directory, Hyper-V, and Azure. Debugging is crucial, so the book shows you how to use some powerful tools to diagnose and resolve issues with Windows Server.
Table of Contents (18 chapters)
16
Other Books You May Enjoy
17
Index

Improvements in ForEach and ForEach-Object

Windows PowerShell users are well versed in the use of both the ForEach statement and the ForEach-Object cmdlet. You can use both of these methods in your scripts to process collections, such as all the users in a specific Active Directory group, or the audio files in a file share. In PowerShell 7, both of these iteration methods are considerably faster.

Using either ForEach mechanism is a quick and easy way of processing a collection. One downside some IT pros may have noticed is that the overhead of ForEach processing in Windows PowerShell grows with the size of the collection. With small collection sizes, you are not likely to notice any difference. As the collection size grows, so does the overhead.

Getting ready

You run this recipe on SRV1 after you have installed PowerShell 7 and have created a console profile file. Run this recipe in an elevated console.

How to do it...

  1. Creating a remoting connection to the localhost using Windows PowerShell
    New-PSSession -UseWindowsPowerShell -Name 'WPS'
    
  2. Getting a remoting session
    $Session = Get-PSSession -Name 'WPS'
    
  3. Checking the version of PowerShell in the remoting session
    Invoke-Command -Session $Session  -ScriptBlock {$PSVersionTable}
    
  4. Defining a long-running script block using ForEach-Object
    $SB1 = {
      $Array  = (1..10000000)
      (Measure-Command {
        $Array | ForEach-Object {$_}}).TotalSeconds
    }
    
  5. Running the script block locally:
    [gc]::Collect()
    $TimeInP7 = Invoke-Command -ScriptBlock $SB1 
    "Foreach-Object in PowerShell 7.1: [{0:n4}] seconds" -f $TimeInP7
    
  6. Running the script block in PowerShell 5.1
    [gc]::Collect()
    $TimeInWP  = Invoke-Command -ScriptBlock $SB1 -Session $Session
    "ForEach-Object in Windows PowerShell 5.1: [{0:n4}] seconds" -f $TimeInWP
    
  7. Defining another long-running script block using ForEach
    $SB2 = {
        $Array  = (1..10000000)
        (Measure-Command {
          ForEach ($Member in $Array) {$Member}}).TotalSeconds
    }
    
  8. Running it locally in PowerShell 7
    [gc]::Collect()
    $TimeInP72 = Invoke-Command -ScriptBlock $SB2 
    "Foreach in PowerShell 7.1: [{0:n4}] seconds" -f $TimeInP72
    
  9. Running it in Windows PowerShell 5.1
    [gc]::Collect()
    $TimeInWP2  = Invoke-Command -ScriptBlock $SB2 -Session $Session
    "Foreach in Windows PowerShell 5.1: [{0:n4}] seconds" -f $TimeInWP2
    

How it works…

In step 1, you use New-PSSession to create a remoting session using a Windows PowerShell endpoint. This step produces output like this:

Figure 2.24: Creating a remoting connection to the localhost

In step 2, you get the session object representing the session you created in the previous step. This creates no output.

In step 3, you obtain the version of PowerShell that the remoting session is using to process commands, namely, Windows PowerShell 5.1. The output of this step looks like this:

Figure 2.25: Checking the PowerShell version in the remoting session

In step 4, you create a script block, $SB1, which uses the ForEach-Object cmdlet to iterate over a large collection. This step creates no output.

You invoke the $SB1 script block in the local session, in step 5. This step runs the script block in PowerShell 7. The output from this step looks like this:

Figure 2.26: Running the script block locally

With step 6, you run the $SB1 script block in Windows PowerShell 5.1, which produces output like this:

Figure 2.27: Running the script block in PowerShell 5.1

You next create a script block that makes use of the ForEach syntax item, in step 7, producing no output. You then run this second script block in PowerShell 7, in step 8, which produces output like this:

Figure 2.28: Running the script block locally in PowerShell 7

In the final step, step 9, you run $SB1 in the remoting session created earlier (in other words, in Windows PowerShell 5.1), which produces output like this:

Figure 2.29: Running the script block in PowerShell 5.1

There's more...

In step 1, you create, implicitly, a remoting session to the localhost using a process transport that is much faster than the traditional remoting session using WinRM.

In steps 5, 6, 8, and 9, you force .NET to perform a garbage collection. These are steps you can use to minimize the performance hits of running a script block in a remote session (in Windows PowerShell) and to reduce any impact of garbage collections while you are performing the tests in this recipe.

As you can see from the outputs, running ForEach-Object is much faster in PowerShell 7, as is running ForEach in PowerShell 7. Processing large collections of objects is a lot faster in PowerShell 7.

The improvements to loop processing that you can see in the recipe, combined with the use of ForEach-Object -Parallel you saw in Exploring parallel processing with ForEach-Object, provide an excellent reason to switch to PowerShell 7 for most operations.

The performance of iterating through large collections is complex. You can read an excellent article on this subject at https://powershell.one/tricks/performance/pipeline. This article also addresses the performance of using the pipeline versus using ForEach to iterate across collections in a lot more detail.