1

I am trying to write a script to pull all e-mail addresses but I am finding that the output of my first get command is adding alot of white space to the result text file

Get-AdUser -Filter * -Properties * | Select EmailAddress | Out-File "C:\T2\EMailAddresses.txt"

Can anyone tell me what I am doing wrong here?

JRN
  • 269
  • 1
  • 3
  • 19
  • @mklement0 I tried that second suggestion one-liner you have, what does .Trim() do exactly? Is that supposed to take out the blanks or just the extra whitespace before and after all the content? Thanks for the input. – cet51 Sep 07 '21 at 19:30
  • 1
    @cet51, `.Trim()` removes _leading and trailing_ whitespace (all forms), so it wouldn't solve the problem of interior blanks. – mklement0 Sep 07 '21 at 19:33

2 Answers2

1

You are seeing whitespace because not every AD account has a value assigned to that property in your environment so it appears as a blank line, I get the same thing upon a quick test.

This should help.

$Emails = Get-ADUser -Filter * -Properties EmailAddress
$Emails | select EmailAddress | Where {$_.EmailAddress -ne $null} | Out-File "C:\T2\EMailAddresses.txt"
cet51
  • 1,196
  • 2
  • 11
  • 29
  • 1
    A quibble: While it doesn't matter here, it's a good habit to form to [place `$null` on the LHS of equality / inequality operations](https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.core/about/about_Comparison_Operators#-eq-and--ne), because it makes a difference with collections; compare `$null -eq (1, 2)` to `(1, 2) -eq $null`, for instance. – mklement0 Sep 07 '21 at 19:40
  • On a loosely related note: strings _created in PowerShell code_ are never `$null`; if they have "no value", their value is the _empty string_; e.g.: `[string] $str = $null; $null -eq $str` yields `$false`. String-typed object _properties_, however, may contain a true `$null`, and it sounds like that is the case here with the objects output by `Get-ADUser`, right? (I can't personally verify). – mklement0 Sep 07 '21 at 19:42
  • Although the solution provided does remove entries with no values it still does not resolve the white space issue for objects with values so for example jsmith@ms.com comes out as jsmith@ms.comXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX (where X is a white space) I have to then manually remove all of the Xs or white spaces or it breaks the next line of code. Any advice?? – JRN Sep 07 '21 at 19:45
  • The next code lines would be: $Emails = Get-Content "C:\T2\EMailAddresses.txt" Add-PSSnapIn -Name Microsoft.Exchange, Microsoft.Windows.AD ForEach ($Email in $Emails) { New-MailboxExportRequest -Mailbox $Email -FilePath "\\qnap1\archive\exchange_Migration\$Email_Primary_mailbox.pst"; New-MailboxExportRequest -Mailbox $Email -FilePath "\\qnap1\archive\exchange_Migration\$Email_Archive_mailbox.pst" -IsArchive } – JRN Sep 07 '21 at 19:48
  • 1
    @JRN I would recommend giving mklement0 's answer a try, I believe it is better than what I threw together. – cet51 Sep 08 '21 at 11:59
  • @mklement0 there is definitely difference here between using `-ne $null` and `-ne ''`. For the answer I threw together `-ne ''` does not get rid of the blank spaces, but i'm guessing that's because the items being shown are properties and not strings like your answer shows. Is that correct? – cet51 Sep 08 '21 at 12:01
  • 1
    @cet51, yes, the implication is that the `.EmailAddress` property contains an actual `$null` when not set. In my answer, by casting to an array of`[string]`s first, `$null` is converted to `''`, which is why using `-ne ''` to filter out unset properties works. – mklement0 Sep 08 '21 at 12:27
1

td;dr

The following writes all email addresses to the target file, ignoring AD users that don't have one:

([string[]] (Get-AdUser -Filter * -Properties EmailAddress).EmailAddress) -ne '' |
  Set-Content C:\T2\EMailAddresses.txt

By writing just the - non-empty - .EmailAddress property values to the file, you're avoiding the problems that stem from saving for-display formatted object representations, which is what your attempt does (see below).

Note that -ne '' acts as a filter here, because its LHS operand is an array; that is, the result of the operation is the sub-array of those LHS elements that aren't the empty string ('').


As for what you tried:

By using Out-File in combination with objects subject to PowerShell's output formatting system, you're saving a for-display representation of your objects to a file, which, in the case at hand includes a table header, a leading and a trailing blank line and - in Windows PowerShell (but no longer in PowerShell (Core) 7+) - right-space-padding to the full console-line width of each line.

  • Even though you're only asking for one property - EmailAddress - Select-Object outputs not just that property's value for each input object, but a [pscustomobject] instance with an .EmailAddress property, and the resulting objects are implicitly formatted with Format-Table.

  • To get just the EmailAddress property values, use Select-Object -ExpandProperty EmailAddress. The resulting string values are not subject to formatting, so your command would work as intended except that it would still include $null values from those AD users who happen not to have a value stored in their .EmailAddress property.

    • While it often won't matter, for string input it's slightly faster to use Set-Content than Out-File / >; note that in Windows PowerShell you'll end up with different character encodings by default (ANSI vs. UTF-16 LE a.k.a "Unicode") - use the -Encoding parameter as needed; PowerShell Core 7+ fortunately now consistently defaults to BOM-less UTF-8.

    • The - faster, but more potentially memory-intensive - alternative to using Select-Object -ExpandProperty EmailAddress for extracting the EmailAddress property values is to use member-access enumeration ((...).EmailAddress, as shown above).

mklement0
  • 382,024
  • 64
  • 607
  • 775
  • Love the depth and knowledge here. This is great! Maybe someday i'll move on from PS 5.1 – cet51 Sep 08 '21 at 11:50
  • Glad to hear it, @cet51; just to be clear: the solution in this answer works just fine in PS 5.1 (Windows PowerShell) too, but the answer points to some general improvements in PS 6+ (PowerShell (Core)). – mklement0 Sep 08 '21 at 12:22