write-output

Powershell – Writing a parameterized function

As a system administrator or an ITPro we need to run cmdlets to administer our environment. Using powershell, administrating gets pretty easy. But if you have to run same cmdlets again and again for multiple boxes, the process may be tiring or irritating. We need a way  to tell the powershell to do tasks repeatedly, without our intervention (unless it is necessary), and a way to achieve modularity among the tasks that we perform. This can be achieved using functions.

We will be talking about three different types of functions in a three part series. In this blog we will discuss about the simplest form of a function called – Parameterized function.

Lets look at the two cmdlets below:

Get-WmiObject Win32_OperatingSystem -ComputerName vaio | select @{l='ComputerName';e={$_.__SERVER}}, BuildNumber, ServicePackMajorVersion
Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName vaio | select @{l='SysDriveFree(MB)';e={$_.Freespace/1MB -as [int]}}

We can run them in the shell. The problem is that these two commands will return two independent sets of results. Another problem is that the computer name is hard coded.

To achieve modulatity, we can break down the task into 3 steps:

  • We need to get a computer name or several computer names from someplace.
  • We have to retrieve the Win32_OperatingSystem WMI Class.
  • We have to retrieve the Win32_LogicalDisk WMI Class.

Trying to get all the output into a single table

$computername = 'vaio'

$os = Get-WmiObject Win32_OperatingSystem -ComputerName vaio | select @{l='ComputerName';e={$_.__SERVER}}, BuildNumber, ServicePackMajorVersion

$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName vaio | select @{l='SysDriveFree(MB)';e={$_.Freespace/1MB -as [int]}}

Write-Host "Computer`tBuildNumber`tSPVersion`tFreeSpace"
Write-Host "========`t==========`t==========`t========="
Write-Host ("{0}`t{1}`t{2}`t{3}" -f ($os.ComputerName),($os.BuildNumber),($os.ServicePackMajorVersion),($disk.'SysDriveFree(MB)'))

The output format is not that great, but the information is what we need.

What we did in the above code was:

  • We have kept the computer name in a variable.
  • We are using Write-Host to create a table header.
  • We are using -f to format the table row.

Wrapping the code in a function

We want to modularize our code into function, which is a self-contained, stand alone unit of work that we can distribute easily. An easy way make a function is to wrap it in a function declaration, as shown here:

function Get-ServerInfo {

$computername = 'vaio'

$os = Get-WmiObject Win32_OperatingSystem -ComputerName vaio | select @{l='ComputerName';e={$_.__SERVER}}, BuildNumber, ServicePackMajorVersion

$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName vaio | select @{l='SysDriveFree(MB)';e={$_.Freespace/1MB -as [int]}}

Write-Host "Computer`tBuildNumber`tSPVersion`tFreeSpace"
 Write-Host "========`t==========`t==========`t========="
 Write-Host ("{0}`t{1}`t{2}`t{3}" -f ($os.ComputerName),($os.BuildNumber),($os.ServicePackMajorVersion),($disk.'SysDriveFree(MB)'))

}

Parameterizing the function

We need to change something in the function, as we do not want the computer name to always be ‘vaio’. The solution is to change the $computername from a variable into a parameter, which we can do by adding it to a Param() block, at the top of the function.

function Get-ServerInfo {

param {
 $computername = 'localhost'
 }

$os = Get-WmiObject Win32_OperatingSystem -ComputerName vaio | select @{l='ComputerName';e={$_.__SERVER}}, BuildNumber, ServicePackMajorVersion

$disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName vaio | select @{l='SysDriveFree(MB)';e={$_.Freespace/1MB -as [int]}}

Write-Host "Computer`tBuildNumber`tSPVersion`tFreeSpace"
 Write-Host "========`t==========`t==========`t========="
 Write-Host ("{0}`t{1}`t{2}`t{3}" -f ($os.ComputerName),($os.BuildNumber),($os.ServicePackMajorVersion),($disk.'SysDriveFree(MB)'))

}

You can see that, we have set the $computername equal to ‘localhost’. That will now serve as a default value. If someone runs this function without specifying a computer name, the function will target ‘localhost’, which is usually a safe operation.

Now, the function can be given any alternative computer name in any of these ways:

Get-ServerInfo -computername vaio

Get-ServerInfo -comp vaio

Get-ServerInfo vaio

Returning Objects from function

Powershell does not really like text – it likes Objects. What we have been doing so far in our function is attempting to format our output as a text table. By doing so we are working against Powershell’s native capabilities, which we are making it harder to get the output we want. That means, we need to stop trying to output texts and instead output objects.

Because we are getting information from two places – Win32_OperatingSystem and Win32_LogicalDisk, we cannot output either of the objects that we got back from WMI. Instead we will create a new blank object [PSObject], that we can use to combine our four pieces of information. We simply need to create a PSObject and add the information in the form of properties.

function Get-ServerInfo {

param (
 $computername = 'localhost'
 )

 $os = Get-WmiObject Win32_OperatingSystem -ComputerName $computername

 $disk = Get-WmiObject Win32_LogicalDisk -Filter "DeviceID='C:'" -ComputerName $computername

 $obj = New-Object -TypeName PSObject

$obj | Add-Member -MemberType NoteProperty -Name ComputerName -Value $computername
 $obj | Add-Member -MemberType NoteProperty -Name BuildNumber -Value ($os.BuildNumber)
 $obj | Add-Member -MemberType NoteProperty -Name SPVersion -Value ($os.ServicePackMajorVersion)
 $obj | Add-Member -MemberType NoteProperty -Name SysDriveFree -Value ($disk.free / 1MB -as [int])

Write-Output $obj


}

Get-ServerInfo | Format-Table -AutoSize

Here is what we did:

  • We have simplifying the WMI queries.
  • After querying the information, we create a new PSObject and put  it in a variable.
  • To add information to that object, we pipe the object to Add-Member four times.
  • By using, Write-Output, we are writing the final object into the pipeline.
  • The above code also shows the command we can use to call the function.

The above function is infinitely flexible, because it outputs objects instead of text. Example, all of the below are legitimate ways of using the function.

Get-ServerInfo | Format-Table -AutoSize
Get-ServerInfo -computername vaio | Export-Csv info.csv
Get-ServerInfo -comp localhost | ConvertTo-Html | Out-File info.html

 

Advertisement