delete the last column from a csv file in powershell - csv

I am new to powershell. Currently we are in need of a poweshell script to compare two large (100000 rows and n columns (n > 300, also column headers are Dates corresponding to each wednesday). The value of n keeps on incrementing each week in the file. We need to compare the files (current week and last week), and need to make sure that the only difference between the two files is the last column.
I have gone through some Forums and Blogs and I could do only Little due to my ignorance.
If there is a way to drop the last column from a csv file in powershell, we may be able to make use of the below script below to compare the previous week's file and the current week's file after droping the last column from current week's file.
It would be really helpful if someone can help me here with your hard earned knowledge
[System.Collections.ArrayList]$file1Array = Get-Content "C:\Risk Management\ref_previous.csv"|Sort-Object
[System.Collections.ArrayList]$file2Array = Get-Content "C:\Risk Management\ref_current.csv"|Sort-Object
$matchingEntries = #()
foreach ($entry in $file1Array) {
if ($file2Array.Contains($entry)) {
$matchingEntries += $entry
}
}
foreach ($entry in $matchingEntries){
$file1Array.Remove($entry)
$file2Array.Remove($entry)
}
Cheers,
Anil

Assuming that the column name you want to exclude is LastCol (adjust to your actual column name):
$previous = Import-csv "C:\Risk Management\ref_previous.csv" | Select-Object -Property * -ExcludeProperty LastCol | Sort-Object;
$current = Import-csv "C:\Risk Management\ref_current.csv" | Sort-Object;
Compare-Object $previous $current;
This will drop the last column from each of the input files and indicate whether the remaining content differs.

Based on the answer that alroc gave, you should be able to get the last column name using a split operation on the first line of the CSV file, and then using that on the -ExcludeProperty parameter.
However, the Compare-Object command on this doesn't work for me, but it does pull back the right data into each variable.
$CurrentFile = "C:\Temp\Current.csv"
$PreviousFile = "C:\Temp\Previous.csv"
$CurrentHeaders = gc $CurrentFile | Select -First 1
$CurrentHeadersSplit = $CurrentHeaders.Split(",")
$LastColumn = $CurrentHeadersSplit[-1] -Replace '"'
$Current = Import-Csv $CurrentFile | Select -Property * -ExcludeProperty $LastColumn | Sort-Object
$Previous = Import-Csv $PreviousFile | Sort-Object
Compare-Object $Current $Previous

The import-csv and export-csv both give the opportunity to exclude columns.
The import-csv has the -header option and you simply name the incoming headers and exclude the last columns header. If there are 10 columns, only name 9. The last column will be excluded.
For export-csv, select the columns you'd like to write out ( |select col1,col2,col3|export-csv... ) and don't select the column you're trying to exclude.

Related

use where-object to find data, but want to add data to every row also the export to csv

Hi I have a script that reads a csv file, creates a json file, checks the users in the file against a service, then i get the result as a json file.
I take that result and finds the users i csv file and creates a new file.
I do that with a where-object
But i need to add some extra values on every user before i export it to csv
This is my 2 lines for finding users and then export
$matches = $users | where-object { $_.number -in $response.allowedItemIds } | Select-Object -Property Number,Surname,Forename,Emailaddress
$matches | Export-Csv -path $Saved$savefile -NoTypeInformation -Append
Is that possible or do i need to do a for each?
Cheers
Assuming I've interpretted your question correctly, you should be able to use PowerShell's Calculated Properties for this purpose.
For example, if you wanted to add a field called "Date" and set the current Date/Time to each user row, you could do the following:
$matches = $users | where-object { $_.number -in $response.allowedItemIds } | Select-Object -Property Number,Surname,Forename,Emailaddress, #{Name="Date";Expression={Get-Date}}
The Expression value can either be a static value such as "StaticValue", a variable such as $i (useful if used as part of a loop, for example) or more complex value that is returned from other cmdlets (as in my example above)

Taking single columns of data and exporting to multiple columns in separate CSV file

I recently created a PowerShell script to gather disk size, usage and free space, then export them into a CSV. Now I need to create a new CSV file with the "free space" column of each created file. I need to have each column grabbed, dropped into a new column. I've been tinkering with a script and digging into articles all day without luck. Below is the closest I've gotten.
$sort = gci | select name | Where-Object {$_.name -like "diskspace_*"}
$count = 0
foreach ($item in $sort) {
$count = ($count +=1)
$free = Import-Csv $item.name | Select-Object 'Free'
$share = Import-Csv $item.name |
Select-Object 'Share',#{Name="something"; Expression={$free.free}} |
Export-Csv free_report.csv -NoTypeInformation
}

How to compare, match, and append multiple values in multiple CSV files?

I'm trying to figure out the best way to do this, and I'm not sure how to Import-Csv with 2 different files through the same pipeline and export a value found...
So lets start with CSV file 1: I only want the values for LoginNumber where Type = H and (ContractorDomain -ne $null -or ContractorDomain -ne ""). For example, this should only pull values 0031482 and 2167312 from below.
Note: I only added spaces and arrows to make it easier to read as columns here. The csv files have no spaces between the column values or arrows.
"LoginNumber","Type","ContractorDomain"
"0031482" ,"H" ,"P12345" <<
"1251632" ,"P" ,"A52671"
"2167312" ,"H" ,"425126" <<
"0598217" ,"L" ,""
"1405735" ,"H" ,""
"2058194" ,"A" ,"L21514"
When the value number for LoginNumber (based on conditions explained above) is found, search for it in CSV file 2. Then grab the value of AccountStatus and SamAccountName for the respective value of UserIDNumber.
"SamAccountName","UserIDNumber","AccountDescriptionDetails","AccountStatus"
"jd12395" ,"0052142" ,"Company CEO" ,"Enabled"
"jwet" ,"2167312" ,"Software Developer" ,"Disabled" <<
"1b3gas5" ,"1385293" ,"Project Manager" ,"Disabled"
"632g1fsa" ,"0031482" ,"QA Tester" ,"Enabled" <<
"4126hs" ,"0000418" ,"Program Manager" ,"Disabled"
"axv" ,"1840237" ,"Accountant Administrator" ,"Disabled"
For the 3rd CSV file we have the following:
"domainName","SameAccountName","DateExpired"
"TempDomain","jwet" ,"20151230" <<
"PermDomain","p21942" ,""
"PermDomain","qz231034" ,""
"TempDomain","632g1fsa" ,"20151231" <<
"TempDomain","ru20da2bb22" ,"20160425"
Next, for the 3rd file, I want to add the column to plug in the Disabled and Enabled values (or User Match Not Found value):
"domainName","SameAccountName","DateExpired","UserStatus"
"TempDomain","jwet" ,"20151230" ,"Disabled" <<
"PermDomain","p21942" ,"" ,"User Match Not Found"
"PermDomain","qz231034" ,"" ,"User Match Not Found"
"TempDomain","632g1fsa" ,"20151231" ,"Enabled" <<
"TempDomain","ru20da2bb22" ,"20160425" ,"User Match Not Found"
I learned how to import-csv and create new columns with something like this...
Import-Csv $file | Select-Object -Property *, #{Name="UserStatus";Expression={
if ($true) {"fill value in here"}
}} | Export-Csv $newFile -NoType
So I'm thinking something like this. I'm just not sure how to search/find/pass multiple CSV files values through the pipeline.
Note: some of these CSV files have like 15 columns before and after the columns we are searching for. Also, some of the columns values have a comma, so I can't really rely on the -Delimiter ,. Also, some of the column values do not have " (if you were to open the CSV in txt format).
Columns containing commas shouldn't be an issue if the values are properly quoted (i.e. if the CSV is valid). Import-Csv will correctly import a record 42,"a,b",c as three values 42, a,b and c. If your CSV isn't well-formed: fix that first.
Fetch the login IDs from the first CSV file:
$logins = Import-Csv 'C:\path\to\file1.csv' |
Where-Object { $_.Type -eq 'H' -and $_.ContractorDomain } |
Select-Object -Expand LoginNumber
You can simplify the ContractorDomain property check to just $_.ContractorDomain, because PowerShell interprets both an empty string and $null as a boolean value $false in that context. The same would happen for other zero or empty values (0, 0.0, empty array, etc.), but that shouldn't be an issue in your scenario.
Next create a hashtable mapping account names to their respective status. Filter the imported second CSV by the list of IDs you created before, so the hashtable contains only relevant mappings.
$accountStatus = #{}
Import-Csv 'C:\path\to\file2.csv' | Where-Object {
$logins -contains $_.UserIDNumber
} | ForEach-Object {
$accountStatus[$_.SamAccountName] = $_.AccountStatus
}
With that hashtable you can now add the UserStatus column to your third CSV:
(Import-Csv 'C:\path\to\file3.csv') |
Select-Object -Property *, #{n='UserStatus';e={
if ($accountStatus.ContainsKey($_.SameAccountName)) {
$accountStatus[$_.SameAccountName]
} else {
'User Match Not Found'
}
}} | Export-Csv 'C:\path\to\file3.csv' -NoType
The parentheses around the Import-Csv statement ensure that the file is completely read and closed before Export-Csv starts writing to it. They're only required if you're writing the modified data back to the same file and can be omitted otherwise. The asterisk selects all imported columns, and the additional calculated property adds the new column you want to include.

