Automate exporting of Excel worksheets to PDF - excel

Editor's note: The OP has abandoned this question and asked a variation at https://stackoverflow.com/questions/38766898/saving-excel-worksheets-to-pdf-using-powershell.
I have been trying to implement the following PowerShell script but without any luck. Can someone please help?
I know this script will save 1 PDF file per Excel workbook, however once I get this working I will look at exporting each Excel worksheet to separate PDF files.
ExportTo-ExcelPDF.ps1 from http://blogs.technet.com/b/heyscriptingguy/archive/2010/09/06/save-a-microsoft-excel-workbook-as-a-pdf-file-by-using-powershell.aspx
$path = "c:\fso"
$xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type]
$excelFiles = Get-ChildItem -Path $path -include *.xls, *.xlsx -recurse
$objExcel = New-Object -ComObject excel.application
$objExcel.visible = $false
foreach($wb in $excelFiles)
{
$filepath = Join-Path -Path $path -ChildPath ($wb.BaseName + ".pdf")
$workbook = $objExcel.workbooks.open($wb.fullname, 3)
$workbook.Saved = $true
"saving $filepath"
$workbook.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $filepath)
$objExcel.Workbooks.close()
}
$objExcel.Quit()
Error messages:
The property 'Saved' cannot be found on this object. Verify that the
property exists and can be set.
At C:\ExportExcel.ps1:23 char:2
+  $workbook.Saved = $true
+ ~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyAssignmentException
saving C:\ExportExcel.pdf
Method invocation failed because [System.__ComObject] does not contain a
method named 'ExportAsFixedFormat'.
At C:\ExportExcel.ps1:25 char:2
+  $workbook.ExportAsFixedFormat($xlFixedFormat::xlTypePDF, $filepath)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
You cannot call a method on a null-valued expression.
At C:\ExportExcel.ps1:26 char:2
+  $objExcel.Workbooks.close()
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
Exception calling "Quit" with "0" argument(s): "Call was rejected by callee.
(Exception from HRESULT: 0x80010001 (RPC_E_CALL_REJECTED))"
At C:\ExportExcel.ps1:28 char:1
+ $objExcel.Quit()
+ ~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : COMException

tl;dr
The most likely cause is that Excel's primary interop assembly isn't installed.
The error messages suggest that even though you managed the create the Excel-related objects per se, accessing their members (properties and methods) failed.
Sometimes, setting $VerbosePreference='Continue' helps; for instance, on my machine I see the following when I instantiate the Excel application object (New-Object -ComObject excel.application):
VERBOSE: The object written to the pipeline is an instance of the type "Microsoft.Office.Interop.Excel.ApplicationClass" from the component's primary interoperability assembly. If
this type exposes different members than the IDispatch members, scripts that are written to work with this object might not work if the primary interoperability assembly is not
installed.
Perhaps a missing interoperability assembly is your problem.
On my machine (PSv5, Excel 2010), this interoperability assembly is (a) not loaded by default, (b) is only loaded when you instantiate the Excel application object.
Thus, your code wouldn't work on my machine, because it references type [Microsoft.Office.Interop.Excel.xlFixedFormatType] - which is part of that interop assembly - before the Excel application object is created, which fails - silently, because the indirect type reference "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type] simply returns $null - without complaining - if the type doesn't exist (yet).
If you instead use [Microsoft.Office.Interop.Excel.xlFixedFormatType] directly, you'll instantly get an error if the type doesn't exist / its assembly has not been loaded (yet).
In short:
Remove line $xlFixedFormat = "Microsoft.Office.Interop.Excel.xlFixedFormatType" -as [type].
In its stead, place $xlFixedFormat = [Microsoft.Office.Interop.Excel.xlFixedFormatType] after the objExcel = New-Object -ComObject excel.application line.
Debug your script and run $objExcel | Get-Member and $wb | Get-Member right after the first $objExcel.workbooks.open($wb.fullname, 3) call to see what members PowerShell can see.
If the $xlFixedFormat = [Microsoft.Office.Interop.Excel.xlFixedFormatType] line produces an error right away, or you don't see the members of interest (Saved, ExportAsFixedFormat, ...), the most likely cause is that the interop assembly isn't installed.
Another way to see if the interop assembly is loaded is to execute [Microsoft.Office.Interop.Excel.ApplicationClass] and see if type information is returned (as opposed to an error message).

Related

Powershell generic error: Exception from HRESULT: 0x800A03EC

