Writing an array to a specific csv column with powershell - powershell

I have a csv file that has a lot of data in it, with one column being a "Username" column. I created a loop to query AD and get each username and now I need to export each of those names to the specific column in the csv. After importing the csv with:
$data = Import-CSV .\data.csv
And using the loop:
foreach($user in $data)
And I use get-aduser $user -server $server and if($? -eq $true){ $user = $user + "01" }
I tried using
$data.Username | Export-CSV .\data.csv and $data.Username | out-file .\data.csv
but so far neither have worked.

You need to keep all the information in the pipeline so you can re-export the whole thing.
Try something like this:
$data | Foreach {
get-aduser $_.Username -server $server
if($? -eq $true){ $_.Username = $_.Username + "01" }
} | export-csv .\data.csv

Related

Compare User AD and CSV file column Powershell

I'm not really good in Powershell, I try to write a script to compare a column "User" in a CSV with my all user AD.
I need to get all users in the CSV where not in our AD.
Here what I have wrote :
$csvfile = Import-CSV USERAccountstocompare.csv
$alladusers = Get-ADUser -Filter * | Select sAMAccountName
foreach($user in $alladusers){
$userAD = $alladusers.SamAccountName
foreach($usercsv in $csvfile){
if ($usercsv | where {$_.user -ne "$userAD"}){ write "$usercsv"}
else{}
}
}
When I put a write $usercsv before the if command; I get the good user
but after the if, it write all user with #{User= before, like "#{User=username}" so the comparison not working.
You don't need a foreach loop for this; just filter with Where-Object.
Assuming the User column in the CSV contains SamAccountNames:
$csvUsers = Import-Csv -Path 'D:\Test\USERAccountstocompare.csv'
$allADUsers = Get-ADUser -Filter * | Select-Object -ExpandProperty sAMAccountName
$notADUsers = $csvUsers | Where-Object { $allADUsers -notcontains $_.User }
# output on screen
$notADUsers | Format-Table -AutoSize
# output to new CSV file
$notADUsers | Export-Csv -Path 'D:\Test\UsersNOTinAD.csv' -NoTypeInformation
$alladusers = Get-ADUser -Filter * | Select sAMAccountName is not a very good idea if the Domain you are working on is big. Using Where-Object is also not a very good idea for filtering big objects, there was a really cool article in powershell.org where Dave Wyatt and Don Jones explained the different ways of filtering an object and their efficiency, sadly it was removed for some reason.
I would do something like this, assuming your Csv has a column 'User' for each user:
$result=New-Object System.Collections.ArrayList
#result array will be only the user that do not exist in AD
$csvfile = Import-CSV USERAccountstocompare.csv
foreach($line in $csvfile.User)
{
$filter="(|(Name=$line)(samAccountName=$line))"
$adusr=Get-ADuser -LDAPFilter $filter
if(!$adusr)
{
$result.add($line) > $null
}
}
If instead, you wanna have a list of the users that are on the Csv and on AD and those that are only in the Csv you could do something like this:
$result=New-Object System.Collections.ArrayList
#result array will be only the user that do not exist in AD
$csvfile = Import-CSV USERAccountstocompare.csv
foreach($line in $csvfile.User)
{
$filter="(|(Name=$line)(samAccountName=$line))"
$adusr=Get-ADuser -LDAPFilter $filter
if(!$adusr)
{
$result.add(
[pscustomobject]#{
'Not In AD'=$line
}) > $null
}
else
{
$result.add(
[pscustomobject]#{
'In AD and Csv'=$line
}) > $null
}
}

use samaccountnames to export user properties(mainly just first name and lastname) to csv file

