Copy selected columns and insert to another csv using powershell - powershell

I have a two csv files. Both have same number of columns but not in row. I would like to copy 3 columns from csv1 and merge into csv2 using powershell.
I am not good at scripting. Could someone help me?
Here is code I am using.
$csv1 = Import-Csv -LiteralPath C:\BackUp\PScripts\SDO\Report.csv
$csv2 = Import-Csv -LiteralPath C:\BackUp\PScripts\SDO\7Saturday9PM.csv
$Results = #()
foreach ($record in $csv2) {
Add-Member -InputObject $record -MemberType NoteProperty -Name FoundInAD -Value $($csv1 | ? { $_.InstalledOrNA -eq $record.InstalledOrNA } | select -Property FoundInAD)
$Results += $record
}
$Results | Select-Object -Property ComputerName,PatchingStyle,LastSyncTime,LastSyncResult,LastReportedStatusTime,PendingReboot,NeededCount,InstalledOrNA,FoundInAD

Related

Take a line from one csv file and split it into columns for another csv file using powershell

I have a csv file that contains lines that I'd like to extract and add as columns to a separate csv file.
This is an example of the contents of the first csv file.
I want to take everything between the third comma and semi-colon for each one and add them as columns to this csv file.
My desired output is this. Because there may be multiple servers in the first csv file I'd like to export a csv for each server but I can figure that bit out.
I've been playing around with the following but I can't figure it out.
Import-CSV $CsvTargetPath | ForEach-Object {
$newData = $_
Import-CSV $CsvSourcePath | ForEach-Object {
$_.AdditionalDisks.split(";") | ForEach-Object {
$newRecordProperties = [ordered]#{
$DriveLetter = $_.split(",")[3]
$Label = $_.split(",")[4]
$Filesystem = $_.split(",")[5]
}
$newRecord = new-object psobject -Property $newRecordProperties
Write-Output $newRecord
}
$CsvTargetPath | Add-Member -MemberType NoteProperty -Name DriveLetter -Value $DriveLetter -PassThru
$CsvTargetPath | Add-Member -MemberType NoteProperty -Name Label -Value $Label -PassThru
$CsvTargetPath | Add-Member -MemberType NoteProperty -Name Filesystem -Value $Filesystem -PassThru
}
} | Export-CSV $CsvTargetPath -NoTypeInformation
Here is the contents of the first csv in plain text.
VmName AdditionalDisks
Server01 90,0,thick,b,sql backup,refs;110,1,thick,d,sql data,refs;60,2,thick,f,sql transaction log,refs;50,3,thin,l,sql audit,refs;30,0,thick,t,sql tempdb data,refs
Server02 90,0,thick,b,sql backup,refs;110,1,thick,d,sql data,refs;60,2,thick,f,sql transaction log,refs;50,3,thin,l,sql audit,refs;30,0,thick,t,sql tempdb data,refs
Assuming the second csv file can also hold info for multiple servers (how else would you know the Uuid for each disk?), you could do like below
$additionalDiskInfo = Import-Csv -Path 'D:\Test\file1.csv'
$serverInfo = Import-Csv -Path 'D:\Test\file2.csv'
$additionalDiskInfo | ForEach-Object {
$server = $_.VmName
$targetItems = $serverInfo | Where-Object { $_.VmName -eq $server }
$extraDisks = $_.AdditionalDisks -split ';'
# make sure you don't run into index errors
$maxItems = [math]::Min($targetItems.Count, $extraDisks.Count)
# loop through the arrays and output combined objects
$result = for ($i = 0; $i -lt $maxItems; $i++) {
$n1, $n2, $n3, $driveLetter, $label, $fileSystem = $extraDisks[$i] -split ','
$targetItems[$i] | Select-Object *,
#{Name = 'DriveLetter'; Expression = {$driveLetter}},
#{Name = 'Label'; Expression = {$label}},
#{Name = 'FileSystem'; Expression = {$fileSystem}}
}
# now write a new csv file for this server
$result | Export-Csv -Path ('D:\Test\DiskInfo-{0}.csv' -f $server) -NoTypeInformation
}
The resulting csv files would look like this
"VMName","Harddisk","Uuid","DriveLetter","Label","FileSystem"
"Server01","Hard disk 2","600C293-7e48-3a63-fb02-cd44df98fe79","b","sql backup","refs"
"Server01","Hard disk 3","600C293-7e48-3a63-fb02-cd44df98f454","d","sql data","refs"
"Server01","Hard disk 4","600C293-7e48-3a63-fb02-cd44df98f10a","f","sql transaction log","refs"
"Server01","Hard disk 5","600C293-7e48-3a63-fb02-cd44df98f483","l","sql audit","refs"
"Server01","Hard disk 6","600C293-7e48-3a63-fb02-cd44df98fced","t","sql tempdb data","refs"
Try like this:
$csv=Import-Csv $CsvSourcePath
$csv|%{
[pscustomobject][ordered]#{
DriveLetter=($_.AdditionalDisks.Split(","))[3]
Label=($_.AdditionalDisks.Split(","))[4]
FileSystem=($_.AdditionalDisks.Split(","))[5]
}}|export-csv $CsvTargetPath -append

