How to share remote folders? - c#

I'm working on a .NET class that will be used in tools to manage our Active Directory accounts. Each of our accounts gets a network home directory, which can be located on a couple different servers, depending on what type of account we're working with.
I can create and delete the folders just fine, but I'm running into trouble sharing the folders. I found some code here that seems to be what I want, but it isn't working properly for me. The return value I get is 2, but I'm not sure what that indicates.
This shouldn't be a file permission issue, since I'm running my test application as myself, and I have full control of the folder that I'm trying to share (and each of its parent folders).
Here's my (modified) version of the code:
char[] delim = { '\\' };
// folderPath is a string (UNC path)
string[] drivePath = folderPath.Split(delim);
// Create a ManagementClass object
ManagementClass managementClass = new ManagementClass("Win32_Share");
// Create ManagementBaseObjects for in and out parameters
ManagementBaseObject inParams =
managementClass.GetMethodParameters("Create");
ManagementBaseObject outParams;
// Set the input parameters
inParams["Description"] = "";
inParams["Name"] = drivePath[3];
inParams["Path"] = folderPath;
inParams["Type"] = 0x0; // Disk Drive
// Invoke the method on the ManagementClass object
outParams = managementClass.InvokeMethod("Create", inParams, null);
I've tried outputting the other outParams, but it looks like ReturnValue is all I get.
Is there a different way to share a remote folder that would work better?

I'll answer myself, in case someone else finds this later.
I ended up going with the extremely unsexy answer of using PSExec and NET SHARE:
// Retrieve drive path from AD
char[] delim = { '\\' };
string[] drivePath = userAD.HomeDirectory.Split(delim);
// Configure startup properties of process
ProcessStartInfo startInfo = new ProcessStartInfo();
startInfo.CreateNoWindow = true;
startInfo.FileName = "C:\\Windows\\System32\\psexec.exe";
// Build arguments for folder on alpha or student
startInfo.Arguments = "\\\\" + serverName + " -s net share " + shareName + "=" folderPath + "$ /GRANT:\"authenticated users\",full";
Process process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit();
Note that in our environment the program will already be running under a user who has Full Control permissions on the folder being shared. To allow similar for a non-privileged user, you have to specify a name and password in startInfo.Arguments.

Related

How to call a console app as a different user, using a Windows service being run under Local System?

I am basically trying to create and run a Windows Service on a server. This service has mainly 2 jobs,
To log a timestamp to a file on a UNC (different Server path) so as to check access
Call a simple console app using a different user
Now, I have created the windows service, but it won't log in the Server path as it is started via Local system. So I tried to deploy it using a user account with access to the Server Path and it logged, but then the whole point is to us the local system.
So now, i changed the requirement a little bit, Now is it possible to deploy the service as Local System only , but instead of directly logging on the server path, i would rather make the console app do the logging. But how should I make the console app run as a different user account.
This is the code I am using for calling the console app via a different user (mind you the service is run under LocalSystem), and it is either giving the error, "Cannot find the file specified" or "Invalid Directory Name" but i assure you both the things exist. I even used the paths fed in the startInfo by debugging to check.
public static void InitiateCommandProcess()
{
Process process = new Process();
SecureString ssPwd = new SecureString();
string fileName = ConfigurationManager.AppSettings["FileName"];
string workingDirectory = ConfigurationManager.AppSettings["ApplicationDirectory"];
string param = ConfigurationManager.AppSettings["PARAM"];
string userName = "myUserName";
string password = "MyPassWord";
for (int x = 0; x < password.Length; x++)
{
ssPwd.AppendChar(password[x]);
}
ProcessStartInfo startInfo = new ProcessStartInfo
{
UseShellExecute = false,
WindowStyle = ProcessWindowStyle.Hidden,
CreateNoWindow = true,
ErrorDialog = false,
FileName = #"" + fileName,
WorkingDirectory = #"" + workingDirectory,
Arguments = #"" + param,
RedirectStandardOutput = true,
RedirectStandardError = true,
RedirectStandardInput = true,
Domain = "EMEA",
UserName = userName,
Password = ssPwd
};
process.StartInfo = startInfo;
try
{
Logger.Log($"Working in Directory Path : {workingDirectory} );");
Logger.Log($" Username : {userName} and Executing : {fileName}");
process.Start();
Logger.Log($"Process \"{ConfigurationManager.AppSettings["FileName"]}\" Executed at {DateTime.Now}");
}
catch (Exception ex)
{
Logger.Log($"Error occured in command process execution, Message : {ex.Message}", true);
}
}
The server path is like this, "\dfs\folder\folder..."
I am a little new to this so please bear with me.

