|
Introduction
ASP programmers for large firms are most often asked to connect UNIX systems to the Web. I was recently asked to convert an application that ran on a UNIX server and make it available on the Web. The trick was that the actual process was to still run on the UNIX server, and only the client side would be Web based. The UNIX server, once it was told what to do, would still run the financial calculating processes and then send an email to the client. This article discusses how to create a simple DLL in Visual Basic (VB) that will call a freeware Windows EXE that connects and sends commands using REXEC to a UNIX server using remote shell calls. With this tool you'll be able to control any UNIX server running any process from a Web page.
download complete source code for this article
Project Outline
The program asks department heads which accounts they wish to get financial information on and then has the result emailed to them. Here's the flow of the project.
- Client-side Web page gets the username, date and account.
- The page is submitted to an ASP page which, server side, calls the WinRSH32Runner COM object on the IIS server
- WinRSH32Runner then runs the freeware program WinRSH32 and sends it parameters, which it uses to Remote Shell into our UNIX server and execute the UNIX program.
- WinRSH32Runner returns and lets the process run synchronously on the UNIX server.
Collect Data on The User
Our first job is to get information about the user and his/her choice. This simple Web page does the trick.
<%@ Language=VBScript %>
<HTML>
<BODY>
<%
'------------------------------------------
' Get the USERNAME from the environment
'------------------------------------------
dim s_username
s_username = Request.ServerVariables("LOGON_USER")
%>
Please choose which account and what time period you would like the report for:
<br>
<form method=post action="process.asp">
<input type=hidden name=txtUsername value="<%=s_username%>">
<select name=cboAccount>
<option value="105">105 Trips</option>
<option value="107">107 Food</option>
<option value="123">123 Shipping</option>
</select>
<p>
Date (MM-YYYY) <input type=text size=7 name=txtDate>
<p>
<input type=submit>
</form>
</BODY>
</HTML>
The first section gets the username from the ServerVariable "LOGON_USER" and writes it to the form in the hidden text field, "txtUserName" so that when the form is submitted the user name will go with the form.
<%
'------------------------------------------
' Get the USERNAME from the environment
'------------------------------------------
dim s_username
s_username = Request.ServerVariables("LOGON_USER")
%>
In order to have the Web server return the name, set the Web page in which this this is running to "Only registered users have browse access" You can get this property page from the Tools | Security menu in MS FrontPage.
The rest of the HTML is rather simple and self-explanatory. We actually create this section dynamically by querying a database for the list of accounts the username is associated with.
Processing the results and sending them to the WinRSH32Runner COM object
The Processing page, process.asp, will now take the form results and pass them to WinRSH32Runner COM object, which I'll show you how to write later on.
The Winrsh32Runner COM object needs to know what server, username and password to run. We set this in the ASP script.
s_UnixLoginUserName = "Report"
s_UnixLoginUserPassword = "BoogieBoogie"
s_UnixServer ="Unixsrv1"
We then build the commands that are sent to the UNIX server. The actual UNIX program that creates and emails the report is called, DoFinanceReport, and it is located in one of the bin directories. To make sure it runs, we set the path environment variable first. The ";" at the end of the Set Path command line is a new command indicator in UNIX scripting. We need this so that we can send more than one command at a time in our call. The second part of the next piece of code combines the parameters that the DoFinanceReport program expects and concatenates them all into one string, s_command.
s_command = "set path = (/usr/ucb /bin /usr/bin) ; "
' The UNIX program "DoFinanceReport" expects [username, date, account]
s_command = s_command & "DoFinanceReport " & s_username & " " & s_date & " " & s_account
We then only have to call our WinRSH32Runner COM object running on the IIS server and it will be passed to the UNIX server and processed.
Dim RunRSH
set RunRSH = CreateObject("Winrsh32Runner.execute")
RunRSH.Go s_UnixServer, s_command,s_UnixLoginUserName,s_UnixLoginUserPassword,false
set RunRSH = nothing
The Freeware WinRSH32 UNIX Calling Program
WinRSH32 is an amazing little freeware tool that will allow you to remote shell into a Unix server and pass it parameters (download). It allows you to completely control username, password, server, and the UNIX command(s) to send, as well as control the way it appears.
Here is a list of command parameters you can use:
-l username - a valid user name on the remote host
-h hostname - a valid remote host name
-o filename - an output file name for the output of the command.
-p password - a valid password for the user name. WinRSH32 will use REXEC protocol if this option is specified instead of the default RSH protocol.
-t seconds - specify the number of seconds WinRSH32 will wait before forcing the connection to close. A value of zero means infinite waiting (default).
-i - WinRSH32 minimizes itself if this option is specified.
-q - WinRSH32 terminates itself when all data are received from the remote side.
Building the WinRsh32Runner COM object
As you can see, it's rather straightforward connecting to our COM object and sending it a command.
Why Wrap the WinRSH32 Program Inside a COM Object?
The IIS server won't let your server-side scripts run executables easily from the ASP server-side code since you are not logged in to the Windows server, so we need to run it inside COM+ so that it will run as a user. COM+ creates a Windows logged-in environment and runs the COM DLL that runs the EXE then inside it. Another advantage is that we can control the way the ASP pages interact with the WinRSH32 program since the ASP script has to pass parameters we want to expose, not necessarily all the parameters the WinRSH32 program does.
To build the WinRsh32Runner COM Object, open up your Visual Studio VB and create a new ActiveX DLL project.
Rename the project as "WinRsh32Runner" and rename the single class as Execute. To do this, right click each of the items, choose properties, and then change the name property.
Now, add a reference to Microsoft Scripting Runtime. To do this, choose the Project menu; choose References and scroll to the big Microsoft section of tools.
Go to the Execute class and enter this code into it. Don't worry. The full source code is included.
Public Result As String
Public Sub Go(ByVal strServer As Variant, _
ByVal strCommand As Variant, _
Optional ByVal strUsername As Variant = "default", _
Optional ByVal strPassword As Variant = "default", _
Optional ByVal WaitUntilFinished As Variant = True)
Dim f_Params As String
Dim oFSO As New Scripting.FileSystemObject
Dim f_FileResult As String
Dim oWshShell, f_Result As String, f_FullCommand As String
Dim f_EXEPath As String
'--------------------------------------------------------------------
' Execute the Winrsh32 EXE in a COM object's logged in environment
' to Remote shell into a Unix system
'--------------------------------------------------------------------
If strServer = "" Then
Err.Raise vbError + 101, "go", "Error: Server not specified"
Exit Sub
End If
If strCommand = "" Then
Err.Raise vbError + 101, "go", "Error: Unix Command not specified"
Exit Sub
End If
'--------------------------------------------------
' If username password not set set it to a default
'--------------------------------------------------
If strPassword = "default" Then strPassword = "Someaccount"
If strUsername = "default" Then strUsername = "somepassword"
'----------------------------------
' Set the path to WinRSH32.exe
'----------------------------------
f_EXEPath = "c:\progra~1\winrsh\WINRSH32.EXE "
'-----------------------------
' Check to see if it exists
'-----------------------------
f_FileResult = "WinRSH32.exe found"
If oFSO.FileExists(f_EXEPath) = False Then
Err.Raise vbError + 101, "go", "Error: " & f_EXEPath & " isn't on the Web server or is corrupt."
Exit Sub
End If
Set oFSO = Nothing
'--------------------------------------------------------
' Ensure the command has double quotes surrounding it
' Since the entire command set must be surrounded by them
'--------------------------------------------------------
strCommand = Trim(strCommand)
If Left(strCommand, 1) <> Chr(34) Then
strCommand = Chr(34) & strCommand
end if
If Right(strCommand, 1) <> Chr(34) Then
strCommand = strCommand & Chr(34)
end if
'--------------------------------------------------------------
' Execute the command on the Unix server using WinRSH32.exe
'--------------------------------------------------------------
'------------------------------------------
' Parameters:
' -h = host name of Unix server
' -l = login name
' -p = password
' -q = Quit once the command has finished
' -i = Minimize during run
'------------------------------------------
f_Params = " -h " & strServer & " -l " & strUsername & " -p " & strPassword & " -q -i "
'----------------------------------------------------------------
' Create an instance of the Windows Scripting Host
' to RUN the WinRSH32.exe
'----------------------------------------------------------------
Set oWshShell = CreateObject("WScript.Shell")
f_FullCommand = f_EXEPath & f_Params & strCommand
f_Result = oWshShell.Run(f_FullCommand, 1, WaitUntilFinished)
Set oWshShell = Nothing
'--------------------------------
' Create optional result report
'--------------------------------
Result = ""
Result = "<pre>"
Result = Result & "WshShell Result = " & f_Result & vbCrLf
Result = Result & f_FileResult & vbCrLf
Result = Result & "Command Executed = " & strCommand & vbCrLf
Result = Result & "Parameters Executed = " & f_Params & vbCrLf
Result = Result & "Full Command Executed: " & f_FullCommand & vbCrLf
Result = Result & "</pre>"
End Sub
The Go method accepts 4 parameters:
Public Sub Go(ByVal strServer As Variant, _
ByVal strCommand As Variant, _
Optional ByVal strUsername As Variant = "default", _
Optional ByVal strPassword As Variant = "default", _
Optional ByVal WaitUntilFinished As Variant = True)
StrServer = the UNIX server name
StrCommand = the UNIX command script
StrUsername = the username to log in as into UNIX
StrPassword = the password to log into UNIX with
WaitUntilFinished = whether the WinRSH32 program should run synchronously or asynchronously
The last three parameters are optional. You may have a built-in username and password for scripts that run on your UNIX server. By using them, the ASP program doesn't need to specify them. It's also a security precaution. The WinRSH32 program can either pause your script as it runs, or send the command to UNIX and then return control instantly to your ASP script. This is set with the WaitUntilFinishedparameter.
'----------------------------------
' Set the path to WinRSH32.exe
'----------------------------------
f_EXEPath = "c:\progra~1\winrsh\WINRSH32.EXE "
At the heart of this application is the WINRSH32.EXE executable that needs to be placed somewhere on your server. In this example, it is located in the WINRSH folder.
'--------------------------------------------------------
' Ensure the command has double quotes surrounding it
' Since the entire command set must be surrounded by them
'--------------------------------------------------------
strCommand = Trim(strCommand)
If Left(strCommand, 1) <> Chr(34) Then
strCommand = Chr(34) & strCommand
end if
If Right(strCommand, 1) <> Chr(34) Then
strCommand = strCommand & Chr(34)
end if
WinRSH32 expects the actual UNIX calls to be in double quotes so we check the left and right most character for them and then add them if needed.
f_Params = " -h " & strServer & " -l " & strUsername & " -p " & strPassword & " -q -i "
'----------------------------------------------------------------
' Create an instance of the Windows Scripting Host
' to RUN the WinRSH32.exe
'----------------------------------------------------------------
Set oWshShell = CreateObject("WScript.Shell")
f_FullCommand = f_EXEPath & f_Params & strCommand
f_Result = oWshShell.Run(f_FullCommand, 1, WaitUntilFinished)
Set oWshShell = Nothing
We then simply build the WinRSH32 command line, first with the parameters, and login information, then with the actual command to execute on the UNIX server.
To run the WinRSH32 program, we call it with the Windows Scripting Host RUN command that will run the EXE on the server. It takes three parameters.
- The command to execute, which is the WinRSH32 program, and the parameters we just built for it.
- The state of the window. 1 simply means a normal window
- If the Windows Scripting Host should wait or not for the process it's calling to complete. It usually would be required, but for testing purposes, put it on to make sure the process works on the UNIX server.
'--------------------------------
' Create optional result report
'--------------------------------
Result = ""
Result = "<pre>"
Result = Result & "WshShell Result = " & f_Result & vbCrLf
Result = Result & f_FileResult & vbCrLf
Result = Result & "Command Executed = " & strCommand & vbCrLf
Result = Result & "Parameters Executed = " & f_Params & vbCrLf
Result = Result & "Full Command Executed: " & f_FullCommand & vbCrLf
Result = Result & "</pre>"
Finally, create a simple report that can be viewed for debugging purposes on the ASP page.
Conclusion
In this article we've seen how to send user's choices to a UNIX program though a Web page. This DLL is generic enough that it can be used for any UNIX application that needs to be made available to Web users.
About the Author
Ian Vink is a Canadian and has worked all over the world in the IT sector, most recently in Haifa,
Israel. He has been an intranet Web master for four years and has been writting code since 1982.
He's taught computer technology since 1994 and owns a number of Web stores. He's married to a
wonderful Australian Oracle designer. Please send comments or questions to Ian at ian@ianvink.com.
|