How to save a read-only file using PowerShell - excel

I have an Excel file that I am opening, applying a password to it, and then saving it using PowerShell. I am getting the following error:
Exception calling "SaveAs" with "3" argument(s): "Cannot save as that name. Document was opened as read-only."
At C:\PasswordProtectExcelFiles.ps1:38 char:45
+ $a = $wb.SaveAs("$($FilePath)",$xlNormal,"$($Password)")
+ ~~~~~~~~~
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
I have searched a lot but nothing has resolved my issue. Here are some questions I refered to already:
Powershell - SaveAs function when file already exists and
How to Remove ReadOnly Attribute on File Using PowerShell?.
My code:
param([string]$FilePath, [string]$Password )
$xl = new-object -comobject excel.application
$xl.Visible = $True
$xl.DisplayAlerts = $False
$wb = $xl.Workbooks.Open("$($FilePath)")
$a = $wb.SaveAs("$($FilePath)",$xlNormal,"$($Password)")
$a = $xl.Quit()
$a = Release-Ref($wb)
$a = Release-Ref($xl)
I have tried these codes after the Workbooks.Open statement to see if it will save the read-only file, and it worked, but then when I closed and reopened the code it stopped working:
Code1:
$file = Get-Item "$($FilePath)"
if ($file.IsReadOnly -eq $true)
{
$file.IsReadOnly = $false
}
Code2:
Set-ItemProperty "$($FilePath)" -name IsReadOnly -value $false
Actually, the file is not read only but the folder is and I am unable to check out the box that says read only. Same as this problem: https://social.technet.microsoft.com/Forums/windowsserver/en-US/f7ec4fc5-3bbe-4fd0-a8ca-c4ead75b010c/unable-to-removeclear-readonly-attribute-from-folder-in-windows-server-2008

According to the documentation for the Open() method, the third argument allows you to specify whether to open the file in read-only mode.
Set it to $false:
$wb = $xl.Workbooks.Open("$($FilePath)", 0, $false)

Related

Powershell script won't run as system when logged out, but works fine as user logged on

I have a PowerShell script to convert a .xls file to .txt file. It runs fine in PowerShell and as a scheduled task when "run only when the user logged on" is checked as my user account, but if I try the system and run whether logged on or not, it doesn't work.
I've tried different arguments and setting some security flags on the account already.
Some debugging shows this when running as system user:
Microsoft Excel cannot access the file 'C:\test\test.xls'. There are several possible reasons:
• The file name or path does not exist.
• The file is being used by another program.
• The workbook you are trying to save has the same name as a currently open workbook.
At C:\test\t.ps1:5 char:1
+ $WorkBook = $Excel.Workbooks.Open($file.Fullname)
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : OperationStopped: (:) [], COMException
+ FullyQualifiedErrorId : System.Runtime.InteropServices.COMException
You cannot call a method on a null-valued expression. At
C:\test\t.ps1:6 char:1
+ $Workbook.SaveAs('c:\test\t.txt', 42) # xlUnicodeText
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
#excel processing
$Excel = New-Object -ComObject Excel.Application
$Excel.visible = $false
$Excel.DisplayAlerts = $false
$file = Get-ChildItem 'c:\test\test.xls'
$WorkBook = $Excel.Workbooks.Open($file.Fullname)
$Workbook.SaveAs('c:\test\t.txt', 42) # xlUnicodeText
# cleanup
$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($WorkBook) | Out-Null
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel) | Out-Null
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
#powershell -ExecutionPolicy ByPass -File C:\test\t.ps1
The expected result creates a new txt file in the test folder, the actual result just produces nothing.

saving xlsx as xls without compability check with powershell

