values in this csv are not being edited - Powershell - 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"

Related

Exporting multiple PSCustomObject s to a single CSV

I have 2 PScustomObjects that i would like to combine into a single csv as follows:
$Output1 = [PSCustomObject]#{
Timestamp1 = (Get-Date)
InstanceName1 = $ProcessName1
Count1 = $Processes1.Count
Memory1 = $MEMLoad1
CPU1 = $CPULoad1
}
$Output2 = [PSCustomObject]#{
Timestamp2 = (Get-Date)
InstanceName2 = $ProcessName2
Count2 = $Processes2.Count
Memory2 = $MEMLoad2
CPU2 = $CPULoad2
}
The CSV should have the titles TimeStamp1, InstanceName1......TimeStamp2, InstanceName2....
This code runs in a loop and exports data each pass.
Is there a way to do this? Also is there a way to do this dynamically to avoid replicating large amounts of code if i am to export data on say 100 PsCustomObjects, maybe lookping through the input data for the object and the putting in in one object and passing that to the csv while dynamically changing titles?
I use the following line to export. I've tried -InputObject $Output1, $Output2 but that gives gibberish.
Export-Csv -InputObject $Output1 -path $Path1 -NoTypeInformation -Append -Force
The only solution i have so far is to export multiple CSV's but that gets bulky fast.
Any help is greatly appreciated!
The best solution is to ensure all the objects your script/function outputs use the same schema (that is, they should all share the same common property names).
If that's not possible, you can use Select-Object to ensure all possible properties are selected for all objects:
$Output1,$Output2 |Select-Object Count1,Count2,CPU1,CPU2,InstanceName1,InstanceName2,Memory1,Memory2,Timestamp1,Timestamp2 |Export-Csv ...
This is obviously not very practical, so if you have many different object schemas, you'll want to automate the discovery of all possible property names.
To do that, we can inspect the psobject hidden memberset:
$allTheObjectsToExport = $Output1,$Output2
$propertyNames = $allTheObjectsToExport |ForEach-Object {
# Discover all the object's properties
$_.psobject.Properties |ForEach-Object {
# Get each property name
$_.Name
}
} |Sort-Object -Unique
# Now the CSV will have a column for every single unique property name
$allTheObjectsToExport |Select-Object $propertyNames |Export-Csv -Path $Path1 -NoTypeInformation

[PowerShell]Get-Content and Add Column Entry?

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

Powershell script to match string between 2 files and merge

I have 2 files that contain strings, each string in both files is delimited by a colon. Both files share a common string and I want to be able to merge both files (based on the common string) into 1 new file.
Examples:
File1.txt
tom:mioihsdihfsdkjhfsdkjf
dick:khsdkjfhlkjdhfsdfdklj
harry:lkjsdlfkjlksdjfsdlkjs
File2.txt
mioihsdihfsdkjhfsdkjf:test1
lkjsdlfkjlksdjfsdlkjs:test2
khsdkjfhlkjdhfsdfdklj:test3
File3.txt (results should look like this)
tom:mioihsdihfsdkjhfsdkjf:test1
dick:khsdkjfhlkjdhfsdfdklj:test3
harry:lkjsdlfkjlksdjfsdlkjs:test2
$File1 = #"
tom:mioihsdihfsdkjhfsdkjf
dick:khsdkjfhlkjdhfsdfdklj
harry:lkjsdlfkjlksdjfsdlkjs
"#
$File2 = #"
mioihsdihfsdkjhfsdkjf:test1
lkjsdlfkjlksdjfsdlkjs:test2
khsdkjfhlkjdhfsdfdklj:test3
"#
# You are probably going to want to use Import-Csv here
# I am using ConvertFrom-Csv as I have "inlined" the contents of the files in the variables above
$file1_contents = ConvertFrom-Csv -InputObject $File1 -Delimiter ":" -Header name, code # specifying a header as there isn't one provided
$file2_contents = ConvertFrom-Csv -InputObject $File2 -Delimiter ":" -Header code, test
# There are almost certainly better ways to do this... but this does work so... meh.
$results = #()
# Loop over one file finding the matches in the other file
foreach ($row in $file1_contents) {
$matched_row = $file2_contents | Where-Object code -eq $row.code
if ($matched_row) {
# Create a hashtable with the values you want from source and matched rows
$result = #{
name = $row.name
code = $row.code
test = $matched_row.test
}
# Append the matched up row to the final result set
$results += New-Object PSObject -Property $result
}
}
# Convert back to CSV format, with a _specific_ column ordering
# Although you'll probably want to use Export-Csv instead
$results |
Select-Object name, code, test |
ConvertTo-Csv -Delimiter ":"

