HTTPS POST request using VBA for Excel - excel

I use "WinHttp.WinHttpRequest.5.1" to send HTTP POST requests from VBA in Excel.
But I could not manage to do it for HTTPS, as I received an SSL certificate error.
What VBA code would you use to negotiate an SSL connection to a website from VBA in Excel ?

The WinHttpRequest object has a SetClientCertificate method. Try this code example taken from the MSDN (I tried to adapt it for VBA):
' Instantiate a WinHttpRequest object. '
Dim HttpReq as new ActiveXObject("WinHttp.WinHttpRequest.5.1")
' Open an HTTP connection. '
HttpReq.Open("GET", "https://www.test.com/", false)
' Select a client certificate. '
HttpReq.SetClientCertificate("LOCAL_MACHINE\Personal\My Certificate")
' Send the HTTP Request. '
HttpReq.Send()

While I have not used the COM component (WinHttpRequest), it seems you need a call to SetClientCertificate prior to calling send, as per the link.
Does that help?

I have the same situation (send a http request from a VBA in Excel); I created three objects:
Set HttpReq = CreateObject("WinHttp.WinHttpRequest.5.1")
-- for the http request class, and
Set fsobj = CreateObject("Scripting.FileSystemObject")
Set txtobj = fso.OpenTextFile("C:\PKCERT.PEM")
-- to get into a variable the certificate contents, to pass it to HttpReq.SetClientCertificate,
certificate_data = txtobj.ReadAll
HttpReq.SetClientCertificate (certificate_content)
So I can send the request including its public key certificate, as usual,
HttpReq.Send
P.S. I found a script at http://www.808.dk/?code-simplewinhttprequest -- it worked fine in my case, hope in yours too.

Related

VBA issues with sending SMS

I have a code for my Excel application. It generates a product invoice and every time the invoice generated it will send the current billed amount along with thanks message. I have purchased a bulk SMS account and they have provided me the API.
I am using the "ActiveWorkbook.FollowHyperlink" method to send SMS, but it is sending SMS 2 times. Can anyone tell me why this method sends sms 2 times??
I have written the following program:
Sub Macro1()
Dim murl As String
murl = "<< SMS API HERE >>"
ActiveWorkbook.FollowHyperlink Address:=murl
End Sub
Consider using a raw GET request to your API, here is an example using late-binding to send a GET request to a google page - the MsgBox line is simply showing the response from google and you can replace the google.co.uk URL with your own API URL.
Public Sub Send_GET()
Dim con As Object ' MSXML2.ServerXMLHTTP60
Set con = CreateObject("MSXML2.ServerXMLHTTP") ' New MSXML2.ServerXMLHTTP60
con.Open "GET", "https://www.google.co.uk", False
con.setRequestHeader "Content-type", "application/x-www-form-urlencoded"
con.send
MsgBox con.responsetext
End Sub
I've used late binding but if you want to explore the proper objects and properties then add a reference to "Microsoft XML v6.0" in your VBA project and you can get rid of the Object and CreateObject parts - sending requests like this is SO USEFUL.
Don't forget to mark an answer as correct if it helps solve your problem.

"The action you have requested is not allowed" error when clicking on the Connect button using Selenium through VBA

I automated a login access to a site, with Selenium in Excel vba, and after i successfully fill the username and the password, when i click on Connect button the page is sending this error: "the action you have requested is not allowed".
Is there a way to eliminate this error ?
This error message...
The action you have requested is not allowed.
...is the result of a Cross-Site Request Forgery (CSRF) error.
A bit more about the relevant HTML DOM and your code trials would have helped us to debug the issue in a better way. However, this error is mainly observed when an end user forcefully executes unwanted actions on a web application in which they're currently authenticated. CSRF attacks specifically target state-changing requests, not theft of data, since the attacker has no way to see the response to the forged request.
However, this issue can occur in either of the following cases:
The config file of the Application Server (config.php) contains the following:
$config['csrf_protection'] = TRUE;
Solution would be to configure:
$config['csrf_protection'] = FALSE;
The config file of the Application Server contains the following when using HTTP:
$config['cookie_secure'] = TRUE;
Solution would be to configure:
$config['cookie_secure'] = FALSE;
Another approach would be to whitelist the URI as explained in CSRF User Guide:
$config['csrf_exclude_uris'] = array('api/person/add');
Finally, as a thumb rule whenever you intend to invoke click() always induce a waiter for the elementToBeClickable
Thank you for your response.
This is the code:
Sub eoriginal_macro()
Dim bot As New WebDriver, myproducts As WebElements, posts As WebElements, myproduct As WebElement, post As WebElement, i As Integer, productnum As String, clicknum As Integer, mysheet As Worksheet
bot.Start "chrome", "https://eoriginal.ro"
bot.Window.Maximize
bot.Get "/login"
bot.Wait 6000
bot.FindElementByName("username").SendKeys ("username")
bot.FindElementByName("password").SendKeys ("password")
bot.Wait 2000
Set posts = bot.FindElementsByName("username")
For Each post In posts
post.FindElementByXPath("//button[contains(#class,'btn-primary')]").Click
Next
MsgBox "complete"
bot.Quit
End Sub
The buton is clickable fromthe beginning.

