Excel workbooks.saveas() error in powershell - excel

I'm trying to convert .xls files to .xlxs
I tried many variations of this code but every time i'm facing this error message :
Exception lors de l'appel de « SaveAs » avec « 2 » argument(s) : « La
méthode SaveAs de la classe Workbook a échoué. » Au caractère
C:\temp\xlsx.ps1:18 : 6
try{$opendoc.saveas($basename, $saveFormat)}
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
CategoryInfo : NotSpecified: (:) [], MethodInvocationException
FullyQualifiedErrorId : ComMethodTargetInvocation
Here is my code :
$excel = new-object -comobject excel.application
$excel.Visible = $false
$saveFormat = "xlOpenXMLWorkbook";
ls c:\temp\*.xls | %{
$opendoc = $excel.workbooks.open($_.FullName)
$excel.DisplayAlerts =$false
$basename = $_.basename
try{
$opendoc.saveas($basename,$saveFormat,$null,$null,$false,$false,"xlNoChange","xlLocalSessionChanges")
# tried this one and got same error : $opendoc.saveas($basename, $saveFormat)}
}
catch{
$opendoc.close();$excel.quit()
$_
}
$opendoc.close();
}
$excel.quit()
do you know the working recipe please ?

Constants passed into the SaveAs method usually represent numeric values, not strings. In your case the second parameter probably should be 51 (xlWorkbookDefault) as documented here. Same goes for the other two strings ("xlNoChange", which should be 1, and "xlLocalSessionChanges", which should be 2). You need to either use the numeric values, or define the constants yourself, e.g.:
$xlWorkbookDefault = 51
$xlNoChange = 1
$xlLocalSessionChanges = 2
Also, you cannot use $null for arguments that should retain default values. Use [Type]::Missing instead.
Change this:
$opendoc.saveas($basename,$saveFormat,$null,$null,$false,$false,"xlNoChange","xlLocalSessionChanges")
into this:
$opendoc.SaveAs($basename, 51, [Type]::Missing, [Type]::Missing, $false, $false, 1, 2)

Related

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 :
...
#>

How to Insert Excel Formula using PowerShell?

