Link to home
Start Free TrialLog in
Avatar of basslogik
basslogik

asked on

URG: Creating a folder on a remote machine (WMI, ADSI, FSO etc)

Hi very urgent question.

I have a windows service that needs to create a folder on a remote machine. Then I need to share it and set security permissions on the share.

I am using c# for my win service. I know that setting share permissions and creating a share can be done using WMI. However I have not tried to implement it yet. Any help on this, especially code examples will be much appreciated.

However more urgent is creating a directory. I heard from someone that it can be done using WMI too. The problem is I can't find any examples or any information on this on the net and I spent good few hours if not more. WMI is the ideal solution for me, as I will later be using it for creating the share and iis website etc. One platform for all is good, plus its a preffered one in the company. Any help with code examples on this and you will be my personal God :).

I have options of creating a slave windows service and install it on all the remote servers. However this is ugly and probably the least preferred method. Another option is creating a share on the machine and then using some user account to impersonate in .NET. But I don't want to go that way either. Any other ideas and options will be good. For example can FSO (FileSystemObject) be used over network? Or any other way?

I am new to WMI and pretty new to c#, although i know my way around it pretty well by now (c# that is :)). So any examples on WMI will be great. If not any info, even link will be appreciated!!! It is very urgent for me, as this is holding my project back and I am not meeting the schedule :S.

I will give all the points for a very good answer on creating share. If this is not answered then i will give full points for an answer to the share problem with examples. If there are good answers from several people on any topic, I will fairly split the points...

Thanks in advance,
Max
Avatar of basslogik
basslogik

ASKER

Oh yeah forgot to mention. I looked around and didn't find another suitable section. If you know of any other where it might be better off, I will copy the question there!!!

Thanks ;)
Max
Hmmmm looks like a hrad question :S

I spend more hours researching. I come to conlusion that you cannot create a folder on remote server using WMI. Although there is a Win32_Directory WMI class.

