Use a reference list instead of adding to powershell script - excel

I have a txt file clients.txt that contains
c:\report1.xlm
c:\report2.xml
I want this to run against each xml
$ws = $wb.Sheets.Item('Report')
$ws.UsedRange.RemoveDuplicates($Columns)
$page = "Report"

Are you trying to substitute 'Report' with the xml reference from clients.txt?
If so:
$reports = get-content c:\clients.txt
$reports | ForEach-Object {
$ws = $wb.Sheets.Item($_)
$ws.UsedRange.RemoveDuplicates($Columns)
$page = "Report"
}
I'm not 100% sure what you are attempting to do.

Related

Reading last row of specific column in Excel sheet and appending more data - in PowerShell

I'm trying to write data to specific column in an Excel spreadsheet with PowerShell. I would like to start below last row with data and continiue downwards. On machine I don't have Excel installed so COM won't work for me. I'm currently using Import-Excel to read whole sheet and used Open-ExcelPackage to read specific cell values.
I could do this in CSV file as opposed to .xlsx if it's easier.
Any help would be great!
Download PSExcel module from https://github.com/RamblingCookieMonster/PSExcel Import it using Import-Module.
Then use the following code:
$File = "Path to xlxs file"
$WSName = "SheetName"
$Excel = New-Excel -Path $File
$Worksheet = $Excel | Get-WorkSheet -Name $WSName
$SampleRows = #()
$SampleRows += [PSCustomObject]#{"A" = 1; "B" = 2; "C" = 3; "F" = 4 }
$row_to_insert = $SampleRows.count
$Worksheet.InsertRow($Worksheet.Dimension.Rows,$row_to_insert)
$WorkSheet.Cells["$($Worksheet.Dimension.Start.Address -replace ""\d"")$($Worksheet.Dimension.End.Row):$($Worksheet.Dimension.End.Address)"].Copy($WorkSheet.Cells["$($Worksheet.Dimension.Start.Address -replace ""\d"")$($Worksheet.Dimension.End.Row - $row_to_insert):$($Worksheet.Dimension.End.Address -replace ""\d"")$($Worksheet.Dimension.End.Row - $row_to_insert)"]);
$WorkSheet.Cells["$($Worksheet.Dimension.Start.Address -replace ""\d"")$($Worksheet.Dimension.End.Row):$($Worksheet.Dimension.End.Address)"] | % {$_.Value = ""}
ForEach ($Row in $SampleRows) {
ForEach ($data in $Row.PSObject.Properties.Name) {
$WorkSheet.Cells["$data$($Worksheet.Dimension.Rows)"].Value = $SampleRow.$data
}
}
$Excel | Close-Excel -Save
This code adds 1 row after the last row in the selected worksheet and adds values to this row from $SampleRows.... I think you got the idea. if you need add more rows to $SampleRows array.

Command to retrieve all non-empty block-content from Excel workbooks?

I have a sheet DataRepo about the size of 300 rows and 10 rows, about 300 such Excel files in XLSX format. I need to read each Excel file and store it as a CSV (because original XLSX files are corrupted with KeyError, other methods in Python/R resulting to KeyError unless resaving manually with Excel).
I am currently using $Sheet.Cells.Item(row, col).Text to get single value as text but the need over the whole block: either I need to 2-loop over the block and save it CSV or find some ready method for the $Sheet, any ready PowerShell method available? Which looping options available in PowerShell?
How can I retrieve all non-empty content in an Excel sheet with PowerShell?
$XLSDoc = 'C:\Users\hhh\Desktop\1.xlsx'
$SheetName = "DataRepo"
$Excel = New-Object -ComObject "Excel.Application"
$Workbook = $Excel.Workbooks.Open($XLSDoc)
$Sheet = $Workbook.Worksheets.Item($SheetName)
#Get data:
$Sheet.Cells.Item(1,2).Text
Can I do something similar to VBA in PowerShell?
Dim i As Integer
Dim j As Integer
i = 1
j = 1
Do While i < 10
Do While j < 10
Sheet.Cells.Item(i, j).Text
j = j + 1
Loop
i = i + 1
Loop
Use something like this to export each worksheet to a separate CSV:
$wbName = $Workbook.Name
$wbPath = $Workbook.Path
$Workbook.Worksheets | ForEach-Object {
$csvName = Join-Path $wbPath ('{0}_{1}.csv' -f $wbName, $_.Name)
$_.SaveAs($csvName, 6)
}
The following code creates a function out of the code here and then loop over all of the xlsx files in the directory, replacement and trimming added to avoid 216 chars limit per file. Then it outputs the CSV files to the directory of each sheet.
Function ExportXLSXToCSVs ($XLSDoc)
{
$Excel = New-Object -ComObject "Excel.Application"
$Workbook = $Excel.Workbooks.Open($XLSDoc)
$wbName = $Workbook.Name
$wbPath = $Workbook.Path
$Workbook.Worksheets | ForEach-Object {
$csvName = Join-Path $wbPath ('{0}_{1}.csv' -f $wbName, $_.Name)
#Trim/replacements added to avoid the limit 216 chars per file
$csvName = $csvName.Trim().Replace(" ", "")
$_.SaveAs($csvName, 6) #CSV
}
}
#DEMO 1 over a single file
#ExportXLSXToCSVs('C:\Users\hhh\Desktop\1.xlsx')
#DEMO 2 over all files in a directory
Get-ChildItem "C:\Users\hhh\Desktop\Data\" -Filter *.xlsx | ForEach-Object {
$myFile = $_.DirectoryName +"\"+ $_.Name
ExportXLSXToCSVs($myFile)
}