I need to save some xlsx files as xls file because our SAS 9.2 cannot read xlsx.
When I save in my powershell script I get this message
I am using this code:
function convert_xlst_to_xls([string]$File) {
$Filepath = Get-Item -Path $File
Write-Host $Filepath
$NewFilepath = Join-Path -Path $FilePath.directory.FullName -ChildPath "$($Filepath.basename).xls"
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $true #or false
$workbook.CheckCompatibility = $false
$Workbook = $Excel.Workbooks.Open($Filepath.FullName, [Type]::Missing, $true)
if (Test-Path $NewFilepath) {
Remove-Item $NewFilepath
}
$Workbook.SaveAs($NewFilepath,56)
$Workbook.Close()
$Excel.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
Remove-Variable Excel
return "$NewFilepath"
}
$New_Excel_File = convert_xlst_to_xls("$filePath")
It will not accept the checkcompalility property on workbook.
My console:
The property 'CheckCompatibility' cannot be found on this object. Verify
that the property exists and can be set.
At S:\UO4\DWH\SIJ\CONVERT-EXCEL BACKGRUND3.ps1:32 char:1
+ $workbook.CheckCompatibility = $false
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : InvalidOperation: (:) [], RuntimeException
+ FullyQualifiedErrorId : PropertyNotFound
Is there anyway to force the saveas to save without showing this compabilitycontrol.

How to convert Excel xlsx file to xls file in batch by PowerShell

I am having multiple .xlsx file genrated from SAP BO4.2
But user reads .xls only so wanted to write some script which will convert .xlsx to .xls
Referred-
https://gallery.technet.microsoft.com/How-to-convert-Excel-xlsx-d9521619
and tried to use same for .xls
$ErrorActionPreference = 'Stop'
Function Convert-xlsInBatch
{
[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)
$xlsFilePath = $_.FullName -replace "\.xlsx$", ".xls"
$workbook.SaveAs($xlsFilePath, [Microsoft.Office.Interop.Excel.XlFileFormat]::xlExcel7)
$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 = "D:\XXX\AA\BB\Apr-2018"
Convert-XlsInBatch -Folder $FolderPath
Error I am getting-
PS D:\Batch Script> D:\Batch Script\ConvertExcelToXlsInBatch.ps1
New-Object : Retrieving the COM class factory for component with CLSID {00000000-0000-0000-0000-000000000000} failed
due to the following error: 80040154 Class not registered (Exception from HRESULT: 0x80040154 (REGDB_E_CLASSNOTREG)).
At D:\Batch Script\ConvertExcelToXlsInBatch.ps1:27 char:14
+ $excelApp = New-Object -ComObject Excel.Application
+ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ CategoryInfo : ResourceUnavailable: (:) [New-Object], COMException
+ FullyQualifiedErrorId : NoCOMClassIdentified,Microsoft.PowerShell.Commands.NewObjectCommand
Not sure if you've seen this solution. It's 4 years old but it seems to work.
https://superuser.com/questions/875831/using-powershell-is-it-possible-to-convert-an-xlsx-file-to-xls

open a password protected Excel in powershell [duplicate]

This question already has answers here:
Script to open encrypted excel file, that has a dynamic filename ending in "mmddyyyy"
(2 answers)
Closed 5 years ago.
I'm trying to open a password protected excel sheet in powershell and output a report on how many rows are in the sheet.
the script works absolutely fine if the sheet isn't password protected but I can't seem to get powershell to open it if there is a password set.
my current script is
$Report = "S:\Business Support\excel tests\MI Tool - Live.csv"
$path = "S:\Business Support\excel tests"
[Array]$Results = $null
$excelSheets = Get-Childitem -Path $path -Include "MI Tool - Live.xlsm" -Recurse
$excel = New-Object -comobject Excel.Application
$excel.visible = $false
$password = "blablabla"
$updatelinks = 0
foreach($excelSheet in $excelSheets)
{
$workbook = $excel.Workbooks.Open($excelSheet,$updatelinks,$password)
$rowCount = $null
$worksheet = $workbook.sheets.item("Data")
$rowMax = ($worksheet.usedRange.rows).count
$rowCount += $rowMax
$Results += New-Object Psobject -Property #{
"File Name"=$excelSheet.Name
"Row Count"=$rowCount}
$excelSheet.Name
$workbook.Sheets.count
$rowCount
}
$excel.quit()
Stop-Process -Name EXCEL -Force
$Results | select "File Name","Row Count" | Export-Csv $Report -NoTypeInformation
This is the error I get:
Exception calling "Open" with "3" argument(s): "Open method of Workbooks class failed"
At line:3 char:35
+ $workbook = $excel.Workbooks.Open <<<< ($excelSheet,$updatelinks,$password)
+ CategoryInfo : NotSpecified: (:) [], MethodInvocationException
+ FullyQualifiedErrorId : ComMethodTargetInvocation
You cannot call a method on a null-valued expression.
At line:5 char:37
+ $worksheet = $workbook.sheets.item <<<< ("Data")
+ CategoryInfo : InvalidOperation: (item:String) [], RuntimeException
+ FullyQualifiedErrorId : InvokeMethodOnNull
If I take out the $password variable it works but I then have to enter the password manually.
Your Open overload is incorrect. The password is the 5th variable. Have a look at MSDN to see
expression .Open(FileName, UpdateLinks, ReadOnly, Format, Password, WriteResPassword, IgnoreReadOnlyRecommended, Origin, Delimiter, Editable, Notify, Converter, AddToMru, Local, CorruptLoad)
So you would need to populate ReadOnly and Format first I believe. You would have to populate those values.
$excel.Workbooks.open($path,0,0,5,$password)
Look at the MSDN to understand what the values represent in the 2,3 and 4 positions.

