$User.Error = "$U not found" | Export-Csv C:\Results.txt -NoTypeInformation -Append -Force
This will be why this doesn’t work. You need to split this line in two:
$User.Error = "$U not found"
$User | Export-Csv C:\Results.txt -NoTypeInformation -Append -Force
Now, as to the other quandary… your main issue here is that you’re opening and closing this file several times a second. There’s absolutely no need for that. Just compile your objects into an array, and have the cmdlet build the file all at once before saving to disk. -Append exists for when you have an existing file that you want to tack on a bunch to, not really meant for building files one piece at a time and saving in between. That much disk I/O will slow everything down, no matter how you do it!
Also, please consider renaming your variables. This is going to give you some grief later. If you come back to this in a month, and already
have to scan through half the script to remember what the variable is for, you need a better name. There’s nothing wrong with
verbose names; the Assembly days are dwindling, and the ability to be verbose is quite valuable.
Additionally, you’ll run into trouble trying to put an object with no properties into a CSV file. CSV files need to have all objects with the same set of properties, so you’ll have to go through and set them to $null in a custom object, and then tack on your error property. All objects will need an error property for it to be exported properly, as well, so we can add it in the Select-Object clause.
$UserList = Get-Content -Path 'C:\UserList.txt'
# Assign a variable to the output of the loop to gather all outputted data into a neat array
$OutputData = foreach ($User in $UserList) {
$PropertyList = 'EmailAddress', 'TelephoneNumber', 'SamAccountName', 'SN', 'GivenName', 'Initials', 'DisplayName', 'CA'
# Braces for -Filter is common, but will give you a lot of grief in many,
# many cases. Just use a plain string; quotes, no braces.
$UserObject = Get-Aduser -Filter "CA -like $User" -Properties $PropertyList -Server $DomainName |
Select-Object -Property $PropertyList, @{
Name = "Error"
Expression = { $null }
} # Adding the error as a null property. If you don't do this, the export will ignore it unless the VERY FIRST object has this property set.
if ($UserObject) {
# 'Drop' the object to output to have the loop pick it up and wrap it into an array for $OutputData variable
# Alternate is to be explicit: Write-Output $UserObject
$UserObject
}
else {
$NullUser = @{}
foreach ($Property in $PropertyList) {
$NullUser[$Property] = $null
}
$NullUser['Error'] = "$User not found"
# Again, output the null user as an object (it's been a simple hashtable up to now)
[PsCustomObject] $NullUser
}
}
# Export the whole thing at once, only one larger disk I/O event
# instead of thousands of tiny ones (less OS file access overhead)
$OutputData | Export-Csv -Path 'C:\Results.txt' -NoTypeInformation