Powershell Compile all matching rows from CSV - powershell

I have a CSV file with a list of Users and who they are managed by with these headers:
DisplayName,Alias,CA5,Managedby
I want to import this list in powershell and be able to send one email to each manager with the list of accounts (DisplayName,Alias,CA5) that they are listed as the manager of in the managedby field. I can create the email with out issue I need to know how to compile all the lines of the CSV file that should all go to into the same email. With the sample CSV below I should end up with three emails (one each to ManagedByA, ManagedbyB and ManagedByC). The email to ManagedByA would have three lines containing:
DN1 A1
DN2 A2 DL
DN3 A3
My CSV look like this:
DisplayName,Alias,CA5,ManagedBy
DN1,A1,,ManagedByA
DN2,A2,DL,ManagedByA
DN3,A3,,ManagedByA
DN4,A4,,ManagedByB
DN5,A5,,ManagedByB
DN6,A6,DL,ManagedByB
DN7,A7,,ManagedByB
DN8,A8,,ManagedByC
DN9,A9,DL,ManagedByC
DN10,A10,,ManagedByC
My Code (from Mathias R. Jessen):
$Import = Import-CSV "C:\powershell\DL\Reports\DLReportEmail.csv"
### Find unique ManagedBy
$Managers = $Import | Sort-Object -Property ManagedBy -Unique
ForEach ($Manager in $Managers){
$Employees = $Import | Where-Object {$_.ManagedBy -eq $Manager.ManagedBy}
$Body = "DearXXXX, `r`n"
ForEach($Employee in $Employees){
$Alias = $Employee.Alias
$DisplayName = $Employee.DisplayName
$CA5 = $Employee.CA5
$Body += "$DisplayName : $Alias : $CA5 `r`n"
}
$Body += "`r`n"
$Body += "Thanks"

You can import the csv, extract each unique manager name, and then compile a subset of the list by using the ManagedBy values you've already extracted:
$Users = Import-Csv C:\filename.csv
$Managers = $Users | Sort-Object -Property ManagedBy -Unique
for($Manager in $Managers)
{
$Employees = $Users |Where-Object {$_.ManagedBy -eq $Manager.ManagedBy}
// send your email here with the contents of $Employees
}

Related

Merging two CSV files with Powershell

I have two CSV files.Columns names are like below example
CSV1
SAMAccountName mail
JohnS johns#example.com
CSV2
GivenName Surname DisplayName Department Title Mail MobilePhone Manager
What I've wanted to do is to compare the CSV1 with CSV2 and match the mail column in CSV2 file with SAMAccountName Column in CSV1 and export a new CSV which gives the below output
CSV3(merged.csv) as in script
GivenName Surname DisplayName Department Title Mail MobilePhone Manager SAMAccountName
I tried the below powershell script which i found in stack overflow site posted sometime back and i never got the values from the SAMAccountName column of CSV1.All other column names are coming up without any issue but SAMAccountName column is blank.I'm not a powershell script expert need some help here.Below is the example script i used.
$csv1 = Import-Csv -Path C:\TEMP\CSV1.csv
$csv2 = Import-Csv -Path C:\temp\CSV2.csv
ForEach($Record in $csv2){
$MatchedValue = (Compare-Object $csv1 $Record -Property "SAMAccountName" -IncludeEqual -ExcludeDifferent -PassThru).value
$Record = Add-Member -InputObject $Record -Type NoteProperty -Name "SAMAccountName" -Value $MatchedValue
}
$csv2|Export-Csv 'C:\temp\merged.csv' -NoTypeInformation
This is very common, You can do this quite easily using:
$csv1 = Import-Csv -Path 'C:\temp\CSV1.csv'
$csv2 = Import-Csv -Path 'C:\temp\CSV2.csv'
$csv3 = foreach ($record in $csv2) {
$matchingRecord = $csv1 | Where-Object { $_.mail -eq $record.mail }
# if your goal is to ONLY export records with a matching email address,
# uncomment the if ($matchingRecord) condition
#if ($matchingRecord) {
$record | Select-Object *, #{Name = 'SamAccountName'; Expression = {$matchingRecord.SamAccountName}}
#}
}
$csv3 | Export-Csv -Path 'C:\temp\merged.csv' -NoTypeInformation

Foreach loop to get department name in powershell office365

I am trying to get the department from a list of UserPrincipalNames
I am able to get this to work for a single user outside of the foreach loop. Its adding the loop where I am having trouble.
Connect-MsolService
$users = Import-Csv C:\Users\me\Desktop\users.csv
foreach ($user in $users){
Get-MsolUser -UserPrincipalName $user | Select-Object firstname, lastname, UserPrincipalName, department |Export-Csv C:\Users\me\Desktop\test.csv
}
There are 50 email addresses listed in the CSV one email address per line. With the first line being "UserPrincipalName"
CSV Sample Data
userprincipalname
useremail1#mydomain.com
useremail2#mydomain.com
useremail3#mydomain.com
useremail4#mydomain.com
Think PowerShell - the pipeline uses objects, and you have a ForEach-Object cmdlet:
Connect-MSOLService
Import-CSV -Path C:\Users\Me\Desktop\Users.CSV |
ForEach-Object { Get-MSOLUser -UserPrincipalName $_.UserPrincipalName |
Select-Object firstname, lastname, UserPrincipalName, department } |
Export-CSV C:\Users\Me\Desktop\test.CSV
In case you need to lookup for data from a csv , then want to use them in a script and export scrip 's result in another CSV
# Importing MsOnline Module
Import-Module MSOnline
Connect-MsolService
#Import excel document containing our data ,Path "C:\list-email.csv"
$ImportData = Import-Csv "C:\list-email.csv"
$Output = foreach ( $Data in $ImportData )
{
#Storing Email column data in $Data for each row
write-host $Data.Email
Get-MsolUser -UserPrincipalName $Data.IONEmail | Select-Object UserPrincipalName,LastPasswordChangeTimestamp, Departement
}
#Output the array to the CSV File
$Output | Export-CSV "C:\LastLogonDateExport.csv"

Powershell to CSV compare

Hello I'm trying to use some code I found on here to compare a CSV with Active Directory. I have a csv file with a list of users. I want to check this file and see if anything in the "Email" column from the spreadsheet matches an email address from AD. If it does, I want to list that email address and include the Canonical Name from AD so I can easily see what OU the user account is in.
This is what I'm working with:
$path = "C:\Scripts\Import.csv"
$outpath = "C:\Scripts\Export.csv"
$csv = Import-Csv $path
Import-Module ActiveDirectory
foreach ($line in $csv)
{
$User = Get-ADUser -LDAPFilter "(&(objectclass=user)(mail=$($line.Email)))" -Properties CanonicalName
If ($User -ne $Null) {"User does exist in OU" + $line.Email + $User.CanonicalName}
Else {"User not found in AD OU - " + $line.Email}
}
I've been able to modify this to suit my needs but I'm having some trouble piping the results out to a CSV file. Running the script as it's shown above outputs what I want to the screen but I'd like to have it in a CSV format. If I do something like:
$Results = foreach ($line in $csv)
and then use
$Results | export-CSV $outpath -NotypeInformation
I get the csv created but it just includes a the string value, header for Length and then a numeric value for each line. I can use Out-File to send the results to a txt file, which includes the same results that were displayed on the screen, but I'd really like this to be a csv, not txt file. I believe I need to reference the properties of the csv file and AD in order to build these into my export file but I'm having trouble doing that as I'm not sure how to build in the status of whether the user was found or not.
Any assistance would be appreciated.
UPDATE - Final code
This is the final code I went with. This compares the users in the csv with AD users in the parent and child domain. It uses the email address field to match the users. It grabs the Canonical Name so I can see the OU the user is in and if the user is not found, it reports that in the Canonical Name field.
$path = "$env:userprofile\Desktop\InFile.csv"
$outpath = "$env:userprofile\Desktop\OutFile.csv"
# Importing CSV file
Import-Module ActiveDirectory
$Users = Import-Csv $path |
ForEach-Object {
Write-Progress -Activity "Comparing Imported File to Active Directory" -Status "Processing $($_.Email)"
# Comparing CSV file to Domain.com users
If (
$Value1 = (Get-ADUser -LDAPFilter "(&(objectclass=user)(mail=$($_.Email)))" -server Domain.com -Properties CanonicalName).CanonicalName)
{$_ | Add-Member -MemberType NoteProperty -Name CanonicalName -Value $value1 -PassThru}
# Comparing CSV file to child.Domain.com users
ElseIF (
$Value2 = (Get-ADUser -LDAPFilter "(&(objectclass=user)(mail=$($_.Email)))" -server child.Domain.com-Properties CanonicalName).CanonicalName)
{$_ | Add-Member -MemberType NoteProperty -Name CanonicalName -Value $value2 -PassThru}
# Writing output for users not found in either domain
Else {$_ | Add-Member -MemberType NoteProperty -Name CanonicalName -Value "Email Address not found in Active Directory" -PassThru}
#Exporting to CSV file
New-Object -TypeName pscustomobject -Property #{
Email = $_.Email
CanonicalName = $_.CanonicalName
LastName = $_."Last Name"
FirstName = $_."First Name"
}
} | Select-Object LastName, Firstname, Email, CanonicalName | Sort-Object CanonicalName | Export-CSV $outpath -NoTypeInformation
I'm not sure what resulting CSV should look like, so this code just adds CannonicalName using Calculated Properties to Import.Csv and saves it as Export.Csv.
$path = "C:\Scripts\Import.csv"
$outpath = "C:\Scripts\Export.csv"
Import-Module ActiveDirectory
Import-Csv -Path $path |
Select-Object -Property *, #{
n = 'CanonicalName'
e = {(Get-ADUser -LDAPFilter "(&(objectclass=user)(mail=$($_.Email)))" -Properties CanonicalName).CanonicalName}
} | Export-Csv -Path $outpath -NoTypeInformation
Update
This version will create a new CSV file with 3 columns: UserExistInOu, Email and CanonicalName if any:
Import-Csv -Path $path | ForEach-Object {
$UserExistInOu = $false
if($CanonicalName = (Get-ADUser -LDAPFilter "(&(objectclass=user)(mail=$($_.Email)))" -Properties CanonicalName).CanonicalName)
{
$UserExistInOu = $true
}
New-Object -TypeName pscustomobject -Property #{
UserExistInOu = $UserExistInOu
Email = $_.Email
CanonicalName = $CanonicalName
}
} | Export-Csv -Path $outpath -NoTypeInformation

