Why GetFiles from a remote folder using Linq is hanging - vb.net

I'm trying to fetch the files inside a folder ordered by LastWriteTime.
The code is running very fast when accessing to a local path (C:\MyFolder), but is hanging when accessing to a remote path (\\MyServer\MyFolder)
Dim myOrderedList As List(Of String) = (From item In IO.Directory.GetFiles(strFolderSource) _
Let file = New IO.FileInfo(item) _
Order By file.LastWriteTime _
Select item).ToList()
Should this code work? Is not allowed this method to get files from a remote folder?
Which alternative code could I use to get the same result without hanging?
EDITED (2019-01-18 16:32):
Sorry guys, I've tried the proposed solution from Rango, and still the same hang. Finally I created a small logging system to catch the step that caused the problem, and realized that all is a credential problem.
Just before the code I posted I do a NET USE to grant access to the remote computer, and the net use is executed, but for any reason, the GetFiles() fails because of Logon failure: unknown user name or bad password.
So, Could I ensure the credentials with the net use before call the GetFiles()?
Maybe using a pause or something like this?
FULL CODE:
Dim processInfo As New System.Diagnostics.ProcessStartInfo()
processInfo.FileName = "C:\WINDOWS\system32\net"
processInfo.Arguments = "net use \\MyServer\IPC$ ""password"" /USER:Username"
System.Diagnostics.Process.Start(processInfo)
Dim myOrderedList As List(Of String) = (From item In IO.Directory.GetFiles("\\MyServer\g$\MyFolder") _
Let file = New IO.FileInfo(item) _
Order By file.LastWriteTime _
Select item).ToList()

You could try to use DirectoryInfo.EnumerateFiles instead wich has two advantages:
No consecutive security handshakes from the remote server necessary
Streaming the files instead of loading all into memory before you start ordering them
Dim di = new DirectoryInfo(strFolderSource)
Dim files = From fi In di.EnumerateFiles() Order By fi.LastWriteTime Select fi.FullName
Dim myOrderedList As List(Of String) = files.ToList()

Finally solved including a sleep of 5 seconds after the net use and before the GetFiles():
System.Threading.Thread.Sleep(5000)
Thanks for your time, and hope this helps anybody with a similar problem.

Related

Using stored credentials in powershell through vb.net

I've written a pair of apps; one that issues powershell scripts to clients (the server) and one that executes powershell scripts passed to it (the client).
I've added functions to detect if a particular script requires elevation.
In the event that a script requires elevation, the server app prompts the user for their credentials. The password is converted to a secure string and saved in a SQL database, as is the username along with the script.
The client app grabs the script and, if elevation is required, grabs the username and secure string then tries to build a credential object from it.
The functionality is working fine for non-elevated scripts, but elevated scripts are not working. Its not erroring or throwing an exception (finally) but the scripts are not executed.
The first part of this process reads the data from SQL into a datatable and then i loop through the rows of that datatable.
Once I've got a row that contains a script that needs running, I build the script.
Here's how I'm building and executing the powershell in VB...
If this_routine_elevation_required = 1 Then
Dim scriptbody As String = row("scriptbody").ToString
Dim elevated_user_un As String = row("elevated_user").ToString
Dim elevated_user_ss As String = row("securestring").ToString
credential_script = "$securepassword = '" & elevated_user_ss & "' | ConvertTo-SecureString; $username='" & elevated_user_un & "';$credential = New-Object System.Management.Automation.PsCredential($username, $securepassword)"
action_response = RunPowershellScript(credential_script & "; " & scriptbody)
End If
and here is the function that executes the powershell (using 'Imports System.Management.Automation)...
Private Function RunPowershellScript(ByVal scriptText As String) As String
' create Powershell runspace
Dim MyRunSpace As Runspace = RunspaceFactory.CreateRunspace()
MyRunSpace.Open()
Dim MyPipeline As Pipeline = MyRunSpace.CreatePipeline()
MyPipeline.Commands.AddScript(scriptText)
Dim results As Collection(Of PSObject) = MyPipeline.Invoke()
MyRunSpace.Close()
Dim MyStringBuilder As New StringBuilder()
For Each obj As PSObject In results
MyStringBuilder.AppendLine(obj.ToString())
Next
Return MyStringBuilder.ToString()
End Function
I've thrown up a messagebox of the script before its passed to the RunPowershellScript function so i could make sure nothing was malformed or to ensure i wasnt doing anything stupid (i've manipulated the secure string for the purposes of this image)...
The example here is just a test to see if the executor could stop the W32Time service, something that would normally require elevation. It does not work.
I get an empty response back from the RunPowershellScript function and the service continues to run.
It occured to me that I'm getting a securestring from the database and then converting that securestring to a securestring, so perhaps its not ending up with the correct valid password in $credential, but from what i understand I have to provide a securestring for the password parameter of PsCredential, and without -ConvertTo-SecureString it would consider the password to just be a string. I tried this and it threw an exception about the password being null.
Can anyone help point me in the right direction?
Many thanks in advance.
Is the script running locally on the target or from the server?
Credential objects are specific to the computer AND user account which creates them, so they are not transferable and can only be used on the computer which creates them.

