PowerShell Pipelines and ForEach-Object: Filter and Process Services

Service objects flow through filtering and action stages in a PowerShell pipeline illustration.

What You’ll Learn

In this lesson, you will learn how to send system objects through a PowerShell pipeline and use ForEach-Object to perform an action on each object that matches a filter.

  • Understand how objects move through a pipeline.
  • Filter service objects with Where-Object.
  • Use ForEach-Object to process one object at a time.
  • Use $_ to refer to the current service.
  • Preview a service action safely with -WhatIf.
Ad

The Concept

PowerShell commands usually work with objects rather than plain text. A command such as Get-Service returns service objects. Each object has properties such as Name, DisplayName, and Status.

The pipeline character, |, sends the output of one command to the next command. You can first filter the objects and then process each remaining object:

Get-Service |
    Where-Object { $_.Status -eq "Running" } |
    ForEach-Object {
        # Action for each running service
    }

Where-Object keeps only objects that satisfy its condition. Inside the script block, $_ means “the current object.”

ForEach-Object then runs its script block once for every object it receives. This is useful when you need to perform an action on each matching service, file, process, or other system object.

Basic Example

The following example looks for the Windows Print Spooler service. If the service is running, it passes the service object to ForEach-Object. The action uses Restart-Service with -WhatIf, so PowerShell shows what it would do without actually restarting the service.

$spoolerService = Get-Service -Name "Spooler" -ErrorAction SilentlyContinue

$spoolerService |
    Where-Object { $_.Status -eq "Running" } |
    ForEach-Object {
        Restart-Service -InputObject $_ -WhatIf
    }

Expected Output

The output depends on whether the Print Spooler service exists and is running on your computer. If it is running, the preview may look like this:

What if: Performing the operation "Restart-Service" on target "Print Spooler (Spooler)".

If the service is missing or stopped, the pipeline has no matching object, so the action does not run and there may be no output.

How the Code Works

A PowerShell service object flows from service retrieval into Where-Object filtering. Nonmatching services exit without action, while each matching service proceeds to ForEach-Object, where the current object is used for a safe WhatIf action preview.
PowerShell sends service objects through a filter, then processes each matching object individually while previewing the action safely.

1. Store the service object:

$spoolerService = Get-Service -Name "Spooler" -ErrorAction SilentlyContinue

Get-Service retrieves the service named Spooler. The result is stored in $spoolerService. The -ErrorAction SilentlyContinue option prevents an error message if that service is not available.

2. Filter the object:

Where-Object { $_.Status -eq "Running" }

The condition checks the current service’s Status property. Only a service whose status equals "Running" continues through the pipeline.

3. Process the matching object:

ForEach-Object {
    Restart-Service -InputObject $_ -WhatIf
}

ForEach-Object runs the script block once for every matching service. At that moment, $_ represents that service. The -InputObject parameter gives the service to Restart-Service.

-WhatIf is useful when learning or testing. It previews the action instead of carrying it out. After checking the result, an administrator could remove -WhatIf to perform the restart, provided the action is appropriate and the PowerShell session has sufficient permissions.

Another Example

This example handles a group of services instead of selecting one service by name. It finds stopped services whose display names begin with Windows and previews starting each one.

Get-Service |
    Where-Object {
        $_.Status -eq "Stopped" -and
        $_.DisplayName -like "Windows*"
    } |
    ForEach-Object {
        Write-Output "Preparing to start: $($_.DisplayName)"
        Start-Service -InputObject $_ -WhatIf
    }

This pipeline may process several service objects. ForEach-Object does not need to know how many objects it will receive; it simply runs the action once for each one. The subexpression $($_.DisplayName) inserts the current service’s display name into the message.

Common Mistakes

  • Using a property without $_: Inside Where-Object and ForEach-Object, use $_.Status or $_.Name to access the current object.
  • Putting the action before the filter: Filter objects before starting or stopping services. Otherwise, the action may run on services that should not be changed.
  • Forgetting that no objects may match: A pipeline can produce no output when the service is missing or does not meet the condition. That is normal behavior.
  • Removing -WhatIf too quickly: Use the preview first, especially when an action changes system state. Starting or restarting a service can affect applications and users.
  • Confusing ForEach-Object with a collection loop: ForEach-Object is designed for pipeline input. It processes each object as it arrives from the previous command.

Try It Yourself

Use the pipeline to find services whose names start with W. For each matching service, display its name and status. Do not start or stop anything yet.

A useful outline is:

Get-Service |
    Where-Object { $_.Name -like "W*" } |
    ForEach-Object {
        Write-Output "$($_.Name): $($_.Status)"
    }

After running it, change the filter to display only services whose status is "Running".

Challenge

Write a pipeline that:

  • Gets all services.
  • Keeps only services whose display names contain the word Windows.
  • Keeps only services with a status of Running.
  • Uses ForEach-Object to preview restarting each matching service.
  • Displays a message containing the service name before each previewed restart.

Use -WhatIf so the challenge does not actually restart services.

Solution

Get-Service |
    Where-Object {
        $_.DisplayName -like "*Windows*" -and
        $_.Status -eq "Running"
    } |
    ForEach-Object {
        Write-Output "Preparing to restart: $($_.Name)"
        Restart-Service -InputObject $_ -WhatIf
    }

The first condition checks whether the display name contains Windows. The second condition keeps only running services. ForEach-Object then processes each remaining service, prints its name, and previews a restart for that specific object.

Key Takeaways

  • The PowerShell pipeline sends objects from one command to another.
  • Where-Object filters objects before an action is performed.
  • ForEach-Object runs a script block once for every object it receives.
  • $_ represents the current object inside the pipeline script block.
  • -WhatIf lets you preview actions that change system state.

Leave a Comment

Your email address will not be published. Required fields are marked *

Scroll to Top
Ad
Ad
Ad