Output department and direct reports

I am trying to create an "initial" text file that will hold a script run of all users + department + direct reports. My next step after making this file is to create another file the same way but compare it to the original to see if the department for the users ever changed. (not sure yet how to compare the department value just yet)
My current issue is that the department, even though the process is identical to another program I have made in the past, won't print it. Furthermore, when it prints my direct reports it prints only the first one with the whole extension of CN=..., OU=... etc.
I want it to print this way:
username | Department(extensionAttribute14) | Direct Reports (as a single string)
we38432 | IT-Security | cm03456: 04555a: ....etc
My original script used this code for department:
$deps = Get-Aduser -filter {name -like *} -Properties name, extensionAttribute14 | Select name, extensionAttribute14 | Export-CSV $listing -notypeinformation
and this worked. I tried the {name -like *} but that gave me errors in my current program. I know the Export-CSV makes it work but I can't use this format anymore.
for the direct reports my original was this:
foreach ($ID in $directReports){
if ($ID -ne $Null){
$directreports = get-aduser $ID
$directreports.name | Out-File $output -Append
}
This code printed line by line the direct reports but I want them all listed in the same excel cell when I send it there.
I have printed a listing of all the members in the past using ":" and it worked but it is not the case with the direct reports listing. I just get errors when I use this format from my other program:
foreach ($member in $empty.members){
$string = $member.substring(3,$member.indexof(",")-3)
$members = $members + ":" + $string
}
I hope someone can help me with my two issues.
Import-Module ActiveDirectory
$documentOld = "C:\Temp\Old_Supervisor_list_mo_yyyy.txt"
Clear-Content $documentOld
$Header = `
"User ID" <#+ "|" + `
"Department" + "|" + `
"Direct Reports"#>
$Header | Out-File $documentOld -Append
$Users = Get-AdUser -Filter * -Properties name, Enabled, Manager, extensionAttribute14 | Select Enabled, name, Manager, extensionAttribute14
foreach ($user in $Users){
if ($user.enabled –eq $true) {
$name = $user.name
$directReports = Get-ADUser -Identity $name -Properties directreports | Select -ExpandProperty directreports
$department = $user.extensionAttribute14
foreach ($ID in $directReports){
if ($ID -ne $Null){
$directreports = get-aduser $ID
# $string = $directreports + ":"
}#end if $ID
}#end foreach $ID
$listing = `
$name + "|" + $deparment + "|" + $directreports#$string
$listing | Out-File $documentOld -Append
}# end if
}# end foreach $user
Let see if we can make this a little easier and efficient.
Import-Module ActiveDirectory
$documentOld = "C:\Temp\Old_Supervisor_list_mo_yyyy.txt"
$Users = Get-AdUser -Filter * -Properties name,Enabled,Manager,extensionAttribute14 | Where-Object{$_.Enabled}
$Users | ForEach-Object{
$props = #{
Name = $_.Name
Department = $_.extensionAttribute14
DirectReports = ($_.Manager | Where-Object{$_} | ForEach-Object{Get-Aduser $_ | Select-object -ExpandProperty Name}) -join ":"
}
New-Object -TypeName psobject -Property $props
} | Select-Object Name,Department,DirectReports | Export-CSV -Delimiter "|" -NoTypeInformation -Path $documentOld
First we get all the users from your directory with Get-AdUser -Filter * taking all the properties outside the norm that we want. Since you just wanted accounts that are enabled we filter those out now with Where-Object{$_.Enabled}.
The fun part is creating the custom object array ( which is necessary for input for Export-CSV). Create a small hashtable called $props where we set the properties by their friendly names. The special one being DirectReports where we take all the users manager DN's ( Assuming they have one where is what Where-Object{$_} does by filtering out nulls/empty strings.) and use Get-Aduser to get there names. Since you could have more than one manager an array is most likely returned we use -join to ensure only a single string is given for the DirectReports property. That property collection is created for every user and it is then used to create a New-Object which is sent to the output stream.
The Select-Object that follows is just to ensure the order of columns in the CSV that is created. No need for making a CSV file with lots of Out-Files when Export-CSV and -Delimiter "|" will do the hard work for you.

