Powershell COM Excel visible not working - excel

I have written a short Powershell script to copy some Excel data. The script works fine, but it opens Excel every time I run it, even thought the visible property is set to $false. Anyone have any ideas why? I have searched for answers, but can't find any solutions. I have also displayed the property and it is set correctly.
Excel opens when the workbook is opened.
Thanks,
Chris J.
Code:
## function to close all com objects
function Release-Ref ($ref{
([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
#Read-Host -Prompt "Press Enter to exit"
#####################################################################
## Load excel com objects attach to file
#####################################################################
$ExcelPath = 'C:\Chris_Test.xls'
$Excel = New-Object -ComObject Excel.Application
$Excel.Visible = $False
write-host "Visible 1"
write-host $Excel.Visible
$ExcelWorkBook = $Excel.Workbooks.Open($ExcelPath)
$Excel.Visible = $False
write-host "Visible 2"
write-host $Excel.Visible
$ExcelWorkSheet = $Excel.WorkSheets.item("Sheet1")
$Excel.Visible = $False
write-host "Visible 3"
write-host $Excel.Visible
$row = 2
$South_HX_Avg = "This"
$Middle_HX_Avg = " is a "
$North_HX_Avg = "test."
##
## Cells.Item(Row,Column)
#$ExcelWorkSheet.Cells.Item($row,1).Value2 = $South_HX_Avg
#$ExcelWorkSheet.Cells.Item(2,2).Value2 = $Middle_HX_Avg
#$ExcelWorkSheet.Cells.Item(2,3).Value2 = $North_HX_Avg
#####################################################################
# Close connections to Excel
# set interactive to false so no save buttons are shown
#####################################################################
$Excel.DisplayAlerts = $false
$Excel.ScreenUpdating = $false
$Excel.Visible = $False
write-host "Visible 4"
write-host $Excel.Visible
$Excel.Visible = $false
$Excel.Visible = $False
write-host "Visible 5"
write-host $Excel.Visible
$Excel.UserControl = $false
$Excel.Interactive = $false
## save the workbook
$ExcelWorkBook.Save()
## quit the workbook
$Excel.Quit()
## close all object references
Release-Ref($ExcelWorkSheet)
Release-Ref($ExcelWorkBook)
Release-Ref($Excel)
# Move-Item c:\scripts\test.zip c:\test -force
Read-Host -Prompt "Press Enter to exit"

When I uncommented the lines 30,31 and 32, it worked ok, but I had to comment out your calls to Release-Ref (including the definition) for it to parse.
Also, when you create a new Excel object using:
$Excel = New-Object -ComObject Excel.Application
the visibility of the window is set by default to false in the object's constructor, so there's no need to set it explicitly...

Yes I did try rebooting and also tried it on a different computer with the same results. Good catch Steve Rathbone, my procedure was missing a parenthesis. After I fixed it, it still opens Excel.
I also tried commenting out the calls to Release-Ref with the same results.

I am doing something similar in a script I've been working with lately. MS Com objects have tons of options in several places.
This works for me.
$xlsFile = "\\your\file.xls"
$Excel = New-Object -ComObject Excel.Application
$excel.DisplayAlerts = $false;
$excel.AskToUpdateLinks = $false;
$Workbook = $Excel.Workbooks.Open($xlsFile, 0, 0, 5, "password")
#do some stuff in excel
$Excel.Quit()
PS, you can also set some of the parameters using the workbooks.open() function.
Here's just a few:
Workbooks.Open(FileName, UpdateLinks, ReadOnly, Format, Password)
You can read more about com object parameters here:
https://learn.microsoft.com/en-us/office/vba/api/excel.workbooks.open

Related

PowerShell opens excel while running script and crashes

I have made some code to run a Macro on 560 Excel files.
There is a small issue with the code, it seems it doesn't save excel file, and opens every excel file, cause excel to crash.
is there a way to have the macro be ran on these 560 files in the backround, and to automatically save once macro is ran, rather than saving it manually?
Thanks
Here is my Code:
# start excel
$excel = New-Object -comobject Excel.Application
# get files
$files = Get-ChildItem 'C:\Users\ME\Desktop\TEST'
# loop through all files in the directory
ForEach ($file in $files){
# open the file
$workbook = $excel.Workbooks.Open($file.FullName)
# make file visible
$excel.Visible = $true
# run macro
$app = $excel.Application
$app.run("PERSONAL.xlsb!Module6.MyMacro")
}
By setting $excel.Visible = $true, the code will become much slower because of all the screen updates involved.
Also, you do not save the workbook after running the code, and because you never quit Excel and remove the COM objects from memory, eventually it will crash because of running out of resources.
Try:
# start excel
$excel = New-Object -comobject Excel.Application
$excel.Visible = $false
$excel.DisplayAlerts = $false
# get files and loop through the list
# the usual extension for macro-enabled Excel files is `*.xlsm`.
# if your files have this extension, add -Filter '*.xlsm' to the
# Get-ChildItem command below.
Get-ChildItem -Path 'C:\Users\ME\Desktop\TEST' -File | ForEach-Object {
# open the file
$workbook = $excel.Workbooks.Open($_.FullName)
# run macro
$app = $excel.Application
$app.run("PERSONAL.xlsb!Module6.MyMacro")
$workbook.Close($true) # $true --> save changes
}
$excel.Quit()
# cleanup COM objects
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($workbook)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($excel)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()

PowerShell find next empty column in Excel

I need a PowerShell snippet that searches for the next empty column in an Excel sheet.
Every help is appreciated.
I've tried this so far:
$Excel = New-Object -Com Excel.Application
$Excel.visible = $True
$WorkBook = $Excel.Workbooks.Open("C:\Users\Garry\Desktop\test.xlsx")
$Sheet = $Excel.WorkSheets.Item(1)
$xlLastCell = [Microsoft.Office.Interop.Excel.Constants]::xlLastColumn
$z=1
Do{$z, $z++}until ($Sheet.Column.Item(1, $xlLastCell).Value -eq "")
I tried to loop it so it checks every column if there is a value with the do and until statement, but I always get the error
"It is not possible to call a method for an expression that has the value NULL." The errorstatement refers to the Do until loop.
Change condition from "0" to "$null" and replace $xlLastCell with counter $z:
Add-Type -AssemblyName Microsoft.Office.Interop.Excel
$excel = New-Object -ComObject Excel.Application
$excel.visible = $true
$workBook = $excel.Workbooks.Open("C:\Users\Garry\Desktop\test.xlsx")
$workSheet = $excel.WorkSheets.Item(1)
# not needed $xlLastCell = [Microsoft.Office.Interop.Excel.Constants]::xlLastColumn
$z = 1
Do {
$z
}
until ( $workSheet.Cells.Item(1, $z++).Value2 -eq $null )

Use PowerShell to get Excel Data Connection's SQL command text

I have a bunch of Excel files each of which has a number of Workbook Connections. Each of these workbook connections has a properties with a Definition, which contains a "Connection String" and also a "Command text"
I would like to retrieve the connection string and command text values through PowerShell but cannot see the function to do this
I have got as far as the following snippet, any advice appreciated...
$excelObj = New-Object -ComObject Excel.Application
$excelObj.Visible = $false
$workbook = $excelObj.Workbooks.Open($xlsxLocation)
foreach ($connect in $workbook.Connections)
{
Write-Host $connect.Name
# This is where I need the connection string and the command text, for this connection.
}
I ran a search for "vba connections command text" which returned Extracting Excel Data Connection Command Text. Then I was able to adapt your code to:
$xlsxLocation="C:\Temp\MyFile.xlsx"
$excelObj = New-Object -ComObject Excel.Application
$excelObj.Visible = $False
$excelObj.DisplayAlerts = $False
$workbook = $excelObj.Workbooks.Open($xlsxLocation)
foreach ($worksheet in $workbook.Worksheets){
foreach ($listobject in $worksheet.ListObjects) {
$commandtext = $listobject.QueryTable.CommandText
if (-not ([string]::IsNullOrWhiteSpace($commandtext))) {
Write-Host $commandtext
}
}
}
$workbook.Close($False) # closed do not save
$excelObj.DisplayAlerts = $True
$excelObj.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($excelObj) | Out-Null
Remove-Variable excelObj | Out-Null
The last two lines of code will dispose the Excel resourse when you terminate the script.

Open, save and close Excel

I have an issue opening a spreadsheet via PowerShell, renaming a worksheet, saving and closing Excel. The issue is when run the first time the $WorkBook variable is null. If I run it a second time the script works fine. Also if I add $ExcelDoc.Visible = $true the script works fine. Does anyone have an idea why the script fails on it first run in the form it is below?
$Path = "C:\ScriptRepository\CQC\DataToLoad\"
$FileName = (Get-ChildItem $Path).FullName
$FileName2 = (Get-ChildItem $Path).Name
Start-Sleep 2
$ExcelDoc = New-Object -ComObject Excel.Application
$WorkBook = $ExcelDoc.Workbooks.Open($FileName)
$WorkSheet = $WorkBook.Worksheets.Item(2)
$WorkSheet.Name = "CQCProviders"
$WorkBook.Save()
$WorkBook.Close()
$ExcelDoc.Quit()
While([System.Runtime.Interopservices.Marshal]::ReleaseComObject($ExcelDoc)) {}

How to use powershell to run personal macro with different paths

I am trying to create automatically a report out of an excel file. I already analyzed one specific file and the report is saved local.
Now I want to use this macro to run it on other files. Therefore I have to change the path in the powershell.
Now I want to run the macro automatically (let`s say at 1am) with powershell.
$excel = New-Object -comobject Excel.Application
$wbPersonalXLSB = $excel.workbooks.open("C:\Users\fami\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB")
$FilePath = "C:\Users\fami\Desktop\example.xls"
$workbook = $excel.Workbooks.Open($FilePath)
$excel.Visible = $false
$worksheet = $workbook.worksheets.item(1)
$excel.Run("PERSONAL.XLSB!run")
$wbPersonalXLSB.Close()
$workbook.save()
$workbook.close()
$excel.quit()
Only the $FilePath needs to be variable.
You just need to use a Parameter for the $FilePath variable instead of hard coding it. Like this:
param([string]$FilePath)
$excel = New-Object -comobject Excel.Application
$wbPersonalXLSB = $excel.workbooks.open("C:\Users\fami\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB")
$workbook = $excel.Workbooks.Open($FilePath)
$excel.Visible = $false
$worksheet = $workbook.worksheets.item(1)
$excel.Run("PERSONAL.XLSB!run")
$wbPersonalXLSB.Close()
$workbook.save()
$workbook.close()
$excel.quit()
Then you would schedule the script and specify the -FilePath paramater like so:
powershell.exe -file C:\folder\yourscript.ps1 -FilePath "C:\Users\fami\Desktop\example.xls"
EDIT: To read a list of files from a text file (with one file on each line) would be this.
param(
[string]$FileList,
[string]$PersonalXLSB="C:\Users\fami\AppData\Roaming\Microsoft\Excel\XLSTART\PERSONAL.XLSB",
[string]$RunMacro="PERSONAL.XLSB!run"
)
$Files = Get-Content $FileList
foreach ($FilePath in $Files) {
$excel = New-Object -comobject Excel.Application
$wbPersonalXLSB = $excel.workbooks.open($PersonalXLSB)
$workbook = $excel.Workbooks.Open($FilePath)
$excel.Visible = $false
$worksheet = $workbook.worksheets.item(1)
$excel.Run($RunMacro)
$wbPersonalXLSB.Close()
$workbook.save()
$workbook.close()
$excel.quit()
}
I've also moved the PersonalXLSB and Macro to Params, as they have a value set this will be used as default if you don't specify anything else. It's most basic form is like this:
powershell.exe -file C:\folder\yourscript.ps1 -FileList "C:\folder\name.text"
You can change the other params like this:
powershell.exe -file C:\folder\yourscript.ps1 -FileList "C:\folder\name.text" -RunMacro="PERSONAL.XLSB!macroname"

Resources