Automatically refresh Excel ODC connections and pivots without opening the file PowerShell - sql

I have several 20+ MB Excel files, and they need to be refreshed every week before business starts (Monday 8 AM).
These files contain one Data sheet, and data comes via external connection (ODC file), from an SQL Server view.
They also have one pivot sheet that also needs to be refreshed after the Data sheet is refreshed.
I am trying to find a solution (Windows PowerShell) to automatize the refreshing of Data and Pivot sheets without the need to touch the files.
"Refresh on opening" and other Excel options are not viable because it takes up to 20 minutes to refresh all the connections.
I also don't want to refresh ALL sheets because the file has custom coloring for charts and "Refresh" resets it to Excel default which cannot happen.
I tried this, but it doesn't seem to work with ODC connection? At least, it doesn't do anything.:
Windows PowerShell:
$ExcelApp = new-object -ComObject Excel.Application
$ExcelApp.Visible = $false
$ExcelApp.DisplayAlerts = $false
$Workbook = $ExcelApp.Workbooks.Open("c:\test\ref_test.xlsx", 3, $false, 5, $null, $null, $true)
Start-Sleep -s 30
$Workbook.RefreshAll()
$Workbook|Get-Member *Save*
$Workbook.Save()
$ExcelApp.Quit()
Any ideas?
Office version: 2010, on Windows 7

Possibly the answer on this question can help. The perl script is also available as a pre-compiled exe file.

I would approach this issue by using Excel VBA, and create your Excel file into a .xlsm.
Then update the file w/ Excel VBA commands and functions to refresh your odbc connection, and then save as a new file for distribution.
http://www.vbforums.com/showthread.php?675977-Auto-Open-Refresh-Pivots-Save-Close-Excel-files-using-VB

Related

Running PowerPoint macro from PowerShell

