Quantcast
Channel: Second Life of a Hungarian SharePoint Geek
Viewing all articles
Browse latest Browse all 206

Using Edge.js as a Replacement for win32ole

$
0
0

Last month I had to create a NodeJS script that invokes methods of ActiveX object. I work in a Windows-only environment, so it should be no problem. I find the win32ole package quickly. Based on its description and the samples I’ve found, it seemed to be the perfect tool for my requirements. However, as many others (see issues on GitHub, and a lot of  threads about the build problem on StackOverflow), I had issues installing the package in my environment:

OS: Windows Server 2008 R2 SP1, Windows Server 2012 R2
npm: 2.15.9
node: 4.5.0

The last two lines are from the output of the npm version command.

As far as I see, a package win32ole depends on (node-gyp) fails to build:

npm ERR! win32ole@0.1.3 install: ‘node-gyp rebuild’
npm ERR! Exit status 1
npm ERR!
npm ERR! Failed at the win32ole@0.1.3 install script ‘node-gyp rebuild’.

As agape824 commented on Aug 28 2015 regarding a similar issue:

“I solved the problem
by installing node.js v0.8.18 & npm v1.4.28.
Previous erros were produced by different version of node files (eg. v8.h).”

So I’ve removed all NodeJS and npm installation on one of our systems, and installed the suggested versions. Downloaded the node-v0.8.18-x64.msi, and the right npm version was installed via the command:

npm install npm@1.4.28 -g

Now invoking the command npm version results:

node: 0.8.18
npm: 1.4.28

and we can install win32ole using:

npm install –save-dev win32ole

Having win32ole installed, we can create NodeJS scripts that interact with ActiveX object.

For example, you can get the content of a web page via the MSXML2.XMLHTTP object:

var win32ole = require(‘win32ole’);

var url = "http://www.yoursite.com";
var xhr = new ActiveXObject("MSXML2.XMLHTTP");
xhr.open("GET", url, false);
xhr.send();
console.log(xhr.responseText);

Of course, you can do it much easier and a platform-independent way using other NodeJS libraries, it is just to illustrate, how to invoke ActiveX object methods. However, you can perform other, not such trivial actions using the win32ole library as well, like interacting with the Windows application that support automation via ActiveX object (like Excel, Word, or Outlook, see the examples here), or even access the HTML DOM loaded into your Internet Explorer browser, and extract values from it.

In my case I needed Internet Explorer to perform Windows-integrated authentication against a SharePoint server. In this case, SharePoint returns an authentication ticket in the response page (in the hidden input field ‘__REQUESTDIGEST’), that one can include in subsequent requests.

var win32ole = require(‘win32ole’);
var uri = "
http://YourSharePointServer";

try{
var ie = new ActiveXObject(‘InternetExplorer.Application’);
  // displaying the UI of IE might be useful when debugging
  //ie.Visible = true;
  console.log(uri);
  ie.Navigate(uri);
  while(ie.ReadyState != 4) {
    win32ole.sleep(1000);
  }
  var token = ie.Document.getElementById("__REQUESTDIGEST").value;
  console.log(token);
  ie.Quit();
}catch(e){
  console.log(‘*** exception cached ***\n’ + e);

So the win32ole package would be really great, but it has not been updated in the past 4 years or so, and we don’t work with obsolete node and npm versions just to be able to use this package. Instead of that, we tried to find a replacement solution for win32ole. And I think, we’ve found something that is even better than win32ole, and it is the Edge.js package. Edge.js enables interaction between your NodeJS and .NET code in both direction, and not only on the Windows platform, as it supports Mono and CoreCLR as well. It supports PowerShell, and other languages beyond C#, like F#, Lisp or Python just to name the most important ones.

To tell the truth, creating ActiveX object and invoking their methods only a very small subset of functionality enabled by this package. Obviously, you can not create ActiveX objects on operating systems that do not support them, but it is not the limitation of the package.

After you install the Edge.js package, for example:

npm install –save-dev edge

you can create NodeJS scripts that invokes your C# code. In the C# code you can create ActiveX objects and invoke their members as well. In the following simple example create an instance of the WScript.Shell ActiveX object, and displays a greeting message via its Popup method:

var edge = require(‘edge’);

var wshShell = edge.func(function () {/*
  async (input) => { 
       dynamic wshShell = Activator.CreateInstance(Type.GetTypeFromProgID("WScript.Shell"));
       wshShell.Popup("Hello, " + input + "!");

        return string.Empty;
    }
*/});

wshShell("world", function (error, result) {
    if (error) throw error;
    console.log(result);
});

Or we can re-create our win32ole example showed above using Edge.js, and read the authentication token via the HTML DOM in Internet Explorer:

var edge = require(‘edge’);

var uri = "http://YourSharePointServer";

var getToken = edge.func(function () {/*
    async (uri) => { 

            dynamic ie = Activator.CreateInstance(Type.GetTypeFromProgID("InternetExplorer.Application"));
            // if you want to see the UI (for example, when debugging)
            //ie.Visible = true;
            ie.Navigate(uri);
            while (ie.ReadyState != 4)
            {
                System.Threading.Thread.Sleep(1000);
            }
            var token = ie.Document.getElementById("__REQUESTDIGEST").value;
            ie.Quit();

        return token.ToString();
    }
*/});

getToken(uri, function (error, result) {
    if (error) throw error;
    console.log(result);
});

An alternative solution to the above is to read a SharePoint web page via the MSXML2.XMLHTTP object and parse the HTML DOM via cheerio to get the hidden field that contains the request digest.

var edge = require(‘edge’);
var cheerio = require(‘cheerio’);

var uri = "http://YourSharePointServer";

var getToken = edge.func(function () {/*
    async (uri) => {

            dynamic xhr = Activator.CreateInstance(Type.GetTypeFromProgID("MSXML2.XMLHTTP"));
            xhr.open("GET", uri, false);
            xhr.send();

            return xhr.responseText;
    }
*/});

getToken(uri, function (error, result) {
    if (error) throw error;
    $ = cheerio.load(result);
        console.log($(‘#__REQUESTDIGEST’).val());  
});

I hope these scripts help other developers frustrated by the build issues of win32ole to create workarounds. I think Edge.js is a really useful NodeJS package, I am sure I will find a lot of application areas for it in the future. In contrast to win32ole, Edge.js is a living project, and that is very important to us. Many thanks to Thomas Janczuk for creating and supporting this gem! Keep up the excellent job!



Viewing all articles
Browse latest Browse all 206

Trending Articles