I have a CSV file containing the samaccount name of some users.
From this list, I want to export the properties of these users to a CSV file.
Kindly share the simplest possible way to do so in Windows Powershell ISE.
I have tried this :
Import-ModuleActiveDirectory
Import-CSV C:\scripts\list.csv | ForEach{Get-ADUser -Identity $samaccountname-Filter*-Properties*|export-csv c:\ADusers.csv
}
Thank you!
You didn't show us the first couple of lines of the CSV file.
A proper CSV file has multiple fields and a header line like this:
"AccountName","EmailAddress"
"doe","john.doe#example.com"
"kent","clark.kent#example.com"
If this is the case, do:
Import-ModuleActiveDirectory
$userProperties = 'GivenName', 'SurName', 'Initials'
Import-Csv -Path "C:\Scripts\List.csv" | ForEach-Object {
$user = Get-ADUser -Filter "SamAccountName -eq '$($_.AccountName)'" -Properties $userProperties -ErrorAction SilentlyContinue
if ($user) {
$user | Select-Object -Property $userProperties
}
} | Export-Csv "C:\ADUsers.csv"
If the file you load only has SamAccountNames each listed on a new line, then this is not a CSV file and you should use:
Import-ModuleActiveDirectory
$userProperties = 'GivenName', 'SurName', 'Initials'
Get-Content -Path "C:\Scripts\List.csv" | ForEach-Object {
$user = Get-ADUser -Filter "SamAccountName -eq '$_'" -Properties $userProperties -ErrorAction SilentlyContinue
if ($user) {
$user | Select-Object -Property $userProperties
}
} | Export-Csv "C:\ADUsers.csv"
As you can see, I'm not using the -Identity parameter here, because in case a user with that SamAccountName is not found, an exception is thrown.
This way, output is only generated when the user actually exists.
Also, it is a bad idea to use -Properties * when you only want some of the properties returned.
Hope that helps
if you wanna do this in the ISE, you probably dont need/want to use oneliner for that.
I would suggest to import the CSV first, and then run foreach.
$list = Import-CSV -path $filePath
$result = New-Object System.Collections.ArrayList
foreach ($name in $list){
$adUser=Get-ADUser -Identity $name
$result += $adUser
}
From here, you can start thinking of error handling etc.
This will help you:
Import-ModuleActiveDirectory
Import-CSV -Path "C:\Scripts\List.csv" | Foreach {
Get-ADUser -Identity $_ -Filter * -Properties *
} | Export-CSV "C:\ADUsers.csv"
Your code was not working because $samaccountname was empty and blank not containing the username. So I replaced it with the automatic variable $_
Put each SamAccountName on its own line in the list file.
Example:
user1
user2
user3
Change list.csv to a text file (list.txt) and try this:
$username = Get-Content "C:\scripts\list.txt"
ForEach($user in $username){
Get-ADUser -Identity $user | Select GivenName,Surname,Initials | Export-CSV -Path "C:\ADUsers.csv"
}

Exporting Membership groups for users from input file

I have this script that reads samaccountnames from a file and outputs the name of the user with its membership information. However, the output file only shows the last record. It seems that my code is overwriting the previous record. What am I missing? Thank you so much.
ForEach ($user in $(Get-Content -Path C:\MyScripts\UsersInput.csv))
{
$username = Get-ADUser –Identity $user -Properties *
Get-ADPrincipalGroupMembership $user | select $username.DisplayName, name |
export-csv "C:\MyScripts\UsersAndTheirADGroups.csv" -NoTypeInformation
}
Export-Csv has an -append parameter, so you could use that. ie it would append to the csv file with every iteration of the loop. You would need to make sure the file didn't exist before you start the loop or it would just get bigger and bigger each time you ran the code.
Another way it to add the items to an object and then export that at the end. ie $username += Get-ADUser......
You are reading a CSV file using Get-Content. This lets me think the file is simply a list of user SamAccountNames, each on a separate line. No headings.
Something like this perhaps:
jdoe
jsmith
If that is the case, read the input file like this:
$users = Get-Content -Path 'C:\MyScripts\UsersInput.csv'
To get an array of user SAMAccountnames.
If however it is a proper CSV file with headers, looking something like this:
"SamAccountName","Email","More","Stuff"
"jdoe","john.doe#yourdomain.com","blah","blah"
"jsmith","jane.smith#yourdomain.com","blah","blah"
Then you should use the Import-Csv cmdlet to get the entries as objects and obtain an array of SamAccountNames from that:
$users = Import-Csv -Path 'C:\MyScripts\UsersInput.csv' | Select-Object -ExpandProperty SamAccountName
Once you have that array, loop through it and get the group membership info for each user
Untested
$result = foreach ($accountName in $users) {
Get-ADUser –Identity $accountName -Properties DistinguishedName, DisplayName |
Select-Object #{Name = 'User'; Expression = {$_.DisplayName}},
#{Name = 'Groups'; Expression = { ( $_ | Get-ADPrincipalGroupMembership | Select-Object -ExpandProperty name) -join ', '}}
}
$result | Export-Csv "C:\MyScripts\UsersAndTheirADGroups.csv" -NoTypeInformation
You are indeed overwriting the code ForEach user. You included Export-Csv in the ForEach. Instead export the whole array that ForEach creates:
ForEach ($user in $(Get-Content -Path C:\MyScripts\UsersInput.csv))
{
$username = Get-ADUser –Identity $user -Properties *
Get-ADPrincipalGroupMembership $user | select $username.DisplayName, name
} | export-csv "C:\MyScripts\UsersAndTheirADGroups.csv" -NoTypeInformation

