Write a file to network location in Linux using C# - c#

The below program written in C# which runs fine in Windows but when it comes to running in Linux ( inside a docker container) it doesn't translate the path properly.
class Program
{
static void Main(string[] args)
{
try {
bool validLogin = ValidateUser("domain", "username", "password" );
if (validLogin)
{
var path = "\\\\10.123.123.123\\folder$\\subfolder";
string fullPath = Path.Combine("\\\\10.123.123.123\\folder$\\subfolder", "file_name1");
string body = "Test File Contents";
if (!Directory.Exists(path))
{
Directory.CreateDirectory((path));
}
File.WriteAllText(fullPath, body);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString() + ex.Message);
}
}
public static bool ValidateUser(string domainName, string username, string password)
{
string userDn = $"{username}#{domainName}";
try
{
using (var connection = new LdapConnection {SecureSocketLayer = false})
{
connection.Connect(domainName, LdapConnection.DefaultPort);
connection.Bind(userDn, password);
if (connection.Bound)
return true;
}
}
catch (LdapException )
{
// Log exception
}
return false;
}
}
What exact path should I use? I have tried all sorts of combinations.

In windows, you have "Local Paths" which start with a letter that refers to a local drive, then you have networked paths, which begin with a double-backslash, followed by some domain/IP, followed by a directory share (all of which can be mapped to another letter, for ease of access)
To access network shares, from Linux, you need to Mount the share to some location of the Linux tree.
You can look at many examples on-line, here is one: Mounting and mapping shares between Windows and Linux with Samba
Also, the resulting Path will look nothing like what you have for Windows, so, you will need to know (somehow) that you are running under which SO, and configure your paths accordingly.