I have been experiencing troubles when running a PowerPoint Macro from Powershell (running Excel macros already works). As there is not much info on the web regarding this topic, I'm willing that you will be able to help me.
I'm trying to automate reporting in my work area and the flow is to query data from MS SQL Server, import data into Excel file, refresh charts and then build the final report with PowerPoint slides.
PowerPoint file's charts' are linked with the Excel (via File -> Edit Links to Files) and after selecting the specific chart, Chart Tools menu appears where on the Design tab I just click "Refresh Data" and the chart refreshes. I already have a macro which refreshes data automatically for me. Now I want to call that macro from Powershell script. Please see my code below:
$ppt = New-Object -ComObject Powerpoint.Application
$FilePath = '\\c03d03\public\Data\uvall\IBNB\OnePager.pptm'
$presentation = $ppt.presentations.Open($FilePath)
$ppt.Visible = $true
$app = $ppt.Application
$tst = #('test')
$presentation.Application.Run("RefreshData",[ref]$tst) / 1st way
$app.Run("RefreshData", [ref]#()) / 2nd way
$app.Run("RefreshData", #()) / 3rd way
$app.Run("RefreshData") / 4th way
$presentation.save()
$presentation.close()
$ppt.Quit()
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($ppt)
And none of these 4 ways of calling a macro works. Sometimes it just returns an error that the "Sub or function not defined", even if it's truly defined, sometimes it returns "You cannot call a method on a null-valued expression" and other errors.
Related:
Run PowerPoint Macro from PowerShell
Automate Powerpoint Macro
Please also be aware that I'm using Office 2013
Maybe someone can carefully look into this and help me out!

using environment variables in excel

So I am using this code in excel to read environment parameters on startup:
Dim ExcelArgs As String
Dim arg As String
ExcelArgs = Environ("ExcelArgs")
MsgBox ExcelArgs
If InStr(UCase(ExcelArgs), "CREO") >= 0 Then
Application.DisplayAlerts = False
If Len(ExcelArgs) > Len("CREO") Then
arg = Split(ExcelArgs, ",")(1)
Call Creo.addNewPartToPartslist(arg)
End If
Application.DisplayAlerts = True
End If
and this line in my batch script:
echo "Launch excel"
Set "ExcelArgs=CREO,DXFWITHOUTDRW
"C:\Program Files (x86)\Microsoft Office\OFFICE16\Excel.exe" /r "%APPDATA%\Microsoft\Excel\XLSTART\PERSONAL.XLSB"
exit 0
The problem is that if i run the batch file once, keep excel open change the excelargs to CREO,wqhatever in batch file and rerun batch file the excelargs, dos not get updated!!!
So my theory is that excel either caches out the environment variable or that if it is being used by one instance the batch script can not set it
link with some info about passing arguments to excel:
https://superuser.com/questions/640359/bat-file-to-open-excel-with-parameters-spaces
Usually excel sees if there is a previous instance running and let this instance handle the file opening.
Is this important? Yes, in your case both requests to open the file are handled by the same excel process.
How does it make a difference? Environment variables are not shared. Each process has it own environment block that is initialized when the process is created (can be a customized block or a copy of the environment of the parent process) and once the environment is created for a process, only this process can change its environment.
In your case, when you start excel the new process gets a copy of the environment block of the cmd process. Later, when you change the cmd environment, the already running excel instance sees no changes in environment and, as the new request to open excel is converted to a request to the previous process, there is not a new process with a new copy of the cmd environment with the changes.
The only way I see to make it work is to force excel to start a new process (that will inherit the changes in the cmd instance) instead of reusing the previous one.
But this depends on the excel version. As far as I know, the 2013 version includes an /x switch to force separate process usage. For previous versions, maybe this question, or this one could help you.
Excel is open
Then i start the batch script:
The it does not open it as read only by default, but prompt me instead, not a big issue but a bit annoying, and it also make it impossible to loop through to run the batch several times for different input parameters.
A bit unsure how I should post this, couldnt paste images in comments, and to edit the the original question, which was how to start excel with enviroment variable in new instance (/x did the trick), but now /r does not work, Should I post as new question and refer to this one or can I leave it as an answer?

Convert .xlsx to .csv and save to specific directory

I have a scheduled task set up (in a separate program) which will email a .xlsx file. I have a rule set up that will save the email to an Outlook folder called 04_CFW REPORT
I need Outlook to open the file with Excel and save as .csv to a network drive.
This will happen at night, when i am away from the computer
The closest thing i've found is a function here:
http://www.devhut.net/2012/05/14/ms-access-vba-convert-excel-xls-to-csv/
but i have no idea how to put this function to use in a sub.
Any help would be greatly appreciated.
This might be a place to start. Taken from here
Then you can research into creating a powershell job to run once daily and loop until the specified email subject is found.
Another point to consider, if you have permission Powershell can perform the SQL query and output a CSV which can be converted into an XLSX.
Add-type -assembly "Microsoft.Office.Interop.Outlook" | out-null
$olFolders = "Microsoft.Office.Interop.Outlook.olDefaultFolders" -as [type]
$outlook = new-object -comobject outlook.application
$namespace = $outlook.GetNameSpace("MAPI")
$folder = $namespace.getDefaultFolder($olFolders::olFolderInBox)
Then I can filter on Inbox items using, for example any unread items.
$folder.items | where {$_.UnRead -eq $true}
***EDIT, getting PowerShell to close Excel's comobject correctly. It's a matter of properly releasing the COM object. First (assuming this isn't done) we Save the workbook and Quit Excel.
Next we release COM objects from smallest (here the variable holding a range of cells) to largest (the Excel ComObject variable) in a loop should more than one iteration be required. Now the last two lines I've noticed are not really required, but in testing scripts it's nice to do but run Garbage Collection. Watch task manager to confirm it's operation.
$xlsObj.ActiveWorkbook.SaveAs($xlsFile) | Out-Null
$xlsObj.Quit()
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsRng)) {'cleanup xlsRng'}
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsSh)) {'cleanup xlsSh'}
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsWb)) {'cleanup xlsWb'}
While ([System.Runtime.Interopservices.Marshal]::ReleaseComObject($xlsObj)) {'cleanup xlsObj'}
[gc]::collect() | Out-Null
[gc]::WaitForPendingFinalizers() | Out-Null

