header image

Expanding server names

Posted by: | June 27, 2014 | No Comment |

I had a comment left on my recent post – “Bad practices – making scripts needlessly interactive” asking how to deal with the situation of N servers consecutively numbered e.g. server01 to server05. Taking the script from that post as an example:

 

[CmdletBinding()]
param (
[string[]]$computername
)

foreach ($computer in $computername){
  Restart-Computer -ComputerName $computer
}

 

the questioner wanted to be able to do something like

./reboot –computername server0[1-5]

which would have the same effect as typing

./reboot –computername server01, server02, server03, server04, server05

 

There are two approaches that come to mind. The first approach would be to put some code to perform the expansion into the script and use parameter sets to differentiate between a set of full names or a group of names to expand.  This would give you something like this:

[CmdletBinding()]
param (

[parameter(ParameterSetName="Names")]
[string[]]$computername,

[parameter(ParameterSetName="Group")]
[string]$computergroup

)

switch ($psCmdlet.ParameterSetName) {
"Names"  {
             foreach ($computer in $computername){
               Restart-Computer -ComputerName $computer
             }
          }
"Group"  {
              $groupdata = $computergroup.Replace("]", "") -split "\["
              $prefix = $groupdata[0]
              $nums = $groupdata[1] -split "-"
             
              $nums[0]..$nums[1] |
              foreach {
                Restart-Computer -ComputerName "$prefix$_"
              }
              
          }
default {Write-Error "Error!!! Should not be here" }
}

 

Two parameters are defined. The computername parameter takes one or more computer names. The computergroup parameter takes some kind of shorthand notation to describe a group of consecutively named machines such as server0[1-5]. Pameter sets are used to make the parameters mutually exclusive .

Processing is based on a switch determined by parameter set name.

For a set of computer names the processing is as previously.

For a shorthand notation the data is split to provide the prefix – ‘server0’  in this case.

The numbers are then split on the “-“ to effectively give a first and last which are used in a range operator and passed through foreach-object to the restart-computer cmdlet where the computer name is created.

This approach works but it has one major drawback. You would need to put the code to expand the server names into each and every script or function you wrote. That’s extra work we can avoid.

The essence of PowerShell cmdlets is that they are a small piece of code that perform a discrete job. If we follow that pattern we can split the expansion of the server names out into a reusable piece of code that then passes computer names to our other scripts or functions. I would make the expand code a function so that you can load it through a module or your profile.

function expand-servername {
[CmdletBinding()]
param (

[string]$computergroup

)
$computers = @()

$groupdata = $computergroup.Replace("]", "") -split "\["
$prefix = $groupdata[0]
$nums = $groupdata[1] -split "-"
             
$nums[0]..$nums[1] |
foreach {
$computers += "$prefix$_"
}

Write-Output $computers
}

 

using the function generates the server names:

£> . .\expand-servername.ps1
£> expand-servername -computergroup server0[1-5]
server01
server02
server03
server04
server05

 

You can use the reboot script like this:

.\reboot.ps1 -computername (expand-servername -computergroup server0[1-5])

 

If I was doing this for my production environment I would make the reboot script into an advanced function that accepted pipeline input. The reboot and expand-servername functions would be part of a module that could auto load. Alternatively. make expand-servername part of a module that you auto load. You could expand the options in expand-servername to accomodate multiple patterns of names.

under: PowerShell original