everyone.
When I issue the Invoke-RestMethod command, via the PS shell (version 7), the expected output is saved into a variable.
However, when I put the same commands into a PS script, then calling said script using VBA, the same output is not saved into a variable (or into a file). Why, and what am I missing?
VBA code (snippet):
strCommand = "pwsh -NoLogo -NonInteractive -ExecutionPolicy Bypass -File C:\Users\....\tpCancelOrder.ps1 " & sCW & " " & sDON & ""
Set WshShell = CreateObject("WScript.Shell")
WshShellexec = WshShell.Run(strCommand)
PS code (snippet from tpCancelOrder.ps1):
$response = Invoke-RestMethod #params -SkipCertificateCheck
Pausing the PS script to see what's being outputted / returned
So, (from the screenshot) we can see that there is (actually, the same expected) output.
However, the next PS commmands
Write-Output $response.ToString | Set-Content "C:\Users\....\tpCancelOrder.log"
$response | ConvertTo-Json
return NULL.
I've tried various combinations of write-host, write-debug... redirection, out-file, tee-object.... but all to no avail.
From a PS shell, no issues——$response stores/contains the expected output.
Thanks in advance.
Related
I have the following macro which works just fine:
Private Sub Macro()
Dim ExecuteCommand As String
ExecuteCommand = "PowerShell -Command ""& 'C:\Program Files\R\R-4.2.2\bin\Rscript.exe' 'C:\Users\MyUser\Cool Calculations.R'"""
Shell ExecuteCommand
End Sub
What I want to do however, is to replace the name "MyUser" with $env:UserName instead.
However this macro does not seem to work:
Private Sub Macro()
Dim ExecuteCommand As String
ExecuteCommand = "PowerShell -Command ""& 'C:\Program Files\R\R-4.2.2\bin\Rscript.exe' 'C:\Users\$env:UserName\Cool Calculations.R'"""
Shell ExecuteCommand
End Sub
I have tried to run the command manually in PowerShell and it works correctly:
& "C:\Program Files\R\R-4.2.2\bin\Rscript.exe" "C:\Users\$env:UserName\Cool Calculations.R"
I am not sure what I am doing wrong when trying to add $env:UserName in my macro?
As Mathias points out, only "..." strings (expandable strings) perform variable expansion (interpolation) in Powershell; '...' strings (verbatim strings) do not.
Thus you must pass what PowerShell ultimately see as a "C:\Users\$env:UserName\Cool Calculations.R" argument (as an aside: consider simplifying to "$env:USERPROFILE\Cool Calculations.R"); since you're calling from VBA, this requires:
Using ""..."" to embed " chars. inside a VBA "..." string...
and \-escaping for the sake of powershell.exe, the Windows PowerShell CLI (which receives its -Command argument as a "..." string, so any " chars. to be retained as part of the command must be escaped)
That is, you need something like the following (sic; spaces added for readability)
" PowerShell -Command "" & '...' \""...\"" "" "
Specifically:
Private Sub Macro()
Dim ExecuteCommand As String
ExecuteCommand = "PowerShell -Command ""& 'C:\Program Files\R\R-4.2.2\bin\Rscript.exe' \""C:\Users\$env:UserName\Cool Calculations.R\"""""
Shell ExecuteCommand
End Sub
mklement0's response is very elegant, tested working. But I tested the command without escape, that seems not required under Windows Powershell, as Mathias suggested, it works also. I replaced Rscript.exe that I have not installed, by Get-ChildItem cmdlet like this:
Sub RunPSFromVba()
Dim ExecuteCommand As String
'ExecuteCommand = "PowerShell -Command ""& 'C:\Program Files\R\R-4.2.2\bin\Rscript.exe' 'C:\Users\$env:UserName\Cool Calculations.R'"""
ExecuteCommand = "PowerShell -NoExit -Command ""& 'Get-ChildItem' ""C:\Users\$env:UserName\Downloads"""""
Shell ExecuteCommand
End Sub
With PowerShell -NoExit, I keep the PowerShell Window alive after execution, I got this screenshot:
Hope this will also help.
I am trying to run a pwershell script from excel, which i can do and it works, but the powershell window does not show the information from the write-host comands in the script. If i run the file from the cmd prompt i get all the write-host texts appearing in the console window, like below.
Powershell run from command prompt
[]
However if i use this code from excel.
Sub RunAndGetCmd()
strCommand = "Powershell -File ""C:\PSFiles\TestOutput.ps1"""
Set WshShell = CreateObject("WScript.Shell")
Set WshShellExec = WshShell.Exec(strCommand)
End Sub
I get no texts shown in the console window, just the a flashing cursor like the following
Same Powershell ran from excel
I know the script runs and dooes everything, but i would like to output the texts as the script runs so i can see how far it has gotten.
Any ideas greatly appreciated.
The WScript.Shell Exec command redirects the stdin, stdout and stderr streams so you can access them from your application. As a result, anything written to stdout by the external application (e.g. using write-host in PowerShell) gets redirected instead of being displayed in the external application's window.
If you want the output displayed in the application's window you can use the Run method instead - e.g.
Option Explicit
Sub RunAndGetCmd()
Dim strCommand As String
Dim WshShell As Object
strCommand = "Powershell -File ""C:\PSFiles\TestOutput.ps1"""
Set WshShell = CreateObject("WScript.Shell")
WshShell.Run strCommand
End Sub
but if you're doing that, you might as well just use the built-in VBA Shell function:
Option Explicit
Sub RunAndGetCmd()
Dim strCommand As String
strCommand = "Powershell -File ""C:\PSFiles\TestOutput.ps1"""
VBA.Shell strCommand
End Sub
Note also that you might want an -ExecutionPolicy RemoteSigned in your command in case the machine has it set to Restricted:
strCommand = "Powershell -ExecutionPolicy RemoteSigned -File ""C:\PSFiles\TestOutput.ps1"""
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
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 {...}
I have a basic FTP upload PowerShell code that I run (hidden) via VBA in Excel:
VBA:
Call Shell("powershell -executionpolicy bypass & """ & ThisWorkbook.Path & "\FTP\FTPUpload.ps1""", vbHide)
FTPUpload.ps1:
$File = "H:\Workbook\file.txt"
$ftp ="ftp://user:pass#ftp.site.org/incoming/file.txt"
"ftp url: $ftp"
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
"Uploading $File..."
$webclient.UploadFile($uri, $File)
I want to be able to display a pass/fail message to the user. What is the best way to do this?
Make the PowerShell script signal its results by an exit code:
try
{
$webclient = New-Object System.Net.WebClient
$uri = New-Object System.Uri($ftp)
"Uploading $File..."
$webclient.UploadFile($uri, $File)
exit 0
}
catch
{
exit 1
}
And modify your VBA code to wait for the exit code and act accordingly.
See VBA Shell and Wait with Exit Code