I know this is a very generic error message and I have spent many hours looking through similar questions without any luck.
Here is my PowerShell script producing this error:
$ExcelObject = New-Object -ComObject excel.application
$excelProcessId = ((get-process excel | select MainWindowTitle, ID, StartTime | Sort StartTime)[-1]).Id
$ExcelObject.visible = $true
$ExcelObject.DisplayAlerts = $true
$folderpath = "C:\myfiles\TESTER.xlsx"
$Workbook = $ExcelObject.Workbooks.Open($folderpath)
$WorkSheet = $Workbook.Worksheets.Item("TAB1")
$sourceList = "value1,value2,value3"
$missing = [system.type]::missing
$sourceRange = $WorkSheet.Range("A3:A22")
$sourceRange.Validation.add(3,1,$missing,$sourceList,$missing)
$Workbook.save()
$Workbook.close()
$ExcelObject.Quit()
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($Workbook)
[void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelObject)
[GC]::Collect()
Remove-Variable ExcelObject
Stop-Process -Id $excelProcessId -Force
resulting error:
Exception from HRESULT: 0x800A03EC
At line:11 char:1
+ $sourceRange.Validation.add(3,1,$missing,$sourceList,$missing)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
I have tried to use the value list directly but same error:
$sourceRange.Validation.add(3,1,$missing,"value1,value2,value3",$missing)
I replaced the $missing but same error:
$sourceRange.Validation.add(3,1,1,$sourceList)
I have no more ideas on how to resolve this issue and would appreciate any suggestions.
Thanks a lot for your time.
I have found the problem: the specified range had to be cleared of any existing validation:
$sourceRange = $WorkSheet.Range("A3:A22")
$sourceRange.Validation.Delete()
$sourceRange.Validation.add(3,1,$missing,$sourceList,$missing)
I feel a little embarrassed, but maybe it is of use to someone down the line.

How to subtract Excel cells using Powershell

I am trying to perform arithmetic on an existing excel sheet that has figures in it. My code:
$Excel = New-Object -ComObject Excel.Application
$ExcelWorkBook = $Excel.Workbooks.Open($temp)
$ExcelWorkSheet = $Excel.WorkSheets.item(1)
$ExcelWorkSheet.activate()
$Prehit = $ExcelWorkSheet.Cells.Item(2,1)
$Hit1 = $ExcelWorkSheet.Cells.Item(2,2)
$Hit2 = $ExcelWorkSheet.Cells.Item(2,3)
$Hit3 = $ExcelWorkSheet.Cells.Item(2,4)
$Remain = 0
If ($hit -eq 1) {
$Remain = $Prehit - $Hit1
}
If ($hit -eq 2) {
$Remain = $Prehit - $Hit1- $Hit2
}
Yields the following error:
Method invocation failed because [System.__ComObject] does not contain a method named 'op_Subtraction'.
At C:\path_to_ps1_file.ps1:40 char:3
+ $Remain = $Prehit - $Hit1- $Hit2
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (op_Subtraction:String) [], RuntimeException
+ FullyQualifiedErrorId : MethodNotFound
I have tried casting all the variables as ints yet that yields the same error. I even casted the numbers as ints in the powershell modules used to create this excel file. What am I missing?
I realize now I was referencing the cell values incorrectly. The correct way is to do:
$Prehit = $ExcelWorkSheet.Cells.Item(2,1).Text
$Hit1 = $ExcelWorkSheet.Cells.Item(2,2).Text
$Hit2 = $ExcelWorkSheet.Cells.Item(2,3).Text
$Hit3 = $ExcelWorkSheet.Cells.Item(2,4).Text
Whenever I've run into this sort of thing, I just the 'Excel Marco Recorder' and review the VBA code it produces and then convert that to PowerShell for later automation use cases.
Yet at no point in the code you posted are you making the XLS visible for you to act on it.
For example:
# Instantiate Excel instnace
$excel_test = New-Object -ComObject Excel.Application
# Make the instance visiable to work with it
$excel_test.visible = $true
# Catch alerts
$excel_test.DisplayAlerts = $true
# Add in the file source
$excel_test.Workbooks.Add('D:\Temp\Test.xlsx')
# Choose a sheet in the workbook
$Sheet = $excel_test.Worksheets.Item(1)
# Assign a formula to the target variable
$strFormula = '=(SUM(A1:C3)/3) - 1'
# Assign the formula to the target variable
$Sheet.Cells.Item(4,4) = $strFormula
$SourcecellCell = ($Sheet.Cells.Item(4,4)).Value2
$NewCell = 3
$sheet.Cells.Item(5,5) = $SourcecellCell - $NewCell
# Exit the XLS without saving
$excel_test.Quit()
Whenever I've run into this sort of thing, I just the 'Excel Marco Recorder' and review the VBA code it produces and then convert that to PowerShell for later automation use cases.
Yet at no point in the code you posted are you making the XLS visible for you to act on it. Since it is not visible, you cannot perform UI actions on it.
Secondly, this...
$excel_test.Worksheets.Item(2).Cells.Item(2,2).Formula() = $strFormula
... is where your issues begin. If you step through this one step at a time, you'll immediately see the aforementioned will simply fail.
For example:
# Instantiate Excel instance
$excel_test = New-Object -ComObject Excel.Application
# Make the instance visible to work with it
$excel_test.visible = $true
# Catch alerts
$excel_test.DisplayAlerts = $true
# Add in the file source
$excel_test.Workbooks.Add('D:\Temp\Test.xlsx')
# Results
<#
Application : Microsoft.Office.Interop.Excel.ApplicationClass
Creator : 1480803660
Parent : Microsoft.Office.Interop.Excel.ApplicationClass
...
#>
# Assign a formula to the target variable
$strFormula = "=((A1:C4/10000)-1)"
# Assign the formula to the target variable
$excel_test.Worksheets.Item(2).Cells.Item(2,2).Formula() = $strFormula
<#
Invalid index. (Exception from HRESULT: 0x8002000B (DISP_E_BADINDEX))
At line:1 char:1
+ $excel_test.Worksheets.Item(2).Cells.Item(2,2).Formula() = $strFormul ...
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
#>
$Error | Format-List -Force
<#
Exception : System.Management.Automation.RuntimeException: The variable '$command' cannot be retrieved because it has not been set.
at System.Management.Automation.VariableOps.GetVariableValue(VariablePath variablePath, ExecutionContext executionContext,
VariableExpressionAst varAst)
at Prompt(Closure , FunctionContext )
TargetObject : command
CategoryInfo : InvalidOperation: (command:String) [], RuntimeException
FullyQualifiedErrorId : VariableIsUndefined
ErrorDetails :
InvocationInfo : System.Management.Automation.InvocationInfo
ScriptStackTrace : at Prompt, C:\Users\Daniel\Documents\WindowsPowerShell\Microsoft.PowerShellISE_profile.ps1: line 55
at <ScriptBlock>, <No file>: line 1
PipelineIterationInfo : {}
PSMessageDetails :
...
#>