An unhandled exception of type 'System.ComponentModel.Win32Exception' occurred in mscorlib.dll

I have an application with WF control hosted in WPF window and i'm proceesing some record and playback actions in my project. I get the below exception while performing play back.
The system cannot find the file specified
I have searched regarding this and seen some suggestions that we need to provide the full path of the file to process.I have tried this also, but still i'm getting this exception.
Please anyone let me know how to resolve this?
var instance = testclass.GetControlForTest();
WindowsFormsHost host = new WindowsFormsHost();
host.Child = instance;
var testwindow = new TestWindow(testdata, testclass, false, (MainWindow)Application.Current.MainWindow, true);
testwindow.testSurface.Children.Add(host);
testwindow.Show();
await Task.Delay(1000);
Process p = new Process();
var mainPath = Directory.GetCurrentDirectory();
do
{
mainPath = Directory.GetParent(mainPath).FullName;
} while (Directory.GetParent(mainPath).Name != "WindowsForms_Testing");
var targetPath = mainPath + "\\exes\\" + "\\";
mainPath = Directory.GetParent(mainPath).FullName;
mainPath = mainPath + "\\TestStudio\\Syncfusion.TestVisualBase.WPF\\RecordAction\\RecordAction.WPF\\bin\\Debug\\RecordAction.WPF.exe";
p.StartInfo.FileName = mainPath.Replace("\\", "/");
p.StartInfo.Arguments = file; //("..//..//test.xml")
p.Start();
Thanks,
You shouldn't replace backslashes p.StartInfo.FileName = mainPath.Replace("\\", "/");, because windows use \ for pathes
You definre variable var targetPath ut do not use it in the future.
If you want put path in variable you might use # for escaping cpecial-symbols, e.g. mainPath = mainPath + #"\TestStudio\Syncfusion.TestVisualBase.WPF\RecordAction\RecordAction.WPF\bin\Debug\RecordAction.WPF.exe";
For concatinate pathes you may use Path.Combine() method
Path for property p.StartInfo.FileName must starts from disc name e.g. C:\, or dot/s e.g. .\your_path or ..\parent_directory\your_path or starts from file or folder directly, relative current directory Directory.GetCurrentDirectory();

Programmatically get the full path of a shared folder on another computer?

