Introduction
A friend of mine had some kind of twisted system where some job ran on a Unix machine somewhere writing some output to a file, post which a job on a Windows machine tried to pull that file information and did some manipulations. Without delving into why such a connected system was designed in the first place, let's look at the environments that we were working with. The Unix machine (I have no idea of what version of Unix it was running) wrote some file (data.dat), and the VB 6.0 code running on a windows server had to query the size of that file (data.dat) to make some decisions. So here we were, presented with such a problem, trying to brainstorm how we can query the size of the file in a Unix server from a VB 6.0 code. Telnet was the first thing that struck my mind, later, a whim and then I asked him, have you ever connected to that Unix machine via an SFTP connection. The answer was affirmative, we ended up exploiting that SFTP connection on that server to retrieve the file properties, and the file itself.
Background
The steps that I am going to describe here require WinSCP - http://winscp.net. WinSCP released a .NET library named WinSCP.dll in a beta phase during its 5.X release I guess. WinSCP also has its own tlb file exposed to COM. So there was our solution to simply call out the WinSCP COM from out VB 6.0 code to query the file size. However, certain factors influencing the new developers in the team who weren't exposed to COM and considering maintainability and ease, we decided to write a C# wrapper over WinSCP.dll just to get the file size, and expose only that method to a COM interface. We ended naming that wrapper SFTPFileSizeGroper
, that was later set up as a COM+, hence solved.
I am going to assume that you have some knowledge about COM+, regasm.exe, gacutil.exe. The complete set of features are only limited to the functionalities exposed by the WinSCP.dll, while this article is going to focus on just retrieving the size of the file present in the Unix server. Since WinSCP is the spine of everything that is done here, and if you haven't used WinSCP before, download the GUI executable from http://winscp.net/eng/download.php and give it a shot before we could move on. Since the Unix server in discussion accepts SFTP connections, the terms Unix server and sftp server will be synonymous for the rest of the article.
http://winscp.net/eng/docs/ssh explains the basics of SSH.
SSH Authentication
There are a number of ways that a connecting party can authenticate themselves to a Unix server using SFTP. Two ways that I know of are using an Active Directory account, or using a public/private key pair.
- Setting up an AD access is pretty easy, all you have to do is ask your IT to create an AD group, or grant a specific AD user, access to that Unix server. In this case, you would be required to supply your credentials in the form of a user name and a password while connecting to the Unix server.
- Setting up a public/private key pair authentication, requires you to create a public private key pair (with tools like puttygen.exe), and ask your IT to add the public key part of the public/private key pair to the Unix server. In this case, you would be required to supply the private key of the public/private key pair while connecting to the server.
In order to obstruct any man in the middle attacks WinSCP enforces that you confirm the HostKey of the SFTP server you are trying to connect to.
When you connect to an SFTP server for the first time with WinSCP, it asks to accept the HostKey for the server you are trying to connect to. On successful connection to the STFP server, WinSCP adds that server and its host key (perhaps some other information) to a WinSCP.ini file. Typically the WinSCP.ini file is found at the same location as the WinSCP.exe.
Arguments in Need
In order to connect to the SFTP server, we need the following information:
- Server name: The FQDN of the target SFTP server
- User Name and Password / Private key file: User name and password to connect, or the private key file
- HostKey: HostKey is a unique identifier for every machine accepting an SFTP connection (or perhaps every Unix machine I believe?). When using WinSCP.dll for functionalities, if WinSCP.ini file does not contain the HostKey of the server, that we are trying to connect to, then an exception is thrown. To avoid this, open WinSCP.exe GUI, and try connecting to the SFTP server once, when prompted to accept the HostKey, proceed with it. This step adds the HostKey to the ini file. Now, during the time of deployment, use the same WinSCP.ini file to avoid the Exception.
- File Path: The path of the file that you would like to query.
WinSCP.net has exemplary code samples and documentation for the methods that are exposed via WinSCP.dll. So if you have a questions about the WinSCP.dll, refer to the documentation at http://winscp.net/eng/docs/library.
Briefly, here are the steps for using WinSCP.dll. (The steps below are not COM or VB specific in any way until the time we start looking at setting a COM+ application.)
private static RemoteFileInfo GetRemoteFileInfo(string pFilePath)
{
RemoteFileInfo remoteFileInfo = default(RemoteFileInfo);
SessionOptions sessionOptions = WinSCPImpl.ObtainSessionInformation();
using (Session session = new Session())
{
session.ExecutablePath = winSCPExecutableLocation;
session.Open(sessionOptions);
remoteFileInfo = session.GetFileInfo(pFilePath);
}
return remoteFileInfo;
}
- Create a new
Session
- Open the session (connect to the server) using the
session.Open(sessionOptions)
method. SessionOptions
contains the server name, authentication information, and so on. - Obtain a
RemoteFileInfo
object using session.GetFileInfo("/obj/myfile.dat");
- Now,
remoteFileInfo
object has a list of properties that you could query right away. Length
is one of them.
There it is. That's the crux. Rest of the code in the file named WinSCPImpl.cs is pretty simple. And SFTPFileSizeGroper.cs is the class that has publicly exposed properties and methods (methods basically calling the WinSCPImpl.cs methods). The properties and methods in SFTPFileSizeGroper.cs file are exposed as COM. Since they are exposed to COM, they should be non static, public, no reference parameters and all that kind of restrictions.
From our VB code, we could instantiate a COM+ object of the type Server.CreateObject("SFTPFileSizeGroper.SFTPFileSizeGroper");
call its method GetFileSize();
which calls the WinSCPImpl.GetRemoteFileInfo();
which delegates the call to the WinSCP.dll's methods; which actually calls the WinSCP.exe with command line scripting parameters.
That's like a lot of chaining, but gets the job done.
We still have a tiny little task left for us to make the statement Server.CreateObject("SFTPFileSizeGroper.SFTPFileSizeGroper");
work. The class SFTPFileSizeGroper.cs file contains the SFTPFileSizeGroper
class that is meant to be exported to COM so any COM aware technologies can instantiate it.
Below is a VB code that would get the size of a file in a label control named lblFileSize
.
lblFileSize.Caption = GetSFTPFileSize(txtFilePath.Text)
End Sub
Private Sub Form_Load()
txtFilePath.Text = "/opt/batchapps/edword/rtg/NVBBackend/Items.dbf"
txtHostName.Text = "myunixserver.domain.com"
txtHostUserName.Text = "usermgr"
txtHostPassword.Text = "He11o111"
txtHostSshHostKey.Text = "ssh-rsa 2048 fd:83:b9:85:91:dd:33:95:a2:46:61:4f:05:76:58:31"
txtHostSshPrivateKey.Text = ""
End Sub
Function GetSFTPFileSize(fileName)
Dim objSftpFileSizeGroper As Object
Set objSftpFileSizeGroper = CreateObject(sftpFileSizeGroper.sftpFileSizeGroper)
objSftpFileSizeGroper.FilePath = fileName
objSftpFileSizeGroper.HostName = txtHostName.Text
objSftpFileSizeGroper.HostUserName = txtHostUserName.Text
objSftpFileSizeGroper.HostPassword = txtHostPassword.Text
objSftpFileSizeGroper.HostSshHostKey = txtHostSshHostKey.Text
objSftpFileSizeGroper.HostSshPrivateKey = txtHostSshPrivateKey.Text
GetSFTPFileSize = objSftpFileSizeGroper.GetFileSize()
Set objSftpFileSizeGroper = Nothing
End Function
Setting up the COM+
At this point, you might think that there is an additional work/wrapper, because, WinSCP already has a COM library that could directly be used from VB 6.0. In our approach, we did not use it, the reason being we had a hand full of C# developers that weren't comfortable with the COM interfaces and we hadn't tested the WinSCP's COM library yet, however, the WinSCP.dll for the .NET Framework was fully tested and a couple of our applications were already using it. That's a little 'tale of rationale', now let's take a quick look at installing SFTPFileSizeGroper.dll as a COM+.
You can directly use the built version of SFTPFileSizeGroper.dll, SFTPFileSizeGroper.tlb, and the SFTPFileSizeGroper.msi. SFTPFileSizeGroperCOMInstaller.bat contains a list of commands that should get you up and running instantly. However, if you'd like to manually do these steps yourself, without getting into much intricacies,
Expand the SFTPFileSizeGroper COM+ application node, right click Components, and create a new Component; hit Next, choose Install new component(s), pick the SFTPFileSizeGroper.tlb out of the Browse File Dialog, hit Next, and Finish.
- Build the
SFTPFileSizeGroper
project from Visual Studio. Obtain the SFTPFileSizeGroper.dll to some location on the file system. Also obtain a copy of WinSCP.exe, WinSCP.dll to the same location. - Open Visual Studio command prompt with Administrator privileges and run the following commands in order. [Install WinSCP.dll, and SFTPFileSizeGroper.dll to GAC; register SFTPFileSizeGroper.dll as COM.]
@echo Install WinSCP.dll to the GAC
gacutil /i WinSCP.dll
@echo Install SFTPFileSizeGroper.dll to GAC
gacutil /i SFTPFileSizeGroper.dll
@echo Register the SFTPFileSizeGroper.dll as COM and generate a tlb file
regasm /tlb /codebase SFTPFileSizeGroper.dll
- Let's open comexp.msc (or dcomcnfg) -- Component Services and create a COM+. This involves a series of steps, but the basic idea is, we are trying to create a new COM+ application and add our SFTPFileSizeGroper.dll COM interfaces to it. (regasm.exe command registered the COM interfaces available). I am going to point you to Once we have create a COM+, it can easily be exported to an MSI file which could later save us the below steps or creating the COM+ step by step.
Refer to the technet link http://technet.microsoft.com/en-us/library/bb687389.aspx To create a new COM+ application. Some preferable settings are "SFTPFileSizeGroper
" or any name in Step 4; "Server Application" in Step 5 (of the technet link); "Network Service" in Step 6 (of the technet link) or any user identity that has privileges to create and run a COM+ application. Final step after creating this component is to go to the Security tab and uncheck the Enforce access checks for this application check box.
- Once we have create a COM+ application, we 'd have to add a Component to it. In our case, the component (COM) that we are going to add is called the
SFTPFileSizeGroper
. When we ran the reagasm /tlb/ codebase SFTPFileSizeGroper.dll, besides registering the available COM interfaces, that command also generated a type library for us called the SFTPFileSizeGroper.tlb at the same location as the DLL. We are going to use this type library file and add the component to our newly created COM+ application - SFTPFileSizeGroper
. - If you would like to deploy this COM+ application on other computers, Right click on the
SFTPFileSizeGroper
COM+ and choose Export, follow the steps, an MSI file would be ready to be ported across many computer. A caveat is that, the MSI installation remembers all the COM+ properties, but the Identity. That is, in our case, we choose Network Service, and then we exported an MSI file out of it. If we used this MSI file to install the COM+ on other computers, then after the installation, if you'd browsed and saw the Identity property of the COM+, it wouldn't be Network Service, be sure to modify this Identify property after an MSI installation of a COM+.
Attachments
Unzip the attachment - the folder named.
SFTPFileSizeGroperCOM-CompletePackage
- contains the SFTPFileSizeGroper DLL, tlb file, MSI file to install the COM+, WinSCP.dll, and WinSCP.exe. The folder also has gacutil.exe and regasm.exe to aid portability.
These binaries could directly be used without a clean and build of the original SFTPFileSizeGroper
VS project.
Points of Interest
If you get Access Denied error when instantiating a COM+, make sure the Enforce access checks for this application check box under the Security tab of the COM+ properties is unchecked. If you get the infamous Active X component can't create object error, make sure you have the COM+ installed with a component named SFTPFileSizeGroper
. If you are calling it from a classic ASP page, fiddle with the Enable 32 bit applications setting of the IIS AppPool. Also check the Allow IIS intrinsic properties under the Advanced tab of the COM properties.
History
- 17th February, 2013: Initial version
- 18th February, 2013: Added Download options at the top of the article