CSV Not Exporting after merge - excel

I asked a similar question here and it got me on a very good track, however while trying to 'all in one' it, I ended up with an issue. I'm very close, but after testing numerous theories I'm starting to reverse what I need.
I have a multiple sheet Excel - I need to pull the first sheet, CSV-ify it, then remove the headers, then only get the first 3 digits from the first line.("List Name")
My PS is:
#Create and get my Excel Obj
$excel = New-Object -comobject Excel.Application
$excel.visible=$false
$excel.DisplayAlerts=$false
$UserWorkBook = $excel.Workbooks.Open("C:\path\to\file\CompleteTest.xls")
$UserWorksheet = $UserWorkBook.Worksheets.Item(1)
$hitlistCSV = "C:\path\to\file\BroadcastReport.csv"
$xlCSV = 6 #changed-grav
#Save, close, and clean up
$UserWorksheet.SaveAs($hitlistCSV,$xlCSV)
$UserWorkBook.close()
$excel.quit()
$excel = $null
$expandfile = "C:\path\to\file\BroadcastReport.csv"
(gc $expandfile | select -Skip 1) | sc $expandfile
Import-Csv $expandfile | ForEach-Object {
$_."List Name" = $_."List Name".SubString(0,3)
$_
}
$expandfile | Export-Csv "C:\path\to\file\BroadcastReport.csv" -NoTypeInformation
I've modified it a lot, and tried to make it single runnable to avoid schedule multiple BATs. Everything seems to work - It pulls the first sheet, renames it, and replaces the top line EVERY time I run the 2nd portion. However, the SubString portion isn't taking effect, nor am I getting a 'FileExport' file.
My last modification now makes it so everytime it replies that I need to 'supply an Input Object' so I feel like it has to do with function-izing it. For reference the line I need to split is double quoted because it has commas. Ex:
"123|ST,City"
I only need the 123. When I just import the file and run my ForEach function, the output is what I expect. Just saving it to the file isn't.
Thanks.
Welcome any input.
XLS Source
This is the header line I need to skip
List Name Broadcast Name ColumC ColumD Colum E ColumF Colum G ColumJ
401|ST, City ST, City - More Text(LSM) (16803) 1 854 73 854 233 27.28%
402|ST, City ST, City - October (LSM) (16807) 1 851 57 851 186 21.86%
CSV Source after XLS -> CSV
One thing that is weird is that once it becomes a CSV, I'm left with ~6 fields of just commas. Example:
List Name,Broadcast Name,ColumC,ColumD,Colum E ,Colum,Colum F,ColumG,,,,,,
"402|ST,City","ST, City - More Text(ACR) (16803)",1,854,73,854,233,27.28%,,,,,,
"402|ST,City","City, ST - Text (LSM) (16807)",1,851,57,851,186,21.86%,,,,,,
UPDATE:
Added example, updated source - Column names keep a space where a space exists.
Broadcast Name column -does- have a comma in it, but I assume it's being exported with double quotes.
RESOLUTION
#Create and get my Excel Obj
$excel = New-Object -comobject Excel.Application
$excel.visible=$false
$excel.DisplayAlerts=$false
$UserWorkBook = $excel.Workbooks.Open("C:\path\to\file\ExcelBook.xls")
$UserWorksheet = $UserWorkBook.Worksheets.Item(1)
$hitlistCSV = "C:\path\to\file\Output.csv"
$xlCSV = 6 #changed-grav
#Save, close, and clean up
$UserWorksheet.SaveAs($hitlistCSV,$xlCSV)
$UserWorkBook.close()
$excel.quit()
$excel = $null
$expandfile = "C:\path\to\file\Output.csv"
$report = get-content $ExpandFile | select -skip 1 | convertfrom-csv | ForEach-Object {
$_."List Name" = $_."List Name".SubString(0,3)
$_
}
$report | Export-Csv ""C:\path\to\file\Output.csv" -force -NoTypeInformation
Issue was a slight modification to the export function being separated functions. I assume due to some sort of write lock.

The problem is on your last line, you are setting $expandfile to the return result of export-csv, it is prompting you to provide an input because it is trying to perform the export but is only provided with a path. Just change the last line to
$expandfile | Export-Csv "C:\Users\Donavin\Desktop\TXRH\FileExport.csv" -NoTypeInformation
EDIT
Ok need to make a few more changes for things to work correctly, valid import/export code is below
$expandfile = "C:\path\to\file\BroadcastReport.csv"
(gc $expandfile | select -Skip 1) | sc $expandfile
Import-Csv $expandfile | ForEach-Object {
$_."List Name" = $_."List Name".SubString(0,3)
$_
} | Export-Csv "C:\path\to\file\BroadcastReport.csv" -force -NoTypeInformation

Related

Excel / Copy paste 2 Columns into one using powershell

I'm really new in powershell and I try to write a script to help me in copying 2 or more columns and paste it into only one with a particular format.
What I want is something like that :
example
It's been 2 days I looked for the correct syntax and I can't find it
Thanks for your help !
Actually, I try to learn how excel and powershell works ( I started 1 week ago so I don't know anything )
I found a script to copy/paste some columns. I understand how it works but know I would like to paste these columns into only one ( like I said )
Here is the script I have :
$ExcelPath = ''
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $true
$WorkBook = $Excel.Workbooks.Open($ExcelPath)
$Worksheet = $Workbook.WorkSheets.item(“lolo”)
$Worksheet2 = $Workbook.WorkSheets.item(“lala”)
$worksheet.activate()
$lastRow1 = $worksheet.UsedRange.rows.count
$range1 = $worksheet.Range("A2:C$lastRow1")
$range1.copy()
$worksheet2.activate()
$lastRow2 = $worksheet2.UsedRange.rows.count + 1
$range2 = $worksheet2.Range("A$($lastRow2)")
$worksheet2.Paste($range2)
Convert your data to CSV by example. After it depends what you want to do, if you want to include null properties or not ...
Import-Csv -Path filepath | Select-Object -Properties *, #{"l"="Col4", e={ "`"$($_.Col1)`", `"$($_.Col2)`",`"$($_.Col3)`",`"`",`"`"" } } | Export-CSV -Path outputpath -Encoding UTF8 -NoTypeInformation

Comparing all properties of PSCustomObjects (Excel sheet data)

I am working on a script for PowerShell to import data from 2 separate Excel sheets, compare all properties of these sheets and export a new Excel worksheet with this output.
The purpose of this script is to compare an updated excel sheet with a previous version and spot what has changed, what has been added and possibly even what has been removed.
I have been using the Import-Excel module to handle the first part, and Compare-Object for the data comparison.
As far as I can tell Import-Excel imports the Excel data into a System.Object which is a hashtable of PSCustomObjects. Each PSCustomObject corresponds to a row in the Excel sheet.
I am running the following code:
$global:InputdataA = Import-Excel -Path $InputA -WorkSheetname $InputSheetA
$global:InputdataB = Import-Excel -Path $InputB -WorkSheetname $InputSheetB
$global:ReferenceObject = $InputdataA
$global:DifferenceObject = $InputdataB
$global:InputdataHeadersA = $InputdataA[0].psobject.properties.name
$global:InputdataHeadersB = $InputdataB[0].psobject.properties.name
$props = $InputdataHeadersA
$props += $InputdataHeadersB
$props = $props | Select -Unique
$compareResult = Compare-Object -ReferenceObject $ReferenceObject -DifferenceObject $DifferenceObject -Property $props -PassThru -CaseSensitive
I am using 2 excel files for testing:
Personnel_16_12_2018 - small2.xlsx (previous version)
Personnel_28_11_2018 - small2.xlsx (new version with changes and additions)
The files can be downloaded here:
https://ufile.io/bmstu
https://ufile.io/3z62x
The output I would like to see would be only the 7 entries that have been changed/added, with data from difference object (the new version of the excel sheet) This would represent the latest and "correct" data.
Currently I get an output from the compare-object, containing the 7 entries AND the 6 entries that have been changed from the reference object including side-indicator.
Is it possible to make the compare-object return only the changes or do I have to process the output afterwards?
Based on your additional information and the sample files, you could try something like this:
$oldFile = Import-Excel ".\personnel_28_11_2018---small2.xlsx"
$newFile = Import-Excel ".\personnel_16_12_2018---small2.xlsx"
$properties = "TRIAL_PK", "TRIALCOUNTRY_PK", "TRIALSSITE_PK", "ASSIGNMENT_LVL", "ROLE", "INT_EXT", "START_DATA", "END_DATE", "PERSONNELL_PK", "TITLE", "LAST_NAME", "FIRST_NAME", "ORGANIZATION_NAME"
$result = Compare-Object -ReferenceObject $oldFile -DifferenceObject $newFile -Property $properties -PassThru -CaseSensitive | Where-Object {$_.SideIndicator -eq "=>"}
$result | Select-Object $properties | Export-Excel ".\changed.xlsx"

Select Excel row --> Create Hashtable from Entries

I have an Excel .xlsx-file which looks like this:
Now I'd like to create a PowerShell script, which can do the following:
Ask the User which row he wants to use (for example 4)
Create a hashtable with those entries
The hashtable should look like this:
Name Value
---- -----
Name Jane Doe
Age 67
Street Grace St. 19
Zipcode 12345
Date 03.03.2013
Does someone know how I can achieve this?
Plus: Is this actually achievable with a xlsx-File or do I need to use a CSV-file?
First, it is achievable if we convert the xls to csv:
$excelFilePath = "C:\Temp\abc.xlsx"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $false
$Excel.DisplayAlerts = $false
$Workbook = $excel.Workbooks.Open($excelFilePath)
$($Workbook.Worksheets | where {$_.Name -eq "Sheet1"}).SaveAs("C:\Temp\abcd.csv", 6)
$Excel.Quit()
I would suggest using an ID instead of row number:
$importedAbcd = Import-Csv -Path "C:\Temp\abcd.csv" -Delimiter ";"
[int]$answer = Read-Host "Select ID to work with"
$object = $importedAbcd | Where-Object {$_.ID -eq $answer}
You have the row now converting it to hash:
$hash = #{}
$object.psobject.properties | Foreach { $hash[$_.Name] = $_.Value }
A more intuitive way is to
read the excel file directly with the Import-Excel module
pipe it to Out-Gridview, select a single line
and populate the hashtable
$HashTable = [ordered]#{}
Import-Excel "x:\path\sample.xls" | Out-GridView -OutputMode Single -Title "Select one line" |
ForEach-Object {$_.psobject.properties | ForEach-Object {
$HashTable[$_.Name]=$_.Value
}
}
$HashTable
Sample output:
> $HashTable
Name Value
---- -----
Name Molly Johnson
Agr 35
Street Murraay St. 86
Zipcode 54321
Date 02.02.2009

Powershell append data into existing XLSX with multiple sheets

New to Powershell and looking to learn.
Goal:
Trying to take the Data out of a .csv file (14 cells of data per row) and import into an existing .xlsx file Starting on the second row columns (A2:N2).
The .xlsx file has 4 sheets with the one I am looking to edit being labeled "Data". Data sheet/tab has 18 columns, the first 14 are where I would like the imported data starting on row (A2:N2-> End will vary).
Looking for a way to automate the report by filling rows A-N with data from a file (.csv) which gets generated automatically.
Sample of "Data" tab with some values:
Current process is to open one xls file and copy/past into cells starting at A2. Looking to automate this and have automated the report -> Emails .xls file, which I convert to .csv and remove some titles and extra info which is not needed using the following code:
Function ExcelCSV ($File)
{
$pwd = "C:\Users\..." #Removed local path
$excelFile = "$pwd\" + $File + ".xls"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $false
$Excel.DisplayAlerts = $false
$wb = $Excel.Workbooks.Open($excelFile)
foreach ($ws in $wb.Worksheets)
{
$ws.SaveAs("$pwd\" + $File + ".csv", 6)
}
$Excel.Quit()
}
$TestFile = (Get-Content .\FileName.xls) -replace 'null',''
$TestFile | Out-File Test.xls
$FileName = "Test"
ExcelCSV -File $FileName
Get-Content Test.csv | Select-Object -Skip 2 | Select-Object -SkipLast 3 | Set-Content Test2.csv
Please use great ImportExcel powershell module ImportExcelModule
using it You can achieve Your goal by simply doing so
$csv=Import-CSV <YourImportParameters>
$csv|Export-Excel -Path $pwd -Show -StartRow 2 -StartColumn 2 -sheet $sheetname
Above will take the object and export it to excel file $pwd,sheet $sheetname starting from second row of second column
If You want to send that via mail to someone afterwards - Powershell can help You do that in 1 line too :)

Powershell 2.0 write back to xlsx

Cross post from powershell.org..
I am trying to have Powershell read an xlsx for username info, convert to a csv (to be imported) and then write back something to the xlsx so next time it won't reimport the same users.
I don't want to delete the users in the xlsx but am thinking to add a date column or some other data maybe the word "created" and have powershell write this data in an available column. But then I would have to have my script ignore this new column if contains a old date or the word created?
<br> Current xlsx columns headers
<br> A B C
<br> 1 Full Name, Personal Email, "write back data"
<br> 2 John Doe Jdoe#gmail.com, Created (Sample write back data)
<br> 3 Don Juan Djuan#gmail.com, Date Imported (sample write back data)
Convert to csv code (This part is working fine.)
$File = "C:\Scripts\Excel\Accounts.xlsx"
$Savepath1 = "C:\Scripts\Csv\Employee Accounts.csv"
$SheetName1 = "Employee Accounts"
$ObjExcel = New-Object -ComObject Excel.Application
$Objexcel.Visible = $false
$Objworkbook=$ObjExcel.Workbooks.Open($File)
$Objworksheet=$Objworkbook.worksheets.item($Sheetname1)
$Objworksheet.Activate()
$Objexcel.application.DisplayAlerts= $False
$Objworkbook.SaveAs($SavePath1,6)
$Objworkbook.Close($True)
$ObjExcel.Quit()
Here is my current import-csv code
$EmployeeAccounts = Import-Csv $savepath1 | Where-Object { $_.Fullname -and $_.PersonalEmail}
Things to consider:
There might be additional concatenated info in additional fields added to the xlsx. Therefore excel might count these as used rows if the fields have formulas in them. So I only want to write the data to the new column if there is a username and email address in columns A & B.
Thanks!
To be honest it's going to be simpler to import the whole thing, perform your process filtering for entries that don't have anything in the Updated field, update the "Updated" field for each entry that you processed, and then just write the entire thing back to the file. So, something like:
$Users = Import-CSV $FilePath
$Users | ?{[String]::IsNullOrEmpty($_.Updated)} | %{
Do stuff here
$_.Updated = Get-Date
}
$Users | Export-CSV $FilePath -Force -NoTypeInfo
Edit: Well then, that does complicate things a little bit. So, this one does take a plugin, but it's a plugin that I whole heartedly feel should be included in almost any installation that's functionally used regularly IMHO. The PowerShell Community Extensions (PSCX) can be gotten from pscx.codeplex.com and will grant you access to the command Out-Clipboard which is awesome for what you want to do.
$Users = Import-CSV $FilePath
$Users | ?{[String]::IsNullOrEmpty($_.Updated)} | %{
Do stuff here
$_.Updated = Get-Date
}
$Users | Select Updated | ConvertTo-CSV -Delimiter "`t" -NoTypeInformation | Out-Clipboard
$SheetName1 = "Employee Accounts"
$ObjExcel = New-Object -ComObject Excel.Application
$Objexcel.Visible = $false
$Objworkbook=$ObjExcel.Workbooks.Open($File)
$Objworksheet=$Objworkbook.worksheets.item($Sheetname1)
$Objworksheet.Activate()
$Range = $Objworksheet.Range("C1","C1")
$Objworksheet.Paste($Range, $false)
$Objexcel.DisplayAlerts = $false
$Objworkbook.Save()
$Objexcel.DisplayAlerts = $true
$Objworkbook.Close()
$Objexcel.Quit()
[void][System.Runtime.Interopservices.Marshal]::FinalReleaseComObject($Objexcel)
That will paste your data, header included, into column C.

Resources