If Else statement Powershell CSV with Output CSV

I am fairly new in powershell scripting and need help on the following output in a csv format. I am trying to select a column e.g. ACCOUNT.UPLOAD and make and if/else statement to output it in another csv file. May someone help please.
Output csv should look like below:
$results = Import-Csv 'C:\Users\test\Desktop\Test\customer.csv' |
Select-Object "ACCOUNT.UPLOAD"
ForEach ($row in $results)
{
If ($row.Type0 -ne 'CP000101', 'CP000102')
{
$row."ACCOUNT.UPLOAD" = "$($row.ACCOUNT.UPLOAD)"
Write-Host $row."ACCOUNT.UPLOAD"
}
}
$results | Export-Csv C:\Users\test\Desktop\Test\test.csv -NoTypeInformation
Thank you
This will get you what you need. Added comments to explain what I have done.
$results = Import-Csv "C:\Users\test\Desktop\Test\customer.csv" | Select-Object "ACCOUNT.UPLOAD"
# Created array to be able to add individual results from foreach
$TheCSV = #()
ForEach ($row in $results) {
# You can use a -ne in the right hand side, if done like this.
If (($row.'ACCOUNT.UPLOAD' -ne 'CP000101') -and $row.'ACCOUNT.UPLOAD' -ne 'CP000102') {
# Adds the ROW column to the entry and finds the index that it was in from $results.
# Did a +2 as it does not include the header and it starts at value 0. So to match it up with the actual excel row numbers, add 2.
$row | Add-Member -Name 'ROW' -type NoteProperty -Value "$([array]::IndexOf($results.'ACCOUNT.UPLOAD',$row.'ACCOUNT.UPLOAD')+2)"
$TheCSV += $row
}
}
$TheCSV | Export-Csv "C:\Users\test\Desktop\Test\test.csv" -NoTypeInformation
Do it PowerShell way:
param(
[Parameter(Position=0)]
$InputFile = 'D:\\Temp\\Data.csv',
[Parameter(Position=1)]
$OutputFile = 'D:\\Temp\\Output.csv'
)
Import-Csv $InputFile |
Select-Object "ACCOUNT.UPLOAD" |
%{
$lineno++
if ($_.'ACCOUNT.UPLOAD' -notin #('CP000101', 'CP000102')) {
$_ | Add-Member -Name 'ROW' -type NoteProperty -Value $lineno
$_ # Output to pipeline
}
} -Begin { $lineno = 1 } |
Export-Csv $OutputFile -NoTypeInformation
Using:
.\Script.ps1
.\Script.ps1 inputfilename.csv outputfilefname.csv

Powershell Export-Csv -Append in new column

Just want to ask how to Export the data in existing CSV file in new column. I have this following code.
$Ex=Compare-Object $ImportWin7 $Importafipd1 -includeequal
$Ex | Select-Object SideIndicator | Export-Csv -Append -Force -NoTypeInformation "C:\NotBackedUp\EndpointAudit\Win7machinetest2.csv"
but it appears that the Data from $EX was appended not on the first row of the column.
You can't just add an additional column to existing csv document. You would want to recreate it again with number of columns you need. Like so:
$ExistingCSV = Import-Csv "C:\NotBackedUp\EndpointAudit\Win7machinetest2.csv"
$Ex=Compare-Object $ImportWin7 $Importafipd1 -includeequal | Select-Object SideIndicator
$obj = #()
$i = 0
foreach ($row in $ExistingCSV)
{
$item = New-Object PSObject -ArgumentList $row
$item | Add-Member -MemberType NoteProperty extra_column -Value $Ex[$i]
$obj += $item
$i++
}
$obj | Export-Csv -Append -Force -NoTypeInformation "C:\NotBackedUp\EndpointAudit\Win7machinetest2.csv"

