Search code examples
powershellfor-loopactive-directoryio-redirectiontxt

Mapping Multiple IDs to their Email Address in Active Directory and Outputting Results to a Single File


I am trying to find a method to map IDs of multiple users to their associated email addresses in Active Directory (AD), and subsequently append the outputs into a txt file, ultimately generating a single file with a list of email addresses. Via the following command leveraging PowerShell AD Tools, I can output the email address of a certain user:

$user= testID
Get-ADUser $user -server ml -Properties * | Select-Object mail

Now I'm trying to adapt this to work across multiple users, although the method I've come across does not append or concatenate each result to the txt file. Each new output when the loop iterates overwrites the contents of the existing text file.

$multiple_users = "testID1", "testID2", "testID3"
foreach ($multiple_user in $multiple_users){
    Get-ADUser $multiple_user -server ml -Properties * | Select-Object mail > ID_to_email.txt
    }

Any direction or insight, is much appreciated!

Thank you


Solution

  • Building on Abraham Zinala's helpful comment:

    The immediate fix is to replace > with >> inside your foreach loop:

    • Redirection > is in effect an alias for Out-File therefore replaces the target file in every iteration, which is not what you want.

    • By contrast, >> is in effect an alias for Out-File -Append and therefore appends to the target file.

    However, using >> inside a loop is best avoided, because it is:

    • inefficient, because the target file must be opened and closed in every iteration.

    • inconvenient, in that you must ensure that the target file doesn't exist yet or is empty before the loop, so as not to accidentally append to preexisting content.

    Therefore, it is preferable to use a pipeline with a single Out-File call / > operation that receives the output from all iterations in a streaming fashion:

    Note:

    • A foreach statement cannot directly be used in a pipeline and therefore with a redirection, which is why the similar ForEach-Object cmdlet is used below, to which the $multiple_users array is piped, causing its elements to be processed one by one, as reflected in the automatic $_ variable.

    • Alternatively, you can wrap a statement such as foreach or while in & { ... } or . { ... } to allow it to participate in a pipeline; e.g.:
      & { foreach ($i in 1..2) { $i } } > out.txt

    • The solution below applies analogously to use of the Set-Content cmdlet (which is more efficient than > / Out-File if you know the objects to write to the file to be strings already): use a single Set-Content call at the end of the pipeline (instead of calling Add-Content in every loop iteration).

    $multiple_users | 
      ForEach-Object {
        Get-ADUser $_ -server ml -Properties mail |
          Select-Object mail
      } > ID_to_email.txt # Write ALL output to ID_to_email.txt
    

    Instead of > ID_to_email.txt, you could use | Out-File ID_to_email.txt instead; explicit use of Out-File is required in the following cases:

    • to force interpretation of the target file path as a literal path, with -LiteralPath, notably if it contains [ and ] (perhaps surprisingly, > and Out-File with the (often positionally implied) -FilePath parameter treat paths as wildcard expressions - see this answer).

    • to control the character-encoding to use for the output file, via the -Encoding parameter.