Exporting Charts from Excel - excel

I am using Import-Excel (great module BTW) to create an Excel Spreadsheet with 1 chart in it. However, I would like to export this chart as a .png file. There are lots of examples using MS ComObject but I am running on a Mac and Com objects don't exist.
I have been able to get this far in my powershell script.
$package = Export-Excel -InputObject $data -Path $filename -TableName Xyz -ExcelChartDefinition $c -AutoNameRange -PassThru
Write-Host "Package is " $package.ToString()
$wb = $package.Workbook
Write-Host "Workbook is " $wb.ToString()
foreach ($ws in $wb.Worksheets) {
Write-Host "Worksheet is " $ws.ToString()
foreach ($excelchart in $ws.Drawings) {
Write-Host "Chart is " $excelchart.ToString()
}
}
with the following output:
Package is OfficeOpenXml.ExcelPackage
Workbook is OfficeOpenXml.ExcelWorkbook
Worksheet is Sheet1
Chart is OfficeOpenXml.Drawing.Chart.ExcelBarChart
Now, I would just like to know how to save this as a .png file.

Check out https://github.com/dfinke/ImportExcel/blob/master/Export-charts.ps1
It is an example, so your mileage may vary. If you have issues with it, please post that on the GitHub repo, and I can track it.

Related

OfficeOpenXml remove HyperLink

Im use Powershell module "ImportExcel" for generating xlsx report.
Some string, as "openstack-9cea5509-ed06-4301-b9e2-10f742e8c174:8", add in cell as HyperLink.
I cant remove HyperLink, next method not work:
$d = #(
[PSCustomObject]#{
HLUNID = "String11`nString22"
HostID = "String33`nStrong44"
}
[PSCustomObject]#{
HLUNID = "String55`nString552"
HostID = "openstack-9cea5509-ed06-4301-b9e2-10f742e8c174:8"
}
)
Export-Excel -Path "out1.xlsx" -InputObject $d -WorksheetName 'Luns' -AutoNameRange
$Excel = Open-ExcelPackage -Path "out1.xlsx"
$Excel.Workbook.Worksheets['Luns'].Cells['HostID'] | Set-ExcelRange -ResetFont
$Excel.Workbook.Worksheets['Luns'].Cells[3,2].HyperLink = ''
Close-ExcelPackage -ExcelPackage $Excel
String steel stay clickable:
Image - "Clickable cell"
Next method is not exist:
$Excel.Workbook.Worksheets['Luns'].Cells[3,2].HyperLink.Remove()
$Excel.Workbook.Worksheets['Luns'].Cells[3,2].HyperLink.Dispose()
Please, give me another method for delete HyperLynk.
Try setting the hyperlink $null
$Excel.Workbook.Worksheets['Luns'].Cells[3,2].HyperLink = $null
It will remove the hyperlink, but won't touch the formatting.
Have a read about the method and the functions to manage hyperlink I have proposed to be included into the module.
How to make Excel hyperlinks with PowerShell?

How to search a string in an Excel using Powershell

I have a folder containing multiple excel files. I want to search for a string like "2501" and find which of my files contains this string then output it's file name to a file (or display it). I wrote some scripts and googled but did not find the answer.
I wrote this :
$Location = "C:\1.xlsx"
$SearchStr = "Mike"
$Sel = Select-String -pattern $SearchStr -path $Location
If ($Sel -eq $null)
{
write-host "$Location does not contain $SearchStr" -ForegroundColor Cyan
}
Else
{
write-host "Found $SearchStr `n$Se in $Location"
}
Write-host "end" -ForegroundColor Yellow
This works only if I specify a txt file, it does not work with Excel.
This may help https://gallery.technet.microsoft.com/office/How-to-search-text-in-e16373b8
Also you may need to loop the folder to search in every excel file

Creating Powershell script to loop through excel file and create folders