How to save file without overwrite excel file

I am using EPPlus.dll in Powershell script to convert csv file to xlsx file, but I no have idea how to save file without overwrite existing data.
I have to generate new information from csv file to excel file,
but I have others, manualy created tab which my script always overwrite.
Script looks like this:
$FileNameCSV = "$env:WORKSPACE/file.csv"
$FileNameExcel = "\\folder\file.xlsx "
$DLLPath = "D:\EPPlus.dll"
[Reflection.Assembly]::LoadFile($DLLPath) | Out-Null
$Format = New-object -TypeName OfficeOpenXml.ExcelTextFormat
$Format.Delimiter = ","
$Format.TextQualifier = '"'
$Format.Encoding = [System.Text.Encoding]::UTF8
$Format.SkipLinesBeginning = '0'
$Format.SkipLinesEnd = '1'
$TableStyle = [OfficeOpenXml.Table.TableStyles]::Medium1
$ExcelPackage = New-Object OfficeOpenXml.ExcelPackage
$Worksheet = $ExcelPackage.Workbook.Worksheets.Add("CM")
$null=$Worksheet.Cells.LoadFromText((Get-Item $FileNameCSV),$Format,$TableStyle,$true)
$Worksheet.Cells[$Worksheet.Dimension.Address+1].AutoFitColumns()
$Worksheet.Column(3).Style.Numberformat.Format = "dd/mm/yyyy";
$ExcelPackage.SaveAs($FileNameExcel)
Write-Host "CSV File $FileNameCSV converted to Excel file $FileNameExcel"
You need to open the existing file named $FileNameExcel by passing the name to the constructor, probably like this:
$ExcelPackage = New-Object OfficeOpenXml.ExcelPackage($FileNameExcel)
Then, add a new worksheet to this workbook, load the csv into this new worksheet the same way you do it currently, and save the workbook again.

Import Excel, Export CSV with PowerShell