XLS to CSV Powershell Conversion, maintaining decimal points/precision

I'm trying to convert an XLS file into CSV using Excel as a ComObject, yet maintaining the precision of the data concerned. I've tried changing the style to "#" or "Text" or similar for the formatting of each cell, but this still results in limited precision and doesn't seem to apply to the whole file.
For example: cell D4 in my source xls document has a value of 0.5124839309949 but is viewed as 0.51 due to Excel's Number formatting. Manually changing this to Text formatting resolves this but I need Powershell to run this for me, and then export (in CSV format) that same 0.5124839309949 rather than 0*.*51.
At the same time, I'm concerned about how this will treat date cells. As it stands, each row in my array has a date which Excel reads as DD/MM/YYYY except when put through to CSV this becomes the Excel serial date number (useless for my ultimate goal of bulk loading this into SQL Server.)
I'm aware that a File-SaveAs exercise in Excel produces a CSV but I need this to be run through Powershell due to business demands, and also, running this 'conversion' exercise manually also results in precision limits, so I am looking for a way around this please.
If you're able to amend the below Powershell script I'd be grateful!
Thanks for your help.
#
# Set the current folder path to temp
Set-Location \\xyz01\data\shared\data_warehouse\ntrs\temp
#Backup files
Copy-Item -path *.* -recurse \\xyz01\data\Shared\data_warehouse\test\performance
# Set variables
$file = "ABC Trust*"
$infile = "\\xyz01\data\shared\data_warehouse\ntrs\temp\"+$file
$outfile = "\\xyz01\data\shared\data_warehouse\test\temp\test_performance.csv"
# Set com object to Excel
$Excel = New-Object -ComObject Excel.Application
# Open the excel file and save as CSV
$workbook=$Excel.Workbooks.Open($infile)
$worksheet=$workbook.Worksheets.Item(1)
$worksheet.range.("D") = $worksheet.range.("D").Text
$workbook.SaveAs($outfile,6) # 6 is the code for .CSV
$workbook.Close($false)
$Excel.Quit()
The below may help? I have tried to replicate all suggested in here, to no avail.
Posh2Scripting - Automating Excel Spreadsheets with Powershell
Stackoverflow - Convert XLS to CSV without Data changes
OzGrid - Convert Excel To Text/CSV Without Losing Decimal Accuracy
Try changing this line...
$worksheet.range.("D") = $worksheet.range.("D").Text
to this...
$worksheet.range.("D") = $worksheet.range.("D").Value

Access Word 'Save As' dialog box with PowerShell script

I've got a PowerShell script (running on Windows Server 2008 R2 Enterprise) that opens a Word doc in Word 2010, performs a SaveAs, and saves the doc as a PDF. In brief my code looks similar to the below:
$word = new-object -ComObject "word.application"
$word.Visible = $true
$doc = $word.documents.open("path\file.doc")
$doc.SaveAs("path\file.pdf", [ref] 17)
$doc.Close()
ps winword | kill
The above works fine, no problems at all and is converting the documents as expected.
My question is:
If I physically open Word myself and navigate to 'File > Save As' I get various options in the dialog when saving as PDF (eg. page range, optimisation etc)
How can I, if at all, access these options from within the PowerShell script when performing the same action?
Any advice would be appreciated. Maybe it's just not possible.
Thanks in advance
After much investigation I've found that option I needed was ExportAsFixedFormat().
The documentation can be found here:
http://msdn.microsoft.com/en-us/library/bb256835%28v=office.12%29.aspx
And you can see it in action within a PowerShell script here:
http://blog.coolorange.com/2012/04/20/export-word-to-pdf-using-powershell/