Export data based on foreach login [Powershell]

I have simple csv file with column 'logins'
logins
john
mark
maria
...
Have powershell script to check their last logontime:
Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$userName)
{
$time = 0
$user = Get-ADUser $userName | Get-ADObject -Properties lastLogon
if($user.LastLogon -gt $time)
{
$time = $user.LastLogon
}
$dt = [DateTime]::FromFileTime($time)
Write-Host $username $dt }
import-csv -Encoding UTF8 -path C:\scripts\loginy.csv | foreach {
Get-ADUserLastLogon -UserName $_.logins
}
This works fine with output
john 2018-05-10 14:11:28
mark 2018-11-29 14:26:58
maria 2018-11-02 11:14:17
...
When I try to export results it to csv file by code
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
$results = #()
foreach ($_.logins in $users) {
$results += Get-ADUserLastLogon -UserName $_.logins
}
$results | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
getting error
At C:\scripts\OstatnieLogowanie.ps1:19 char:12
+ foreach ($_.logins in $users) {
+ ~
Missing 'in' after variable in foreach loop.
At C:\scripts\OstatnieLogowanie.ps1:19 char:29
+ foreach ($_.logins in $users)
}
I can't get it work over 2 hours :/
Edit: I've confused LastLogon and LastLogonTimestamp. LastLogonDate is based on LastLogonTimestamp. The differences between these properties are explained here and here. I will come back and update my answer.
You're using Write-Host to output data:
Write-Host $username $dt
This won't work. Write-Host means "write to the console screen, not to standard output." That will work just fine if you're trying to display data, but calling $x = Get-ADUserLastLogon -UserName $login will print the results to the console screen and nothing would be assigned to the $x variable. For example:
PS C:\> $x = Write-Host 0
0
PS C:\> $x
PS C:\>
See how Write-Host still wrote to the console and $x doesn't have a value?
Your function should look something like $username, $dt or Write-Output $username, $dt or return $username, $dt.
Although that's still not really going to work like you want. I would probably use a custom object (see Get-Help about_Object_Creation -ShowWindow) like this:
Import-Module ActiveDirectory
function Get-ADUserLastLogon([string]$userName) {
$user = Get-ADUser $userName -Properties LastLogonDate
[PSCustomObject]#{'Logins' = $username; 'LastLogonDate' = $user.LastLogonDate}
}
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
$results = foreach ($user in $users) {
Get-ADUserLastLogon -UserName $user.logins
}
$results | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
Frankly, however, if I were doing what you're trying to do here, my actual code would look like this:
Import-Csv -Encoding -Path C:\scripts\loginy.csv |
Select-Object -ExpandProperty logins |
Get-ADUser -Properties LastLogonDate |
Select-Object #{n = 'Logins'; e = {$_.SamAccountName}}, LastLogonDate |
Export-Csv -Path C:\scripts\Eksporty\logowania.csv -Encoding UTF8 -NoTypeInformation
Select-Object -ExpandProperty logins will pass just the bare value of the logins column. Get-ADUser accepts identities from the pipeline, and it fetches the LastLogonDate for each user, as long as the SamAccountName (a default property) which is the logon name.
The next line, Select-Object #{n = 'Logins'; e = {$_.SamAccountName}}, LastLogonDate uses a calculated property (See the examples in Get-Help Select-Object -ShowWindow) to rename the SamAccountName property in a column named Logins. You could use Select-Object SamAccountName, LastLogonDate if you don't care about the column name. And the -NoTypeInformation parameter on Export-Csv just keeps it from adding that annoying "#TYPE System.Management.Automation.PSCustomObject" nonsense on the first line.
$_ is the variable for the current value in pipeline. In your second part of code, since you don't have a pipeline, hence $_ is empty and doesn't have any property/method associated with it.
What you can do is -
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
foreach ($user in $users) {
Get-ADUserLastLogon -UserName $user.logins | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
}
OR
$users = import-csv -Encoding UTF8 -path C:\scripts\loginy.csv
foreach ($_ in $users) {
Get-ADUserLastLogon -UserName $_.logins | Export-CSV C:\scripts\Eksporty\logowania.csv -Append -encoding "utf8"
}
Although I would recommend not using the latter since $_ is an automatic variable $PSItem and beside you can have plenty other names for a variable which are not keywords, functions etc.
The use of += to extend an array requires creating a new instance behind the scenes in every iteration.

