Load/save documents to SFTP Linux server with VB.NET - linux

So I am using Visual Studio 2013 (Community)
And so far I've build a program that can create files using textboxes and so forth.
It saves to XML, and hopefully reads from XML (Even if I am getting access denied)
The time has come for the Application to talk to a server, where all the files will be saved, and read from.
The server is a Linux Server Edition (Latest) and its up and running fine.
I want my application to connect to it, log in, and then just list and read files from the server.
So far, it does this a bit.
Private Sub Loginbutton_Click(sender As Object, e As EventArgs) Handles Loginbutton.Click
Dim mySessionOptions As New SessionOptions
With mySessionOptions
.Protocol = Protocol.Sftp
.HostName = "192.168.0.247"
.UserName = "username" - these are default on purpose
.Password = "password"
.SshHostKeyFingerprint = "ssh-rsa 2048 [Hidden]"
End With
Using mySession As Session = New Session
' Connect
mySession.Open(mySessionOptions)
End Using
Form1.Show()
Me.Close()
End Sub
That works like a charm, and it moves on.
Once Form1 is loaded, its showing me the correct files from the server folder..
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each i As String In Directory.GetFiles("\\192.168.0.247\Database")
Objectlist1.Items.Add(Path.GetFileName(i))
Next
Objectlist1.Refresh()
End Sub
And when I save files to it
Private Sub Savebutton_Click(sender As Object, e As EventArgs) Handles Savebutton.Click
If IO.File.Exists(Pholderbox.Text) = False Then
Dim settings As New XmlWriterSettings()
settings.Indent = True
Dim XmlWrt As XmlWriter = XmlWriter.Create("\\192.168.0.247\Database\" + Pholderbox.Text, settings)
With XmlWrt
All of that, works as intended.
I want to mention that the folder in Question, or "Share" in question on the server, is password protected, and the username and password are inserted in the Login Code (Temporary)
My problem comes here when I doubleclick the file (activate) to READ it.
Private Sub Objectlist1_ItemActivate(sender As Object, e As EventArgs) Handles Objectlist1.ItemActivate
Caseworker.Show()
Me.Objectlist1.MultiSelect = False
Dim selectedListViewItem As String
selectedListViewItem = Me.Objectlist1.SelectedItems.Item(0).ToString
Const basepath As String = "\\192.168.0.247\Database"
Dim xmlpath = IO.Path.Combine(basepath, Objectlist1.SelectedItems.Item(0).Text)
If (IO.File.Exists(xmlpath)) Then
Dim document As XmlReader = New XmlTextReader(basepath)
Dim mySessionOptions As New SessionOptions
While (document.Read())
' - This little bugger screams out everytime
' "An unhandled exception of type 'System.UnauthorizedAccessException' occurred in System.Xml.dll
' Additional information: Access to the path '\\192.168.0.247\Database' is denied."
What in the world is wrong here? I would assume since it can list the content of that folder, and for testing I gave EVERYONE Full access to that folder (User, Group, Other) FULL Access on Linux (0777)
I put it like that to test if it would help.
This might be out of your expertize, as it involves the library WinSCP and is in fact a Linux Server.
Being that its only the "Read XML" feature that denies it, I must be very close?
I see that very many suggest other Third Party libraries, the best for me, would be a solution in plain VB.NET if possible.

You are combining SFTP login with an access to a remote resource via UNC path. This cannot work. Either use the SFTP only (what you can use WinSCP .NET assembly for) or login to the remote (Samba?) server, so that you can use UNC paths only.
An SFTP solution follows. I do not know VB.NET, so excuse mistakes in syntax. Also note, that you need to make the mySession global, so that you can access it from other functions.
Loading list of remote files:
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
For Each i As RemoteFileInfo In mySession.ListDirectory("/Database").Files
Objectlist1.Items.Add(i.Name)
Next
Objectlist1.Refresh()
End Sub
Reference: https://winscp.net/eng/docs/library_session_listdirectory
Saving:
Private Sub Savebutton_Click(sender As Object, e As EventArgs) Handles Savebutton.Click
Dim settings As New XmlWriterSettings()
settings.Indent = True
Dim TempPath As String = IO.Path.Combine(IO.Path.GetTempPath, Pholderbox.Text);
Dim XmlWrt As XmlWriter = XmlWriter.Create(TempPath , settings)
With XmlWrt
End With
mySession.PutFiles(TempPath, "/Database/").Check()
End Sub
Reference: https://winscp.net/eng/docs/library_session_putfiles
Loading:
Private Sub Objectlist1_ItemActivate(sender As Object, e As EventArgs) Handles Objectlist1.ItemActivate Caseworker.Show()
Me.Objectlist1.MultiSelect = False
Dim selectedListViewItem As String
selectedListViewItem = Me.Objectlist1.SelectedItems.Item(0).ToString
Dim xmlpath = IO.Path.Combine(IO.Path.GetTempPath, Objectlist1.SelectedItems.Item(0).Text)
mySession.GetFiles("/Database/" + Objectlist1.SelectedItems.Item(0).Text, xmlpath).Check();
If (IO.File.Exists(xmlpath)) Then
Dim document As XmlReader = New XmlTextReader(basepath)
Dim mySessionOptions As New SessionOptions
While (document.Read())
Reference: https://winscp.net/eng/docs/library_session_getfiles

Related

Catch event trigger from external application in Excel VBA

I use VBA to automate an external application that recently changed their COM API. The new API loads files asynchronously (used to be synchronous) so I need to wait for the file loaded trigger before I continue when I try to load a file.
I have tried the methods listed on the Microsoft website (EX1, EX2) which were also part of an accepted answer on StackOverflow.
Below is the code I have in a class module named UCExternal to contain the external application object:
Public WithEvents obj As External.Application
Private fileLoaded As Boolean
Private Sub obj_OnFileLoaded(ByVal lLayer As Long, ByVal strUNCPath As String)
Debug.Print lLayer
Debug.Print strUNCPath
fileLoaded = True
End Sub
Public Sub LoadSingleFile(fileStr As String)
fileLoaded = False
obj.LoadFile 0, fileStr
Do
DoEvents
Loop Until fileLoaded
End Sub
And then this is what I had in a normal code module to run using a button on the sheet:
Sub TryLoadFile()
Dim extObj as New UCExternal
set extObj.obj = CreateObject("External.Application")
filePath = "path/to/file"
extObj.LoadSingleFile filePath
End Sub
The event code never seems to fire and instead the Do Loop just runs until Excel crashes. I don't know if there is a way to confirm the application actually sent the event trigger? I have read through the new documentation for the application and that is the event they say to wait for. I have reached out to them for help as well but I wasn't sure if there was something more general I may have been missing. I have not worked with events external to Excel in the past. If I just step through it using the debugger and manually exit the Do Loop eventually the rest of the code that works on the loaded file works as well, so it does load the file.
extObj needs to be declared outside of TryLoadFile, or it will go out of scope and get cleared as soon as TryLoadFile completes
Dim extObj as New UCExternal
Sub TryLoadFile()
Set extObj = New UCExternal
set extObj.obj = CreateObject("External.Application")
filePath = "path/to/file"
extObj.LoadSingleFile filePath
End Sub

Can't see created objects

I've created some simple classes in excel and I'm trying to create new objects from these classes. It works fine and let's me create them and I can also access the variables given to the object. I can't see the object in the local window though and I don't really understand why. Is it not created correctly because you are supposed to see your objects there I understand?
Here is the code for the class
Option Explicit
'Teams
Public Name As String
Public Group As String
Public GF As Integer
Public GA As Integer
Public Points As Integer
'Public Players(25) As String
Private Sub class_initialize()
Points = 5
End Sub
and here is the code where I try to create an object
Sub TestTeams()
Dim Madagaskar As Object
Set Madagaskar = New ETeam
MsgBox (Madagaskar.Points)
End Sub
If you put Stop on the line after the MsgBox call and run TestTeams, you will see the object in the locals window.
It will only be there while Madagaskar is in scope and you're in break mode.

EPPlus: Cannot open file when another person is blocking

I use the following code to open an excel-file:
Private EPXlApp As OfficeOpenXml.ExcelPackage
Private EPXlFile As FileInfo
Private EPXlSheet As ExcelWorksheet
Private EPXlWorkbook As ExcelWorkbook
Public Sub New(newFilePath As String, Optional password As String = "")
PathFile = newFilePath
OfficeOpenXml.ExcelPackage.LicenseContext = LicenseContext.NonCommercial
EPXlFile = New FileInfo(PathFile)
EPXlApp = New OfficeOpenXml.ExcelPackage(EPXlFile, password) ' ---> here the error occurs
EPXlWorkbook = EPXlApp.Workbook
EPXlSheet = EPXlApp.Workbook.Worksheets(1)
End sub
This works. But if one person block the file, i can't open it again. I don't understand the error message
System.IO.InvalidDataException: "File S:\Team\file.xlsm is not an encrypted package"
because thats the rigt password, it has already worked if no one blocked the excel file.
Thank you very much in advance!

IIS - VBScript to create HTTPS binding - is my way correct?

I would like to automatize the process of SSL certificate installation for IIS 7.5. The preferred way is to use VBScript. I work on the problem to create a new HTTPS binding and to bind correct certificate to this binding.
I actually solved this problem activating Add IIS Management Scripts and Tools role for my web-server and using script like this:
Set serverWebAdmin = GetObject("winmgmts:root\WebAdministration")
' EC8BCFF70983EA26BFEA087683329CB8C07366A5 is an certificate hash of the fake certificate
' that i obtain from the staging environment of Let's Encrypt
' "MY" is the name of certificate storage
serverWebAdmin.Get("SSLBinding").Create "*", 443,"EC8BCFF70983EA26BFEA087683329CB8C07366A5", "MY"
Set newBinding = serverWebAdmin.Get("BindingElement").SpawnInstance_
newBinding.BindingInformation = "*:443:"
newBinding.Protocol = "https"
Set issuedWebSite = serverWebAdmin.Get("Site.Name='sitename.com'")
webSiteBindings = issuedWebSite.Bindings
ReDim Preserve webSiteBindings(UBound(webSiteBindings) + 1)
Set webSiteBindings(UBound(webSiteBindings)) = newBinding
issuedWebSite.Bindings = webSiteBindings
Set pathResult = issuedWebSite.Put_
It works well but before to use WMI to manage the server i tried to use (and expand a little) an example from MSDN how to create a binding. I took the example on VBScript and added the declaration of certificate hash and certificate storage name (i checked also these properties, they are existing so seems to be possible to set them. I also checked the code of some open-source projects like WinAcme - written in C# - and they use the same properties).
So my code was looking like this (the part that sets properties of binding):
Set bindingElement1 = bindingsCollection.CreateNewElement("binding")
bindingElement1.Properties.Item("protocol").Value = "https"
bindingElement1.Properties.Item("bindingInformation").Value = "*:443:"
bindingElement1.Properties.Item("certificateHash").Value = "EC8BCFF70983EA26BFEA087683329CB8C07366A5"
bindingElement1.Properties.Item("certificateStoreName").Value = "MY"
bindingsCollection.AddElement(bindingElement1)
adminManager.CommitChanges()
It works BUT it only creates the binding and DOES NOT append good certificate to this binding. My problem is solved by the previous code snippet but I would like to understand: is it the second code snippent wrong? Is it possible to bind good certificate this way?
Thank you by advance.
The reason it did not work with your bindingElement1 variant is simply because you can't add it to the bindingCollection, instead you have to add it to a method:
First part which you already had:
Dim bindingElement1 As ConfigurationElement = bindingsCollection.CreateElement("binding")
bindingElement1("protocol") = "https"
bindingElement1("bindingInformation") = "192.168.1.1:443:contoso.com"
bindingsCollection.Add(bindingElement1)
After that simply add:
Dim method = bindingElement1.Methods.Item("AddSslCertificate").CreateInstance()
method.Input.Attributes.Item("certificateHash").Value = "EC8BCFF70983EA26BFEA087683329CB8C07366A5"
method.Input.Attributes.Item("certificateStoreName").Value = "MY"
method.Execute()
Commit changes:
serverManager.CommitChanges()
So in total with some error-catching it could look like this:
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles Button1.Click
Dim serverManager As ServerManager = New ServerManager
Dim config As Configuration = serverManager.GetApplicationHostConfiguration
Dim sitesSection As ConfigurationSection = config.GetSection("system.applicationHost/sites")
Dim sitesCollection As ConfigurationElementCollection = sitesSection.GetCollection
Dim siteElement As ConfigurationElement = FindElement(sitesCollection, "site", "name", "contoso")
If (siteElement Is Nothing) Then
MsgBox("Element not found!")
End If
Dim bindingsCollection As ConfigurationElementCollection = siteElement.GetCollection("bindings")
Dim bindingElement1 As ConfigurationElement = bindingsCollection.CreateElement("binding")
bindingElement1("protocol") = "https"
bindingElement1("bindingInformation") = "192.168.1.1:443:contoso.com"
Try
bindingsCollection.Add(bindingElement1)
Catch ex As Exception : MsgBox(ex.Message) : End Try
Dim method = bindingElement1.Methods.Item("AddSslCertificate").CreateInstance()
method.Input.Attributes.Item("certificateHash").Value = "EC8BCFF70983EA26BFEA087683329CB8C07366A5"
method.Input.Attributes.Item("certificateStoreName").Value = "MY"
Try
method.Execute()
Catch ex As Exception : MsgBox(ex.Message) : End Try
serverManager.CommitChanges()
End Sub
Private Function FindElement(ByVal collection As ConfigurationElementCollection, ByVal elementTagName As String, ByVal ParamArray keyValues() As String) As ConfigurationElement
For Each element As ConfigurationElement In collection
If String.Equals(element.ElementTagName, elementTagName, StringComparison.OrdinalIgnoreCase) Then
Dim matches As Boolean = True
Dim i As Integer
For i = 0 To keyValues.Length - 1 Step 2
Dim o As Object = element.GetAttributeValue(keyValues(i))
Dim value As String = Nothing
If (Not (o) Is Nothing) Then
value = o.ToString
End If
If Not String.Equals(value, keyValues((i + 1)), StringComparison.OrdinalIgnoreCase) Then
matches = False
Exit For
End If
Next
If matches Then
Return element
End If
End If
Next
Return Nothing
End Function

Emulate document locking in Lotusscript

In my Lotus Notes Application, when a user clicks an action, the action will call a run-on-server agent that will process the current document. The invoked agents sometimes doesn't run (which I think because of the concurrent agent limit of the server). This is why every 5 minutes there is a maintenance agent that runs to processed documents that are not processed by the invoked agents. The problem is, sometimes, a document is SIMULTANEOUSLY processed by these 2 agents, producing unacceptable results.
Is there a way I can emulate the document locking, such that documents can only be processed by one agent at a time? I don't like to use the native document locking because problems with the business rules might arise. I tried tagging the documents when one of the agents process it, then clears the flag after it is done. But the problem here is that there will still be a chance that the agents get hold of the document reference AT THE SAME TIME (due to the delay of saving the document, maybe).
Please help me. Thanks! :D
Yeah, that is not hard. Create a locking database where you have locking documents. They really only need to contain the UNID of the document being locked.
When your agents start processing a document, check if a locking document exists. If not, create one.
If there is one, either wait or skip the document for now.
After the document is done processing, delete the locking document.
This is trivial. Back when we were still on Notes/Domino 5, I even wrote a simple class to handle document locking in one of my application. The code below is referencing some functions and variables from another script library, but you get the idea. I am sure you can easily modify the code to work for you.
Option Public
Option Declare
Use "Functions.Globals"
Class DocumentLock
Private lockdb As NotesDatabase
Private lockview As NotesView
Private lockdoc As NotesDocument
Private lockservername As String
Private lockdbname As String
Private lnpdoc As NotesDocument ' Document to lock/unlock
Public Sub New(doc As NotesDocument)
me.lockservername = globals.GetValue("LockServer")
me.lockdbname = AppHomeDir + globals.GetValue("LockDBname")
If me.lockdb Is Nothing Then
Set me.lockdb = New NotesDatabase(me.lockservername, me.lockdbname)
End If
Set me.lockview = me.lockdb.GetView("LockedDocs")
Call me.lockview.Refresh()
Set me.lnpdoc = doc
End Sub
Public Sub LockMe()
Set me.lockdoc = New NotesDocument(me.lockdb)
me.lockdoc.Form="Locked"
me.lockdoc.LockUNID=me.lnpdoc.UniversalID
me.lockdoc.LockUser= globalcurrentusername
me.lockdoc.LockTime=Str(Now())
me.lockdoc.ClaimNumber = me.lnpdoc.GetItemValue("ClaimNumber")(0)
me.lockdoc.DocumentForm = me.lnpdoc.GetItemValue("Form")(0)
Call me.lockdoc.Save(True,True)
End Sub
Public Sub UnlockMe()
Call me.lockview.Refresh()
Set me.lockdoc = me.lockview.GetDocumentByKey(me.lnpdoc.UniversalID)
If Not me.lockdoc Is Nothing Then
Call me.lockdoc.Remove(True)
Call me.lockview.Refresh()
End If
End Sub
Public Function IsLocked(flagShowInfo As Boolean) As Boolean
Call lockview.Refresh()
Set me.lockdoc = me.lockview.GetDocumentByKey(me.lnpdoc.UniversalID)
If me.lockdoc Is Nothing Then
me.IsLocked = False
Else
me.IsLocked = True
If flagShowInfo = True Then
MsgBox "Document locked " & locktext & "." & Chr$(13) & "Please wait a while and try again.."
End If
End If
End Function
Public Function LockText() As String
LockText = "by " & LockUserName() & " at " & me.lockdoc.LockTime(0)
End Function
Public Function LockUserName() As String
Dim lockedby As String
lockedby = me.lockdoc.LockUser(0)
If lockedby = globalcurrentusername Then
LockUserName = "you"
Else
LockUserName = lockedby
End If
End Function
End Class

Resources