Powershell could not saveas excel after data written

I am a brand newbie to powershell. I am trying to generate a report to gather all printers' information in our environment. The report is well generated by opening Excel worksheet; however, it fails to save and simply jumps onto close
Below script I used to generate a report:
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$xlFixedFormat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlWorkbookDefault
$xl = New-Object -ComObject Excel.Application
$xl.Visible = $True
$xls = $xl.Workbooks.Add()
$Sh = $xls.Worksheets.Item(1)
$Sh.Name = "Printer Info"
.
.
.
.
$xls.SaveAs("C:\temp\Test.xlsx", $xlFixedFormat)
$xls.Close()
$xl.Quit()
Error message received is what below:
PS C:\WINDOWS\system32> $Sh.Name = "Printer Info"
PS C:\WINDOWS\system32> $xls.SaveAs("C:\temp\Test.xlsx", $xlFixedFormat)
Exception calling "SaveAs" with "2" argument(s): "SaveAs method of Workbook class failed"
At line:1 char:1
+ $xls.SaveAs("C:\temp\Test.xlsx", $xlFixedFormat)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
The script works find in Windows Server 2008 R2 without any issues; however, it simply fails to work in Windows 7 64 bit.
I would really appreciate if I get an assistance asap.

why do I get a null valued expression error when converting a csv file to excel using powershell?

