create a new sheet using showdetail on pivottabes field in Powershell + VBA - vba

Double Clicking on Pivot tables GrandTotal data creates a separate sheet with entire data source. Would like to get this done through powershell. Below is the code I tried with Powershell 5.1.
$excelFile = "C:\test\Testfile.xlsb"
$Excel = New-Object -ComObject Excel.Application
$wb = $Excel.Workbooks.Open($excelFile)
$s=$wb.worksheets(1).range("C7").select
$s.showdetail
$wb.saveas("C:\test\Testfile_modified.xlsb")
$wb.close()
$Excel.quit()

More direct - no need for select or intermediate variable $s:
$excelFile = "C:\tester\Testfile.xlsb"
$Excel = New-Object -ComObject Excel.Application
$wb = $Excel.Workbooks.Open($excelFile)
$wb.worksheets(1).range("C7").showdetail = $true
$wb.saveas("C:\tester\Testfile_modified.xlsb")
$wb.Close()
$Excel.Quit()
#make sure Excel process is ended (or it may persist)
[System.Runtime.Interopservices.Marshal]::ReleaseComObject($Excel)
Remove-Variable Excel
in a script file called from cmd using:
powershell -noexit "& ""C:\Tester\psExcelTest.ps1"""

Related

Export SQL data to Excel - Best possible approach?