Powershell to get user attributes given samaaccount

I have a notepad list of 100 users. Normally I use the below script to get all the users within one OU but this time I have users from different OU and I have to search using Samaccountname.
clear
$UserInfoFile = New-Item -type file -force "C:\Scripts\UserInfo.txt"
"Login`tGivenname`tEmail" | Out-File $UserInfoFile -encoding ASCII
Import-CSV "C:\Scripts\OU.txt" | ForEach-Object {
$dn = $_.dn
$ObjFilter = "(&(objectCategory=User)(objectCategory=Person))"
$objSearch = New-Object System.DirectoryServices.DirectorySearcher
$objSearch.PageSize = 15000
$objSearch.Filter = $ObjFilter
$objSearch.SearchRoot = "LDAP://$dn"
$AllObj = $objSearch.FindAll()
foreach ($Obj in $AllObj)
{ $objItemS = $Obj.Properties
$Ssamaccountname = $objItemS.samaccountname
$SsamaccountnameGN = $objItemS.givenname
$SsamaccountnameSN = $objItemS.sn
$SsamaccountnameEN = $objItemS.mail
"$Ssamaccountname`t$SsamaccountnameGN`t$SsamaccountnameSN`t$SsamaccountnameEN" | Out-File $UserInfoFile -encoding ASCII -append
} # End of foreach
} # End of ForEach-Object
I am trying to use the list of samaccountname to get the name and email of those users. I am new to Powershell so the above script itself was a bit difficult for me to grasp and now I am on an even more difficult task.
Not sure if I understand your question correctly, but if you want to filter the user list by account names you could do something like this:
$accounts = Get-Content userlist.txt
...
$objSearch.FindAll() | ? {
$accounts -contains $_.Properties.sAMAccountName
} | % {
"{0}`t{1}`t{2}" -f ($_.Properties.givenname, $_.Properties.sn, $_.Properties.mail)
}
BTW, I'd recommend using the ActiveDirectory PowerShell module if possible. That will allow you to retrieve user accounts with a simple Get-ADUser, thus simplifying your code. The OU can be extracted from the user's distinguished name by splitting the dn at the first comma. Something like this:
$accounts = Get-Content userlist.txt
Get-ADUser * -Properties * | ? {
$accounts -contains $_.Properties.sAMAccountName
} | select #{n="ou";e={($_.distinguishedName -split ",", 2)[1]}}, mail, givenName, sn, homeDirectory
or like this:
Get-Content userlist.txt | Get-ADUser -Properties * |
select #{n="ou";e={($_.distinguishedName -split ",", 2)[1]}}, mail, givenName, sn, homeDirectory
Untested, though, since I don't have an AD at hand here.
I can't test it now but give this a try. You don't need to search AD if you know the user's DN. You can bind to it directly using the DN.
Import-CSV "C:\Scripts\OU.txt" | ForEach-Object {
$dn = $_.dn
$user = [adsi]"LDAP://$dn"
New-Object PSObject -Propertry #{
samaccountname = $user.Properties['samaccountname']
givenname = $user.Properties['givenname']
sn = $user.Properties['sn']
mail = $user.Properties['mail']
}
} | Export-Csv $UserInfoFile