Excel VBA MSXML2.XMLHTTP60 PUT request fail on "send" action

I'm creating an integration with Jira on Excel using VBA.
I'm able to login securely (using POST) and retrieve Jira issues (using GET) using Jira's API.
Now I'm trying to update issues, and the HTTP verb on Jira's API is GET. This shouldn't be a problem, but the fact is I can't even make the request.
Here's my current code - it's based on the POST code, but I'm not sure if I'm missing some other params.
I'm omitting some variable declarations - this is not the issue!
Public JiraService As New MSXML2.XMLHTTP60
JiraDataUrl = "https://atlassian.XXXXXXXX.com/jira/rest/api/2/issue/" & JiraId
body = "{""fields"" : {""customfield_13800"":""2011-10-03""}}"
Call JiraLogin(user, pass) 'This calls another Sub that log into Jira
JiraService.Open "PUT", JiraDataUrl, False
JiraService.setRequestHeader "Content-Type", "application/json"
JiraService.setRequestHeader "Accept", "application/json"
JiraService.setRequestHeader "X-Atlassian-Token:", "nocheck"
JiraService.send body
jsonText = JiraService.responseText
sStatus = JiraService.Status
When I run the script, it's interrupted by excel with the following messages:
I click on Debug and the JiraService.send body part is marked on the code
If I click on play, I get the final error (This method cannot be called after the send method has been called), that doesn't make any sense to me:
If I replace PUT for POST it runs normally, but Jira API returns with 405 HTTP error - as the method I'm trying to use requires a PUT.
Any idea on what am I doing wrong in this code?
I am doing the same thing right now, and I've figured out, that updating an issue requers async connection:
JiraService.Open "PUT", URL, True
In that case
JiraService.send data
will be succesful, but JiraService.status returns 1223! However, an issue field will be updated...
There is a discussion with the same "problem" with MSXML2.XMLHTTP60 and it seems, 1223 code is a kind of "success code":
https://social.msdn.microsoft.com/Forums/en-US/c4911cd8-caba-4c25-b71c-fe2e1a7ef8be/update-sharepoint-list-metadata-using-rest-from-vba-using-msxml2xmlhttp60

Excel Internet Explorer Automation Causes IE Environment to Crash

