Solved

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

Posted on 2004-04-14
18
9,725 Views
Last Modified: 2010-05-18
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
0
Comment
Question by:basslogik
  • 10
  • 2
  • 2
  • +3
18 Comments
 

Author Comment

by:basslogik
ID: 10829153
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
0
 

Author Comment

by:basslogik
ID: 10834433
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
0
 
LVL 10

Expert Comment

by:ptmcomp
ID: 10836894
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.
0
 

Author Comment

by:basslogik
ID: 10837052
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
0
 
LVL 10

Expert Comment

by:ptmcomp
ID: 10840016
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.
0
 
LVL 5

Accepted Solution

by:
tgannetts earned 500 total points
ID: 10842256
I think I have come up with a possible workaround using the CopyEx method of the Win32_Directory, although its a bit messy.

As you say you can move a folder using Rename, but you can also copy a Directory and its contents using the Copy method. The CopyEx method with the correctly set parameters will ignore child folders and only copy the child files for the specified folder. If you pick a folder that usually contains no immediate files then you will be able to create an empty directory in the required location. In the example below, I used the Inetpub folder. (Tested on Windows 2000)

using System.Management;

...

//Connection credentials to the remote computer
ConnectionOptions oConn = new ConnectionOptions();
oConn.Username = "someusername";
oConn.Password = "somepassword";
oConn.EnablePrivileges = true;

//Set Machine Name and Directory Location
string MachineName = @"\\somemachinename";
string DirectoryName = @"c:\Inetpub";

//Set Arguments for WMI Method Invocation
object[] MethodArgs = {@"c:\Test", "", "", false};
      
//Set scope for WMI call
ManagementScope oMs = new System.Management.ManagementScope(MachineName, oConn);    

// Get Directory to be copied - will throw exception if cannot be found
using (ManagementObject dir = new ManagementObject (oMs, new ManagementPath(String.Format(MachineName + @"\root\cimv2:Win32_Directory.Name='{0}'",DirectoryName.Replace(@"\", @"\\") )), null))
{
         //Invoke CopyEx Method
         dir.InvokeMethod("CopyEx", MethodArgs);
}

Once you have created the folder, you can then use the Create method of the Win32_Share WMI Class to set share settings. (Although this is a lot more complicated)

Hope this is of some help.
0
 

Author Comment

by:basslogik
ID: 10849443
Sorry just came back, didn't have access to the net. Will try it now..
0
 

Author Comment

by:basslogik
ID: 10851173
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
0
 

Author Comment

by:basslogik
ID: 10851197
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
0
What Security Threats Are You Missing?

Enhance your security with threat intelligence from the web. Get trending threat insights on hackers, exploits, and suspicious IP addresses delivered to your inbox with our free Cyber Daily.

 

Author Comment

by:basslogik
ID: 10851423
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.

0
 
LVL 5

Expert Comment

by:tgannetts
ID: 10854821
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
0
 

Author Comment

by:basslogik
ID: 10855485
Great thanks :)
0
 
LVL 1

Expert Comment

by:foobar43
ID: 11012592
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.
0
 

Author Comment

by:basslogik
ID: 11012908
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. :)
0
 

Expert Comment

by:lyphtec
ID: 11124021
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
0
 

Expert Comment

by:lyphtec
ID: 11124043
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(@"\", @"\\") + "'");

0
 

Author Comment

by:basslogik
ID: 11124647
Well thanks for your solution :) I have already finished the project, but I can see where I can could use your code.
0
 

Expert Comment

by:eddy25
ID: 23585249
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

0

Featured Post

Enabling OSINT in Activity Based Intelligence

Activity based intelligence (ABI) requires access to all available sources of data. Recorded Future allows analysts to observe structured data on the open, deep, and dark web.

Join & Write a Comment

Suggested Solutions

Article by: Ivo
C# And Nullable Types Since 2.0 C# has Nullable(T) Generic Structure. The idea behind is to allow value type objects to have null values just like reference types have. This concerns scenarios where not all data sources have values (like a databa…
We all know that functional code is the leg that any good program stands on when it comes right down to it, however, if your program lacks a good user interface your product may not have the appeal needed to keep your customers happy. This issue can…
This video shows how to remove a single email address from the Outlook 2010 Auto Suggestion memory. NOTE: For Outlook 2016 and 2013 perform the exact same steps. Open a new email: Click the New email button in Outlook. Start typing the address: …
This video demonstrates how to create an example email signature rule for a department in a company using CodeTwo Exchange Rules. The signature will be inserted beneath users' latest emails in conversations and will be displayed in users' Sent Items…

760 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question

Need Help in Real-Time?

Connect with top rated Experts

26 Experts available now in Live!

Get 1:1 Help Now