I am currently working on an automation which requires to export sql results to excel data. I want to do this via SQL query. Few options i know are as below, but before i start exploring these things. I would like to know the best possible approach .
PS - It would be really great if there is a way to dynamically create excel during query execution and export data in multiple excel sheets.
OPENROWSET
bcp_cmd
You can CREATE VIEW and utilize that view in Excel 2016 under its data connections through PowerQuery. Views are preferred since they are managed independently in the server, and provide realtime data results without requiring a full query to be embedded in the Excel file. The resulting set exists in the workbook as a refresh-able table. Results that need to be recorded should be done via new workbooks or UPDATE's back to the server in a separate script.
In the PowerQuery Editor, Home tab, click Advanced Editor. The database connection string and call to the server is below. You can also dynamically pass parameters from an Excel table to the query utilizing a table in the Name Manager.
Excel tab, table name: tbl_Parameters
A B
1 StartDate 01/01/2020
2 EndDate 02/01/2020
let
Source = Sql.Database("ServerName" , "Database", [Query="
DECLARE #Start_Date AS datetime
DECLARE #End_Date AS datetime
SET #Start_Date = '"&StartDate&"'
SET #End_Date = '"&EndDate&"'
SELECT * FROM uvw_product
WHERE item_sold_date BETWEEN
#Start_Date AND #End_Date
"])
in
Source
A while back I cobbled this Powershell script together.
It querys sql server data, saves as csv, formats it and saves as xls, then mails via smtp.
You can set up a windows scheduled task to automate it.
There's also an import xls module for powershell.
Import-Module Sqlps -DisableNameChecking;
#execute mysql query as excel
$Server = "DB SERVER";
$Database = "DBNAME";
$Query = #"
*SELECT QUERY HERE*
"#
$a = Get-Date
#note: if you run get-location from ide, it will use the ide path instead of the script path
$currentLocation = Split-Path -Parent $PSCommandPath
$FilePath = $currentLocation + "\CSVName.csv"
$SavePath = $currentLocation + "\XLSFileName" +$a.Day+ $a.Month + $a.Year + ".xls"
$SqlConnection = New-Object System.Data.SqlClient.SqlConnection
$SqlConnection.ConnectionString = "Server = $Server; Database = $Database; User ID = DBUSERNAME; Password = PASSWORD";
$SqlConnection.Open()
$sqlcmd = $SqlConnection.CreateCommand()
$sqlcmd.Connection = $SqlConnection
$sqlcmd.CommandText = $Query
$SqlAdapter = New-Object System.Data.SqlClient.SqlDataAdapter
$SqlAdapter.SelectCommand = $sqlcmd
$DataSet = New-Object System.Data.DataSet
$SqlAdapter.Fill($DataSet)
$DataSet.Tables[0] | Export-Csv -notypeinformation $FilePath
$SqlConnection.Close()
#Invoke-Sqlcmd -Query $Query -ConnectionString $SqlConnection.ConnectionString | Export-Csv -notypeinformation $FilePath
#release memory function
function Release-Ref($ref){
([System.Runtime.InteropServices.Marshal]::ReleaseComObject([System.__ComObject]$ref) -gt 0)
[System.GC]::Collect()
[System.GC]::WaitForPendingFinalizers()
}
#format excel to display correct date
$objExcel = new-object -comobject excel.application
$objWorkbook = $objExcel.Workbooks.open($FilePath)
$objWorksheet = $objWorkbook.Worksheets.Item(1)
$objRange = $objWorksheet.UsedRange
[void] $objRange.EntireColumn.Autofit()
$objWorkbook.Saved = $True
$objExcel.DisplayAlerts = $False
$objWorkbook.SaveAs($SavePath,1)
$objExcel.Quit()
#release memory
Release-Ref($objWorksheet)
Release-Ref($objWorkbook)
Release-Ref($objExcel)
#create mail
$smtpServer = "SMTPSERVER"
$smtp = new-object Net.Mail.SmtpClient($smtpServer)
$att = new-object Net.Mail.Attachment($SavePath)
$msg = new-object Net.Mail.MailMessage
$msg.Subject = "EMAIL SUBJECT"
$msg.From = "FROM EMAIL"
#$msg.To.Add("TO EMAIL 1")
$msg.To.Add("TO EMAIL 2")
$msg.Body = #"
Hi,
MSG BODY HERE
Best Regards
"#
$msg.Attachments.Add($att)
$smtp.Send($msg)
$att.Dispose()
Download and install the 64-bit or 32-bit version of the driver, based on what you have installed.
https://www.microsoft.com/en-us/download/details.aspx?id=13255
Then, you should be able to run this.
insert into OPENROWSET('Microsoft.Jet.OLEDB.4.0',
'Excel 8.0;Database=D:\testing.xls;',
'SELECT * FROM [SheetName$]') select * from SQLServerTable
Notice: this may not work if you have one 32-bit technology and one 64-bit technology. In this case, you may need to employ some kind of workaround.
See this link for additional ideas of how to integrate SQL Server and Excel.
https://solutioncenter.apexsql.com/how-to-import-and-export-sql-server-data-to-an-excel-file/

Simulate a "ENTER" keyPress for Excel Userform with powershell

I am trying to open my .xlsm file with a Userform that is in a workbook Event OPEN and create an ENTER keypress simulation so the MACRO starts. I know that I can call the macro directly but we are using the Userform to show some information while the code is running.
I have built a Powershell script but as soon as I open my excel file my code stops there and does not execute the rest needed until I close the excel file. Is it a way to force my code to jump to the next execution or a different solution. thank you advance
$excel = New-Object -comobject Excel.Application
#open file
$FilePath = 'Q:\Detail\DT_HAL_TMPC\App\POFI_Planificateur_Taches_Exec.xlsm'
$workbook = $excel.Workbooks.Open($FilePath)
#make it visible (just to check what is happening)
$excel.Visible = $true
$workSheet = $workBook.Worksheets.Item(1)
$wshell = New-Object -ComObject wscript.shell;
sleep 10
$wshell.SendKeys('~')
as soon as I close my excel file the .sendKeys works but I want to do it while my excel file is open, not close

Powershell script works but not in vb.net code

I need to run a powershell script from vb.net. I wrote it and tried it in powershell ISE and the powershell console and it's working properly.
But when I try to use it in my vb.net code, nothing happens.
The script put into text file citrix session from some user.
here is my powershell script :
$username = 'domain\myusername'
$password = 'mypassword'
$securePassword = ConvertTo-SecureString $password -AsPlainText -Force
$credential = New-Object System.Management.Automation.PSCredential $username, $securePassword
Start-Process C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -Credential $credential -NoNewWindow -ArgumentList "add-pssnapin citrix*`nGet-BrokerSession -AdminAddress 'ipadresshere' | Out-File -FilePath C:\inetpub\wwwroot\gestusers\ajax\data\arrays.txt"
and here's my vb.net code :
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
' open it
MyRunSpace.Open()
' create a pipeline and feed it the script text
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
' add an extra command to transform the script output objects into nicely formatted strings
' remove this line to get the actual objects that the script returns. For example, the script
' "Get-Process" returns a collection of System.Diagnostics.Process instances.
MyPipeline.Commands.Add("Out-String")
' execute the script
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
' close the runspace
MyRunSpace.Close()
' convert the script result into a single string
Dim MyStringBuilder As New StringBuilder()
For Each obj As PSObject In results
MyStringBuilder.AppendLine(obj.ToString())
Next
' return the results of the script that has
' now been converted to text
Return MyStringBuilder.ToString()
When I try to use a smaller script like :
$test = "blablabla"
$test | Out-File -filepath "C:\inetpub\wwwroot\gestusers\ajax\data\arrays.txt"
it works so I don't really understand why the first script is not working .. if you have some suggestion I would be thankful
I finaly found a solution to my problem.
I am running my web app on a IIS server and when I was launching my script it was the default user "IIS default/application_pool" which was lauching it although I specified a specific user to run it, it was like my script doesn't work.
So I choosed to go in my IIS server params and I just made an other app_pool with my specific user. I put my app under this pool and now it works perfectly.
Here's how to make a specific pool on IIS Server : https://www.developer.com/net/asp/article.php/2245511/IIS-and-ASPNET-The-Application-Pool.htm
cya

"Permission Denied" error while trying to run Powershell script from Word Macros

I need to run a powershell script with a parameter from a word macros. For now even the attempts to simply run a script from VBA are not sucessful. I do the following:
Sub Powershell_Run()
sCmd = "powershell -file ""C:\Users\i351063\Desktop\Scripts\NewAttempt.ps1"""
Set xShell = CreateObject("Wscript.Shell")
Set xShellExec = xShell.Run(sCmd)
rReturn = xShellExec.Run("C:\Users\i351063\Desktop\Scripts\NewAttempt.ps1")
End Sub
The execution of this code returns an error: "Run-time error '70': Permission denied" on the line Set xShellExec = xShell.Run(sCmd). What do I do wrong? How to fix the error?
Thanks a lot in advance!
UPD: Powershell code (I want to pass the filename as a parameter from VBA to PS, for now it's initialized right in the code)
Param([string]$filename)
$filename = "HT.docm"
Add-Type -AssemblyName "Microsoft.Office.Interop.Word"
$word = [Runtime.Interopservices.Marshal]::GetActiveObject('Word.Application')
$wshell = New-Object -ComObject Wscript.Shell
$doc = $word.Documents | Where-Object {$_.Name -eq "$filename"}
If (!$doc)
{
$form.Close()
[void] $wshell.Popup("Failed to find an opened report",0,"Report not found",0x1)
$word.ScreenUpdating = $true
Break
}
Else {...}

Run a macro on multiple worksheets in a workbook via powershell

I am using the following Powershell script to run some macro's on worksheets within a workbook. What I want to do is open a workbook, run a certain macro on specific worksheets, and save the workbook to a different location. For testing purposes, I am just running it on all the worksheets.
Here is what I have so far:
$excel = New-Object -ComObject excel.application
$xlfileformat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlOpenXMLWorkbook
$workbook = $excel.Workbooks.Open($(join-path -path R:\TestOutput\Nick -childpath tmp.xlsm))
$worksheets = $Workbook.Worksheets | ForEach-Object {$_.name}
ForEach ($Worksheet in $Worksheets) {
$WS = $Workbook.Worksheets.Item($Worksheet)
$excel.Run("RunMacro")
$workbook.save()
} #End ForEach
$workbook.saveas($(join-path -path "R:\TestOutput\Nick" -childpath "Test_Output-post"), $xlfileformat)
$excel.quit()
With this script I would expect the macro to run on all the worksheets within the workbook, however, only the last worksheet has the macro applied to it. At first I didn't have the $workbook.save() in there. I added it because I though it was reinitialize the workbook every time it loaded a new worksheet, therefor losing the changes from the last run. This didn't fix the issue though.
I know I could modify the VBA script itself, but I want to eventually turn this into a function with the macro and worksheet(s) as variable inputs.
As I was typing this out, I found the answer. The problem was, I never activated the worksheet I selected. The following code fixed the problem:
$excel = New-Object -ComObject excel.application
$excel.DisplayAlerts = $false
$xlfileformat = [Microsoft.Office.Interop.Excel.XlFileFormat]::xlOpenXMLWorkbook
$workbook = $excel.Workbooks.Open($(join-path -path R:\TestOutput\Nick -childpath tmp.xlsm))
$worksheets = $Workbook.Worksheets | ForEach-Object {$_.name}
ForEach ($Worksheet in $Worksheets) {
$WS = $Workbook.Worksheets.Item($Worksheet)
$WS.Activate()
$excel.Run("RunMacro")
} #End ForEach
$workbook.saveas($(join-path -path "R:\TestOutput\Nick" -childpath "Test_Output-post"), $xlfileformat)
$excel.quit()
The fix was adding the $WS.Activate() command in the loop.