powershell - compare username to a csv and report non-matches

I'm migrating users from a legacy system into Active Directory and need to add them into an AD group. Usernames don't match (or have any logic!) between the two systems so I've got a csv with the old and new usernames in:
Input.csv:
SamAccountName,LegacyUsername
ChristopherSpraggons,CSprag
JakeSquirrell,JakeSq
GeorgeCornish,CornishG
I've written the powershell to do the lookup and add the user to the group but ideally need it to report any users that it cannot match out to a txt file so they can be done manually. I'm totally stuck on how to do this.
Here's what I have so far:
$ImportCSV = C:\TEST.csv
Import-module ActiveDirectory
$InputCSV=get-content $ImportCSV
$MatchedUsers = Import-CSV 'Input.csv' | Where{$InputCSV -match $_.LegacyUsername} | ForEach-Object {Add-ADGroupMember -Identity "ADGroupName" -Member $_.SamAccountName}
TEST.csv is just plain a list of legacy usernames with no headings.
Don't filter the CSV data before the loop. Instead, put an conditional inside the loop and add the non-matching names to a second array:
Import-Module ActiveDirectory
$legacyNames = Get-Content 'C:\TEST.csv'
$NonMatchedUsers = #()
$MatchedUsers = Import-CSV 'Input.csv' | % {
if ( $legacyNames -contains $_.LegacyUsername ) {
Add-ADGroupMember -Identity "ADGroupName" -Member $_.sAMAccountName
$_.sAMAccountName
} else {
$NonMatchedUsers += $_.sAMAccountName
}
}
I'd rename TEST.csv to something like LegacyNames.txt, though, because it isn't a CSV in the first place.
Edit: Since you want TEST.csv to be the actual input I'd suggest a slightly different approach. Load Input.csv into a hashtable (a dictionary) and make TEST.csv the input for the pipeline:
Import-Module ActiveDirectory
$mapping = #{}
Import-Csv 'Input.csv' | % { $mapping[$_.LegacyUsername] = $_.sAMAccountName }
$NonMatchedUsers = Get-Content 'TEST.csv' | % {
if ( $mapping.contains($_) ) {
Add-ADGroupMember -Identity "ADGroupName" -Member $mapping[$_]
} else {
$_
}
}
Assuming you have headers in your CSV, you should be able to use PowerShell's array methods easily without manually enumerating both CSVs repeatedly.
$ImportCSV = C:\TEST.csv
Import-Module ActiveDirectory
$InputCSV = Get-Content $ImportCSV | `
ForEach-Object {
if ($ImportCSV -notcontains $_.UserName) {
$_ | Out-File C:\MissingNames.txt -Append
} }