What does ,() around a pipeline command do?

I came across this example - Moving Data From Excel to SQL Server with PowerShell (Relatively Painlessly) - Red Three Consulting where they showed how the pipeline could be sped up when passing data to SQL Server. They enclosed the first pipeline command in ,( ) and said "It tells PowerShell to complete the first command before sending data to the pipe. " I’ve never seen that before, but it dramatically increased the speed of sending data into SQL Server - taking something that took 20 mins to run to running in just 15 seconds.

Is there a name for this technique? Is ,( ) some short of shorthand for something else? Is this documented anywhere? I don’t know the correct term to Google to find more information on this.

Hi, welcome to the forum :wave:

In all my years loitering on PowerShell forums and looking at other people’s code, I don’t recall ever seeing this technique used. It’s not mentioned in Month of Lunches or PowerShell in Depth (as far as I can tell) and the wonderfully comprehensive Everything you wanted to know about arrays - PowerShell | Microsoft Docs doesn’t mention it either.

It is mentioned in about Operators - PowerShell | Microsoft Docs, under Comma operator but there’s not a lot of explanation.

What is does is create a single element array:

PS E:\Temp> $array = @(1..10)
PS E:\Temp> $array.Count
PS E:\Temp> $array2 = ,(1..10)
PS E:\Temp> $array2.Count

I would be very interested if someone can elaborate on this because I’ve not found very much on how or where to use this.

That helps a lot!

In my code, I have some 38,000 transactions in $transactions, which Get-Member reports as being PSCustomObject.

If I use:

$transactions | Write-SqlTableData ...

… it takes forever to run, and I can see that it is calling SQL Server once for every transaction.

If I use:

,($transactions) | Write-SqlTableData ...

… Get-Member then tells me that ,($transactions) is of type System.Object (an array of objects). I can see it waiting in PowerShell as it builds the array, and then it makes ONE call to SQL Server to do a bulk insert.

The original comment in the article “It tells PowerShell to complete the first command before sending data to the pipe” was a bit misleading but correct. It tells PowerShell to build an array and then send that all at once, so the side effect is that it completes the first command before sending it along.

Also found this in the article you mentioned: About Operators

Grouping Operator ( )
" When used as the first segment of a pipeline, wrapping a command or expression in parentheses invariably causes enumeration of the expression result. If the parentheses wrap a command , it is run to completion with all output collected in memory before the results are sent through the pipeline."

Comma Operator ,
“As a binary operator, the comma creates an array or appends to the array being created. In expression mode, as a unary operator, the comma creates an array with just one member. Place the comma before the member.”

It is also called jagged array, an array of arrays. You use it when you need to group data. Often, you use a pscustomobject or hashtable to group data.

I might have misunderstood but I don’t think that’s quite the same. A jagged array can have more than 1 element but using this operator always creates an array with a single element.

PS E:\Temp> $array = @(1..5),@(6..10)
PS E:\Temp> $array.Count
PS E:\Temp> $array2 = ,(@(1..5),@(6..10))
PS E:\Temp> $array2.Count

You are nesting even more there, because of the extra set of parentheses…

$array2[0][0][0] # first element of 1..5
$array2[0][1][0] # first element of 6..10

There is also a context that I’m forgetting. In this case, it is used to prevent PS from unwrapping / enumerating the data. If the data must be passed as a set instead of one by one then you nest it like this.

Example of use:

$a = 1,2
$a | Get-Member # unwraps and gets members of items in array
,$a | Get-Member # gets members of array