You can also move directories using WMI like this.
strComputer = "."
Set objWMIService = GetObject("winmgmts:" _
    & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
Set colFolders = objWMIService.ExecQuery _
    ("Select * from Win32_Directory where name = 'c:\\Scripts'")
For Each objFolder in colFolders
    errResults = objFolder.Rename("C:\Admins\Documents\Archive\VBScript")
    Wscript.Echo errResults
Next


But I don't see how u can create one... No methods for that. Pretty lame if you aks me... Allow such an extensive management, and assume that system administrators will not want to create a folder??? Its not even a security risk, since if u have proper rights you can do much more damage than creating a folder with other WMI directives.....

I guess the way to go is to impersonate in .NET using some user account. And then have a share with access right to only that user. I will give fullpoints for this kind of answer as well now. Please include code samples if possible.
I am also curious how can I create a username to be used by my application and also to use for permissions on a remote computer. I think there are complicatiomns with different domains etc.... Basically stuff that you can find out in several days, but I don't have this luxury at the moment. I am sure someone has done this kind of thing before (not using WMI, but using a impersonation)...

Please help!

Max
For impersonating you need Windows 2003 and .net Framework 1.1 (I don't know if it works on XP)
Else you could allow the ASPNET user to create the folders (low security). You can also do the impersonating in a service and control it by .net remoting.
Hey thanks for your comment. Do I need Windows 2003 to impersonate? The company I work for will only be EOLing windows2003 end of this year and the project is currently based on Windows 2000.

I considered using ASP.NET user however this is low security, especially in my case. What I am doing is creating a website folder on drive d, where there are other 100+ websites. If I allow ASP.NET user to write to such share, that mean no security whatsoever. (espcially as we do not want other developers to access the server. All applications are written in .net, meaning that anyone with their head screwed on and some time can easily gain access to drive d.)

If you could, please expand your though on your last point about impersonating in a service, as I don't quite understand what u meant.

Thanks,
Max
Windows 2003 has this whole stuff built in. I don't know if may be windows authentication could allow you to impersonate under Windows 2000. But there also seem to be problems: http://support.microsoft.com/?id=824308 
http://support.microsoft.com/default.aspx?kbid=317012&product=aspnet
In a service running under SYSTEM or Administrator account you can use the Win32 API to impersonate the current thread.
ASKER CERTIFIED SOLUTION
Avatar of tgannetts
tgannetts

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Sorry just came back, didn't have access to the net. Will try it now..
Hi,
Thanks a lot for your code, looks like just what I need. I mamanged to get it running on my machine no problem, I just had to remove the connection object. However when I am trying to make it work on the remote Windows 2000 machine, I get an exception and it sais "Access Denied". I am using my administrators account, which I am able to use on many servers since in the admin group. I can log in to the machine with full rights with that account. However using those credentials I cannot use the code. Should I specificly add this account to some group that enabled me to use WMI? O rmay be WMI uses some other credentials. I am trying to find something out at the moment. But if you have any ideas or know what might be wrong, could you please post it here :)

Thanks,
Max
Haha sorry my fault,
I read through MSDN about the connection object. I had to specify the domain as well as username i.e.
I was using "username"
And it had to be "domain\username"

All works now! Amazing thank you so much, you might just have made my project meet the timeline :D

I will award the points right now.


Max
One more thing. I would really apreciate if you could give a code example of how I can check if the directory exists using WMI (on that remote server). This is so that I don't have to create the directory if it is already there.

I would suggest the best thing to do to check if the folder exists is to try and reference it first through a WMI call. If the directory is not found, a ManagementException will be thrown with the message 'Not Found' when you try and access the class properties.

Something like:

try
{
     // Check to see if folder already exists
     using (ManagementObject dir = new ManagementObject (oMs, new ManagementPath(String.Format(MachineName + @"\root\cimv2:Win32_Directory.Name='{0}'",NewDirectoryName.Replace(@"\", @"\\") )), null))
{
         //Attempt to access a property
         String dirTest = dir.Properties["Name"].ToString()
}
}
catch (Exception ex)
{
        if(ex.Message="Not Found")
        {
         
             // Directory not found so create

        }
}

This should solve your problem.

Tom
Great thanks :)
As far as I remember in WMI you don't call methods like Create() to create instances of an classes like WIN32_Directory but you instantiate them with some method I can't remember.
Well thanks, but could you please clarify how to do it and the reasoning behind it?
It works for me, and I don't want to modify my code unless I know why. :)
This is another solution I used to create a directory on a remote server using WMI.

Basically, I've created a simple batch or command file (createfolder.cmd in this example) on the remote server that has just this single line in it:

mkdir %1

Then used WMI to create a process on the remote server to call that cmd file. The reason being, you can't call "mkdir" directly using Win32_Process since it expects a proper path to file.

My WMI code for calling the cmd file goes something like so:

string remoteDir = "newfolder";
ManagementPath myPath = new ManagementPath();
myPath.NamespacePath = @"root\CIMV2";
ManagementScope scope = new ManagementScope(myPath, oConn);
ObjectQuery oq = new ObjectQuery("select Name from Win32_Directory where Name = '" + remoteDir + "'");
using (ManagementObjectSearcher os = new ManagementObjectSearcher(scope, oq))
{
      if (os.Get().Count == 0)      //It don't exist, so create it!
      {
            ManagementPath path2 = new ManagementPath();
            path2.Server = "ServerName";
            path2.ClassName = "Win32_Process";
            path2.NamespacePath = @"root\CIMV2";
            ManagementScope scopeProcess = new ManagementScope(path2, oConn);

            using (ManagementClass process = new ManagementClass(scopeProcess, path2, null))
            {
                  string commandLine = "C:\\createfolder.cmd \"" + remoteDir + "\"";

                  ManagementBaseObject inParams = null;
                  inParams = process.GetMethodParameters("Create");
                  inParams["CommandLine"] = commandLine;
                  inParams["CurrentDirectory"] = null;
                  inParams["ProcessStartupInformation"] = null;
                  ManagementBaseObject outParams = process.InvokeMethod("Create", inParams, null);
                  int retVal = Convert.ToInt32(outParams.Properties["ReturnValue"].Value);

                  inParams.Dispose();
                  outParams.Dispose();
            }
      }
}

After this u can use the searcher again to determine if it the folder was created:

//Now query again to see if it's created
using (ManagementObjectSearcher os = new ManagementObjectSearcher(scope, oq))
{
      if (os.Get().Count == 0)
            throw new Exception("Cannot create directory at \"" + remoteDir + "\" on ServerName");
}


Nguyen
Sorry, just a further clarification to my example above..

The variable "remoteDir" needs a full path,
so instead of:

string remoteDir = "newfolder";

It should be:

string remoteDir = @"C:\newfolder";


And the line:
ObjectQuery oq = new ObjectQuery("select Name from Win32_Directory where Name = '" + remoteDir + "'");

should be:
ObjectQuery oq = new ObjectQuery("select Name from Win32_Directory where Name = '" + remoteDir.Replace(@"\", @"\\") + "'");

Well thanks for your solution :) I have already finished the project, but I can see where I can could use your code.
Hello
May be it's irrelevant, but I've found an easy way to create directories on remote machine just using the
"cmd" (command line) without creating batch files or enything else.
Here is a code, may be it'll be helpful for anybody.


       public bool CreateDirectory(string remoteDir, string MachineName, string UserName, string Password)
        {
            string TempName = remoteDir;
            int Index = TempName.IndexOf(":");
            string DriveLetter = "C";
            if (Index != -1)
            {
                string[] arr = TempName.Split(new char[] { ':' });
                DriveLetter = arr[0];
                TempName = TempName.Substring(Index + 2);
            }
            ManagementPath myPath = new ManagementPath();
            myPath.NamespacePath = @"root\CIMV2";
 
            ConnectionOptions oConn = new ConnectionOptions();
            oConn.Username = UserName;
            oConn.Password = Password;
            oConn.EnablePrivileges = true;
            myPath.Server = MachineName;
 
            ManagementScope scope = new ManagementScope(myPath, oConn);
            scope.Connect();
            //without next strange manipulation, the os.Get().Count will throw the "Invalid query" exception
            remoteDir = remoteDir.Replace("\\", "\\\\");
            ObjectQuery oq = new ObjectQuery("select Name from Win32_Directory where Name = '" + remoteDir + "'");
            using (ManagementObjectSearcher os = new ManagementObjectSearcher(scope, oq))
            {
                if (os.Get().Count == 0)      //It don't exist, so create it!
                {
                    ManagementPath path2 = new ManagementPath();
                    path2.Server = MachineName;
                    path2.ClassName = "Win32_Process";
                    path2.NamespacePath = @"root\CIMV2";
                    ManagementScope scopeProcess = new ManagementScope(path2, oConn);
 
                    using (ManagementClass process = new ManagementClass(scopeProcess, path2, null))
                    {
                        string commandLine = String.Format(@"cmd /C  mkdir {0} ", TempName);
                        using (ManagementBaseObject inParams = process.GetMethodParameters("Create"))
                        {
                            inParams["CommandLine"] = commandLine;
                            inParams["CurrentDirectory"] = DriveLetter + @":\\";
                            inParams["ProcessStartupInformation"] = null;
                            using (ManagementBaseObject outParams = process.InvokeMethod("Create", inParams, null))
                            {
                                int retVal = Convert.ToInt32(outParams.Properties["ReturnValue"].Value);
                                return (retVal == 0);
                            }
                        }
                    }
                }
                else
                    return true;//if exists, return true; you may want to return false, of course
            }
            return false;
        }
    }

Open in new window