How to export data into a specific column in a csv file in PowerShell

What I am trying to do is I import data from a csv file which has UserPrincipalnames and I am taking the names before the # symbol and then I want to export that data to a specific column in the same CSV file which in this case is o365Users.csv. I am able to write it out to a text file but I need to know how to export it out to Column G with the header name as SAM
This is my code:
$Addys = Import-Csv "C:\scripts\o365Users.csv"
$UPNs = $Addys.UserPrincipalName
foreach ($UPN in $UPNs) {
$Name = $UPN.Split("#")[0]
Write-Output $Name >> c:\scripts\o365Names.txt
}
To append a new column with the header SAM use Select-Object with a calculated property:
(Import-Csv 'C:\scripts\o365Users.csv') |
Select-Object -Property *,#{n='SAM';e={$_.UserPrincipalName.Split('#')[0]}}
If the new property has to be in a specific position you can't use the wildcard * but will have to enumerate all headers/columns/properties in the desired order, i.e.
(Import-Csv 'C:\scripts\o365Users.csv') |
Select-Object -Property ColA,ColB,ColC,ColD,ColE,ColF,#{n='SAM';e={$_.UserPrincipalName.Split('#')[0]}},ColH
replace Col_ with your real headers.
Due to enclosing the (Import-Csv) in parentheses you can export to the same file name (not recommended while still testing) - simply append
| Export-Csv 'C:\scripts\o365Users.csv' -NoTypeInformation
Here is a quick way to get just the output you are looking for. You would import the current CSV. Create an blank output array and in your loop add each name. Then export the CSV
$Addys = Import-Csv "C:\scripts\o365Users.csv"
$UPNs = $Addys.UserPrincipalName
[System.Collections.ArrayList]$Output = #()
foreach ($UPN in $UPNs) {
$Name = $UPN.Split("#")[0]
$Output.Add($Name) | Out-Null
}
$Output | Export-Csv -Path "C:\scripts\o365Users.csv" -NoTypeInformation

Parse line of text and match with parse of CSV

As a continuation of a script I'm running, working on the following.
I have a CSV file that has formatted information, example as follows:
File named Import.csv:
Name,email,x,y,z
\I\RS\T\Name1\c\x,email#jksjks,d,f
\I\RS\T\Name2\d\f,email#jsshjs,d,f
...
This file is large.
I also have another file called Note.txt.
Name1
Name2
Name3
...
I'm trying to get the content of Import.csv and for each line in Note.txt if the line in Note.txt matches any line in Import.csv, then copy that line into a CSV with append. Continue adding every other line that is matched. Then this loops on each line of the CSV.
I need to find the best way to do it without having it import the CSV multiple times, since it is large.
What I got does the opposite though, I think:
$Dir = PathToFile
$import = Import-Csv $Dir\import.csv
$NoteFile = "$Dir\Note.txt"
$Note = GC $NoteFile
$Name = (($Import.Name).Split("\"))[4]
foreach ($j in $import) {
foreach ($i in $Note) {
$j | where {$Name -eq "$i"} | Export-Csv "$Dir\Result.csv" -NoTypeInfo -Append
}
}
This takes too long and I'm not getting the extraction I need.
This takes too long and I'm not getting the extraction I need.
That's because you only assign $name once, outside of the outer foreach loop, so you're basically performing the same X comparisons for each line in the CSV.
I would rewrite the nested loops as a single Where-Object filter, using the -contains operator:
$Import |Where-Object {$Note -contains $_.Name.Split('\')[4]} |Export-Csv "$Dir\Result.csv" -NoTypeInformation -Append
Group the imported data by your distinguishing feature, filter the groups by name, then expand the remaining groups and write the data to the output file:
Import-Csv "$Dir\import.csv" |
Group-Object { $_.Name.Split('\')[4] } |
Where-Object { $Note -contains $_.Name } |
Select-Object -Expand Group |
Export-Csv "$Dir\Result.csv" -NoType