PowerShell Error Creating XLSX

Okay, I have 6 CSVs each containing one column. For this example, the data from the first CSV is used to create the initial document, and each after that is attempting to save to the document.
#ID
$csvFile = "$path\ID.csv"
$fpath = $Filename
$processes = Import-Csv -Path $csvFile
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add()
$excel.cells.item(1,1) = "ID"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,1) = $process.ID
$i++
} #end foreach process
$workbook.saveas($fpath)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
#SRP
$csvFile = "$path\SRP.csv"
$processes = Import-Csv -Path $csvFile
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add()
$excel.cells.item(1,2) = "SRP"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,2) = $process.SRP
$i++
} #end foreach process
$workbook.save($fpath)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()
When I get down to the save line on the second one (#SRP section) I get the following error:
Cannot find an overload for "Save" and the argument count: "1".
At D:\UserAdminScripts\0_Powershell_Test_Scripts\Scripts_For_Lisa\NED Stuff\NED_Reports.ps1:130 char:15
+ $workbook.save <<<< ($fpath)
+ CategoryInfo : NotSpecified: (:) [], MethodException
+ FullyQualifiedErrorId : MethodCountCouldNotFindBest
If I let the script run after the error, I get the same result for each column.
I'm aware this script isn't clean, because I don't need to close and reopen Excel for each run, but I butchered this script from http://blogs.technet.com/b/heyscriptingguy/archive/2010/09/09/copy-csv-columns-to-an-excel-spreadsheet-by-using-powershell.aspx. The saveas works correctly in the first attempt, it's just the save causing an error.
I find when I break the script, I get a pop-up to confirm whether or not I want to make changes to Book2.xlsx. I tell it yes and I check and Book2 has the 2nd column filled out with the data I wanted as the second column on my original sheet.
Any help is appreciated.
Have a look at the $Workbook object with Get-Member:
Save Method void Save ()
The Save() method doesn't accept any arguments and it's failing to work out what to do with that method and your file name argument.
You Quit the Excel app in the #ID section (thus closing the file) so you need to reopen the file before accessing the workbook and trying to write to it.
Well, it looks like I answered my own question, due to ConanW's inspiration to actually, you know, think critically. The answer to my issue is as follows:
#ID
$csvFile = "$path\ID.csv"
$fpath = $Filename
$processes = Import-Csv -Path $csvFile
$Excel = New-Object -ComObject excel.application
$Excel.visible = $false
$workbook = $Excel.workbooks.add()
$excel.cells.item(1,1) = "ID"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,1) = $process.ID
$i++
} #end foreach process
#SRP
$csvFile = "$path\SRP.csv"
$processes = Import-Csv -Path $csvFile
$excel.cells.item(1,2) = "SRP"
$i = 2
foreach($process in $processes)
{
$excel.cells.item($i,2) = $process.SRP
$i++
} #end foreach process
$workbook.saveas($fpath)
$Excel.Quit()
Remove-Variable -Name excel
[gc]::collect()
[gc]::WaitForPendingFinalizers()

Resources