I know that you can get the path to a mapped drive (e.g. Find UNC path of a network drive?), but what if the only thing I have is just the path to the shared folder?
For example, let's say I have a friend who is sharing the folder C:\MyDocs\PublicDoc over the network. I can access it under the path \\danas-pc\PublicDoc. Is there any way that I could, being on another computer, determine that \\danas-pc\PublicDoc actually maps to \\danas-pc\c$\MyDocs\PublicDoc?
I ask because I am given a path to a log file that has the path (e.g. \danas-pc\c$\MyDocs\PublicDoc\mylog.log )and I need to check if it matches the same path that is set in another location. The other location has the "short path" (e.g. \\danas-pc\PublicDoc\mylog.log ), and thus, even though the log paths lead to the same location, the program determines that they are different. I wanted to see if there's a way to figure out that they are pointing to the same location.
I can't imagine why you might need this since for the remote instance's full path is \danas-pc\PublicDoc but if you let your imagination thrive I'd suggest something like this:
(1) on the remote computer inside the share folder you can drop a small script that if executed return the full path. You have to search for appropriate coding for windows or linux environment also you need to have execution privilege or rights on it. for example on windows you can have a vbscrit or cscript and a .sh script in linux.
Also please note that seeing it from the remote host, in terms of the remote host the full path is \NAME-OR-IP\Path\to\Folder\or\File etc. For you on the remote connection that is the full path ;)
UPDATE:
as per the comment below, this is a full script that does the following
creates a vbscript with code in it to retrieve the current full path
copies the files into the network desired path
executes the vbscript and reads the result back
deletes the vbscript
Assuming: you have the read/write access on the network folder
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Mime;
using System.Runtime.CompilerServices;
using System.Text;
using System.Threading.Tasks;
namespace GetNetworkFullPath
{
class Program
{
static void Main(string[] args)
{
var networkFolder = "\\\\REMOTE-PC-NAME\\SharedFolder";
var nameOfVBScript = "capturepath.vbs";
var vbsOutput = "";
//Get the name of the current directory
var currentDirectory = Directory.GetCurrentDirectory();
Console.WriteLine("Current Dir: " + currentDirectory);
//1. CREATE A VBSCRIPT TO OUTPUT THE PATH WHERE IT IS PRESENT
//Ref. https://stackoverflow.com/questions/2129327/how-to-get-the-fully-qualified-path-for-a-file-in-vbscript
var vbscriptToExecute = "Dim folderName \n" +
"folderName = \"\" \n" +
"Dim fso \n" +
"Set fso = CreateObject(\"Scripting.FileSystemObject\") \n" +
"Dim fullpath \n" +
"fullpath = fso.GetAbsolutePathName(folderName) \n" +
"WScript.Echo fullpath \n";
//Write that script into a file into the current directory
System.IO.File.WriteAllText(#""+ nameOfVBScript + "", vbscriptToExecute);
//2. COPY THE CREATED SCRIPT INTO THE NETWORK PATH
//Ref. https://learn.microsoft.com/en-us/dotnet/csharp/programming-guide/file-system/how-to-copy-delete-and-move-files-and-folders
string sourceFile = System.IO.Path.Combine(currentDirectory, nameOfVBScript);
string destFile = System.IO.Path.Combine(networkFolder, nameOfVBScript);
System.IO.File.Copy(sourceFile, destFile, true);
//3. EXECUTE THAT SCRIPT AND READ THE OUTPUT
//Ref. https://stackoverflow.com/questions/27050195/how-do-i-get-the-output-from-my-vbscript-console-using-c
Process scriptProc = new Process();
ProcessStartInfo info = new ProcessStartInfo();
info.WorkingDirectory = #"" + networkFolder + "";
info.FileName = "Cscript.exe";
info.Arguments = nameOfVBScript;
info.RedirectStandardError = true;
info.RedirectStandardInput = true;
info.RedirectStandardOutput = true;
info.UseShellExecute = false;
info.WindowStyle = ProcessWindowStyle.Hidden;
scriptProc.StartInfo = info;
scriptProc.Start();
scriptProc.WaitForExit();
bool exit = false;
while (!scriptProc.StandardOutput.EndOfStream)
{
vbsOutput = scriptProc.StandardOutput.ReadLine();
}
Console.WriteLine("vbscript says: " + vbsOutput);
//4. DELETE THE FILE YOU JUST COPIED THERE
System.IO.File.Delete(#"" + networkFolder + "\\" + nameOfVBScript);
}
}
}
Unfortunately when executed remotely the script replies with the Network Path :( so disappointed...really sorry! As long as execution is happening from a user outside the remote system it will reply with the absolute path related to that instance. I think an internal process/user should execute the file and reply back with the answer to the application.
I'll try to think something more tomorrow and maybe reply back if I'm lucky.

Web service that creates text file tries to create it on system making rest call, not locally as desired

I have a very simple C# web service written to handle offline domain joins for Windows builds. Part of the offline domain join provision process is the creation of a .txt file that is then retrieved later in the process. I have this web service dropping the .txt file in a folder that is locally on the web server which is a UNC share. For some reason when I make a rest call to this service passing the parameter, the service tries to put the .txt file on my local machine in that directory, which doesn't exist so it errors out. Why is it trying to put it on the machine of the box making the rest call, rather than locally? Here is the pertinent code:
public string ODJComputerName(string computername)
{
ProcessStartInfo startInfo;
Process process;
string path = Server.MapPath(".");
string share = Server.MapPath("~");
startInfo = new ProcessStartInfo(path + #"\djoin.exe");
startInfo.WorkingDirectory = share + #"\ODJ_files\";
startInfo.UseShellExecute = true;
startInfo.CreateNoWindow = true;
string outFile = startInfo.WorkingDirectory + computername + ".txt";
startInfo.Arguments = "/provision /domain mydomain.com /machine " + computername + " /reuse /savefile " + outFile;
process = new Process();
process.StartInfo = startInfo;
process.Start();
process.WaitForExit(60000);

Could not find a part of the path :While copying file on Mapped drive using Windows Service

I have a Windows Service which goes and update some files on the Network which is mapped as drive "Z:\". When i run the code from VS as administrator I am able to copy the file on the mapped drive but same thing fails when it is run from the Service which is running under administrator account.
The Mapped drive is created from same account under which service is running. Bit puzzling why its working when run from the VS but not from service.
Is it better to use UNC than network drive.
There is a workaround at below forum
http://support.microsoft.com/default.aspx?scid=kb;en-us;827421#appliesto
but it has used UNC not mapped drive.
We experienced this as well, and while I can't tell you WHY our resolution worked, i can tell you WHAT worked.
Map the drive in the code. Don't rely on the drive being mapped just because you're using the same account.
Based on the behavior we saw, this is what i would GUESS was happening in our situation and what's happening in yours.
The service we had issues with used a drive that was mapped in a login script. If we had the machine logged in as the same user the service was using, it worked, but if not it wouldn't work. Based on that, I surmised that the drive simply isn't mapped because the service doesn't really "log on".
Mapping the drive in code fixed it.
As a side note, you can also reference the UNC path directly, but we had permissions issues with that as well. Mapping the drive, passing in a username and password worked much better for us.
Our code for doing this:
public static class NetworkDrives
{
public static bool MapDrive(string DriveLetter, string Path, string Username, string Password)
{
bool ReturnValue = false;
if(System.IO.Directory.Exists(DriveLetter + ":\\"))
{
DisconnectDrive(DriveLetter);
}
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": " + '"' + Path + '"' + " " + Password + " /user:" + Username;
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
public static bool DisconnectDrive(string DriveLetter)
{
bool ReturnValue = false;
System.Diagnostics.Process p = new System.Diagnostics.Process();
p.StartInfo.UseShellExecute = false;
p.StartInfo.CreateNoWindow = true;
p.StartInfo.RedirectStandardError = true;
p.StartInfo.RedirectStandardOutput = true;
p.StartInfo.FileName = "net.exe";
p.StartInfo.Arguments = " use " + DriveLetter + ": /DELETE";
p.Start();
p.WaitForExit();
string ErrorMessage = p.StandardError.ReadToEnd();
string OuputMessage = p.StandardOutput.ReadToEnd();
if (ErrorMessage.Length > 0)
{
throw new Exception("Error:" + ErrorMessage);
}
else
{
ReturnValue = true;
}
return ReturnValue;
}
}
Using the above class, you can map and disconnect the drive at will. If this is a service, I would recommend mapping the drive just before you need it and disconnecting the drive immediately after you need it.
I would suggest UNC is a better idea.
What if the mapped drive is mapped on login? A service may run without a user even logging in so the mapping might never be created.
I struggled a lot (~3 days) to solve the same issue. Seems it is more related to NTFS and file level permissions. It is better if you use shared location rather than a drive.

Categories

Resources