2

In the following Powershell example, how can I get $server to populate within line #5? I'm trying to save the results of a Get-EventLog query to an array for each $server loop iteration.

Example:

$serversArray = @("one", "two", "three")
ForEach ($server in $serversArray) {
  echo $server "Variable array iteration populates here correctly"
  $eventArray = @()
  $eventArray += Get-EventLog -computerName $server #But not here, where I need it
  $eventArray  #Yet it populates from calling the second array correctly
}
  1. I've tried assigning the scope of the $server variable to global or script.
  2. I've researched other similar issues, but none that I could find had this circumstance
  3. I've tried different combinations of piping, quotes, back ticks, etc.

As always, thanks in advance.

Edit Ok, ISE was caching some of the variables (or something strange), as the above example began working after I restarted ISE. Anyways, the issue is with the $servers array input, which in the full script is from a MySQL query. If I statically assign the array with server names (like in the example above) the script works. If I use the input from the MySQL query, Get-EventLog fails with The network path was not found. So even though the server values look correct (and something could be expanding), it could be a text encoding issue, etc. Sorry to waste time, but discussing it has helped narrow it down. Here's the pertinent part of the actual script:

#Open SQL Connection
[System.Reflection.Assembly]::LoadWithPartialName("MySql.Data")
$connectionString = "server=dbserver;uid=odbc;pwd=password;database=uptime;"
$connection = New-Object MySql.Data.MySqlClient.MySqlConnection
$connection.ConnectionString = $connectionString
$connection.Open()
#Get server names from db
$sqlGetServers = "select server_nm from servers limit 3;"
$command = New-Object MySql.Data.MySqlClient.MySqlCommand($sqlGetServers, $connection)
$dataAdapter = New-Object MySql.Data.MySqlClient.MySqlDataAdapter($command)
$dataSet = New-Object System.Data.DataSet
$recordCount = $dataAdapter.Fill($dataSet, "sample_data")
$server_names = @()
$server_names += $dataSet.Tables["sample_data"] 
#$server_names = @("server-1","server-2")  <-- this works
#loop through array of server names
foreach($server in $server_names) {
$eventData = @()
$eventData += Get-EventLog -computerName $server -LogName System -Newest 10
foreach($event in $eventdata) {Do-Stuff}
}
4
  • I cant reproduce your issue. What version of powershell are you using? Commented Aug 17, 2014 at 2:40
  • v3. I've found that the issue is something with the input for $servers, which in the actual script are from a MySQL query. I edited the question to include the original script reflecting this. Commented Aug 17, 2014 at 4:28
  • Try $server_names = $dataSet.Tables["sample_data"] (don't make it an empty array, don't use +=. Then run $server_names | gm and look at what it is. There's probably a property that you can use (likely the column name) to access the actual string you want. Commented Aug 17, 2014 at 5:39
  • @briantist Ok, I finally got it. The data type from the SQL query loses it's formatting when it's passed through the loop. Through your suggestion, I found the property in $server_names | gm and used select, and it worked: $server_names += $dataSet.Tables["sample_data"]| Select -Expand "server_nm" Thank you again. Choosing your answer below because I still needed to pipe the output of the array to ForEach-Object for it to work, which you originally suggested. Commented Aug 17, 2014 at 15:08

2 Answers 2

5

I am not 100% certain what the problem is that you're having. I am assuming that the issue is that your $eventArray ends up with just the last result.

If that is correct, then the reason is because you're reinitializing it as empty on every iteration in line 4: $eventArray = @()

Try this:

$serversArray = @("one", "two", "three")
$eventArray = @()
ForEach ($server in $serversArray) {
  echo $server "Variable array iteration populates here correctly"
  $eventArray += Get-EventLog -computerName $server #But not here, where I need it
  $eventArray  #Yet it populates from calling the second array correctly
}

or, alternatively, with ForEach-Object like this:

$serversArray = @("one", "two", "three")
$eventArray = $serversArray | ForEach-Object {
  echo $_ "Variable array iteration populates here correctly"
  Get-EventLog -computerName $_ #But not here, where I need it
  #Yet it populates from calling the second array correctly
}

Explanation for Method 1:

Declaring $eventArray as an empty array before the loop starts, then adding items to it within each iteration of the loop, as opposed to initializing it on every iteration.

The way you had it, $eventArray would be reset to an empty array every time, and in the end it would just contain the last result.

Explanation for Method 2:

ForEach-Object is a pipeline cmdlet and returns the result of its code block (which is run once for each object piped into it.

In this case we use $_ to represent the individual object. Instead of assigning the result of Get-EventLog to $eventArray, we simply call it, allowing the return value to be returned from the block.

We assign the entire ForEach-Object call into $eventArray instead, which will end up with the collection of results from the entire call.

Sign up to request clarification or add additional context in comments.

5 Comments

I wasn't clear on what it wasn't doing. The variable $server isn't expanded; it's literally $server (or $_ when using ForEach-Object). I see your point about declaring the empty array, but in this case I want to clear the results of the previous server's events before it populates with the next server's results. Thanks.
And as I mentioned above, this variable will not expand on line 5 with all forms of loops that I have tried here. It must be something specific to array population, because if I call it within the loop but not using $eventArray += it expands correctly.
Try wrapping it in parentheses like this $eventArray += (Get-EventLog -computerName $server) or even wrappin git in $() like this: $eventArray += $(Get-EventLog -computerName $server)
Still no dice. Interestingly, the variable $server is populating the actual array elements correctly; if I call $eventArray after running the above, it outputs the server names. It just that my "array member" in this case is doubling as a command (Get-EventLog) and as a means to capture the output (the actual script captures the events queried). I'll look at changing the structure.
See eventual solution above in comments below original question.
2

Instead....

$serversArray = @("one", "two", "three")
$eventArray = @()
$serversArray | ForEach-Object {
  echo $_ "Variable array iteration populates here correctly"
  $eventArray += Get-EventLog -computerName $_ #But not here, where I need it
  $eventArray  #Yet it populates from calling the second array correctly
}

Pipe the array into a for-each loop. then you can use $_

3 Comments

The other answer then might be more viable. What happened with this answer? Was there and error or was $eventarray not populated?
Using ForEach-Object on the code above still returns the literal $_ and not the subsitution on line 5. I also tried with the clunkier for ($i=0; $i -le $serversArray.length-1; $i++) with the same result. Is there something specific to array population that is preventing this?
Not that im aware of. Maybe it needs to be $($_) but that just seems silly

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.