how can i make foreach output two different files?

时间:2018-09-18 20:03:25

标签: sql-server powershell

I have this variable

$sync_output = Join-Path $syncPATH $CUBE_input

I have this foreach loop:

$i=0
$Destination_Server = @()

foreach($row in $Table | where { $_.cube_name -match $CUBE })
{   
    $i++
    $Destination_Server += $row.Item("query_server")
    write-host " > Query Server $($i):" $Destination_Server[$Destination_Server.length -1]
    $sync_output += "_$Destination_Server.txt"
    Invoke-ASCmd –InputFile $XML_file -Server $Destination_Server[$Destination_Server.length -1] >$sync_output
}

it does what it needs to do, except for the sync_output, I am getting this created:

enter image description here

as you can see, the first file,

CUBE_Destination_Server1

is perfectly created.

however, the second file, should be named

CUBE_Destination_Server2

but instead its for some reason appending the Destination_Server2 after appending Destination_Server1 twice...

Why is that?

2 个答案:

答案 0 :(得分:2)

The += operator appends. So this line:

$sync_output += "_$Destination_Server.txt"

takes the existing value of $sync_output and then adds "_$Destination_Server.txt" onto the end.

One way to get your desired result is to assign (not append) $syncResult inside your loop, with a statement like this:

$sync_output = (Join-Path $syncPATH $CUBE_input) + "_$Destination_Server.txt"

Update: it looks like you have a similar problem with the $Destination_Server variable--you should use plain assignment (=) with it too, rather than appending (also called concatenation) (+=).

答案 1 :(得分:1)

The string is appending, because that is what you told it to do.

Straight up, the += says to add the new content at the end, so in the case of

$sync_output = Join-Path $syncPATH $CUBE_input
...
$sync_output += "_$Destination_Server.txt"

It sets a string, and then appends things to the end of that string, and keeps appending to it each time that command is executed when the ForEach-Object loop cycles. This is compounded by your other use of +=, which is appending objects into an array, since you setup $Destination_Server = @() which sets that variable as an empty array. So when you append to your string you are appending an entire array to that string.

So to replicate your example:

$sync_output = 'CUBE'
$destination_server = @()

Then inside the loop on the first pass you add a string to the array:

$destination_server += 'Destination_Server1'

So that array has 1 item in it. You then add that array to $sync_output which expanding the variables basically reads like:

"CUBE" += "_Destination_Server1.txt"

So now $sync_output has a value of CUBE_Destination_Server1.txt. Next iteration of the loop! You add another string to the $Destination_Server array:

$destination_server += 'Destination_Server2'

Now that array has 2 strings in it, so when you append it to the $sync_output string variable you essentially are doing this:

"CUBE_Destination_Server1.txt" += "_Destination_Server1Destination_Server2.txt"

It does that because the array of strings simply concocts all of the strings in its array into one string. In order to really fix this you need to be consistent and reference the last string in the array. I recommend not re-using the same variable for this, and will use $sync_output_file.

$sync_output = Join-Path $syncPATH $CUBE_input
$i=0
$Destination_Server = @()

foreach($row in $Table | where { $_.cube_name -match $CUBE })
{   
    $i++
    $Destination_Server += $row.Item("query_server")
    write-host " > Query Server $($i):" $Destination_Server[$Destination_Server.length -1]
    $sync_output_file = $sync_output + '_' + $Destination_Server[-1] + '.txt'
    Invoke-ASCmd –InputFile $XML_file -Server $Destination_Server[$Destination_Server.length -1] >$sync_output_file
}

Edit: Here's why $Destination_Server[$Destination_Server.length - 1] works like $Destination_Server[-1]:

In PowerShell an each item in an array has an index. That index is zero based. You can reference an item in the array by its index number as such $Array[X] where X is the index number of the item you are interested in. So given this array:

$MyArray = 'cat','dog','fish','goat','banana'

If you reference $MyArray[0] it will return cat, since that is the first item in the array. With arrays in PowerShell the .length and .count properties are synonymous, so when you reference $MyArray.length you are simply getting the count of items in the array. When you count items you start at 1, but array indexes start at 0, which is why you have to do .length - 1 to get the index number of the last item in the array. In my example if we do $MyArray.Length it would return 5, because my array has 5 items in it. So $MyArray[$MyArray.Length - 1] is essentially $MyArray[5 - 1], or $MyArray[4], which is the last item in $MyArray.

In addition to referencing items by index you can also use negative numbers, which will start at the end of the array, and count backwards. This method is not zero based, so $MyArray[-1] references the last item in the array, just like $MyArray[-2] is the second to the last item in the array.

So the difference between $MyArray[$MyArray.length - 1] and $MyArray[-1] is that in the first you calculate the index number for the last item in the array, where the second references the last item in the array regardless of what its index number is.

You can also specify ranges this way, so $MyArray[0..2] would get you the first 3 items in the array, and $MyArray[-2..-1] would get you the last 2 items in the array. That doesn't really apply to your situation right now, but it's handy to know in general and might be helpful in the future for you.

相关问题