# PowerShell – Returning one object from a function as an Array

Few weeks had passed since I’ve initially written PowerShell – Few tricks about HashTables and Arrays I wish I knew when I started. I was happily using my tips and tricks myself till today when I noticed a strange problem. Do you know how I showed you that you could use a comma to return Array with just one member (that otherwise would be unwrapped and end up a string)?

blog

08 Mar 2019 es

![PowerShell – Returning one object from a function as an Array](/wp-content/uploads/2019/03/img_5c822ceaa1fb2.png)

[Ver imágenes (8)](#pf-content-image-1-0)

Few weeks had passed since I've initially written **[PowerShell – Few tricks about HashTables and Arrays I wish I knew when I started](https://evotec.xyz/powershell-few-tricks-about-hashtable-and-array-i-wish-i-knew-when-i-started/)**. I was happily using my **tips and tricks** myself till today when I noticed a strange problem. Do you know how I showed you that you could use a comma to return **Array** with just one member (that otherwise would be unwrapped and end up a string)?

```powershell
function Show-ThirdExample {
    param(
        [string[]] $Test
    )
    [Array] $Output = foreach ($my in $Test) {
        $my
    }
    # I want to do something with value before returning
    if ($Output -is [array]) {
        Write-Color 'Array' -Color Green
    }
    # Actually returning
    , $Output
}
```

[!\[PowerShell console output from Show-ThirdExample demonstrating the array-preserving return pattern\](/wp-content/uploads/2019/03/img_5c81861eeccc5.png)](/wp-content/uploads/2019/03/img_5c81861eeccc5.png)

```powershell
Write-Color 'Example 3' -Color Cyan
$Value1 = Show-ThirdExample -Test 'one', 'two'
$Value1 -is [array]
$Value2 = Show-ThirdExample -Test 'one'
$Value2 -is [array]
```

Works great right? So I thought till today.

### 💡 The problem

Today I wanted to use one of my functions (**Get-Events**) when working with **ForEach-Object**. You see I usually don't use **ForEach-Object** and I mostly do **foreach**, but today I wanted to show someone trick that I've shared on**[PowerShell – Everything you wanted to know about Event Logs and then some](https://evotec.xyz/powershell-everything-you-wanted-to-know-about-event-logs/)** but instead of using **Get-WinEvent** I tried to use **Get-Events**.

```powershell
$FilterHashTable = @{
    LogName   = 'Application'
    ID        = 1534
    StartTime = (Get-Date).AddHours(-1)
    EndTime   = Get-Date
}


$Events = Get-WinEvent -FilterHashtable $FilterHashTable | ForEach-Object {
    $Values = $_.Properties | ForEach-Object { $_.Value }

    # return a new object with the required information
    [PSCustomObject]@{
        Time      = $_.TimeCreated
        # index 0 contains the name of the update
        Event     = $Values[0]
        Component = $Values[1]
        Error     = $Values[2]
        User      = $_.UserId.Value
    }
}

$Events | Format-Table -AutoSize
```

The trick is related to how you can read hidden properties from **Event**, but for this post, we're carrying only about the use of **ForEach-Object** and how it's used in this case. It basically uses **Get-WinEvent** to get events from event log and as they show up it passes it thru pipeline creating **PSCustomObject**, finally saving it in **$Events** variable. Seems easy enough. But when I've run this on my own functions I was getting strange results.

```powershell
$FilterHashTable = @{
    LogName = 'Security'
    ID      = 4625
}
Write-Color 'Get-WinEvent', ' - ', ' ForEach' -Color Yellow, White, Green
$WinEvent = Get-WinEvent -FilterHashtable $FilterHashTable -MaxEvents 3 -ComputerName 'AD1.AD.EVOTEC.XYZ'
foreach ($Event in $WinEvent) {
    $Event.TimeCreated.Count
    $Event.ProviderName.Count
}
Write-Color 'Get-WinEvent', ' - ', ' ForEach-Object' -Color Yellow, White, Green
Get-WinEvent -FilterHashtable $FilterHashTable -MaxEvents 3 -ComputerName 'AD1.AD.EVOTEC.XYZ' | ForEach-Object {
    $_.TimeCreated.Count
    $_.ProviderName.Count
}
```

The code above is a simplified version for testing behavior of **ForEach-Object** and **ForEach**. I asked for three events from Event Log and I'm simply checking Count for two variables.

[!\[PowerShell output comparing Get-WinEvent behavior in ForEach and ForEach-Object loops\](/wp-content/uploads/2019/03/img_5c818a216b5bb.png)](/wp-content/uploads/2019/03/img_5c818a216b5bb.png)

Results aren't really surprising, and that's what I expected. The same test for **Get-Events** (**[PSEventViewer PowerShell Module](https://evotec.xyz/hub/scripts/pseventviewer-powershell-module/)**) went slightly surprising.

```powershell
$MyData = @{
    LogName   = 'Security'
    ID        = 4625
    Machine   = 'AD1.ad.evotec.xyz'
    MaxEvents = 3
}

Write-Color 'Get-Events', ' - ', ' ForEach' -Color Yellow, White, Green
$Events = Get-Events @MyData
foreach ($Event in $Events) {
    $Event.TimeCreated.Count
    $Event.ProviderName.Count
}
Write-Color 'Get-Events', ' - ', ' ForEach-Object' -Color Yellow, White, Green
Get-Events @MyData | ForEach-Object {
    $_.TimeCreated.Count
    $_.ProviderName.Count
}
```

[!\[PowerShell output showing Get-Events returns inconsistent counts when piped to ForEach-Object\](/wp-content/uploads/2019/03/img_5c818b1b5506f.png)](/wp-content/uploads/2019/03/img_5c818b1b5506f.png)

For a moment I thought that maybe my **PowerShell foo** is failing me and I just don't know how to use **ForEach** properly but it seems it's related to **comma** operator that I was so happy to brag about earlier on. To confirm my suspicion about comma I've decided to use my old example.

```powershell
function Show-ThirdExample {
    param(
        [string[]] $Test
    )
    [Array] $Output = foreach ($my in $Test) {
        $my
    }
    # I want to do something with value before returning
    if ($Output -is [array]) {
        Write-Color 'Array' -Color Green
    }
    # Actually returning
    , $Output
}
```

[!\[PowerShell test output confirming the comma operator affects how a single returned array is handled\](/wp-content/uploads/2019/03/img_5c81a305792ef.png)](/wp-content/uploads/2019/03/img_5c81a305792ef.png)

```powershell
function Show-ThirdExample {
    param(
        [string[]] $Test
    )
    [Array] $Output = foreach ($my in $Test) {
        $my
    }
    # I want to do something with value before returning
    if ($Output -is [array]) {
        Write-Color 'Array' -Color Green
    }
    # Actually returning
    , $Output
}


Write-Color 'Example - ForEach (two elements)' -Color Cyan
$Value1 = Show-ThirdExample -Test 'one', 'two'
foreach ($Value in $Value1) {
    $Value.Count
}
Write-Color 'Example - Foreach (one element)' -Color Cyan
$Value2 = Show-ThirdExample -Test 'one'
foreach ($Value in $Value2) {
    $Value.Count
}
Write-Color 'Example - ForEach Object' -Color Cyan
Show-ThirdExample -Test 'one', 'two' | ForEach-Object {
    $_.Count
}
```

[!\[Console output comparing ForEach and ForEach-Object results when a comma is used to return an array\](/wp-content/uploads/2019/03/img_5c81a3b048eab.png)](/wp-content/uploads/2019/03/img_5c81a3b048eab.png)

Testing my idea proves that for some reason (**unknown to me**) using a comma to preserve **Array** is making **ForEach-Object** unusable. **ForEach** works just fine. While I can continue using it that way, most likely someone will use **ForEach-Object** and will get wrong results. So how do I fix it?

```powershell
function Show-ThirdExample {
    param(
        [string[]] $Test
    )
    [Array] $Output = foreach ($my in $Test) {
        $my
    }
    # I want to do something with value before returning
    if ($Output -is [array]) {
        Write-Color 'Array' -Color Green
    }
    # Actually returning
    @($Output)
}


Write-Color 'Example - ForEach (two elements)' -Color Cyan
$Value1 = Show-ThirdExample -Test 'one', 'two'
foreach ($Value in $Value1) {
    $Value.Count
}
Write-Color 'Example - Foreach (one element)' -Color Cyan
$Value2 = Show-ThirdExample -Test 'one'
foreach ($Value in $Value2) {
    $Value.Count
}
Write-Color 'Example - ForEach Object' -Color Cyan
Show-ThirdExample -Test 'one', 'two' | ForEach-Object {
    $_.Count
}
```

As you can see above, this gives proper result when it comes to **ForEach-Object** vs. **ForEach**. But if we will check what is returned it isn't **Array** for one element anymore.

[!\[PowerShell output after switching to at-parentheses array wrapping, restoring loop behavior but not single-item array typing\](/wp-content/uploads/2019/03/img_5c822ceaa1fb2.png)](/wp-content/uploads/2019/03/img_5c822ceaa1fb2.png)

### 💡 Getting an Array for one element and at the same time preserving ForEach-Object/ForEach consistency

So how do I get what I need? An Array for one or multiple elements and at the same time **ForEach-Object** behaving the same way as **ForEach**?

```powershell
function Show-ThirdExample {
    [OutputType([Array])]
    param(
        [string[]] $Test
    )
    [Array] $Output = foreach ($my in $Test) {
        $my
    }
    # I want to do something with value before returning
    if ($Output -is [array]) {
        Write-Color 'Array' -Color Green
    }
    # Actually returning
    $Output
}

Clear-Host
Write-Color 'Example - ForEach (two elements)' -Color Cyan
$Value1 = Show-ThirdExample -Test 'one', 'two'
foreach ($Value in $Value1) {
    $Value.Count
}
Write-Color 'Example - Foreach (one element)' -Color Cyan
[Array] $Value2 = Show-ThirdExample -Test 'one'
foreach ($Value in $Value2) {
    $Value.Count
}
Write-Color 'Example - ForEach Object' -Color Cyan
Show-ThirdExample -Test 'one', 'two' | ForEach-Object {
    $_.Count
}

Write-Color 'Example - Verify if still array' -Color  Yellow
$Value1 -is [Array]
$Value2 -is [Array]
Write-Color 'Example - Verify if string (one element)' -Color Yellow
$Value2 -is [string]
```

[!\[PowerShell output after adding OutputType Array, preserving array typing and consistent loop behavior\](/wp-content/uploads/2019/03/img_5c822ddc5b47f.png)](/wp-content/uploads/2019/03/img_5c822ddc5b47f.png)

We tell it that the value returned from a function is of type **Array**. As you can notice above I've removed any comma or wrapping into **Array** in function in favor of defining type later on and it seems to work just the way I want it to. Alternatively, you could always go for returning an object with a comma only if it's a single element. This way you get both of worlds.

```powershell
function Show-ThirdExample {
    [OutputType([Array])]
    param(
        [string[]] $Test
    )
    [Array] $Output = foreach ($my in $Test) {
        $my
    }
    # I want to do something with value before returning
    if ($Output -is [array]) {
        Write-Color 'Array' -Color Green
    }
    # Actually returning
    if ($Output.Count -eq 1) {
        , $Output
    } else {
        $Output
    }
}
```

[!\[ForEach vs ForEach-Object\](/wp-content/uploads/2019/03/img_5c8236d1df3db.png)](/wp-content/uploads/2019/03/img_5c8236d1df3db.png)

I still have no explanation why comma operator does what it does when it comes to **ForEach-Object** so if you ever read this and have an answer feel free to contact me and I'll be more than happy to update this article.

## Proyectos relacionados

Proyectos que encajan con las etiquetas, categorías y contenido de este artículo.

[Todos los proyectos](/es/proyectos/)

Buscando proyectos relacionados...

[Volver al blog](/blog)

## Artículos relacionados

- [PowerShell – Few tricks about HashTables and Arrays I wish I knew when I started](/es/blog/powershell-few-tricks-about-hashtable-and-array-i-wish-i-knew-when-i-started/)
- [Check an API write after a PowerShell timeout](/es/blog/verify-uncertain-api-outcomes-powershell/)
- [Compose PDF reports and automate page workflows with PSWriteOffice](/es/blog/automate-pdf-reports-and-page-workflows-pswriteoffice/)

<!-- PowerForge markdown artifact sha256:497710C8243AD947CCF7FC80DCA1A0DB0C2D5FDD600107439177F21729529839 -->
