PowerShell + Excel - $workbook.save() hangs up on me - excel

I started messing around with Excel on PowerShell, specially because I had to go through 138 files changing every instance of $B$1 to TEXT($B$1,"0000") and I didn't want to do that manually.
Found a couple of resources online and changed the formula but when I try .Save(), PowerShell seems to just sit there, waiting for something I have no idea what.
PS C:\> $excel = New-Object -com Excel.Application
PS C:\> Get-ChildItem '\\UNC\Path\to\folder' <Common file string>*.xls -Recurse | Select-Object -First 1 | % {
>> $workbook = $excel.Workbooks.Open($_.Fullname)
>> $workbook.Save()
>> }
Any ideas on what could be the problem?

When Excel hangs in this regard I would suspect it is waiting for you to do something. The easiest was to confirm this is setting the visibility to True.
$excel.Visible = $true
That would just show you the dialog that was hidden from you previously. As discussed in comments it appears you got a message from the Compatibly Checker. Once you know what it is and are willing to suppress it then just have the following
$excel.Visible = $false
$excel.displayAlerts = $false

Related

Refresh Excel connections using Powershell

I have the below code that opens a spreadsheet, deletes all connections and "Saves" a new file.
$a = New-Object -COM "Excel.Application"
$a.Visible = $false
$b = $a.Workbooks.Open("F:\Scripts\All Users.xlsx")
do
{
$b.Connections.Item(1).Delete()
$Count = $b.Connections.Count()
} until($Count -eq 0)
$b.SaveAs("F:\Scripts\Users Home Drive Search.xlsx")
$b.Close()
I would like to know two things:
How do I get the sheet to RefreshAll connections? I've tried "$b.Connections.refreshall()" but the refreshall() doesn't exist.
How do I quit Excel application? I ran "New-Object -COM "Excel.Application" | Get-Member -MemberType Methods" and I don't see a quit or exit method.
RefreshAll() is a method of the WorkBook object, so use that to refresh the external connections:
$b.RefreshAll()
To exit Excel and remove the used COM objects from memory, use
$a.Quit()
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($b)
$null = [System.Runtime.Interopservices.Marshal]::ReleaseComObject($a)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
BTW, I would use more descriptive variable names, so $excel instead of $a and $workbook instead of $b to avoid confusion later on.

CSV to Excel with pivot table

