[PowerShell]Get-Content and Add Column Entry? - powershell

I am trying to input a list of users into PowerShell and get a specific security group attached to the user's account. At this current time, I have two pieces - an Excel sheet with multiple pieces of data, and a .txt with just the user's usernames. The script I have currently just inputs the user's usernames from the .txt and gets the security group from their account that matches a specific prefix, however I noticed doing it this way doesn't give any specific order. Even though the users are in a specific order (copied and pasted exactly from the excel document), the actual output doesn't come back well.
So, here's what I'd Like to do now, I just don't know how. I would like to get the content from the Excel document, take all of the usernames and do Get-ADPrincipalGroupMembership like I am now, and then write the security group Back to the line that matches the username. For example, if I looked up the SG for msnow, it would get the SG for msnow and then write the SG back to the row that has msnow, and continues through the list. Instead of just doing an Out-GridView, it would actually write this to the Excel document.
Any help on making this work?
Here is the code I have right now.
Import-Module ActiveDirectory
$Names = Get-Content C:\Temp\Users.txt
$Records = #()
Foreach ($ADUsers in $Names) {
Try {
$SG = Get-ADPrincipalGroupMembership -Identity $ADUsers | Select Name | Where {$_.Name -Like "SG - *"}
$SGName = $SG.Name
}
Catch [ADIdentityNotFoundException] {
$SGName = "User not found"
}
$Records += New-Object PSObject -Property #{"UserName" = $ADUsers;"Security Group" = $SGName}
}
Write-Host "Generating CSV File..."
$Records | Out-GridView
Thank you!

If you save the Excel as CSV, so it will look something like
"UserName","Security Group","InsideInfo"
"bloggsj","","tall guy"
"ftastic","","nothing worth mentioning"
things shouldn't be that hard to do.
$out = 'D:\Test\Updated_usersandgroups.csv'
$csv = Import-Csv -Path 'D:\Test\usersandgroups.csv'
Write-Host "Updating CSV File..."
foreach ($user in $csv) {
try {
$SG = Get-ADPrincipalGroupMembership -Identity $user.UserName -ErrorAction Stop
# if more groups are returned, combine them into a delimited string
# I'm using ', ' here, but you can change that to something else of course
$SGName = ($SG | Where-Object {$_.Name -Like "SG - *"}).Name -join ', '
}
catch [ADIdentityNotFoundException] {
$SGName = "User $($user.UserName) not found"
}
catch {
# something else went wrong?
$SGName = $_.Exception.Message
}
# update the 'Security Group' value
$user.'Security Group' = $SGName
}
Write-Host "Generating updated CSV File..."
$csv | Export-Csv -Path $out -UseCulture -NoTypeInformation
# show output on screen
$csv | Format-Table -AutoSize # or -Wrap if there is a lot of data
# show as GridView (sorts by column)
$csv | Out-GridView
Output in console would then look like
UserName Security Group InsideInfo
-------- -------------- ----------
bloggsj SG - Group1, SG - Group1 tall guy
ftastic SG - Group1 nothing worth mentioning
Note: I don't know what delimiter your Excel uses when saving to CSV file. On my Dutch machine, it uses the semi-colon ;, so if in your case this is not a comma, add the delimiter character as parameter to the Import-Csv cmdlet: -Delimiter ';'
Excel uses whatever is set in your locale as ListSeparator for the delimiter character. In PowerShell you can see what that is by doing (Get-Culture).TextInfo.ListSeparator. On output, the -UseCulture switch will make sure it uses that delimiter so Excel will understand

Related

Working with a list of AD 'displayNames' in Powershell. How to indicate which users were not found?