I have a powershell script that downloads a CSV file from yahoo finance, and my goal is to convert it to an excel file (.xlsx). The script is:
$path = "D:"
$client = New-Object System.Net.WebClient
$url = "http://download.finance.yahoo.com/d/quotes.csv?s=EDV,VEA,VWO,VHT,BND,VTI&f=sl1d1t1c1ohgv&e=.csv"
$csv_filename = Join-Path $path "prices.csv"
$client.DownloadFile($url, $csv_filename)
$xl_filename = Join-Path $path "prices.xlsx"
$xl = New-Object -COM "Excel.Application"
$xl.Visible = $true
$wb = $xl.Workbooks.OpenText($csv_filename)
$wb.SaveAs($xl_filename, 51)
$wb.Close()
$xl.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($xl)
The script is located in `D:\get_prices.ps1' and I execute it with
C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Unrestricted -File D:\get_prices.ps1
When I run it I get two errors:
You cannot call a method on a null-valued expression.
At D:\get_prices.ps1:14 char:11
+ $wb.SaveAs <<<< ($xl_filename, 51)
+ CategoryInfo : InvalidOperation: (SaveAs:String) [], RuntimeExc
eption
+ FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression.
At D:\get_prices.ps1:15 char:10
+ $wb.Close <<<< ()
+ CategoryInfo : InvalidOperation: (Close:String) [], RuntimeExce
ption
+ FullyQualifiedErrorId : InvokeMethodOnNull
The conversion code is adapted from this question-answer (How to export a CSV to Excel using Powershell).
I looked at the documentation for Workbook.SaveAs and as far as I nkow Im using it correctly, and the file format (the 51 argument) is correct too based on this. I also looked at the docs for Workbook.Close and that all looks correct too.
I'm using powershell v2.0 (according to get-host) and Excel 2013 on Windows 7 x64.
What am I doing wrong?
$xl.Workbooks.OpenText returns void not a workbook.
Make this change:
$xl.Workbooks.OpenText($csv_filename)
$wb=$xl.ActiveWorkbook

How to read cell data in excel and output to command prompt

I'm a sys admin and I am trying to learn how to use powershell... I have never done any type of scripting or coding before and I have been teaching myself online by learning from the technet script centre and online forums.
What I am trying to accomplish is to open an excel spreadsheet get information from it (usernames and password) and then output it into the command prompt in powershell. When ever I try to do this I get an Exception calling "InvokeMember" anyway, here is the code I have so far:
function Invoke([object]$m, [string]$method, $parameters)
{
$m.PSBase.GetType().InvokeMember(
$method, [Reflection.BindingFlags]::InvokeMethod, $null, $m, $parameters,$ciUS )
}
$ciUS = [System.Globalization.CultureInfo]'en-US'
$objExcel = New-Object -comobject Excel.Application $objExcel.Visible = $False $objExcel.DisplayAlerts = $False
$objWorkbook = Invoke $objExcel.Workbooks.Open "C:\PS\User Data.xls" Write-Host "Numer of worksheets: " $objWorkbook.Sheets.Count
$objWorksheet = $objWorkbook.Worksheets.Item(1) Write-Host "Worksheet: " $objWorksheet.Name
$Forename = $objWorksheet.Cells.Item(2,1).Text $Surname = $objWorksheet.Cells.Item(2,2).Text
Write-Host "Forename: " $Forename Write-Host "Surname: " $Surname
$objExcel.Quit() If (ps excel) { kill -name excel}
I have read many different posts on forums and articles on how to try and get around the en-US problem but I cannot seem to get around it and hope that someone here can help!
Here is the Exeption problem I mentioned:
Exception calling "InvokeMember" with "6" argument(s): "Method 'System.Management.Automation.PSMethod.C:\PS\User Data.x
ls' not found."
At C:\PS\excel.ps1:3 char:33
+ $m.PSBase.GetType().InvokeMember <<<< (
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : DotNetMethodException
Numer of worksheets: You cannot call a method on a null-valued expression. At C:\PS\excel.ps1:18 char:45 + $objWorksheet = $objWorkbook.Worksheets.Item <<<< (1) + CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
Worksheet: You cannot call a method on a null-valued expression. At C:\PS\excel.ps1:21 char:37 + $Forename = $objWorksheet.Cells.Item <<<< (2,1).Text + CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
You cannot call a method on a null-valued expression. At C:\PS\excel.ps1:22 char:36 + $Surname = $objWorksheet.Cells.Item <<<< (2,2).Text + CategoryInfo : InvalidOperation: (Item:String) [], RuntimeException + FullyQualifiedErrorId : InvokeMethodOnNull
Forename:
Surname:
This is the first question I have ever asked, try to be nice! :))
Many Thanks
Max
I find OLE DB and the Office 2007 drivers a little easier to use. If you don't have Office 2007, you can download the drivers from MS.
$filepath = 'C:\Users\u00\documents\backupset.xlsx'
$connString = "Provider=Microsoft.ACE.OLEDB.12.0;Data Source=`"$filepath`";Extended Properties=`"Excel 12.0 Xml;HDR=YES`";"
#Connection String for Excel 2003:
#$connString = "Provider=Microsoft.Jet.OLEDB.4.0;Data Source=`"$filepath`";Extended Properties=`"Excel 8.0;HDR=Yes;IMEX=1`";"
$qry = 'select * from [sheet1$]'
$conn = New-Object System.Data.OleDb.OleDbConnection
$conn.ConnectionString = $connString
$conn.open()
$cmd = new-object System.Data.OleDb.OleDbCommand($qry,$conn)
$da = new-object System.Data.OleDb.OleDbDataAdapter($cmd)
$dt = new-object System.Data.dataTable
[void]$da.fill($dt)
$conn.close()
$dt
thanks for your help...I have fixed the problem! I was using PowerShell V2 CTP2, now I have upgraded to CTP3 this has fixed the language barrier problem and I can now run scripts without worrying about the invoke function and all is fine!
Many Thanks
Max

Resources