Powershell: Reading in a column from a .CSV file and then adding a specific string to the beginning and exporting again

I'm attempting to write a script which will read in a CSV generated by querying AD for user information (that part is done) but then will allow me to add a string to the beginning of each value of a column in the CSV file and then export it.
For instance we have this CSV file:
"displayname","Office"
Bob,7142
Janet,8923
SantaClaus,0912
NicCage,0823
I want to take each entry for "Office", add the string "BUG" before it and then export it back out. The modified CSV should look like:
"displayname","Office"
Bob,BUG7142
Janet,BUG8923
SantaClaus,BUG0912
NicCage,BUG0823
At this point, I've been attempting to read in just the "Office" column and then displaying it with "Write-Host". The idea being that if I can do that then maybe I can create a new variable that would be something like:
$BUG = "BUG"
$NewVar = $BUG$Office
Which would hopefully look like the second CSV file. I am extremely new to powershell scripting.
The attempts I've made so far are these:
Attempt #1:
$UserList = Import-CSV C:\Users\username\CSV.csv
$UserList | ForEach-Object ($_.Office) { $UserList }
Attempt #2:
$projectName = import-csv C:\Users\username\CSV.csv | % {$_.Office}
$BUG = "BUG"
$projectName | ForEach-Object ($_) {$projectName}
Attempt #3:
$UserList = Import-CSV C:\Users\username\CSV.csv
#ForEach ($Office in $Userlist) {
#Write-Host $UserList.Office
#}
Attempt #4:
Import-Csv "C:\Users\username\CSV.csv" -Header ("displayname","Office","whenCreated","EmailAddress") | Select-Object Office | Export-CSV -Path C:\users\Username\test.csv
I have gotten it to read out just the Office numbers before using the ForEach-Object loop structure but then it never stops reading out the office numbers so that's unhelpful.
I think I'm going in the right direction, but I just can't figure out how to modify a column like this.
Instead of trying to extract the Office column, just pipe the full data set (all columns) to ForEach-Object, change the value of the Office property and pipe it back to Export-Csv:
$Prefix = "BUG"
Import-Csv .\file.csv | ForEach-Object {
$_.Office = $Prefix + $_.Office
$_
} | Export-Csv .\file_modified.csv -NoTypeInformation

