Take the 2-minute tour ×
Stack Overflow is a question and answer site for professional and enthusiast programmers. It's 100% free, no registration required.

I'm sure this is an easy one, but it's got the better of me this afternoon (I'm relatively new to Powershell). Also, I'm fairy sure my code could be more elegant.

To start with, I've got some code that goes to our exchange servers, and returns sent messages from a particular user. It puts this into an array called @Results. So, a few entries will look like this (edited for privacy):

C:\Windows\system32>$Results[3..5]

Timestamp         MessageSubject        Recipients
---------         --------------        ----------
01/09/2013 09:12:57   Subject1      {[email protected]}
01/09/2013 09:30:44   Subject2      {[email protected]}
01/09/2013 09:42:11   Subject3      {[email protected], recipient2@gmail...

So, I'm pretty happy with this. However, my issue is with the multiple recipient lists above. Effectively, this is its own array. From the list of sent mail, I'm not interested in internal mail, so I'd like to exclude entries with our domain on them (let's say it's globocorp.com above). So, my solution was to have a couple of loops to list out all the entries as their own lines. This is where I've got to:

For ($k=0; $k -eq $Results.count; $k++)
    {
    For ($j=0; $j -eq $Results[$k].Recipients.Count; $j++)
        {write-host $Results[$k].timestamp, $Results[$k].Recipients[$j], $Results[$k].MessageSubject 
        }
    }

This works, but uses a couple of loops which I think is inelegant. There must be a tidier way of achieving the above (maybe the for-each command?). My main issue is, however, what to do with the output. I don't want to use 'write-host' and would rather create the outputs as objects which I can then tabularise or create a csv from it. I can then use the 'where-object ToUpper(Recipients) -notlike "*@GLOBOCORP.COM"'function to exclude internal mail.

However, I can't just list the output, then pipe it as I get the 'empty pipe element not allowed' error, and listing out the objects sticks each entry on a new line, i.e.:

04 September 2013 18:19:12
[email protected]
Message subject

Any advice greatly appreciated!

share|improve this question

3 Answers 3

I would create (in fact re-create) a flattened object like this:

Foreach ($result in $Results) { 
    foreach ($recipient in $result.recipients) {
        if ($recipient -notmatch '@globalcorp.com') {
            [PSCustomObject]@{
                TimeStamp = $result.timestamp;
                MessageSubject = $result.MessageSubject;
                Recipient = $recipient 
            }
        }
    }
}

At the end of that, you will end up with (series of) a new object for each recipient excluding internal email.

If you expect the number of results to be fairly large so that you can encounter memory issues, then you might avoid foreach and instead use "pipe" losing on speed:

$Results| % { 
    $result = $_;
    foreach ($recipient in $result.$recipients) {
        if ($recipient -notmatch '@globalcorp.com') {
            [PSCustomObject]@{
                TimeStamp = $result.timestamp;
                MessageSubject = $result.MessageSubject;
                Recipient = $recipient 
            }
        }
    }
}
share|improve this answer

Something like this might work:

$Results | % {
  foreach ($recipient in $_.Recipients) {
    if ($recipient -notlike '*@globocorp.com') {
      Write-Host $_.Timestamp, $recipient, $_.MessageSubject
    }
  }
}

or like this:

$Results | % {
  $timestamp = $_.Timestamp
  $subject   = $_.MessageSubject
  $_.Recipients | ? { $_ -notlike '*@globocorp.com' } | % {
    Write-Host $timestamp, $_, $subject
  }
}
share|improve this answer
$Results | 
Foreach-Object {$Entry=$_;$Entry.Recipeints |
    Where-Object {$_ -notlike '*@globocorp.com'} | 
    Foreach-Object {Write-Output ([PSCustomObject]@{TimeStamp=$Entry.TimeStamp;MessageSubject=$Entry.MessageSubject;Recipeint=$_)}}
}

It's pretty much the same thing that you did except it's using the power of the PIPE with foreach-ing and where-ing. It's pretty easy to create custom objects just use the [PSCustomObject] accelerator. It takes a hash table. Now you should be able to export to a cvs, just add this at the end | Exprot-CSV C:\foo.csv

Hope this helps. Get great PS tips here.

share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.