try to determine the max number of character in each column

I have written a script that tries to determine the max no. of character for each column. This is what I wrote:
$path = 'folder path'
$file = Get-ChildItem $path\*
$FileContent = foreach ($files in $file) {
$FileHeader = #( (Get-Content $files -First 1).Split($delimiter) )
$importcsv = #( Import-Csv $files -Delimiter "$delimiter" )
for ($i=0; $i -lt $FileHeader.Length; $i++) {
#select each column
$Column = #( $importcsv | select $FileHeader[$i] )
#find the max no. of character
$MaxChar = #(($Column[$i] |
Select -ExpandProperty $FileHeader[$i] |
Measure-Object -Maximum -Property Length).Maximum)
$output = New-Object PSObject
$output | Add-Member NoteProperty FullName ($files.FullName)
$output | Add-Member NoteProperty FileName ($files.Name)
$output | Add-Member NoteProperty Time (Get-Date -Format s)
$output | Add-Member NoteProperty FileHeader ($($FileHeader[$i]))
$output | Add-Member NoteProperty MaxCharacter ($($MaxChar[$i]))
Write-Output $output
}
}
The script above is just part of it, so $delimiter is already defined. And finally I will export the result as CSV.
The script runs without any error, but when I open the file it only gives me the first column/header the max no. of character, and the rest of column/header are missing.
The perfect result will be showing each column/header the max no. of character.
Is something wrong with my loop?
my boss is trying to create an automate process to finding all the information from the raw data and use those information to upload to the database, so part of the script that is missing is about determine the delimiter of the raw file, the $CleanHeader is clean version of $FileHeader (remove all special characters, turn capital letters to small letters), those cleanheaders will be use for headers in the table in the database. and he also want to know the maximum character in each column, so that info can use them in creating the size of the column in the table in the database (he knows this part can be done in sql), but he ask me whether it can be done in PowerShell or not.
This should work:
$ht = #{}
# import a CSV and iterate over its rows
Import-Csv $f.FullName -Delimiter "$delimiter" | ForEach-Object {
# iterate over the columns of each row
$_.PSObject.Properties | ForEach-Object {
# update the hashtable if the length of the current column value is greater
# than the value in the hashtable
if ($_.Value.Length -gt $ht[$_.Name]) {
$ht[$_.Name] = $_.Value.Length
}
}
}
# create an object for each key in the hashtable
$date = Get-Date -Format s
$ht.Keys | ForEach-Object {
New-Object -Type PSObject -Property #{
FullName = $f.FullName
Name = $f.Name
Time = $date
FileHeader = $_
MaxCharacter = $ht[$_]
}
}
FileHeader[$i] was returning the column name with quotes : "ColumnName" instead of ColumnName
To fix, just add a trim to the line where you pull the header :
$FileHeader = #( (Get-Content $files -First 1).Split($delimiter).trim('"') )

Powershell. Need help importing hostnames from .csv. The rest of this works