Setting MS Access password at runtime in vb.net designer generated system

I am developing a VB.NET update system for a volunteer organisation’s MS Access database. The database is protected by a password as it contains personal information. I have created the application using the VB designer. I need to be able to code the application so that, if the owner decides to change the MS Access password, they will have no need to come back to me to change the code and rebuild the solution. In other words, I do not want the password to be hard coded in the app.config file or the settings.designer.vb file. My code should not need to know the password as a simple call to one of the Fill functions can test any password entered by the user. My problem is that I have found no way to alter the connection string that is tested in the setttings.designer.vb code whenever the database is accessed. I am using Visual Studio 2017.
I have spent a long time searching the web for answers and have tried various solutions involving the configurationmanager without success. I am new to this area so I would be most grateful if anyone here can help.
Here is my latest attempt which still produces an invalid password error even though the third debug statement suggests that the connection string, including the password, has been correctly set.
Public Sub UpdateConnString(connString As String)
Dim configFileMap As New ExeConfigurationFileMap()
Dim config As Configuration = ConfigurationManager.OpenExeConfiguration(configFileMap.ExeConfigFilename)
Dim connStringName As String = "TestConnectionString"
Debug.Print("0 " + config.ConnectionStrings.ConnectionStrings(connStringName).ConnectionString)
config.ConnectionStrings.ConnectionStrings(connStringName).ConnectionString = connString
Debug.Print("1 " + config.ConnectionStrings.ConnectionStrings(connStringName).ConnectionString)
config.Save(ConfigurationSaveMode.Modified, True)
Debug.Print("2 " + config.ConnectionStrings.ConnectionStrings(connStringName).ConnectionString)
End Sub
Just because a connection string is stored in the config file, you aren't required to use it as it is. You can read in that default value and then edit it before using it, e.g.
Dim builder As New OleDbConnectionStringBuilder(My.Settings.DefaultConnectionString)
builder.DataSource = dataSource
Dim connectionString = builder.ConnectionString
You can add or modify any part of a connection string you want that way at run time.
Thank you for your response. Unfortunately, the code throws a compilation error - "DefaultConnectionString is not a member of My.Settings".
Fortunatley I have now managed to find a working solution:
'My.Settings.Item("TestConnectionString") = connectionString

SQLite database file can't be opened when placed in network folder

Can someone help me to understand why this works fine...
Dim cs = "Data Source=C:\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.Open() ' no exception
... while this breaks when opening connection (it is exactly the same file)...
Dim cs = "Data Source=\\NetworkServer\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.Open() ' exception: {"unable to open database file"}
... and fix it because I need to place database file in network location so I can access it regardless of the computer I run the application?
Thank you very much!
Ok, so by trial and error I found the solution, although I can't quite understand the reason it works:
Dim cs = "Data Source=\\NetworkServer\folder\Livros.sdb;Version=3;"
Dim cn = New System.Data.SQLite.SQLiteConnection(cs)
cn.ParseViaFramework = True ' JUST ADDED THIS STATEMENT
cn.Open() ' no exception
If somebody can explain why .ParseViaFramework = True does the trick, please feel free to comment.
Similar question was asked here.
SQLite: Cannot open network file programmatically, even though worked before
The top answer gives a few more fixes. Linking here as this is the first stackoverflow that came up when I searched. Also I was using a SQLiteConnectionStringBuilder and could not find a way to set the parseViaFramework so the first solution was the one I needed.
Double the leading two backslashes in the file name (e.g. "\\\\network\share\file.db").
Use a mapped drive letter.
Use the SQLiteConnection constructor that takes the parseViaFramework boolean argument and pass 'true' for that argument.

Access to path is denied when trying to import from the client's desktop with SSIS