The formula =LEFT(AB4,FIND(" ",AB5)-1 works perfectly in Excel, but seems to be causing errors in PowerShell where I get this error:
Exception from HRESULT: 0x800A03EC
At C:\Scripts\Excel_NUID2.ps1:21 char:1
+ $worksheet.range("AH5:AH$rows").formula = "=LEFT(AB4,FIND(" ",AB5)-1"
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
My PowerShell Script Code;
#Open Up the Workbook#
$excel = new-object -comobject Excel.Application
$excel.visible = $false
$workbook =
$excel.workbooks.open("c:\Users\Jack\documents\NUID_Status_Report.xlsx")
$worksheet = $workbook.Worksheets.Item(1)
$rows = $worksheet.range("A1").currentregion.rows.count
### Set up a filter ###
$headerRange = $worksheet.Range("a4","aj4")
$headerRange.AutoFilter() | Out-Null
#### Trims Password Expiration Date Name ###
$worksheet.range("AH4").formula = "Shortened Expiration Date"
[void]$worksheet.Cells.Item(1,1).select()
$excel.visible = $true
#### Trims Password Expiration Date Formula ###
$worksheet.range("AH5:AH$rows").formula = "=LEFT(AB4,FIND(" ",AB5)-1"
[void]$worksheet.Cells.Item(1,1).select()
$excel.visible = $true
Quotes within a quoted string need to be doubled-up.
$worksheet.range("AH5:AH$rows").formula = "=LEFT(AB4,FIND("" "",AB5)-1)"
'you can also get rid of the inside quotes with the CHAR function
$worksheet.range("AH5:AH$rows").formula = "=LEFT(AB4, FIND(CHAR(32), AB5)-1)"
ASCII character 32 is a space. I've also added a bracket to make a legal formula.

Importing CSV Into New Worksheet

I'm trying to import a CSV file into a newly created Excel worksheet, but haven't been able to utilize existing Q&A here (and elsewhere) to solve this issue.
Also, I'm sure I'm making this WAY more difficult than it should be, so please feel free to correct this bloated code if you see fit:
$varOneSheet = "OneSheet"
$xlsNewFile = New-Object -ComObject Excel.Application
$xlsNewFile.SheetsInNewWorkbook = 3
$xlsNewFile.displayAlerts = $false
$xlsNewFile.Visible = $false
$xlsWorkbook = $xlsNewFile.Workbooks.Add()
$sheetToRename = $xlsNewFile.Sheets.Item("Sheet1")
$sheetToRename.Name = $OneSheet
#this all works below, we need to push the data over to #xlsWorkbook now
$xlsCSVFile = New-Object -ComObject Excel.Application
$xlsCSVFile.displayAlerts = $false
$csvFilename = (".\DATA.CSV")
$xlsCSVFile.Workbooks.OpenText($csvFilename, 2, 1, 1, 1, $false, $false, $false, $true)
$xlsCSVFile.Visible = $true
$tmpSheetTOFile = $xlsWorkbook.Sheets.Item(1)
$tmpWorksheet = $xlsCSVFile.Sheets.Item(1)
#########################above is fine
#########################below should copy into $xlsWorkbook Sheet 1
$tmpWorksheet.Copy($tmpSheetTOFile)
The last line above is the failure point, which yields:
Exception calling "Copy" with "1" argument(s): "Copy method of Worksheet class
failed"
At line:1 char:23
+ $tmpWorksheet.Copy <<<< ($tmpSheetTOFile)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
Do I really need to create a separate/temporary workbook? Why was I not able to simply use OpenText on the already Saved/existing Workbook?
EDIT: I used this previous question to get to where I am now, so that's why I'm uncertain as to where the failure point lies. As the answer was accepted and signed-off on.
You're creating two different Excel application instances:
$xlsNewFile = New-Object -ComObject Excel.Application
...
$xlsCSVFile = New-Object -ComObject Excel.Application
Copying only works within the same instance, and using two instances isn't required anyway. Simply remove
$xlsCSVFile = New-Object -ComObject Excel.Application
$xlsCSVFile.displayAlerts = $false
...
$xlsCSVFile.Visible = $true
and change
$xlsCSVFile.Workbooks.OpenText($csvFilename, 2, 1, 1, 1, $false, $false, $false, $true)
...
$tmpWorksheet = $xlsCSVFile.Sheets.Item(1)
...
$tmpWorksheet.Copy($tmpSheetTOFile)
to
$xlsNewFile.Workbooks.OpenText($csvFilename, 2, 1, 1, 1, $false, $false, $false, $true)
...
$xlsNewFile.Workbooks.Item(2).Sheets.Item(1).Copy($tmpSheetTOFile)
Having that said, Excel auto-creates a workbook with a new sheet when it imports a CSV anyway (which is also the reason why OpenText doesn't import a CSV into an existing workbook), so why do you need to copy it to another new workbook in the first place? Normally it would suffice to just save the imported CSV as an Excel workbook. If you require additional sheets you can just add them.
$wsName = 'OneSheet'
$csvFilename = '.\data.csv'
$xlsFilename = '.\data.xlsx'
$xl = New-Object -ComObject 'Excel.Application'
$xl.DisplayAlerts = $false
$xl.Visible = $false
$xl.Workbooks.OpenText($csvFilename, 2, 1, 1, 1, $false, $false, $false, $true)
$wb = $xl.Workbooks.Item(1)
$ws = $wb.Sheets.Item(1)
$ws2 = $wb.Sheets.Add([Type]::Missing, $ws)
$ws3 = $wb.Sheets.Add([Type]::Missing, $ws2)
$ws.Name = $wsName
$wb.SaveAs($xlsFilename, 51)

Powershell script for Excel error code

I'm trying to convert an Excel .xls file that has several worksheets into a .csv with Powershell 4.0. I know the SaveAs in the for each loop isn't phrased right, and that the error is pointing to line 17 and character 9, I just don't know how to fix it or how to interpret the error code 0x800A03EC.
Here's the script:
Function ExportWSToCSV ($inputWorkbookPath, $outputFilePrefix, $outputDirectory)
{
#Start Excel invisibly without pop-up alerts.
$inputWorkbookPath = "R:\Unclaimed Property\NC State\Jun 2015\" + `
"NC_RAW_JUL1986thruMAR2013" + ".xls"
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
#Open Excel file.
$workBook = $excel.Workbooks.Open($inputWorkbookPath)
foreach ($workSheet in $workBook.Worksheets)
{
$n = $inputWorkbookPath + "_" + $workSheet.Name
$workSheet.SaveAs($outputDirectory + $n + ".csv", 6)
}
$excel.Quit()
}
ExportWSToCSV -inputWorkbookPath "R:\Unclaimed Property\NC State\Jun 2015\NC_RAW_JUL1986thruMAR2013.xls" `
-outputFilePrefix "output_" `
-outputDirectory "R:\Unclaimed Property\NC State\Jun 2015\"
Here's the error:
Exception calling "SaveAs" with "2" argument(s): "Exception from HRESULT: 0x800A03EC"
At \\ncdfs1\documents$\ANDREWN\My Documents\PSscript_for_NC.ps1:17 char:9
+ $workSheet.SaveAs($outputDirectory + $n + ".csv", 6)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
I strongly feel your issue is coming from your path concatenation logic. Lets look at the following code from within your loop.
$n = $inputWorkbookPath + "_" + $workSheet.Name
$workSheet.SaveAs($outputDirectory + $n + ".csv", 6)
In your example call your variables I think are mapped as follows:
$inputWorkbookPath equals "R:\Unclaimed Property\NC State\Jun 2015\NC_RAW_JUL1986thruMAR2013.xls"
$workSheet.Name equals "Bagel" # I made that up.
$outputDirectory equals "R:\Unclaimed Property\NC State\Jun 2015\"
So you are going to try and set the new file name as:
R:\Unclaimed Property\NC State\Jun 2015\R:\Unclaimed Property\NC State\Jun 2015\NC_RAW_JUL1986thruMAR2013.xls_Bagel.csv
Which does not look right at all. If you just had the line in your loop
$outputDirectory + $n + ".csv"
I think you would see the issue. Just some simple debugging.
Lets fix this
First guess is that you just need to change it to something like this
$path = $outputDirectory + $workSheet.Name + ".csv"
$workSheet.SaveAs($path, 6)
Outside the scope of this question it would be a good idea to check if that path exists before saving it. It would save some potential headache.

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

Resources