I am trying to figure out how to correct this script I've wrote. I know it is something wrong with the way it is importing the list of hostnames. I don't know how to fix it.
Part 1: This is supposed to import a .csv with the hostnames and dig the registry for the application's uninstall information, put it into an array, and export into .csv's for later use. Also it creates .txt files in order to later compare the applications on the system to a baseline.
$path = "\\path"
$computers = Import-Csv -Path "\\Path\hostnames.csv"
$array = #()
foreach($pc in $computers)
{
$computername = $pc.computername
#$computername = "KNOWN_HOSTNAME" #test line for one system
$UninstallKey = "SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall"
$reg = [microsoft.win32.registrykey]::OpenRemoteBaseKey('LocalMachine',$computername)
$regkey = $reg.OpenSubKey($UninstallKey)
$subkeys = $regkey.GetSubKeyNames()
foreach($key in $subkeys)
{
$thisKey=$UninstallKey+"\\"+$key
$thisSubKey=$reg.OpenSubKey($thisKey)
$obj = New-Object PSObject
$obj | Add-Member -MemberType NoteProperty -Name "ComputerName" -Value $computername
$obj | Add-Member -MemberType NoteProperty -Name "DisplayName" -Value $($thisSubKey.GetValue("DisplayName"))
$obj | Add-Member -MemberType NoteProperty -Name "DisplayVersion" -Value $($thisSubKey.GetValue("DisplayVersion"))
$obj | Add-Member -MemberType NoteProperty -Name "Publisher" -Value $($thisSubKey.GetValue("Publisher"))
$obj | Add-Member -MemberType NoteProperty -Name "InstallDate" -Value $($thisSubKey.GetValue("InstallDate"))
$array += $obj
$ExportArray = $array | Where-Object { $_.DisplayName } |
select ComputerName , DisplayName, DisplayVersion, Publisher, InstallDate
$ExportArray |
Export-csv $path\$computername.csv -NoTypeInformation
$ExportArray2 = $array |
Where-Object { $_.DisplayName } |
select DisplayName, DisplayVersion, Publisher
$ExportArray2 |
Export-csv $path\$computername.txt -NoTypeInformation
}
}
Part 2: This portion compiles the .csv's into one excel document for reporting
$csvs = Get-ChildItem $path\* -Include *.csv
$outputfilename = "Network_" + (Get-Date -Format yyyyMMdd)
$excelapp = new-object -comobject Excel.Application
$excelapp.sheetsInNewWorkbook = $csvs.Count
$xlsx = $excelapp.Workbooks.Add()
$sheet=1
foreach ($csv in $csvs)
{
$row=1
$column=1
$worksheet = $xlsx.Worksheets.Item($sheet)
$worksheet.Name = $csv.Name
$file = (Get-Content $csv.PSPath | ForEach-Object {$_ -replace '"', ""})
foreach($line in $file)
{
$linecontents = $line -split ‘,(?!\s*\w+”)’
foreach($cell in $linecontents)
{
$worksheet.Cells.Item($row,$column) = $cell
$column++
}
$column = 1
$row++
}
$sheet++
}
$output = $path + “\” + $outputfilename + ".xlsx"
$xlsx.SaveAs($output)
$excelapp.quit()
Part 3: This portion loads up a baseline, and the .txt's created preciously, and checks for differences in the files. (also deletes blank ouput files)
$bline = Get-ChildItem $path\* -Include Baseline.txt
$txts = Get-ChildItem $path\* -Include *.txt -Exclude Baseline.txt
foreach ($txt in $txts)
{
Compare-Object -referenceobject $(Get-Content $bline) -differenceobject $(Get-Content $txt) |
ft inputobject, #{n = "file"; e = {if ($_.SideIndicator -eq '=>') {"System"} else {"Baseline"}}} |
Out-File $txt'_has_diff'.csv -Width 256
Get-ChildItem $path |
where {$_.Length -eq 0} |
Remove-Item
}
Thank you
Edit:
The Hostnames.csv files I've tried are:
HOSTNAME1
HOSTNAME2
and
"HOSTNAME1","HOSTNAME2"
It's a little unclear what the problem is, because you say there is "something wrong with the way it is importing the list of hostnames", but you haven't specified what kind of results you're getting and how they differ from the intended results.
However, based on your sample data I think I can infer what the problem is: You're trying to use Import-Csv on non-CSV data. Neither of your examples looks like a CSV file. They both look like lists. A list in which the items are separated by commas, such as
"HOSTNAME1","HOSTNAME2","HOSTNAME3","HOSTNAME4"
is not called a "CSV file". CSV files are a form of "flat file", in which the data represents the rows and columns of a single database table. An example of a CSV file would be something like this, where the first line is a list of field (column) names, and the other lines are records (rows) with the comma-separated values corresponding to the columns in the header row:
"Hostname","OS","OS Version","Primary Function","Location"
"BOSEXCH01","Windows","Server 2012","Microsoft Exchange","Boston"
"BOSDC01","Windows","Server 2008 R2","Active Directory domain controller","Boston"
"MYWEB","Linux","Ubuntu 13.04","Apache web server","Phoenix"
The cmdlet Import-Csv imports a CSV file into an array of objects in which the properties are the field names in the header row, and the values are the comma-separated items in each row corresponding to the property names derived from the header row. Export-Csv does the reverse—it creates a CSV file from an array of objects.
It looks like what you're trying to do is read a simple list of hostnames into an array of strings. If your data looks like the first example,
HOSTNAME1
HOSTNAME2
[etc...]
you can read it into an array by simply using Get-Content, as follows (note that I changed the extension to .txt to reflect the actual format of the data):
$computers = Get-Content "\\Path\hostnames.txt"
If your data looks like the second example,
"HOSTNAME1","HOSTNAME2",[etc...]
you can read it into array like this:
$computers = (Get-Content "\\Path\hostnames.txt") -split ','
On the other hand, it appears that you are using Export-Csv correctly: You're exporting a bunch of objects with the same properties into a flat file, which is the correct usage of the term "CSV".