Replace value in html table Powershell

I'm writing a script which displays the last 7 backups of my server. The scripts outputs the following: TimeCreated, Level, ID, Message,Size in a html table.
my script:
$lastsevendays = (get-date) - (new-timespan -day 7)
$MyObject = Get-WinEvent -FilterHashTable #{LogName='Microsoft-Windows-Backup'; StartTime=$lastsevendays}
$BackupSize = #{ Name = "BackupSize"; Expression = { (($objFSO.GetFolder("C:\Users\LaBackup").Size) / 1MB) } }
$MyObject |
Select 'TimeCreated', 'LevelDisplayName','ID', 'Message', $BackupSize |
ConvertTo-HTML -Head $Header |
Out-file C:\Users\script.htm
I want the script to run everyday and automatically remove backups row which date back from more than 7 seven.
I think i'm supposed to select row which have "Date" less or equal than seven days ago,
and delete them to add more recent row.
I have no idea how i could do this as, ConvertTo-HTML seems to regenerate a whole table each time it's called.
Some ideas??
thanks in advance
Give this a try:
Get-WinEvent -LogName Microsoft-Windows-Backup | Where-Object -FilterScript { $_.TimeCreated -gt [DateTime]::Now.AddDays(-7); }
This uses the Where-Object cmdlet to filter events that are older than 7 days in the Microsoft-Windows-Backup log.
EDIT
I guess I misunderstood what you were looking for. All I did was change the -lt operator to -gt.