1

I want to run multiple custom processing steps using the pipeline in powershell.

In linux I could do something like this:

listServers.sh | <some commands to filter servers> | commandToApplyToEachServer.sh

And put code relevant to each step in different scripts (each command could take a number of parameters and at least the last one could be replaced by a different script entirely)

I would like to do something similar in powershell, without adding any "overhead" (having to source scripts before using their functions, having to re-source scripts if there have been changes etc)

Running the commands directly at the prompt is easy:

"server1","server2" | % {Get-Service -Name myservicename -ComputerName $_ | Set-Service -Status Stopped }

...but I want to enable users (and myself) an easier & more robust way of doing this and similar commands (basically wrapping each step in a script or function, whatever is the most powershelly way of doing things).

The closest I've gotten is this:

[CmdletBinding()]
param(
    [Parameter(Mandatory=$true)]
    $env
)

Function global:srv {
  Begin {
  }

  Process {
    Get-Service -Name someServiceName -ComputerName $_
  }

  End {
  }
}

Get-Content "$env.csv"

Which allows me to run things like:

.\listServers.ps1 appServers | srv

But unfortunately the srv function gets updated only AFTER the entire command has finished running (so any changes to the echo-pipe function will not take effect until the second time I run it, and of course I need to source listServers.ps1 before I can do anything at all, because srv doesnt exist until then)

UPDATE: I've gone forward using a single-script approach (using some parameters to handle filtering and control which command I want to be executed in the end, not using pipeline). But it would still be interesting to know if it is possible to use the pipeline.

4
  • Is there a reason that you can't pass the server names as parameters normally?
    – soandos
    Commented Sep 17, 2014 at 12:38
  • Yes, there could be 10+ servers and I want to read them from a file.
    – Cyberwiz
    Commented Sep 17, 2014 at 14:13
  • WHy not write a function that reads the file and then passes it as an array of server names?
    – soandos
    Commented Sep 17, 2014 at 14:20
  • I'm not sure how you mean, could you elaborate?
    – Cyberwiz
    Commented Sep 17, 2014 at 14:31

2 Answers 2

1

It seems that the most literal translation of

listServers.sh | <some commands to filter servers> | commandToApplyToEachServer.sh

would be like:

Get-content listServers.txt | Where-Object {*attributes and whatever} | CommandToRun

With PowerShell and piping it really all is up to you how you get anything and pipe it around. For example say I want to reboot all my servers that are named MAILSERVERxxxx:

Get-QADComputer -name * | where-object {$_.Name -Match "$MAILSERVER"} | Restart-Computer -ComputerName $_.Name

could be done, but more inline with PowerShell practices you can often handle this very differently:

Get-QADComputer -Name "MAILSERVER*" | Restart-Computer $_.Name

A few notes:

  • PowerShell is very flexible
  • PowerShell was meant to bring the Windows commandline to BASH levels of utility
  • The syntax is also flexible
  • Get-QADComputers is a cmdlet from Quest and now Dell

You can also use a C-like syntax to do many of the same things, and this further extends the power of PowerShell.

If you wanted to, for example read a file, build and array based on match criteria and then do something before moving on:

$someArray = @()
Get-Content "H:\SomeFile.txt" | `
Foreach-object {
 if ($_ -MAtch "$MAILSERVER") { $someArray += $_}
 }

$someArray | foreach-Object {
  if (Test-Connection "$_") {
    $Version = (Get-WmiObject -ComputerName "$_" -Class "Win32_OperatingSystem").Version
  }
}

I hope this helps.

1
  • Hi! Thanks, your answer was very informative (especially Get-QADComputer, I'll definitely have use for that). However, it does not solve my core problem: How do I use script files in the pipeline? (or any similar feature that allows me to run the command conveniently and without having to re-source files if there have been changes before running my actual command)
    – Cyberwiz
    Commented Sep 26, 2014 at 8:09
0
Get-Content 'ComputerNames.txt' | Restart-Computer

Done. This will read the lines from the file, and pass each one down the pipeline. Restart-Computer can take a string from the pipeline as the ComputerName argument and so that's how it works.

If you want to confirm the names before triggering each restart, add -Confirm to Restart-Computer.

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .