I already have this file Workspacesize.csv. I am adding a TEST value to cell (1,2) and trying to save. It is asking me for a prompt that the file already exists, do you want to overwrite. I donot want this prompt. I have used $Excelobject.DisplayAlerts= 'False' but still it does not work.
$Excelobject=New-object -ComObject Excel.Application
$Excelobject.visible = $False
$workbook=$Excelobject.Workbooks.Open("C:\Users\Siddhartha.S.Das2\OneDrive - Shell\Desktop\Workspacesize.csv")
$worksheet=$workbook.worksheets.Item(1)
$worksheet.Activate()
$worksheet.cells.item(1,2)="TEST"
$workbook.SaveAs("C:\Users\Siddhartha.S.Das2\OneDrive - Shell\Desktop\Workspacesize.csv")
$workbook.close
$Excelobject.DisplayAlerts= 'False'
$Excelobject.Quit()
You're better off not using excel for csv files, it unnecessarily complicates things.
$Path = "C:\Users\Siddhartha.S.Das2\OneDrive - Shell\Desktop\Workspacesize.csv"
$Content = Import-Csv -Path $Path
$Content[0].Col1 = 'TEST' #Put your actual column name rather than Col1
$Content | Export-Csv -Path $Path
Related
I have a folder that has over 50 excel files in it ("Project dump' in the path below.) All of these files contain the same exact data (its archived monthly data that's used for a MoM report) I need to update all of these files to add 10 new column headers - none of these columns will have any data in them, they just need to be added to the table to match the most current month extract that will have data in it going forward.
I've been using Powershell, and have a script that can add one column to one file at a time, but it would honestly be faster for me to manually open each file and add the columns myself. I cant seem to figure out how to change my script to do what its doing to multiple files (and with multiple columns), any help would be greatly appreciated!
background; the reference is a specific file in my project dump folder. Column 50 is the first blank column, that needs to be added to the table:
(Get-ChildItem "C:\Downloads\Project dump\ArchiveJAN21.xlsx")|
foreach-object {
$xl=New-Object -ComObject Excel.Application
$wb=$xl.workbooks.open($_)
$ws = $wb.worksheets.Item(1)
$ws.Columns.ListObject.ListColumns.Add(50)
$ws.Cells.Item(1,50) ='Call Type'
$wb.Save()
$xl.Quit()
while([System.Runtime.Interopservices.Marshal]::ReleaseComObject([System.__ComObject]$xl)){'released'| Out-Null}
}
You need to define the Excel object before the loop and quit afterwards.
Also, use Get-ChildItem to get FileInfo objects from a folder path, not a hardcoded path to a file.
Try:
# an array with the new column names
$newColumns = 'Call Type','NewCol2','NewCol3','NewCol4','NewCol5','NewCol6','NewCol7','NewCol8','NewCol9','NewCol10'
# create the Excel object outside of the loop
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $false
# loop thtrough the files in the folder
(Get-ChildItem -Path 'C:\Downloads\Project dump' -Filter '*.xlsx' -File ) | ForEach-Object {
$wb = $xl.WorkBooks.Open($_.FullName)
$ws = $wb.Worksheets.Item(1)
# get the number of columns in the sheet
$startColumn = $ws.UsedRange.Columns.Count
for ($i = 0; $i -lt $newColumns.Count; $i++) {
$startColumn++ # increment the column counter
$ws.Cells.Item(1, $startColumn) = $newColumns[$i]
}
$wb.Close($true) # $true saves the changes
}
# quit Excel and clean COM objects from memory
$xl.Quit()
# clean up the COM objects used
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($ws)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($wb)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
I try to create a powershell script, to perform a few steps:
In a specific folder, I put a .xlsx file, it converts it to csv. Until now I got this:
$ErrorActionPreference = 'Stop'
Function Convert-CsvInBatch
{
[CmdletBinding()]
Param
(
[Parameter(Mandatory=$true)][String]$Folder
)
$ExcelFiles = Get-ChildItem -Path $Folder -Filter *.xlsx -Recurse
$excelApp = New-Object -ComObject Excel.Application
$excelApp.DisplayAlerts = $false
$ExcelFiles | ForEach-Object {
$workbook = $excelApp.Workbooks.Open($_.FullName)
$csvFilePath = $_.FullName -replace "\.xlsx$", ".csv"
$workbook.SaveAs($csvFilePath, [Microsoft.Office.Interop.Excel.XlFileFormat]::xlCSV)
$workbook.Close()
}
# Release Excel Com Object resource
$excelApp.Workbooks.Close()
$excelApp.Visible = $true
Start-Sleep 5
$excelApp.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelApp) | Out-Null
}
#
# 0. Prepare the folder path which contains all excel files
$FolderPath = "C:\exacthpath"
Convert-CsvInBatch -Folder $FolderPath
The columns in the file, are still there, so I want to remove them, and insert a ';' instead, like:
H;1;43;185;
At this point I'm stuck. I can import it into Powershell like:
Import-Csv -Path 'C:\folder\filename.csv' | ForEach-Object {
$_
}
I get this look, and the most important task is here, in the first row only:
H;1;43;185;
This should be modified into:
H;01;43;185
the rest should be left untouched.
After I need to export back it into a CSV file, like:
Export-Csv -Path 'C:\folder\modified_filename.csv'
But this whole process should be inserted in one single powershell script, which performs the above steps on it's own. So in short:
identifies any .xlsx file - regardless of it's name
convers it into .csv
modifies the outlook of the document, to separate the columns with a ";"
modify the first line to have 'H;01;43;185' - this is a static line, it will always look like this
save the created file as a final .csv file
Can you help me somehow to include/optimize the above scripts and let powershell perform the modification too? Example content of a file like this (final look) Usually it includes more 1000+ lines:
H;01;43;185
D;111;3;1042;2
D;222;3;1055;3
D;333;3;1085;1
T;3;;;
Any help is highly appreciated.
Regards,
Armin
If as you say in your comment, your Excel already creates a csv with the semi-colon as delimiter, you can do this inside the loop, just below $workbook.Close()
# read the file created by Excel as string array
$data = Get-Content $csvFilePath
# overwrite the file with just the new header
Set-Content -Path $csvFilePath -Value 'H;01;43;185'
# add the rest of the data to the file
$data[1..($data.Count -1)] | Add-Content -Path $csvFilePath
P.S. I would delete the lines
$excelApp.Visible = $true
Start-Sleep 5
because I don't see the need to have Excel show itself and pause the function for 5 seconds.. Instead, have Excel not show at all so it will work a lot faster by adding
$excelApp.Visible = $false
right after you have created the $excelApp
I need to remove several columns from a CSV file without importing the CSV file in Powershell. Below is an example of my input CSV and what I hope the output CSV can look like.
Input.csv
A,1,2,3,4,5
B,6,7,8,9,10
C,11,12,13,14,15
D,15,16,17,18,19,20
Idealoutput.csv
A,3,5
B,8,10
C,13,15
D,17,20
I have tried doing this the following code, but it is giving me plenty of errors and saying that I cannot use the "Delete" method this way (which I have done in the past)...Any ideas?
$Workbook1 = $Excel.Workbooks.open($file.FullName)
$header = $Workbook1.ActiveSheet.Range("A1:A68").EntireRow
$unneededcolumns1 = $Workbook1.ActiveSheet.Range("A1:O1").EntireColumn
$unneededcolumns2 = $Workbook1.ActiveSheet.Range("B1:K1").EntireColumn
$unneededcolumns3 = $Workbook1.ActiveSheet.Range("F1:I1").EntireColumn
$unneededcolumns4 = $Workbook1.ActiveSheet.Range("G1:I1").EntireColumn
$unneededcolumns5 = $Workbook1.ActiveSheet.Range("H1:O1").EntireColumn
$unneededcolumns6 = $Workbook1.ActiveSheet.Range("J1:AL1").EntireColumn
$unneededcolumns7 = $Workbook1.ActiveSheet.Range("K1").EntireColumn
$unneededcolumns8 = $Workbook1.ActiveSheet.Range("L1:AK1").EntireColumn
$unneededcolumns9 = $Workbook1.ActiveSheet.Range("F1:I1").EntireColumn
$unneededcolumns10 = $Workbook1.ActiveSheet.Range("M1:AB1").EntireColumn
$unneededcolumns11 = $Workbook1.ActiveSheet.Range("N1:X1").EntireColumn
$unneededcolumns12 = $Workbook1.ActiveSheet.Range("O1:BA1").EntireColumn
$unneededcolumns13 = $Workbook1.ActiveSheet.Range("P1:U1").EntireColumn
$header.Delete()
$unneededcolumns1.Delete()
$unneededcolumns2.Delete()
$unneededcolumns3.Delete()
$unneededcolumns4.Delete()
$unneededcolumns5.Delete()
$unneededcolumns6.Delete()
$unneededcolumns7.Delete()
$unneededcolumns8.Delete()
$unneededcolumns9.Delete()
$unneededcolumns10.Delete()
$unneededcolumns11.Delete()
$unneededcolumns12.Delete()
$unneededcolumns13.Delete()
$Workbook1.SaveAs("\\output.csv")
I am just going to add this anyway since I hope to convince you how easy it will be to avoid having to use Excel.
$source = "c:\temp\file.csv"
$destination = "C:\temp\newfile.csv"
(Import-CSV $source -Header 1,2,3,4,5,6 |
Select "1","4","6" |
ConvertTo-Csv -NoTypeInformation |
Select-Object -Skip 1) -replace '"' | Set-Content $destination
We assign arbitrary headers to the object and that way we can call the 1st, 4th and 6th columns by position. Once exported the file will have the following contents which match what I think you want and not what you had in the question. Your last line had an extra value (20) on it which I don't know if it was on purpose or not.
A,3,5
B,8,10
C,13,15
D,17,19
If this is not viable I am really interested as to why.
Excel Approach
Alright, so the file is enormous so Import-CSV is not a viable option. Keeping with your excel idea I came up with this. What it will do is take column indexes and delete any column that is not in those indices.
Wait you say?... that wont work since the column indexes change as you remove columns. Using the indices we want to keep we get the inverse to delete based on the UsedRows of the sheet. We then take each of those columns to delete and remove a value equal to is array position. Reason being is that when a column is actually deleted the next value has already been adjusted to account for the shift.
$file = "c:\temp\file.csv"
$ColumnsToKeep = 1,4,6
# Create the com object
$excel = New-Object -comobject Excel.Application
$excel.DisplayAlerts = $False
$excel.visible = $False
# Open the CSV File
$workbook = $excel.Workbooks.Open($file)
$sheet = $workbook.Sheets.Item(1)
# Determine the number of rows in use
$maxColumns = $sheet.UsedRange.Columns.Count
$ColumnsToRemove = Compare-Object $ColumnsToKeep (1..$maxColumns) | Where-Object{$_.SideIndicator -eq "=>"} | Select-Object -ExpandProperty InputObject
0..($ColumnsToRemove.Count - 1) | %{$ColumnsToRemove[$_] = $ColumnsToRemove[$_] - $_}
$ColumnsToRemove | ForEach-Object{
[void]$sheet.Cells.Item(1,$_).EntireColumn.Delete()
}
# Save the edited file
$workbook.SaveAs("C:\temp\newfile.csv", 6)
# Close excel and release the com object.
$workbook.Close($true)
$excel.Quit()
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
Remove-Variable excel
I was having issues with Excel remaining open even after reading up on the "correct" way to do it. The inner logic is what is important. Don't forget to change your paths as needed.
Here's a better approach that I use, but it's not the most performant on large files. Both have been tested on 1GB files.
Powershell:
Import-Csv '.\inputfile.csv'
| select ColumnName1,ColumnName2,ColumnName3
| Export-Csv -Path .\outputfile.csv -NoTypeInformation
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-csv?view=powershell-5.1
If you want to get rid of those pesky quotes that the tool adds, upgrade to Powershell 7.
Powershell 7+:
Import-Csv '.\inputfile.csv'
| select ColumnName1,ColumnName2,ColumnName3
| Export-Csv -Path .\outputfile.csv -NoTypeInformation -UseQuotes Never
https://learn.microsoft.com/en-us/powershell/module/microsoft.powershell.utility/export-csv?view=powershell-7
I have this excel sheets and I want to have the same format for csv files. Could some one help me with a automation script please (to convert multiple excel sheets to csv files)??
I tried this script, but the 16th digit of the card number is turning to be zero as excel can read only 15 digits right. Can we modify this code to convert multiple excel sheets to csv files?
Could someone help me with this.
Convert Excel file to CSV
$xlCSV=6
$Excelfilename = “C:\Temp\file.xlsx”
$CSVfilename = “C:\Temp\file.csv”
$Excel = New-Object -comobject Excel.Application
$Excel.Visible = $False
$Excel.displayalerts=$False
$Workbook = $Excel.Workbooks.Open($ExcelFileName)
$Workbook.SaveAs($CSVfilename,$xlCSV)
$Excel.Quit()
If(ps excel){kill -name excel}
Excel is really particular in its handling of CSV files..
Although the 16 digit numbers are written out in full when using the SaveAs method, if you re-open it by double-clicking the csv file, Excel screws up these numbers by converting them to numeric values instead of strings.
In order to force Excel to NOT interpret these values and simply regard them as strings, you need to adjust the values in the csv file afterwards, by prefixing them with a TAB character.
(this will make the file useless for other applications..)
Of course, you need to know the correct column header to do this.
Let's assume your Excel file looks like this:
As you can see, the value we need to adjust is stored in column Number
To output csv files on which you can double-click so they are opened in Excel, the code below would do that for you:
$xlCSV = 6
$Excelfiles = 'D:\test.xlsx', 'D:\test2.xlsx' # an array of files to convert
$ColumnName = 'Number' # example, you need to know the column name
# create an Excel COM object
$Excel = New-Object -comobject Excel.Application
$Excel.Visible = $False
$Excel.DisplayAlerts = $False
foreach ($fileName in $Excelfiles) {
$Workbook = $Excel.Workbooks.Open($fileName)
# use the same file name, but change the extension to .csv for output
$CSVfile = [System.IO.Path]::ChangeExtension($fileName, 'csv')
# have Excel save the csv file
$Workbook.SaveAs($CSVfile, $xlCSV)
$Workbook.Close($false)
}
# close excel and clean up the used COM objects
$Excel.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Workbook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# now import the csv files just created and update the card number
# column by prefixing the value with a TAB character ("`t").
# this will effectively force Excel NOT to interpret the value as numeric.
# you better not do this inside the same loop, because Excel keeps a lock
# on outputted csv files there.
foreach ($fileName in $Excelfiles) {
# use the same file name, but change the extension to .csv for output
$CSVfile = [System.IO.Path]::ChangeExtension($fileName, 'csv')
# the '-UseCulture' switch makes sure the same delimiter character is used
$csv = Import-Csv -Path $CSVfile -UseCulture
foreach ($item in $csv) { $item.$ColumnName = "`t" + $item.$ColumnName }
# re-save the csv file with updates values
$csv | Export-Csv -Path $CSVfile -UseCulture -NoTypeInformation
}
I want create powershell script which create me csv file from .xls file but I don't know excacly how to use powershell wihout vba.
So far i have this :
ConvertTo-Csv "C:\Users\Me\TestsShella\test.xlsx" | Out-File Q:\test\testShella.csv
But it doesn't working.
With Excel present on the running machine use it as a COM-object:
## Q:\Test\2019\01\31\SO_54461362.ps1
$InFile = Get-Item "$($Env:USERPROFILE)\TestsShella\test.xlsx"
$OutFile= $InFile.FullName.replace($InFile.Extension,".csv")
$Excel = new-object -ComObject "Excel.Application"
$Excel.DisplayAlerts = $True
$Excel.Visible = $False # $True while testing
$WorkBook = $Excel.Workbooks.Open($InFile.FullName)
$WorkBook.SaveAs($OutFile, 6) # 6 -> type csv
$WorkBook.Close($True)
$Excel.Quit()
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
Depending on the locale (decimal point/comma) the csv file will either be comma or semicolon seperated.
Without Excel being installed, use the already suggest module ImportExcel
$InFile = Get-Item "$($Env:USERPROFILE)\TestsShella\test.xlsx"
$OutFile= $InFile.FullName.replace($InFile.Extension,".csv")
Import-Excel $Infile.FullName | Export-Csv $OutFile -NoTypeInformation
This yields a .csv file with all fields double quoted and comma seperated.
There is a prebuilt library for this:
https://www.powershellgallery.com/packages/ImportExcel/5.4.4
You will then have the import-excel function/cmdlet available to you and will be able to import, convert to csv and then export
Maybe this could work:
rename-item -Path "C:\Users\Me\TestsShella\test.xlsx" -NewName "item.csv"
you will get a message when open the CSV, but the format of CSV is like XLSX.