Same Command. Different Return Types.

My command seems to behave differently depending on how many items were returned.

This is something that the PowerShell Team hears from the community or our internal partners every couple of weeks. This blog post will explain when a Windows PowerShell command returns different types and offer some reasons for why it is done this way.

In general, Windows PowerShell commands can return one of three things:

  1. Null (not really a thing, I know)
  2. A single object of a particular type
  3. An array of objects (Object[])

Executing the commands below returned each of the types listed above. 

(Get-Service foobar).GetType()
(Get-Service NetLogon).GetType()
(Get-Service Net*).GetType()

Compare this to executing a WMI query in VBScript. Because you always get an array back, administrators have to litter their scripts with useless for-each loops. An extreme example is shown below, where the WMI query gets the Win32_OperatingSystem class to compute system uptime. It returns an array, even though there can never be multiple Win32_OperatingSystem items.

Set colOperatingSystems = objWMIService.ExecQuery _
    ("Select * from Win32_OperatingSystem")

For Each objOS in colOperatingSystems
    dtmBootup = objOS.LastBootUpTime
    dtmLastBootupTime = WMIDateStringToDate(dtmBootup)
    dtmSystemUptime = DateDiff("h", dtmLastBootUpTime, Now)
    Wscript.Echo dtmSystemUptime
Next

Since Windows PowerShell is also an interactive shell, we wanted to make it very easy for Administrators to work at the command line. A set of Windows PowerShell commands that do the same uptime calculation is shown below. Note that I didn’t have to do any indexing or iterating over a collection.

$os = Get-WmiObject Win32_OperatingSystem
$lastBootup = $os.ConvertToDateTime($os.LastBootUpTime)
$uptime = ((Get-Date) – $lastBootup).TotalHours
Write-Host $uptime

This behavior allows for some fairly lazy, err… convenient interactive console experiences. For example, let’s say that I wanted to get the “Microsoft SharePoint Workspace Audit Service” that is installed on my machine.

Get-ServiceName

Mcx2Svc
Microsoft SharePoint Workspace Audit Service
MMCSS
MpsSvc

I can do that with very little typing:

$svc = Get-Service Mi*

Here I used a wildcard expression (that, in many cases, would return multiple values) but Windows PowerShell returned a single object that I can work with directly.

On the other hand, if you’re writing some scripts or managed code and want to guarantee that you get an array back, we offer the array cast operator @(). More details can be found in an old post by Bruce.

In closing: we can’t (or at least shouldn’t) try to infer what you meant, but at least we can make your life easier in a lot of cases by being smart about what we send back to you.

Travis Jones [MSFT]
Windows PowerShell PM
Microsoft Corporation