I have written enough PS code to go through a list of displayNames (e.g "John Smith", "Taylor Hanson" - all stored on seperate lines of a txt file) to spit back enough data into another text file that can be used for mailmerge etc. Convincing thousands of employees to simply update Windows is like breaking stones! It has to be automatted to some degree...
Here is the code... the functions that let the user open a specific text file and later save are out of view...
$displayname = #()
$names = get-content $FileIN
foreach ($name in $names) {
$displaynamedetails = Get-ADUser -filter { DisplayName -eq $name } | Select Name, GivenName, Surname, UserPrincipalName
$displayname += $displaynamedetails
}
$displayname | Export-Csv -NoTypeInformation -path $fileOUT -Encoding UTF8
From time to time, a name might be spelled incorrectly in the list, or the employee may have left the organisation.
Is there any way that a statement such as 'Not Found' can be written to the specific line of the text file if an error is ever made (so that an easy side-by-side comparison of the two files can be made?
For most of the other solutions I've tried to find, the answers are based around the samAccoutName or merging the first and last names together. Here, i am specifically interested in displaynames.
Thanks
You can give this a try, since -Filter or -LDAPFilter don't throw any exception whenever an object couldn't be found (unless you're feeding a null value) you can add an if condition to check if the variable where the AD User object is going to be stored is not null and if it is you can add this "not found" user into a different array.
$domain = (Get-ADRootDSE).DefaultNamingContext
$names = Get-Content $FileIN
$refNotFound = [System.Collections.Generic.List[string]]::new()
$displaynamedetails = foreach($name in $names)
{
if($aduser = Get-ADUser -LDAPFilter "(DisplayName=$name)")
{
$aduser
continue
}
$refNotFound.Add(
"Cannot find an object with DisplayName: '$name' under: $domain"
)
}
$displaynamedetails | Select-Object Name, GivenName, Surname, UserPrincipalName |
Export-Csv -NoTypeInformation -path $fileOUT -Encoding UTF8
$refNotFound # => Here are the users that couldn't be found
Side note, consider stop using $displayname = #() and += for well known reasons.
As for AD Cmdlets, using scriptblock based filtering (-Filter {...}) is not supported and even though it can work, it can also bring you problems in the future.

values in this csv are not being edited - Powershell

$users = Import-Csv -Path "C:\scripts\door-system\test\testChange.csv" -Encoding UTF8
$users | ft
$output = forEach ($user in $users)
{
if ($user.GroupName -like "Normal")
{
$output.GroupName = "edited"
}
}
$output | export-csv .\modified.csv -noTypeInformation
you have two glitches in your code. [grin]
the 1st is modifying the $Output collection inside the loop AND assigning the output of the loop to the $Output collection. do one or the other, not both.
the 2nd is not outputting anything to put in the $Output collection. that will give you an empty collection since you assigned nothing at all to it.
here's my version & what it does ...
fakes reading in a CSV file
when you are ready to do this with real data, remove the entire #region/#endregion block and use Import-CSV.
sets the target and replacement strings
iterates thru the imported collection
tests for the target in the .GroupName property of each object
if found, it replaces that value with the replacement string
sends the modified object out to the $Results collection
displays $Results on screen
saves $Results to a CSV file
the code ...
#region >>> fake reading in a CSV file
# in real life, use Import-CSV
$UserList = #'
UserName, GroupName
ABravo, Normal
BCharlie, Abnormal
CDelta, Other
DEcho, Normal
EFoxtrot, Edited
FGolf, Strange
'# | ConvertFrom-Csv
#endregion >>> fake reading in a CSV file
$TargetGName = 'Normal'
$ReplacementGName = 'Edited'
$Results = foreach ($UL_Item in $UserList)
{
if ($UL_Item.GroupName -eq $TargetGName)
{
$UL_Item.GroupName = $ReplacementGName
}
# send the modified data to the $Results collection
$UL_Item
}
# show on screen
$Results
# send to CSV
$Results |
Export-Csv -LiteralPath "$env:TEMP\Connor Tuohy_-_Modified.csv" -NoTypeInformation
on screen output ...
UserName GroupName
-------- ---------
ABravo Edited
BCharlie Abnormal
CDelta Other
DEcho Edited
EFoxtrot Edited
FGolf Strange
CSV file ["C:\Temp\Connor Tuohy_-_Modified.csv"] content ...
"UserName","GroupName"
"ABravo","Edited"
"BCharlie","Abnormal"
"CDelta","Other"
"DEcho","Edited"
"EFoxtrot","Edited"
"FGolf","Strange"

Mix found values and error msg in csv - Get-ADUser search

I would like to take a csv of e-mail addresses and find users that match those addresses. Output should be either the found user info OR if a matching user is not found a line that puts the searched for e-mail address then "Not Found"
$base_path = "C:\scripts\validate_users\"
$source_file = "input_emails.csv"
$out_file = "results.csv"
#read the file, look them up
$users = Import-csv -Path ($base_path + $source_file) -delimiter ";" | ForEach {
try {
Get-ADUser -Filter "EmailAddress -eq '$($_.email)'" -Properties EmailAddress
}
catch {
"No user for" + '$_.email'
}
}
# Output the resultant collection to a csv file
$users | Export-csv -Path ($base_path + $out_file)
Which gives me all the found records and no error messages.
I'd like to avoid making $users into an array and adding a value there. Is there a way to add in-line "searchedforuser#fakedomain.com NOT FOUND" inline with the results I get now.
Input is along the lines of
joesmith#ourdomain.com
janejones#ourdomain.com
freddielee#ourdomain.com
guywhoquit#ourdomain.com <== won't find this one
realuser#ourdomain.com
Right now the output is just the results for the four found users with no indication the "guywhoquit#ourdomain.com" was ever in the original list
Sorry if this is a newb question. I am a ps newb, but I searched for quite a bit and I'm missing if a similar question has already been answered.
Since you're using Get-AdUser with the -Filter parameter, it will simply return $null if no matching user is found (assuming the -Filter argument is well-formed) - it won't report an error.
Therefore, check the Get-ADUser's output to see if a user was found.
The -ov (-OutVariable) common parameter allows you to capture a cmdlet's output in a variable (independently of its output behavior), which you can inspect later:
$base_path = "C:\scripts\validate_users"
$source_file = "input_emails.csv"
$out_file = "results.csv"
Import-csv -Path (Join-Path $base_path $source_file) -delimiter ";" | ForEach {
# Get and output the user for the email address at hand;
# also store the output in variable $user, via `-ov user`
Get-ADUser -Filter "EmailAddress -eq '$($_.email)'" -Properties EmailAddress -ov user
if ($user.Count -eq 0) { # User not found?
# Emit a dummy object with an .EmailAddress property
# whose value indicates that the user wasn't found.
# This will show up in the CSV file as a row with all columns
# except the "EmailAddress" one empty.
[pscustomobject] #{ EmailAddress = "No user for $($_.email)" }
}
} | Export-csv -Path (Join-Path $base_path $out_file)
Note: The reason that just emitting string "No user for" + '$_.email' to the output stream wouldn't be enough is that Export-Csv locks in the columns it outputs based on the 1st input object.
A [string] instance has no properties in common with an AD users object, so you'd get a CSV row without any values.
By constructing a dummy custom object with an .EmailAddress property ([pscustomobject] #{ EmailAddress = "..." }), that property value will show up in the file (though all other column values will be empty).
Your problem here is that Powershell only catches "Terminating exceptions" to solve this you could try either of this 2 following modifications:
Get-ADUser -Filter "EmailAddress -eq '$($_.email)'" -Properties EmailAddress -ErrorAction Stop #This will only affect this cmdlet.
Or
$ErrorActionPreference = 'Stop' #This affects every cmdlet execution you have after this line.

How do you export a list of PC names and a specific group membership of that endpoint using powershell?

I have a list of end points and we are trying to see if they have this specific group membership but I cannot figure out how to export the endpoint and the group its a member of.
$Groups = foreach ($pc in (Get-Content "C:\Users\*\Desktop\DefualtTest.csv")) {
try {
Get-ADComputer $pc -Properties memberof |
select -Expand memberof |
dsget group -samid |
? {$_ -match 'bit9'}
} catch {
Write-Output "$pc does not have bit9 group"
}
}
$Groups | Out-File "C:\Users\*\Desktop\testONE.csv"
trying to do this in comments is ... to difficult. [grin]
here's an example of what i mean by "do it one line at a time" in the foreach loop ...
# fake reading a list of systems from a text file
# in real life, use Get-Content
$ComputerList = #'
pc01
pc02
pc03
pc04
pc05
pc666
'# -split [environment]::NewLine
# fake getting a list of Computers & the groups they are in
# in real life, use Get-ADComputer & the ".MemberOf" property
$GroupMembershipLookup = #{
'pc01' = #('GroupA', 'GroupB')
'pc02' = #('GroupB', 'GroupC', 'GroupD')
'pc03' = #('GroupA', 'GroupB', 'GroupE')
'pc04' = #('GroupZ')
}
$NoGroupFound = '__No Group Found__'
$Results = foreach ($CL_Item in $ComputerList)
{
# use a real call to Get-ADComputer here [*grin*]
# pro'ly something like "(Get-ADComputer $CL_Item -Property MemberOf).MemberOf -join '; '"
$GroupList = $GroupMembershipLookup[$CL_Item] -join '; '
if ([string]::IsNullOrEmpty($GroupList))
{
$GroupList = $NoGroupFound
}
[PSCustomObject]#{
ComputerName = $CL_Item
GroupMembership = $GroupList
}
}
# on screen
$Results
# to CSV
$Results |
Export-Csv -LiteralPath "$env:TEMP\Del_GroupMembershipList.csv" -NoTypeInformation
on screen output ...
ComputerName GroupMembership
------------ ---------------
pc01 GroupA; GroupB
pc02 GroupB; GroupC; GroupD
pc03 GroupA; GroupB; GroupE
pc04 GroupZ
pc05 __No Group Found__
pc666 __No Group Found__
csv content ...
"ComputerName","GroupMembership"
"pc01","GroupA; GroupB"
"pc02","GroupB; GroupC; GroupD"
"pc03","GroupA; GroupB; GroupE"
"pc04","GroupZ"
"pc05","__No Group Found__"
"pc666","__No Group Found__"
what the above does ...
creates an array of system names as if they had been read in via Get-Content
creates a lookup table as if one had used Get-ADComputer to get the group membership for each system
made a "not found" value & stored that in a $Var for reuse
iterated thru the $ComputerList collection
grabbed the list/array of groups and converted them into a semicolon delimited string
tested for "no groups found" & added the value saved earlier if the list was empty
built a [PSCustoObject] and sent that to the output stream
captured the output stream to an array named $Results all at one time to avoid the += array penalty
displayed the results on screen
sent the $Results collection to a CSV file

Export Powershell output to CSV

I have the following code intended to take a list of user names and output a CSV report of username - GroupMembership. At the command line the output looks great as i get "name" on the left and recursive "group memberships" on the right (see pic http://i.stack.imgur.com/zLxUR.jpg for command line output, sorry can't post imbedded Pics yet)
I would like to have the output written to a CSV file with the same format, namely Username in one column and GroupMemberships in the second column.. Original code from: http://thesurlyadmin.com/2013/03/21/get-a-users-group-memberships/ with a few small changes.
Param (
[Parameter(Mandatory=$true,ValueFromPipeLine=$true)]
[Alias("ID","Users")]
[string[]]$User
)
Begin {
Try { Import-Module ActiveDirectory -ErrorAction Stop }
Catch { Write-Host "Unable to load Active Directory module, is RSAT installed?"; Break }
}
Process {
ForEach ($U in $User)
{ $UN = Get-ADUser $U -Properties MemberOf
$Groups = ForEach ($Group in ($UN.MemberOf))
{ (Get-ADGroup $Group).Name
}
$Groups = $Groups | Sort
ForEach ($Group in $Groups)
{ New-Object PSObject -Property #{
Name = $UN.Name
Group = $Group
}
}
}
}
I tried using this "$PSObject | Export-CSV C:\Scripts\GroupMembershipList.csv" but it only writes the first line to the CSV and nothing after that.
Nate,
In Powershell v3.0, the Export-CSV cmdlet introduced the -Append parameter.
Reference: http://technet.microsoft.com/en-us/library/hh849932.aspx
Not knowing the version of Powershell you are using, this may require an update on your side to make use of the new functionality.
In my own cases, I generally see the opposite issue if I forget to -Append to my CSV; I will only end up with the LAST entry as opposed to just the first.
I won't claim this to be your fix, but might be worth a shot...
Example: $PSObject | Export-CSV C:\Scripts\GroupMembershipList.csv -Append