I'm creating a html page that will import an excel file in to a tracking system. On a button click event excel file is located / ssis package is fired / data imported then closed out. Thats the idea work flow. Problem is the excel file access is being denied before the package even executes
Here is the exact error :
I've tried :
excel file properties have been shared to everyone
identity impersonate set to true
hard coding the path
here is the VB code
Protected Sub bntExecute_Click(sender As Object, e As EventArgs) Handles btnExecute.Click
Dim app As Application = New Application()
Dim package As Package = Nothing
'Dim fileName As String = "C:\Users\Desktop\T. Bryant III\PTSID_Update_Template"'
Try
Dim fileName As String = Server.MapPath(System.IO.Path.GetFileName(FileUpload1.PostedFile.FileName.ToString()))
FileUpload1.PostedFile.SaveAs(fileName)
package = app.LoadPackage("#C:\Users\Desktop\T.Bryant III\KitImport", Nothing)
'excel connection from package'
package.Connections("SourceConnectionExcel").ConnectionString = "provider=Microsoft.Jet.OLEDB.4.0data source =" + fileName + "Extended Properties = Excel 8.0"
'Execute the pakage'
Dim results As Microsoft.SqlServer.Dts.Runtime.DTSExecResult = package.Execute()
Catch ex As Exception
Throw ex
Finally
package.Dispose()
package = Nothing
End Try
End Sub
Thanks in advance or if there is an easier way to do this please let me know. The package when executing it in ssis works fine with its own connection manager etc.
A few things to try. If they don't work for you as permanent solutions, they should at least confirm that your code is working and you are dealing with a persmissions issue (which appears to be the case).
Move your file to the public folder (C:\Users\Public).
Run your application (or web browser) as an administrator (if applicable to your version of Windows).
If you are using a web browser, try using a different one.
If nothing else works, try pasting your code into a Windows Form Application.
If you still get the same error after trying all of this, it's time to take another look at your code. Remove the Try/Catch block to determine precisely which line is throwing the error. If you've tried hard coding, I'm guessing it's the SaveAs method. I'm not sure what class FileUpload1 is, but some SaveAs methods won't overwrite existing files unless you explicitly tell them to. Check the appropriate documentation and see if you don't need to pass a True value somewhere along with filename.
Update us with the results. At the very least, this should narrow down your problem and allow for a better diagnosis of it.

How do I "kick-start" a jcl stream on the mainframe using FTP inside vb.net 2008

The following is the code that uploades a bytearray into a file DSN on our mainframe. It works very well. What I want to do is upload the jcl which should then start to execute. That's the part I am stuck on. I used to be able to do it through WININET, but I want to get away from that and use the better FTP commands in vb.net
Public Shared Sub UploadToMainFrame( _
ByVal ftpHost As String, _
ByVal ftpMainframeDSN As String, _
ByVal UserName As String, _
ByVal Password As String, _
ByVal DataToUpload As String)
Dim ftpRequest As FtpWebRequest
Dim ftpFullMainframePath = String.Format("ftp://{2}//'{3}'", ftpHost, ftpMainframeDSN)
ftpRequest = WebRequest.Create(ftpFullMainframePath)
ftpRequest.Credentials = New NetworkCredential(UserName, Password)
ftpRequest.KeepAlive = True
ftpRequest.UseBinary = False
ftpRequest.Method = WebRequestMethods.Ftp.UploadFile
ftpRequest.
Dim byteArray() As Byte = StrToByteArray(DataToUpload)
ftpRequest.ContentLength = byteArray.Length
Dim ftpStream As Stream = ftpRequest.GetRequestStream()
ftpStream.Write(byteArray, 0, byteArray.Length)
ftpStream.Close()
ftpStream = Nothing
ftpRequest = Nothing
End Sub
If you want your uploaded file to be treated as a JCL job, it's a simple matter to put:
quote site filetype=jes
into the FTP commands.
This will direct JES to treat the incoming dataset as JCL and automatically submit it.
How you would achieve that with VB is not within my domain but the following works fine from cmd.exe:
ftp -n bigiron.com -s:bigiron.ftp
with bigiron.ftp containing:
user MYNAME MYPASSWORD
quote site filetype=jes
quote site jeslrecl=80
put commands.jcl
bye
If, for some reason, you can't do this from within VB, my next move would be to have a started task running under z/OS which monitored a specific data set and submitted any new members that appeared there.
I'd use the sentinel method to ensure you're not trying to submit half-uploaded jobs:
client uploads member into date dataset (e.g., "DATA.MYJOB").
client then uploads dummy member into sentinel dataset (e.g., "SENTINEL.MYJOB").
started task continuously looks for new members in sentinel dataset.
if found, submits the equivalent data member to JES and deletes both sentinel and data members.
We've actually used this method before when sysprogs weren't keen on allowing those foreign machines direct access to JES (despite passwords).
Update, after a bit of searching:
It doesn't look good for the "quote site" solution. This post from 2006 (but with updates well into 2009) seems to indicate MS won't allow "quote site" to be implemented since it would expose the inner workings of their code. I won't comment of the validity of that argument and their reasoning may have changed, but I can't see anything in the current docs that indicates they've added this feature.
So I guess you're stuck with an external FTP solution.