I've successfully automated a VBA Excel macro to iterate through a loop and hit a series of URL's to trigger a server-side script - this is simply done with:
myIE.Navigate ("http://someURL.php?VARIABLE=" & var_string)
where var_string is assigned within the loop as it iterates through. Before this, I've cleared cache, cookies and history with:
Shell "RunDll32.exe InetCpl.cpl,ClearMyTracksByProcess #
I've tried many #'s including 8,2, 16 etc to see if any of these had an effect (and combination of #'s).
The issue I am having, is that although the entire script SOMETIMES works, if I were to run it a second time the line where I navigate to the URL fails to call the URL even though the domain/URL is fully live and functional. Any other URL I manually type into the IE window works just fine - just not the one I am calling inside the loop. IE is locking me out of that domain temporarily. If I come back to the script a few hours from last running it, it generally works.
Again the domain is functional and script is fine - I verify it all the time with another machine.
It's as if I am setting something environmentally and breaking Internet Explorer within VBA even though the script is absurdly simple.
I've tried CreateObject(), GetObject as well as InternetExplorerMedium for myIE object.
If all you need is to "touch" that URL for its side effects, you can as well use a XMLHTTP object. In VBA, go to menu Tools, then References and choose Microsoft XML, v6.0. Then:
Dim Request As New XMLHTTP
Request.open "GET", Url & "?VARIABLE=" & var_string, False
Request.send
' Check Request.status, probably for 200
Some notes:
You may want to use POST instead of GET, if you're having problems with caching
You should pass the data in the POST body, if the server can handle it
The value of var_string should be escaped, in this case, URL encoded
If you don't want to block waiting for responses, you can make requests asynchronously (True third argument to open)
Following these notes, here's a more elaborate example:
Dim Request As New XMLHTTP
Request.open "POST", Url, True
Dim Handler As New CXMLHTTPHandler
Handler.Initialize Request
Set Request.onreadystatechange = Handler
Request.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
Request.send UrlEncode("VARIABLE") & "=" & UrlEncode(var_string)
' This returns immediately, the check must now be done in the Handler
For the missing pieces, here's the code for CXMLHTTPHandler, which I actually found through stackoverflow, and a definition of UrlEncode at stackoverflow.
You should specialize CXMLHTTPHandler for your needs, probably even make it accept an AddressOf a procedure and call it in the actual default procedure. The default procedure should set the m_xmlHttp to Nothing when m_xmlHttp.readyState is 4.
EDIT 1: If your request code is in a loop, you need to break the Dim ... New statements in two, to ensure you're using fresh objects:
Dim Request As XMLHTTP
Set Request = New XMLHTTP
Request.open "POST", Url, True
Dim Handler As CXMLHTTPHandler
Set Handler = New CXMLHTTPHandler
Handler.Initialize Request
Set Request.onreadystatechange = Handler
Request.setRequestHeader "Content-Type", "application/x-www-form-urlencoded"
Request.send UrlEncode("VARIABLE") & "=" & UrlEncode(var_string)
' This returns immediately, the check must now be done in the Handler

Sending Data from Excel to a Website

I have been asked to make a Macro which sends the Excel Data to a Website. There should not be any database involved. I have been trying to use HTTP Post after reading examples on this website. I have made a ASP.NET webpage which runs on localserver. While debugging the macro, the control does reach the webpage Page_load event but I am unable to see the data there.
Can anybody help me find my mistake?
Excel Code:
Sub SendData()
'
' SendData Macro
'
Dim sdata As String
sdata = "Abhh"
'
Set objHTTP = CreateObject("MSXML2.ServerXMLHTTP")
URL = "localhost:2782/Default.aspx?"; + sdata
objHTTP.Open "POST", URL, False objHTTP.setRequestHeader "User-Agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.0)"
objHTTP.send ("")
End Sub
C# Code
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
namespace Fetch
{
public partial class _Default : System.Web.UI.Page
{
protected void Page_Load(object sender, EventArgs e)
{
Label1.Text = Request.Url.Query;
// I dont know where the data is in the Request object.(If it is there at all..)
}
}
}
Thanks
Abi
Does the 'website' have to be a standard webpage? Can you not send it to a 'website' running an ASP.NET WebService instead?
See here & here on how to write a webservice, and then read here & here on how to call the WebService via VBA.
Although I can't give you an exact example in Excel, I'm pretty certain Excel has a function or two to lookup values from any website using a GET request. The difference between a GET and POST request is that in the former all data passed is part of the URL string. Assuming the HTTP support in Excel is basic, I suspect you will have better luck using a GET request, carefully building your URL with the data with simple string manipulation. Although I do not know the exact syntax, imagine a formula in a cell like =lookuphtml("http://some.url.com/send?var1="&B2&"&var2="&B3), where cells B2 and B3 would contain your variable values (the values you want to pass to the script). This assumes the receiving end is capable of receiving data through GET requests (not only POST requests). Most decent server-side libraries allow data passed through both GET and POST request, although YMMV.
I'm not a .NET guy but it looks very much like URI.Query would only show the GET data because POST data isn't part of the URI.
You might want to look at using the standard form syntax of name1=value1&name2=value2&... in your sData string and then on the server use Request.Form as per the examples here

Resources