Few suggestions
Check the hosing environment & manipulate paths accordingly.
You can use Path.Combine() to formulate your paths.
An example of this application is below
using System.Runtime.InteropServices;
class Program
{
static void Main(string[] args)
{
try {
bool validLogin = ValidateUser("domain", "username", "password" );
if (validLogin)
{
var path = Path.Combine("\\\\10.123.123.123", "folder$", "subfolder");
string fullPath = Path.Combine(path, "file_name1");
if (!RuntimeInformation.IsOSPlatform(OSPlatform.Windows))
{
path = path.Replace(#"\", #"/");
fullPath = fullPath.Replace(#"\", #"/");
}
string body = "Test File Contents";
if (!Directory.Exists(path))
{
Directory.CreateDirectory((path));
}
File.WriteAllText(fullPath, body);
}
}
catch (Exception ex)
{
Console.WriteLine(ex.ToString() + ex.Message);
}
}
public static bool ValidateUser(string domainName, string username, string password)
{
string userDn = $"{username}#{domainName}";
try
{
using (var connection = new LdapConnection {SecureSocketLayer = false})
{
connection.Connect(domainName, LdapConnection.DefaultPort);
connection.Bind(userDn, password);
if (connection.Bound)
return true;
}
}
catch (LdapException )
{
// Log exception
}
return false;
}
}

Related

Is that possible to find a file in SharePoint site without specifying the drive contains it?

I'm now getting a file from specific drive on SharePoint,but the customer asked to search for the file without specifying a drive.
public static byte[] SharePointDownload(string token, string fileName, string sharepointTargetLibrary)
{
string baseSiteId = GetSiteId(token);
string folderId;
if (string.IsNullOrEmpty(baseSiteId))
{
return null;
}
else
{
folderId = GetFolderId(token, baseSiteId, sharepointTargetLibrary);
if (string.IsNullOrEmpty(folderId))
{
return null;
}
}
try
{
WebClient wc = new WebClient();
byte[] result;
wc.Headers[HttpRequestHeader.Authorization] = "Bearer " + token;
wc.Headers[HttpRequestHeader.Accept] = "application/json";
result = wc.DownloadData(string.Format(#"https://graph.microsoft.com/v1.0/sites/{0}/drives/{1}/root:/{2}:/content", baseSiteId, folderId, fileName));
wc.Dispose();
if (result.Length>0)
{
return result;
}
else
{
return null;
}
}
catch (Exception ex)
{
LoggerHelper.Log(ex.Message);
return null;
}
}
now i want to know if this line
result=wc.DownloadData(string.Format(#"https://graph.microsoft.com/v1.0/sites/{0}/drives/{1}/root:/{2}:/content", baseSiteId, folderId, fileName));
can get rid of folderId and searches with the fileName only specified
Using Microsoft Graph, you search a drive
GET /sites/{site-id}/drive/root/search(q='{search-text}')

how to get a specific file address in a computer in c#?

I want to find a video (.mp4) file which is present in some specific folder which is unknown to me. The file has the attributes Hidden, System and Directory.
I have written the code to find the file with that extension, but still the code is not finding that particular file.
static void Main(string[] args)
{
List<string> path = new List<string>();
string fileName = "javascript_part1.mp4";
foreach(DriveInfo d in DriveInfo.GetDrives().Where(x=>x.IsReady))
{
foreach(string d1 in Directory.GetDirectories(d.Name))
{
try
{
foreach(string d2 in Directory.GetDirectories(d1))
{
try
{
path.AddRange(Directory.GetFiles(d2, fileName, SearchOption.AllDirectories));
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
catch(Exception ex)
{
Console.WriteLine(ex.Message);
}
}
}
foreach(string s in path)
{
Console.WriteLine(s);
}
Console.ReadLine();
}
Please if anyone can suggest what the problem is in the code or any suggestion for modification of the code to get the desired result.
As Peter B already mentioned, you don't look deep. So you need kinda recursion, like this:
public static string FindFile(DirectoryInfo folder, string fileName)
{
if (folder.EnumerateFiles().Where(x => x.Name == fileName).Any())
{
return folder.FullName;
}
foreach (var newFolder in folder.EnumerateDirectories())
{
return FindFile(newFolder, fileName);
}
return "Nothing found";
}

check for IP address and download the data

I have two devices having separate IP addresses and want to check if any one is connected and if connected download the database from the device and any given time only one device is connected.My query works fine for one device how to check which one is connected. I have updated my code but not sure how is it gone work.
private void button7_Click(object sender, EventArgs e)// 1)first download database to local system.
{
this.Process1();
}
public void Process1()
{
string _ftpURL = #"131.000.00.0"; // fake Host URL or address of the SFTP server
/* how to check for another IP adddress if exists */
string _UserName = "root"; //fake User Name of the SFTP server
string _Password = "3term"; // fake Password of the SFTP server
int _Port = 2222; //Port No of the SFTP server (if any)
string _ftpDirectory = "/home/root/systools/WM/WebMobility.db"; //The directory in SFTP server where the files will be uploaded
string LocalDirectory = "F:\\Explor\\final test"; //Local directory from where the files will be uploaded
try
{
Sftp Connection = new Sftp(_ftpURL, _UserName, _Password);
Connection.Connect(_Port);
Connection.Get(_ftpDirectory, LocalDirectory);
Connection.Close();
}
catch (Exception ex)
{
if (ex is SshConnectionException || ex is SocketException)
{
_ifwInstance.Error(string.Format("Ignoring {0} during listing directory", ex.Message));
}
else
{
string _ftpURL = #"131.111.11.11"; // fake Host URL or address of the SFTP server
/* how to check for another IP adddress if exists */
string _UserName = "root"; //fake User Name of the SFTP server
string _Password = "3term"; // fake Password of the SFTP server
int _Port = 2222; //Port No of the SFTP server (if any)
string _ftpDirectory = "/home/root/systools/WM/WebMobility.db"; //The directory in SFTP server where the files will be uploaded
string LocalDirectory = "F:\\Explor\\final test"; //Local directory from where the files will be uploaded
throw new Exception("Login to SFT FAILED", ex);
}
}
}
updated Code:
string[] _ftpURL = { #"100.100.0.0", #"101.0.0.0" }; //Array of address to SFTP servers
string _UserName = "root"; //fake User Name of the SFTP server
string _Password = "310rp3"; // fake Password of the SFTP server
int _Port = 2222; //Port No of the SFTP server (if any)
string _ftpDirectory = "/home/root/systools/WM/WebMobility.db"; //The directory in SFTP server where the files will be uploaded
string LocalDirectory = "F:\\Explor\\final test"; //Local directory from where the files will be uploaded
bool online = false;
foreach(string furl in _ftpURL)
{
Sftp Connection = new Sftp(furl, _UserName, _Password);
try
{
Connection.Connect(_Port);
online = true;
}
catch
{
online = false;
}
if(online == true)
{
Connection.Get(_ftpDirectory, LocalDirectory);
Connection.Close();
break;
}
}
Add these two methods to some class and call public DownloadSftpFile from your desktop code.
// returns true if the file had downloaded
public static bool DownloadSftpFile(string[] hosts, int port, string username, string password, string remotePathAndFile, string localPath)
{
foreach (var host in hosts)
{
try
{
DownloadSftpFile(host, port, username, password, remotePathAndFile, localPath);
return true;
}
catch(SshConnectionException exception)
{
// log
}
catch(SocketExcpetion exception)
{
// log
}
}
return false;
}
private static void DownloadSftpFile(string host, int port, string username, string password, string remotePathAndFile, string localPath)
{
using (var sftp = new Sftp(host, username, password))
{
sftp.Connect(port);
sftp.Get(remotePathAndFile, localPath);
}
}

Error 0x80005000 with LdapConnection and LDAPS

Before I start, I've already visited Unknown Error (0x80005000) with LDAPS Connection and changed my code and while it did solve the problem it seems that it has mysteriously come back.
Here's the good stuff:
public static bool Authenticate(string username, string password, string domain)
{
bool authentic = false;
try
{
LdapConnection con = new LdapConnection(
new LdapDirectoryIdentifier(Host, Port));
if (IsSSL)
{
con.SessionOptions.SecureSocketLayer = true;
con.SessionOptions.VerifyServerCertificate = ServerCallback;
}
con.Credential = new NetworkCredential(username, password);
con.AuthType = AuthType.Basic;
con.Bind();
authentic = true;
}
catch (LdapException)
{
return false;
}
catch (DirectoryServicesCOMException)
{ }
return authentic;
}
public static bool IsSSL
{
get
{
return ConnectionString.ToLower().Contains("ldaps");
}
}
public static string ConnectionString
{
get
{
if (string.IsNullOrEmpty(_connectionString))
_connectionString = CompleteConfiguration.GetLDAPConnectionString();
return _connectionString;
}
set { _connectionString = value; }
}
public static int Port
{
get
{
var x = new Uri(ConnectionString);
int port = 0;
if (x.Port != -1)
{
port = x.Port;
}
else
{
port = x.OriginalString.ToLower().Contains("ldaps")
? 636
: 389;
}
return port;
}
}
public static string Host
{
get
{
var x = new Uri(ConnectionString);
return x.Host;
}
}
private static bool ServerCallback(LdapConnection connection, X509Certificate certificate)
{
return true;
}
Here's the bad stuff:
When I attempt to authenticate to the application I get the following error, to be precise this is triggered by the con.Bind() line:
[COMException (0x80005000): Unknown error (0x80005000)]
System.DirectoryServices.DirectoryEntry.Bind(Boolean throwIfFail) +378094
System.DirectoryServices.DirectoryEntry.Bind() +36
System.DirectoryServices.DirectoryEntry.get_NativeObject() +31
Complete.Authentication.GCAuthentication.Authenticate(String username, String password, String domain) in c:\Builds\6\Idealink.Open.Pancanal\Panama Canal\Sources\Idealink.Open\Complete.Authentication\GCAuthentication.cs:27
Complete.Authentication.AuthenticationFactory.ValidateUserLdap(String username, String password, String domain, Boolean isValid, String usernameWithDomain) in c:\Builds\6\Idealink.Open.Pancanal\Panama Canal\Sources\Idealink.Open\Complete.Authentication\AuthenticationFactory.cs:93
It is quite confusing as it seems that some user accounts work and others don't. However when I place the above code in an isolated test environment it does succeed each and every time regardless of which account I use. When I place it back on the Windows 2008 R2 Server with ASP.NET and IIS it fails as stated above. The failures are consistent though - accounts consistently fail or succeed, from that perspective there is no randomness.
The LDAP Server must be accessed using LDAPS and NOT LDAP which is why we cannot use the DirectoryEntry object - the LDAP server is controlled by a client and therefore cannot be reconfigured or altered in any way. We simply want to capture username/password on a web form and then use BIND on the LDAP server to check credentials.
We are using .NET 3.5 and cannot upgrade at this time so I respectfully ask that if your main suggestion and arguments are to upgrade than please hold off on your contribution.
Thanks, hope you can help
Would something like this work for you..?
const string Domain = "ServerAddress:389";
const string constrParts = #"OU=Users,DC=domain,DC=com";
const string Username = #"karell";
PrincipalContext principalContext = new PrincipalContext(ContextType.Domain, Domain, constrParts);
UserPrincipal userPrincipal = UserPrincipal.FindByIdentity(principalContext, username);
Here is a really good site for great references and examples
DirectoryServices DirectoryEntry
for Connection over SSL you could do something like the following
const int ldapInvalidCredentialsError = 0x31;
const string server = "your_domain.com:636";
const string domain = "your_domain.com";
try
{
using (var ldapSSLConn = new LdapConnection(server))
{
var networkCredential = new NetworkCredential(username, password, domain);
ldapSSLConn.SessionOptions.SecureSocketLayer = true;
ldapSSLConn.AuthType = AuthType.Negotiate;
ldapSSLConn.Bind(networkCredential);
}
// If the bind succeeds, the credentials are valid
return true;
}
catch (LdapException ldapEx)
{
// Invalid credentials a specific error code
if (ldapEx.ErrorCode.Equals(ldapInvalidCredentialsError))
{
return false;
}
throw;
}
MSDN list of Invalid LDAP Error Codes

rename computer programmatically c# .net

I need to rename my computer via .net application.
I have tried this code:
public static bool SetMachineName(string newName)
{
MessageBox.Show(String.Format("Setting Machine Name to '{0}'...", newName));
// Invoke WMI to populate the machine name
using (ManagementObject wmiObject = new ManagementObject(new ManagementPath(String.Format("Win32_ComputerSystem.Name='{0}'",System.Environment.MachineName))))
{
ManagementBaseObject inputArgs = wmiObject.GetMethodParameters("Rename");
inputArgs["Name"] = newName;
// Set the name
ManagementBaseObject outParams = wmiObject.InvokeMethod("Rename",inputArgs,null);
uint ret = (uint)(outParams.Properties["ReturnValue"].Value);
if (ret == 0)
{
//worked
return true;
}
else
{
//didn't work
return false;
}
}
}
but it didn't work.
and i have tried this one:
using System.Runtime.InteropServices;
[DllImport("kernel32.dll")]
static extern bool SetComputerName(string lpComputerName);
public static bool SetMachineName(string newName)
{
bool done = SetComputerName(newName);
if (done)
{
{ MessageBox.Show("Done"); return true; }
}
else
{ MessageBox.Show("Failed"); return false; }
}
but it also didn't work.
I have tried all the ways i have found to change computer name and no one works.....it doesn't change the computer name...
the only way it worked is when i chaged some registry key values , this is the code , is it ok to do so?
public static bool SetMachineName(string newName)
{
RegistryKey key = Registry.LocalMachine;
string activeComputerName = "SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ActiveComputerName";
RegistryKey activeCmpName = key.CreateSubKey(activeComputerName);
activeCmpName.SetValue("ComputerName", newName);
activeCmpName.Close();
string computerName = "SYSTEM\\CurrentControlSet\\Control\\ComputerName\\ComputerName";
RegistryKey cmpName = key.CreateSubKey(computerName);
cmpName.SetValue("ComputerName", newName);
cmpName.Close();
string _hostName = "SYSTEM\\CurrentControlSet\\services\\Tcpip\\Parameters\\";
RegistryKey hostName = key.CreateSubKey(_hostName);
hostName.SetValue("Hostname",newName);
hostName.SetValue("NV Hostname",newName);
hostName.Close();
return true;
}
and after the restart the name changes....
A WMI objects sets the computer name. Then the registry is used to check whether the name was set. Because the System.Environment.MachineName is not updated right away.
And the 'hostname' command in CMD.exe still outputs the old name. So a reboot is still required. But with the registry check can see if the name was set.
Hope this helps.
Boolean SetComputerName(String Name)
{
String RegLocComputerName = #"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName";
try
{
string compPath= "Win32_ComputerSystem.Name='" + System.Environment.MachineName + "'";
using (ManagementObject mo = new ManagementObject(new ManagementPath(compPath)))
{
ManagementBaseObject inputArgs = mo.GetMethodParameters("Rename");
inputArgs["Name"] = Name;
ManagementBaseObject output = mo.InvokeMethod("Rename", inputArgs, null);
uint retValue = (uint)Convert.ChangeType(output.Properties["ReturnValue"].Value, typeof(uint));
if (retValue != 0)
{
throw new Exception("Computer could not be changed due to unknown reason.");
}
}
RegistryKey ComputerName = Registry.LocalMachine.OpenSubKey(RegLocComputerName);
if (ComputerName == null)
{
throw new Exception("Registry location '" + RegLocComputerName + "' is not readable.");
}
if (((String)ComputerName.GetValue("ComputerName")) != Name)
{
throw new Exception("The computer name was set by WMI but was not updated in the registry location: '" + RegLocComputerName + "'");
}
ComputerName.Close();
ComputerName.Dispose();
}
catch (Exception ex)
{
return false;
}
return true;
}
From the MSDN Documentation of SetComputerName..
Sets a new NetBIOS name for the local computer. The name is stored in
the registry and the name change takes effect the next time the user
restarts the computer.
Did you try restarting the computer?
Programmatically renaming a computer using C#
It is a long article and I'm not sure what exactly will be directly relevant so I won't paste a snippet

Categories