I'm new to Powerscript and looking at writing a solution to loop through an excel file and create a folder for each row in the file.
At the moment I have the following:
$objExcel = new-object -comobject excel.application
$objExcel.Visible = $True
$ExcelFilesLocation = “D:\Users\”
$UserWorkBook = $objExcel.Workbooks.Open($ExcelFilesLocation + “ProjectCodes.xlsx”)
$UserWorksheet = $UserWorkBook.Worksheets.Item(1)
$intRow = 2
Do {
$Projectcode = $UserWorksheet.Cells.Item($intRow, 1).Value()
$pos = $userLogOnEmail.IndexOf(“#”)
$intRow++
} While ($UserWorksheet.Cells.Item($intRow,1).Value() -ne $null)
$objExcel.Quit()
$a = Release-Ref($UserWorksheet)
$a = Release-Ref($UserWorkBook)
$a = Release-Ref($objExcel)
The idea is to loop through the project code column for each row. Then create a folder that is named for the project code.
Having spent painful hours wrangling Excel COM objects with PowerShell, my advice is to give up! Office COM objects are confusing, unwieldy and slow.
Replace the technology you use to access Excel in PowerShell with something better. For example, this module: https://github.com/dfinke/ImportExcel. You can use Install-Module ImportExcel -Scope CurrentUser if you're using PS 5.
Apart from being easier to use and much faster it doesn't require Excel to be installed, making your final script more portable.
Admitedly, you don't get full Excel functionality with this module but since you seem to be doing no more than reading cells, you should be fine.
Alternatively, Save your Excel file as CSV and use Import-Csv instead.
To create a new directory, use New-Item
For example, assuming $Projectcode is a string containing a valid path:
New-Item -Path $Projectcode -Type Directory

Check header row of Excel sheet for particular column

I have over 150 excel files where some have an extra column (let's call it "ExtraColumn"), while some do not have this column. Instead of opening each file manually to see which ones have the extra column, I want to use powershell to figure it out.
The code I have tried so far hasn't seemed to have gotten me anywhere. If you have any suggestions or can point me to the correct answer, that would be very wonderful and much appreciated!
gci -Path C:\Test -Recurse | % {
$ExcelFile = (Get-Content $_.FullName -TotalCount 1)
if ($ExcelFile -like "ExtraColumn") {
Write-Host "$_ has the extra column"
} else {
Write-Host "$_ does not have the extra column"
}
}
You can use Excel ComObject, for the code simplicity just name the sheet otherwise you can find the sheet as well, add foreach section to run it on all files,
For the example i named the column - 'extracol'
$excel = New-Object -ComObject excel.application
$WB = $excel.Workbooks.Open('C:\exceltest.xlsx')
$WS = $Excel.WorkSheets.item("Sheet1")
$ExtraCol = ($ws.Columns.Find('extracol'))
if ($ExtraCol) {$ExtraCol.Delete()}
$wb.Save()
$wb.Close()
$excel.Quit()

Is there a faster way to parse an excel document with Powershell?

I'm interfacing with an MS Excel document via Powershell. There is a possibility of each excel document of having around 1000 rows of data.
Currently this script seems to read the Excel file and write a value to screen at a rate of 1 record every .6 seconds. At first glance that seems extremely slow.
This is my first time reading an Excel file with Powershell, is this the norm? Is there a faster way for me to read and parse the Excel data?
Here is the script output (trimmed for readability)
PS P:\Powershell\ExcelInterfaceTest> .\WRIRMPTruckInterface.ps1 test.xlsx
3/20/2013 4:46:01 PM
---------------------------
2 078110
3 078108
4 078107
5 078109
<SNIP>
242 078338
243 078344
244 078347
245 078350
3/20/2013 4:48:33 PM
---------------------------
PS P:\Powershell\ExcelInterfaceTest>
Here is the Powershell script:
########################################################################################################
# This is a common function I am using which will release excel objects
########################################################################################################
function Release-Ref ($ref) {
([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
########################################################################################################
# Variables
########################################################################################################
########################################################################################################
# Creating excel object
########################################################################################################
$objExcel = new-object -comobject excel.application
# Set to false to not open the app on screen.
$objExcel.Visible = $False
########################################################################################################
# Directory location where we have our excel files
########################################################################################################
$ExcelFilesLocation = "C:/ShippingInterface/" + $args[0]
########################################################################################################
# Open our excel file
########################################################################################################
$UserWorkBook = $objExcel.Workbooks.Open($ExcelFilesLocation)
########################################################################################################
# Here Item(1) refers to sheet 1 of of the workbook. If we want to access sheet 10, we have to modify the code to Item(10)
########################################################################################################
$UserWorksheet = $UserWorkBook.Worksheets.Item(2)
########################################################################################################
# This is counter which will help to iterrate trough the loop. This is simply a row counter
# I am starting row count as 2, because the first row in my case is header. So we dont need to read the header data
########################################################################################################
$intRow = 2
$a = Get-Date
write-host $a
write-host "---------------------------"
Do {
# Reading the first column of the current row
$TicketNumber = $UserWorksheet.Cells.Item($intRow, 1).Value()
write-host $intRow " " $TicketNumber
$intRow++
} While ($UserWorksheet.Cells.Item($intRow,1).Value() -ne $null)
$a = Get-Date
write-host $a
write-host "---------------------------"
########################################################################################################
# Exiting the excel object
########################################################################################################
$objExcel.Quit()
########################################################################################################
#Release all the objects used above
########################################################################################################
$a = Release-Ref($UserWorksheet)
$a = Release-Ref($UserWorkBook)
$a = Release-Ref($objExcel)
In his blog entry Speed Up Reading Excel Files in PowerShell, Robert M. Toups, Jr. explains that while loading to PowerShell is fast, actually reading the Excel cells is very slow. On the other hand, PowerShell can read a text file very quickly, so his solution is to load the spreadsheet in PowerShell, use Excel’s native CSV export process to save it as a CSV file, then use PowerShell’s standard Import-Csv cmdlet to process the data blazingly fast. He reports that this has given him up to a 20 times faster import process!
Leveraging Toups’ code, I created an Import-Excel function that lets you import spreadsheet data very easily.
My code adds the capability to select a specific worksheet within an Excel workbook, rather than just using the default worksheet (i.e. the active sheet at the time you saved the file). If you omit the –SheetName parameter, it uses the default worksheet.
function Import-Excel([string]$FilePath, [string]$SheetName = "")
{
$csvFile = Join-Path $env:temp ("{0}.csv" -f (Get-Item -path $FilePath).BaseName)
if (Test-Path -path $csvFile) { Remove-Item -path $csvFile }
# convert Excel file to CSV file
$xlCSVType = 6 # SEE: http://msdn.microsoft.com/en-us/library/bb241279.aspx
$excelObject = New-Object -ComObject Excel.Application
$excelObject.Visible = $false
$workbookObject = $excelObject.Workbooks.Open($FilePath)
SetActiveSheet $workbookObject $SheetName | Out-Null
$workbookObject.SaveAs($csvFile,$xlCSVType)
$workbookObject.Saved = $true
$workbookObject.Close()
# cleanup
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbookObject) |
Out-Null
$excelObject.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelObject) |
Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
# now import and return the data
Import-Csv -path $csvFile
}
These supplemental functions are used by Import-Excel:
function FindSheet([Object]$workbook, [string]$name)
{
$sheetNumber = 0
for ($i=1; $i -le $workbook.Sheets.Count; $i++) {
if ($name -eq $workbook.Sheets.Item($i).Name) { $sheetNumber = $i; break }
}
return $sheetNumber
}
function SetActiveSheet([Object]$workbook, [string]$name)
{
if (!$name) { return }
$sheetNumber = FindSheet $workbook $name
if ($sheetNumber -gt 0) { $workbook.Worksheets.Item($sheetNumber).Activate() }
return ($sheetNumber -gt 0)
}
If the data is static (no formulas involved, just data in cells), you can access the spreadsheet as an ODBC data source and execute SQL (or at least SQL-like) queries against it. Have a look at this reference for setting up your connectionstring (each worksheet in a workbook will be a "table" for this exercise), and use System.Data to query it the same as you would a regular database (Don Jones wrote a wrapper function for this which may help).
This should be faster than launching Excel & picking through cell by cell.

Resources