Due to restrictions I either need to use VB or PowerShell for this task.
I have an Excel that looks like:
ColumA, ColumB,ColumC,ColumD,ColumE,ColumF
000|Txt,MoreTxt , ColumB,ColumC,ColumD,ColumE,ColumF
I read about import_csv -header, but I'm under to successfully do it. I'll post my script below. The export I expect is:
ColumA, ColumB, ColumC, ColumD, ColumE, ColumF
000, ColumB, ColumC, ColumD, ColumE, ColumF
Only Colum gets modified, and I -only- need the digits from before that pipe. It also has to stay three digits, so 1 becomes 001, etc.
This is the script I modified based on some previous inquiries I saw, and the MS Tutorial.
$file = import-csv "C:\path\to\my\file\test.csv"
foreach ($row in $file){
$tempfile = New-Object psobject -Property #{
ColumA = $row. 'ListName'.substring(0,2)
ColumB = $row. 'ColumB'
ColumC = $row. 'ColumC'
ColumE = $row. 'ColumE'
ColumF = $row. 'ColumF'
}
$expandfile = #()
$expandfile += $tempfile | select ColumA, ColumB, ColumC, ColumD, ColumE, ColumF
}
PS gives me both errors on not liking everything I have in quotes (Which I thought was the column name, but I guess not. And also a parse error on the entire array. Essentially the entire script.
UPDATE
Providing real examples of source.
"Tiam
Name",SiamName,Siam,Ciam,Piam,Liam,Niam,Diam
"002|City, State","City, State - Some text (15092)",1,"3,408",99,"3,408",780,22.89%
"009|City, State","City, State - Some Text (E) (15450)",1,"1,894",81,"1,894",543,28.67%
Edit:
$expandfile = Import-Csv "C:\path\to\my\file\test.csv" | ForEach-Object {
$_."Tiam`r`nName" = $_."Tiam`r`nName".SubString(0,3)
$_
}

Faster way of writing out to excel in powershell

I have a powershell script that reads in a csv and then appends to an excel worksheet.
It runs quite painfully slow. I have searched and it seems this is a limitation of using com to write to excel. Some suggestions I have found to speed this up are to write out entire ranges instead of cell by cell. However I need to format the cells and it doesn't seem to be possible to do this when writing out ranges. Any suggestions on how to optimize the below code would be welcome.
I do not have the option to use a DB.
$csvPath = "Z:\script_test\"
$outputFile = "Z:\script_test\exceltest.xlsx"
foreach($csvFile in Get-ChildItem $csvPath -Filter "STATS*.txt" ){
$csvFilePath = [io.path]::combine($csvPath, $csvFile)
$rawcsvData = Import-Csv -Delimiter ";" -Path $csvFilePath
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.Open($outputFile)
$ExcelWorkSheet = $Excel.WorkSheets.item("2016")
$ExcelWorkSheet.activate()
$excel.cells.item(1,1) = “PEX”
$excel.cells.item(1,2) = “RUN DATE”
$excel.cells.item(1,3) = “EXECS”
$excel.cells.item(1,4) = “CPU AV.”
$excel.cells.item(1,5) = “CPU HI.”
$excel.cells.item(1,6) = “CPU TOT.”
$excel.cells.item(1,7) = “#VALUE!”
$excel.cells.item(1,8) = “ELAPS AV.”
$excel.cells.item(1,9) = “ELAPSE HI.”
$excel.cells.item(1,10) = “ELAPSE TOT”
$i = $ExcelWorkSheet.UsedRange.rows.count + 1
foreach($rawcsv in $rawcsvData)
{
$RUNDATE = $rawcsv.“RUN DATE ”.replace("--1","")
$EXECS = $rawcsv."EXECS ".replace("?","")
$CPUAV = $rawcsv.“CPU AV. ”.replace("-",":")
$CPUHI = $rawcsv.“CPU HI. ”.replace("-",":")
$CPUTOT = $rawcsv.“CPU TOT. ”.replace("-",":")
$ELAPSEAV = $rawcsv.“ELAPSE AV.”.replace("-",":")
$ELAPSEHI = $rawcsv.“ELAPSE HI.”.replace("-",":")
$ELPASETOT = $rawcsv.“ELPASE TOT”.replace("-",":")
Write-Output("working" + $i)
$excel.cells.item($i,1) = $rawcsv."PEX "
$excel.cells.item($i,2) = $RUNDATE
$excel.cells.item($i,2).NumberFormat = “yyyy/mm/dd”
$excel.cells.item($i,3) = $EXECS
$excel.cells.item($i,4) = $CPUAV
$excel.cells.item($i,4).NumberFormat = “hh:mm:ss.00”
$excel.cells.item($i,5) = $CPUHI
$excel.cells.item($i,5).NumberFormat = “hh:mm:ss.00”
$excel.cells.item($i,6) = $CPUTOT
$excel.cells.item($i,6).NumberFormat = “hh:mm:ss.00”
$excel.cells.item($i,7) = “=((HOUR(F"+$i+")*3600)+(MINUTE(F"+$i+")*60)+SECOND(F"+$i+"))*21”
$excel.cells.item($i,8) = $ELAPSEAV
$excel.cells.item($i,8).NumberFormat = “hh:mm:ss.00”
$excel.cells.item($i,9) = $ELAPSEHI
$excel.cells.item($i,9).NumberFormat = “hh:mm:ss.00”
$excel.cells.item($i,10) = $ELPASETOT
$excel.cells.item($i,10).NumberFormat = “hh:mm:ss.00”
$i++
}
$ExcelWorkSheet.UsedRange.RemoveDuplicates()
#$workbook.saveas($outputFile)
$workbook.save()
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
Move-Item -Path $csvFilePath -Destination "Z:\script_test\used files"
}
The slow part is all about COM object performance. You won't be able to speed this up good enough if you will keep working with COM object, sadly.
Back in days I had some project related to Excel and I found some great module that uses external DLL, you can take a look on it: PSExcel
Best part is that you will not need to have Excel installed, like you do with COM object.
There is a Powershell cmdlet you can install called Export-XLSX that works very similarly to the native Export-CSV: https://gallery.technet.microsoft.com/office/Export-XLSX-PowerShell-f2f0c035
The documentation there is pretty good, but here's an example of how you would use it:
# 1. Define path of Export-XLSX.ps1 script:
$ExportXLSX = "C:\YourFilePath\Export-XLSX\Export-XLSX.ps1"
# 2. Call script same as any other function by preceding filename with a period (.$ExportXLSX) and following it with parameters:
Get-ChildItem $env:windir | Select-Object Mode,LastWriteTime,Length,Name | .$ExportXLSX -Path 'c:\temp\PSExcel.xlsx' -WorkSheetName 'Files'
UPDATE: Having compared this option with the full PSExcel module presented in the other answer, I actually prefer the PSExcel module. The performance speed-wise is pretty much the same in my testing, but the PSExcel module appears to create much smaller files.
For example, using the above list of the windows directory outputs a 53KB file using the Export-XLSX.ps1 on my machine. However, the PSExcel module outputs a 7KB file. Given its ease of use, I would go with it.

Resources