So I am trying to write a easy code to convert a csv to excel, insert a pivot table and then save it. the below code runs fine but the excel file is being saved with the name $name instead of the content of $name... and also can I use VBA code in powershell script ? I want to insert a pivot table and I can only find vba code for it....
Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
InitialDirectory = [Environment]::GetFolderPath('Desktop')
Filter = 'SpreadSheet (*.csv)|*.csv'
}
$FileBrowser.ShowDialog()
$file = $FileBrowser.FileName
$name= $FileBrowser.SafeFileName
Write-Host $name
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$excel.DisplayAlerts = $false
$excel.Workbooks.Open($file)
$excel.Workbooks.item(1).SaveAs('C:\Users\User\Desktop\$name.xlsx',51)
$excel.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
so after fixing the code here is the end product....
Add-Type -AssemblyName System.Windows.Forms
$FileBrowser = New-Object System.Windows.Forms.OpenFileDialog -Property #{
InitialDirectory = [Environment]::GetFolderPath('Desktop')
Filter = 'SpreadSheet (*.csv)|*.csv'
}
$FileBrowser.ShowDialog()
$file = $FileBrowser.FileName
$name = $FileBrowser.SafeFileName -replace ".{4}$"
$excel = New-Object -ComObject Excel.Application
$excel.Visible = $true
$excel.DisplayAlerts = $false
$excel.Workbooks.Open($file)
#$excel.Workbooks.Item(1).activate()
#$excel.ActiveSheet.Cells.Select()
$excel.Workbooks.item(1).SaveAs("C:\Users\User\Desktop\$name.xlsx",51)
$excel.Quit()
[System.Runtime.InteropServices.Marshal]::ReleaseComObject($excel)
Now I want to add a Pivot table to this. I added the lines to activate the workbook and select all the cells... now I have the VBA code but can someone help me translate it to the powershell ?
Sheets.Add
ActiveWorkbook.PivotCaches.Create(SourceType:=xlDatabase, SourceData:= _
"2!R1C1:R1048576C27", Version:=6).CreatePivotTable TableDestination:= _
"Sheet1!R3C1", TableName:="PivotTable3", DefaultVersion:=6
Sheets("Sheet1").Select
Cells(3, 1).Select
With ActiveSheet.PivotTables("PivotTable3").PivotFields("Domain")
.Orientation = xlRowField
.Position = 1
The above VBA is a macro that I recorded that gives us the steps... now we just have to translate it to power shell... I am lost as figuring the code till now itself was hours of tinkering...
It is because this is exactly what you told it to do.
$excel.Workbooks.item(1).SaveAs('C:\Users\User\Desktop\$name.xlsx',51)
Quotes are important. Single quotes mean to pass the string exactly as-is.
As defined in the help files.
about_Quoting_Rules - PowerShell | Microsoft Docs
Variables must be expanded, and in a string, you must use double-quotes.
$excel.Workbooks.item(1).SaveAs("C:\Users\User\Desktop\$name.xlsx",51)
Here are a couple of good articles for your edification on the topic as well:
A Story of PowerShell Quoting Rules
Windows PowerShell Quotes
Point of note:
That Write-Host is not needed if all you are doing is outputting text to the screen. In Powe3rShell output to the screen is the default. Also, depending on what version of PowerShell you are on, Write-Host empties the buffer, and anything after that is not usable elsewhere. Later versions of PowerShell does not have this issue, but it's still best to avoid Write-Host, unless you are sending a colorized text to the screen, or other custom formatting scenarios.
Additional reading:
Write-Host Considered Harmful
... Jeffrey Snover changes his stance on this as of May 2016.
With PowerShell v5 Write-Host no longer "kills puppies". data is
captured into info stream ...
https://twitter.com/jsnover/status/727902887183966208 ...
https://learn.microsoft.com/en-us/powershell/module/Microsoft.PowerShell.Utility/Write-Information?view=powershell-5.1
Lastly, you are no completely cleaning up behind yourself. Though you are quitting Excel, you are not exiting the Excel process, thus releasing those resources and the COM stuff. So, stopping that process and garbage collection is warranted.
For example:
Get-Process -Name 'EXCEL' | Stop-Process
Function Clear-ResourceEnvironment
{
# Clear any PowerShell sessions created
Get-PSSession | Remove-PSSession
# Release any COM object created
$null = [System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$Shell)
# Perform garbage collection on session resources
[System.GC]::Collect()
[GC]::Collect()
[GC]::WaitForPendingFinalizers()
<#
Remove any custom variables created
some list of your variable, or a wildcard when prefix was used.
#>
Get-Variable -Name MyShell -ErrorAction SilentlyContinue | Remove-Variable
}

Powershell to refresh Excel with OLAP Query. Credential issues

I'm rather new with PowerShell scripting so please be patient with me :)
I have multiple excel file with OLAP Query connections connecting to Power BI Datasets, following are the script;
$libraryPath = "C:\Repos\AUSD\3.0\Test"
$excel = new-object -comobject Excel.Application
$excel.Visible = $false
# Give delay to open
Start-Sleep -s 3
$allExcelfiles = Get-ChildItem $libraryPath -recurse -include “*.xls*”
foreach ($file in $allExcelfiles)
{
$workbookpath = $file.fullname
Write-Host "Updating " $workbookpath
# Open the Excel file
$excelworkbook = $excel.workbooks.Open($workbookpath)
$connections = $excelworkbook.Connections
# This will Refresh All the pivot tables data.
$excelworkbook.RefreshAll()
# The following script lines will Save the file.
$excelworkbook.Save()
$excelworkbook.Close()
Write-Host "Update Complete " $workbookpath
}
$excel.quit()
It is working fine if following options;
$excel.Visible is true
However this is going to be scheduled in the server and hopefully this could be done in the background, hence the $excel.Visible = $false
This causing the following error;
I suspect this is due to the Automatic sign in which happen when the Excel are open, due to its not being open, its failing the sign in process.
How do I bypass or rather set the credentials/permission right?

How to select Excel Add-ins with a script?

I'm trying to get a solution to select specific Excel Add-ins with a script.
I was able to catch all the information about Excel.Application and change "Installed" property to $true, but it comes back to $false when the code stops running. Anybody knows a different solution or a way to save the Excel property?
$excel = New-Object -ComObject Excel.Application
$excel.Addins | Where-Object { $_.Title -eq "NameOfAdd-ins" } | ForEach-Object {
$_.Installed = $true
}
$_.Installed property should stay $true after Run-Time

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)) {}

Resources