NOTE: Please don't disregard based on the title being similar to others.
I'm trying to share a folder on a Windows 7 machine. And I want to give everyone full permissions to it via C#.
I've seen several articles on other pages including here, that tell how to do it. But like some others, it doesn’t work for me. Below is a snippet taken from SO.
DirectorySecurity sec = Directory.GetAccessControl(path);
// Using this instead of the "Everyone" string means we work on non-English systems.
SecurityIdentifier everyone = new SecurityIdentifier(WellKnownSidType.WorldSid, null);
sec.AddAccessRule(new FileSystemAccessRule(everyone, FileSystemRights.FullControl | FileSystemRights.Synchronize, InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit, PropagationFlags.None, AccessControlType.Allow));
Directory.SetAccessControl(path, sec);
Sharing the folder is already done before I invoke the code above. The below images are the results of what i get:
So far, so good. But on the next image you'll see that the the two remaining checkboxs are still unchecked.
What am I missing please?
Thanks!
EDIT: Below is the code used to do the actual sharing.
private static void QshareFolder(string FolderPath, string ShareName, string Description)
{
try
{
ManagementClass managementClass = new ManagementClass("Win32_Share");
ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
ManagementBaseObject outParams;
inParams["Description"] = Description;
inParams["Name"] = ShareName;
inParams["Path"] = FolderPath;
inParams["MaximumAllowed"] = null;
inParams["Password"] = null;
inParams["Access"] = null;
inParams["Type"] = 0x0; // Disk Drive
// Invoke the method on the ManagementClass object
outParams = managementClass.InvokeMethod("Create", inParams, null);
// Check to see if the method invocation was successful
if ((uint) (outParams.Properties["ReturnValue"].Value) != 0)
{
throw new Exception("Unable to share directory.");
}
}
catch (Exception ex)
{
MessageBox.Show(ex.Message, "error!");
}
}
Permissions on share and underlying folder are separate - your code set ACL on files/folders... So you are missing portion of setting ACL on network share itself.
One gets minimum between permissions on file and share when finally accessing file via share.
I don't know how to set ACL on share but here is a related C++ question that may be good staring point on how to set permissions on shares: How to create read-only network share programmatically?.
Actually I had the opposite problem of yours and your first code snippets solved it for me... Your implementation is just missing a SecurityDescriptor.
private static ManagementObject GetSecurityDescriptor()
{
ManagementObject Trustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);
Trustee["SID"] = GetWellKnwonSid(WellKnownSidType.WorldSid);
Trustee["Name"] = "Everyone";
ManagementObject userACE = new ManagementClass(new ManagementPath("Win32_Ace"), null);
userACE["AccessMask"] = 2032127;//Full access
userACE["AceFlags"] = AceFlags.ObjectInherit | AceFlags.ContainerInherit;
userACE["AceType"] = AceType.AccessAllowed;
userACE["Trustee"] = Trustee;
ManagementObject secDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);
secDescriptor["ControlFlags"] = 4; //SE_DACL_PRESENT
secDescriptor["DACL"] = new object[] { userACE };
secDescriptor["Group"] = Trustee;
return secDescriptor;
}
private static byte[] GetWellKnwonSid(WellKnownSidType SidType)
{
SecurityIdentifier Result = new SecurityIdentifier(SidType, null);
byte[] sidArray = new byte[Result.BinaryLength];
Result.GetBinaryForm(sidArray, 0);
return sidArray;
}
This you'd have to assign to the Access property the Win32_Share instance
Related
Quick question if anyone happens to know. I'm working on a Worker app in dotnet6 that is intended to be made into a service and I need to store a json file somewhere. Doing some research it seems like CommonApplicationData(ex: "C:/ProgramData") is the place to go. My question is, I can't seem to write a file to that folder. I am able to create a directory just fine. But my access is denied to creating an actual file.
This service will be used on servers in the field right now and cannot answer UAC prompts. I'm unsure what else to do. I can have the file created manually and access, edit it. That seems to work fine. But I'd like to have a logs files dynamically created and more.
Heres the code("its pretty basic")
var dirPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.CommonApplicationData), "MyServerService");
var path = dirPath + "\\service.json";
var doesDirExist = Directory.Exists(dirPath);
var doesFileExist = File.Exists(path);
if (!doesDirExist || !doesFileExist)
{
Directory.CreateDirectory(dirPath); //<- directory is created just fine
using var file = File.Create(dirPath); // <- fails here (access is denied)
//do stuff
}
This bit of code worked for me. It was indeed a permission issue with the directory being created.
public static bool CreateDirWithAccess(string fullPath, bool readOnly)
{
var dInfo = Directory.CreateDirectory(fullPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule(new SecurityIdentifier(WellKnownSidType.WorldSid, null), readOnly ? FileSystemRights.Read : FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.NoPropagateInherit, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
return true;
}
I am detecting whether or not I'm attempting a connection against localhost, and creating (or not) the WMI connection options as follows:
if (NetworkUtils.IsLocalIpAddress(machineName))
{
_scope = new ManagementScope(string.Format(#"\\{0}\root\cimv2", machineName));
}
else
{
_connectionOptions = new ConnectionOptions
{
Username = username,
Password = password,
Impersonation = ImpersonationLevel.Impersonate
};
_scope = new ManagementScope(string.Format(#"\\{0}\root\cimv2", machineName), _connectionOptions);
}
When I call _scope.Connect() in either case, it works. That is, no exception and IsConnected is true.
However, when I attempt to invoke a method in the local case, such as Win32_Share.Create I get errors. The following code always works for remote connections for me:
var winSharePath = new ManagementPath("Win32_Share");
var winShareClass = new ManagementClass(_scope, winSharePath, null);
var shareParams = winShareClass.GetMethodParameters("Create");
shareParams["Path"] = pathName.TrimEnd('\\');
shareParams["Name"] = shareName;
shareParams["Type"] = 0;
shareParams["Description"] = "CMC Bootstrap Share";
var outParams = winShareClass.InvokeMethod("Create", shareParams, null);
if ((uint) (outParams.Properties["ReturnValue"].Value) != 0)
{
throw new Exception("Unable to share directory. Error code: " +
outParams.Properties["ReturnValue"].Value);
}
I create the pathName directory just prior to invoking this method, so I guarantee pathName exists in all cases.
When executing locally ONLY on Windows Server 2008 & 2012, the above code throws the exception with error code 24. Executing against localhost on Windows 8 works just fine.
What is the correct way to specify "blank credentials" when invoking WMI methods against localhost, as I believe this is the underlying issue?
I tried the code below on my local PC and this works (shares my temp folder). Could you try the same please? Also, which is the patch & share name you're using?
string pathName = #"c:\temp\";
string shareName = "tempFolder";
var scope = new ManagementScope(string.Format(#"\\{0}\root\cimv2", "localhost"));
// your code below
var winSharePath = new ManagementPath("Win32_Share");
var winShareClass = new ManagementClass(scope, winSharePath, null);
var shareParams = winShareClass.GetMethodParameters("Create");
shareParams["Path"] = pathName.TrimEnd('\\');
shareParams["Name"] = shareName;
shareParams["Type"] = 0;
shareParams["Description"] = "CMC Bootstrap Share";
var outParams = winShareClass.InvokeMethod("Create", shareParams, null);
if ((uint)(outParams.Properties["ReturnValue"].Value) != 0)
{
throw new Exception("Unable to share directory. Error code: " +
outParams.Properties["ReturnValue"].Value);
}
the above code throws the exception with error code 24
That doesn't have anything to do with the error you mention in the title of your question. Error codes for Win32_Share.Create method are documented in this MSDN article. Return value 24 means "Unknown Device or Directory".
In other words, your pathName variable is wrong.
I'm creating a method to create Active Directory sites. It works fine to create a site, add subnets, create site link, etc... But I can't find a way to add a subnet description.
When I create the subnet I do:
var contextType = new DirectoryContext(DirectoryContextType.Forest, "forest", "user","Password"]);
var site = System.DirectoryServices.ActiveDirectory.ActiveDirectorySite.FindByName(contextType, SiteCode);
foreach (string sn in Subnet)
{
try
{
var subnet = new ActiveDirectorySubnet(contextType, sn, SiteCode);
subnet.Location = Location;
subnet.Save();
}
catch (Exception ex)
{
...
}
}
It adds the subnets in the list to the site, but I can't find a way to add the description.
The ActiveDirectorySubnet Class doesn't seem to have any property for the description, but it is there in the "Active Directory Sites and Services" UI...
Does anyone know where to save this information?
It's a PowerShell but should be easy to translate to C# (this link might be useful http://support.microsoft.com/kb/315716)
$object = [adsi]'LDAP://CN=192.0.2.0\/24,CN=Subnets,CN=Sites,CN=Configuration,DC=example,DC=com'
$object.description = "Test-net"
$object.CommitChanges()
;-p
Impove it. Just play a bit with string
You can use it :
SetSubnetDescription("LDAP://CN=10.197.6.128\/25,CN=Subnets,CN=Sites,CN=Configuration,DC=test,DC=domain");
public static bool SetSubnetDescription(string Subnet)
{
try
{
DirectoryEntry ent = new DirectoryEntry(Subnet);
Object ads = ent.NativeObject;
Type type = ads.GetType();
type.InvokeMember("Description",
BindingFlags.SetProperty,
null,
ads,
new object[] {"your new description"});
// The changes to the object must always be committed or else they
// will be lost.
ent.CommitChanges();
return true;
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
return false;
}
I need to share a folder programmatically in VS2010 using C# on a machine running windows8. there were many solutions on the net out of which i used the one described used Managementclass. It didnt work on my machine. I think for windows 8 the process might be little bit different. I'm trying to figure out whats the problem in my code, till then if I cud get some help, much time will be saved. The code returns an access denied error. Please Help!!!
This is the code I'm using:
ManagementClass managementClass = new ManagementClass("Win32_Share");
ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
ManagementBaseObject outParams;
inParams["Description"] = "Dump";
inParams["Name"] = "Dump";
inParams["Path"] = "D:\\Dump";
inParams["Type"] = 0x0; // Disk Drive
DirectoryInfo d = new DirectoryInfo("D:\\Dump");
if (d.Exists)
{
}
outParams = managementClass.InvokeMethod("Create", inParams, null);
// Check to see if the method invocation was successful
if ((uint)(outParams.Properties["ReturnValue"].Value) != 0)
{
throw new Exception("Unable to share directory.");
}
}
here is my code it shares the folder but that does not work correctly when i want to access it , it shows access denied help required,
private static void ShareFolder(string FolderPath, string ShareName, string Description)
{
try
{
// 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"] = Description;
inParams["Name"] = ShareName;
inParams["Path"] = FolderPath;
inParams["Type"] = 0x0; // Disk Drive
//Another Type:
//DISK_DRIVE = 0x0;
//PRINT_QUEUE = 0x1;
//DEVICE = 0x2;
//IPC = 0x3;
//DISK_DRIVE_ADMIN = 0x80000000;
//PRINT_QUEUE_ADMIN = 0x80000001;
//DEVICE_ADMIN = 0x80000002;
//IPC_ADMIN = 0x8000003;
//inParams["MaximumAllowed"] = int maxConnectionsNum;
// Invoke the method on the ManagementClass object
outParams = managementClass.InvokeMethod("Create", inParams, null);
// Check to see if the method invocation was successful
if ((uint)(outParams.Properties["ReturnValue"].Value) != 0)
{
throw new Exception("Unable to share directory. Because Directory is already shared or directory not exist");
}//end if
}//end try
catch (Exception ex)
{
MessageBox.Show(ex.Message, "error!");
}//end catch
}//End Method
You have to add permissions to the shared folders. This post Adding Permissions to a shared folder using WMI and Microsoft .Net explains the steps in detail.
Excerpt from the post
To assign permission to the user, the
following needs to be done
Get hold of the Shared folder object’s setting and extract its
security descriptor.
Extract Access Control List (ACL) from the security descriptor.
Get hold of the user account object and extract its security
descriptor.
Create a Windows Trustee object for the user using its security
descriptor.
Create an Access Control Entry (ACE) using the Trustee object.
Add Access Control Entry to Access Control List.
Assign List back to Security Descriptor for the folder
Reassign security descriptor to the shared folder.
Return Values
Returns one of the values in the following table or any other value to indicate an error.
0 – Success
2 – Access denied
8 – Unknown failure
9 – Invalid name
10 – Invalid level
21 – Invalid parameter
22 – Duplicate share
23 – Redirected path
24 – Unknown device or directory
25 – Net name not found
Where are you accessing the shared folder from? If from another computer, make sure you have given read privileges on that folder to the computer that you are accessing it from.. Hope this helps...
Thanks,
Ram