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
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.