Is it possible to read the sharing permissions assigned to a shared folder? I'm able to read in the local security settings programmaticaly (the ones found under Right Click > Properties > Security) no problem. But, I'm wondering how I can read the permissions under Right Click > Sharing and Security... > Permissions
Here is an image of the Permissions I want to read:
Is this possible? I'm running an XP Pro machine if it helps.
Edit:
As per my answer I was able to iterate through all the shares, and get the access you (ie the person running the program) has on that share, but have not found a way to read the permissions others have on that share. This was done using Win32_Share class, however it does not have an option for getting the share permissions of other users. If anyone has any helpful hints that would be a huge help.
I was able to get this working by expanding on the approach taken by Petey B. Also, be sure that the process that runs this code impersonates a privileged user on the server.
using System;
using System.Management;
...
private static void ShareSecurity(string ServerName)
{
ConnectionOptions myConnectionOptions = new ConnectionOptions();
myConnectionOptions.Impersonation = ImpersonationLevel.Impersonate;
myConnectionOptions.Authentication = AuthenticationLevel.Packet;
ManagementScope myManagementScope =
new ManagementScope(#"\\" + ServerName + #"\root\cimv2", myConnectionOptions);
myManagementScope.Connect();
if (!myManagementScope.IsConnected)
Console.WriteLine("could not connect");
else
{
ManagementObjectSearcher myObjectSearcher =
new ManagementObjectSearcher(myManagementScope.Path.ToString(), "SELECT * FROM Win32_LogicalShareSecuritySetting");
foreach(ManagementObject share in myObjectSearcher.Get())
{
Console.WriteLine(share["Name"] as string);
InvokeMethodOptions options = new InvokeMethodOptions();
ManagementBaseObject outParamsMthd = share.InvokeMethod("GetSecurityDescriptor", null, options);
ManagementBaseObject descriptor = outParamsMthd["Descriptor"] as ManagementBaseObject;
ManagementBaseObject[] dacl = descriptor["DACL"] as ManagementBaseObject[];
foreach (ManagementBaseObject ace in dacl)
{
try
{
ManagementBaseObject trustee = ace["Trustee"] as ManagementBaseObject;
Console.WriteLine(
trustee["Domain"] as string + #"\" + trustee["Name"] as string + ": " +
ace["AccessMask"] as string + " " + ace["AceType"] as string
);
}
catch (Exception error)
{
Console.WriteLine("Error: "+ error.ToString());
}
}
}
}
}
I know you can with Windows Home Server:
http://msdn.microsoft.com/en-us/library/bb425864.aspx
You can do this in MMC and most of that is available through code, so it should be possible. If you can't find it there then you should check out Windows API calls. I've seen it done in C++, so it should also be possible in C#. Sorry, I don't have any sample code or other links to provide for those. I'll see if I can dig some up though.
I also just saw this on SO:
how to create shared folder in C# with read only access?
Another good link:
http://social.msdn.microsoft.com/Forums/en/windowssdk/thread/de213b61-dc7e-4f33-acdb-893aa96837fa
The best I could come up with is iterating through all the shares on a machine and reading the permissions you have on the share.
ManagementClass manClass = new ManagementClass(#"\\" +computerName +#"\root\cimv2:Win32_Share"); //get shares
//run through all the shares
foreach (ManagementObject objShare in manClass.GetInstances())
{
//ignore system shares
if (!objShare.Properties["Name"].Value.ToString().Contains('$'))
{
//print out the share name and location
textBox2.Text += String.Format("Share Name: {0} Share Location: {1}", objShare.Properties["Name"].Value, objShare.Properties["Path"].Value) + "\n";
Int32 permissions = 0;
try
{
//get the access values you have
ManagementBaseObject result = objShare.InvokeMethod("GetAccessMask", null, null);
//value meanings: http://msdn.microsoft.com/en-us/library/aa390438(v=vs.85).aspx
permissions = Convert.ToInt32(result.Properties["ReturnValue"].Value);
}
catch (ManagementException me)
{
permissions = -1; //no permissions are set on the share
}
textBox2.Text += "You have permissions: " + permissions + "\n\n";
}
}
If anyone could figure out how to get the permissions others have on the share that would be amazing.
Related
From what I can see 'ServiceController' doesn't have the option to pull the 'Log On As' information from local Windows Services.
Currently I'm using ServiceController to provide me with the Display Name of the service and the current status but I would also like to pull in the 'Log On As' information too.
I did see wmic can get this information from startname using:
wmic service get name,startname
Currently this is my code:
public string GetLocalServices()
{
var sc = new System.ServiceProcess.ServiceController();
ServiceController[] svcList = ServiceController.GetServices();
try
{
foreach (ServiceController service in ServiceController.GetServices())
{
string serviceDisplayName = service.DisplayName;
string status = service.Status.ToString();
var serviceDetails = "Display Name: " + serviceDisplayName + "Service Status: " + status + "\r\n" + "\r\n";
File.AppendAllText(Path.Combine(_TempPath, #"LocalServices.txt"), serviceDetails.ToString());
}
return "Retrieving Local Services Information complete.";
}
catch (Exception ex)
{
return string.Concat("!!! Exception: Unable to gather information on local services ", ex.Message);
}
}
Is anyone aware of how I can query wmic in this class and append this to the serviceDetails variable so I can print out the Log On As information too?
Take a look at the WMI code creator tool from microsoft(link below to download). This tool gives you the snippets of code in C# for what you are looking for.
https://www.microsoft.com/en-us/download/details.aspx?id=8572
Click on the link to see an image of how the tool works.
WMI Code Creator
Attempting to pull the automatic update settings from the registry of a remote server. For some reason, it's returning a 0 even though a manual check of the key is 1-4. What am I overlooking? Snippet below:
ManagementScope msAutoUpdateReg = new ManagementScope(#"\\" + remoteServer + #"\root\DEFAULT:StdRegProv", connection);
msAutoUpdateReg.Connect();
ManagementClass ci = new ManagementClass(msAutoUpdateReg, new ManagementPath(#"DEFAULT:StdRegProv"), new ObjectGetOptions());
ManagementBaseObject inParams = ci.GetMethodParameters("GetDWORDValue");
inParams["hDefKey"] = 0x80000002; //HKLM
inParams["sSubKeyName"] = #"Software\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update";
inParams["sValueName"] = "AUOptions";
ManagementBaseObject outParams = ci.InvokeMethod("GetDWORDValue", inParams, null);
UInt32 auValue = (UInt32)outParams["uValue"];
if (auValue.ToString() != "0")
{
if (auValue == 1)
{
string currentSetting = "Keep my computer up to date has been disabled in Automatic Updates.";
}
if (auValue == 2)
{
string currentSetting = "Notify of download and installation.";
}
if (auValue == 3)
{
string currentSetting = "Automatically download and notify of installation.";
}
if (auValue == 4)
{
string currentSetting = "Automatically download and scheduled installation.";
}
}
else
{
string currentSetting = "Unknown";
}
I guess a process of elimination might help here...
1) Is this happening on just one server or are you getting this on all servers? How about on your own local machine? Is it a Windows version thing? For example it seems my Windows 10 box doesn't show the SubKey name you are looking for.
2) Do you also get zero if you change the sValueName to "foo"? Is a value of 0 representing an error?
3) Can you put a watch on outParams and check to see what values have been returned?
4) Are you being blocked by UAC, firewall or other permission issues? Can you execute other WMI commands against this server without any problems? Do you need to Run As Administrator to get this to work?
5) Are you getting an other exceptions or return values? I'm guessing you've posted just a portion of the code here so is this code inside a try/catch block?
Sorry if this sounds either vague or simplistic but I think you may need to look at what does work and what doesn't to see if you can identify a pattern.
I am using System.DirectoryServices.DirectoryEntry to create AD user and everything work fine except for some Remote Desktop specifics properties.
Exemple :
newUser.Properties["msTSConnectClientDrives"].Value = false;
newUser.Properties["msTSConnectPrinterDrives"].Value = false;
newUser.Properties["msTSDefaultToMainPrinter"].Value = false;
This doesn't throw any exception, so I guess the properties are found in the object but they don't have any effect. When I go into the property window of that user, under "Environment" tab, these 3 checkbox are still checked on.
Am I missing something particular for these properties ?
Thank for your help.
EDIT :
Sorry I have been really busy, here is a code sample :
private string CreateNewADAccount(string accountName, string accountPassword)
{
try
{
PrincipalContext context = new PrincipalContext(ContextType.Domain, "SV-LITE", #"LITE\xxxxxxxx", "yyyyyyyy");
UserPrincipal newUser = new UserPrincipal(context);
newUser.SamAccountName = accountName;
newUser.UserPrincipalName = accountName;
newUser.Name = "LiteUser2015 - " + accountName;
newUser.DisplayName = "LiteUser2015 - " + accountName;
newUser.SetPassword(accountPassword);
newUser.PasswordNeverExpires = true;
newUser.UserCannotChangePassword = true;
newUser.Save();
// Set advanced properties
if (newUser.GetUnderlyingObjectType() == typeof(DirectoryEntry))
{
DirectoryEntry entry = (DirectoryEntry)newUser.GetUnderlyingObject();
entry.Properties["msTSConnectClientDrives"].Value = false;
entry.Properties["msTSConnectPrinterDrives"].Value = false;
entry.Properties["msTSDefaultToMainPrinter"].Value = false;
entry.Properties["msTSInitialProgram"].Value = "test";
entry.CommitChanges();
}
return newUser.Guid.ToString();
}
catch (Exception e)
{
MessageBox.Show("Failed to create PrincipalContext. Exception: " + e);
}
return null;
}
After making the changes, you have to call CommitChanges - newUser.CommitChanges();
See https://msdn.microsoft.com/en-us/library/system.directoryservices.directoryentry.commitchanges%28v=vs.110%29.aspx
By default, changes to properties are made locally to a cache..
It might have something to do with the Server OS version you're using. I found this answer on another site that talks about Windows 2000 and 2003. It should work for Windows2008 and above:
For 2000 / 2003 you have to access them using the Terminal Services
ADSI extension. The reference for that is here:
http://msdn.microsoft.com/en-us/library/aa380823(VS.85).aspx
In part of a program I am writing, I'm trying to pull device information about specified local hard drives. I've been able to create a few value returning methods using the DriveInfo class like this:
//Gets drive format
public string GetDriveFormat(string driveName)
{
foreach (DriveInfo drive in DriveInfo.GetDrives())
{
if (drive.IsReady && drive.Name == driveName)
{
return drive.DriveFormat;
}
}
return "";
}
//Example of use
MessageBox.Show(GetDriveFormat("C:\\"));
The problem I'm running into now is that there doesn't seem to be a Model property to the DriveInfo class. I've looked all over but am unable to find a way to construct a value returning method that will return the model of a drive like what is viewable in device manager.
Any help would be greatly appreciated,
Thanks!
Unfortunately, you cannot get the Drive's Manufacturer and Model using the DriveInfo class.
You'll have to resort back to WMI:
WqlObjectQuery q = new WqlObjectQuery("SELECT * FROM Win32_DiskDrive");
using (ManagementObjectSearcher res = new ManagementObjectSearcher(q)) {
foreach (ManagementObject o in res.Get()) {
Console.WriteLine("Caption = " + o["Caption"]);
Console.WriteLine("DeviceID = " + o["DeviceID"]);
Console.WriteLine("Decsription = " + o["Description"]);
Console.WriteLine("Manufacturer = " + o["Manufacturer"]);
Console.WriteLine("MediaType = " + o["MediaType"]);
Console.WriteLine("Model = " + o["Model"]);
Console.WriteLine("Name = " + o["Name"]);
// only in Vista, 2008 & etc: //Console.WriteLine("SerialNumber = " + o["SerialNumber"]);
} }
Not sure if you need to consider mounted drives as well:
foreach(ManagementObject volume in new ManagementObjectSearcher("Select * from Win32_Volume" ).Get())
{
...
}
You'll need to use a lower-level API to get this information, and even then it still might not be accurate.* The internal details of the hard drives is exposed in the Win32 APIs, which you can still access in C# through WMI.
*: Note that this is still limited to the hardware information as Windows is able to see it. In some conditions, it won't or can't be accurate (e.g. with a RAID array, where Windows sees N drives as a single drive).
I'm not entirely sure if you can get that info without using lower level api's. This post should help you achieve your goal.
http://www.codeproject.com/Articles/17973/How-To-Get-Hardware-Information-CPU-ID-MainBoard-I
Quick summary of the link:
Add a reference to the System.Management library
Then you can use:
var disks = new ManagementObjectSearcher("SELECT * FROM Win32_DiskDrive");
foreach (ManagementObject disk in disks.Get())
{
Console.WriteLine(disk["Model"].ToString());
Console.WriteLine("\tSerial: " + disk["SerialNumber"]);
}
here is something that can also work for you feel free to tweak it as you please
String drive = "c";
ManagementObject disk = new ManagementObject("Win32_LogicalDisk.DeviceID=\"" + drive + ":\"");
disk.Get();
Console.WriteLine(disk["VolumeName"]);
foreach (var props in disk.Properties)
{
Console.WriteLine(props.Name + " " + props.Value);
}
Console.ReadLine();
I have a windows service which polls for a specific folder for creation of new files. This works fine when the folder is in one of the local drives such as C: or D:
The service fails to find a folder on a mapped drive.
Here is the code which does the checking for folder exist before polling:
System.Security.Principal.WindowsIdentity userIdentity =
System.Security.Principal.WindowsIdentity.GetCurrent();
System.Security.Principal.WindowsPrincipal principal =
new System.Security.Principal.WindowsPrincipal(userIdentity);
MappedDriveResolver mdr = new MappedDriveResolver();
if (mdr.isNetworkDrive(folderPath))
{
LoggingAppWrapper.LogDeveloperMessage(folderPath + " is on a Mapped drive", 1, TraceEventType.Information, string.Empty);
}
MappedDriveResolver is a class that I found hereHow do I determine a mapped drive's actual path?
The code in that link works fine from a simple console application, but fails when it is part of windows service.
Any suggestions as to what has to be done for the code to work for a windows service?
Regards.
I would recommend you configure your service to use UNC paths for folders not on the server running the service.
Mapped drives are a usability feature for users and as such they are specific to that users profile/environment. Meaning, when you login you may have a drive X: that is mapped to \\server1\share1 but when I login my drive X: could be mapped to \\server2\share2 instead. The actual mapping process is either saved as part of your profile with the "Reconnect at logon" or is handled by a logon script.
You need to check what account the service is running under and make sure that mapped drive exists for that user environment (This might help How to map a network drive to be used by a service).
Edit:
The reason your console application works and the service doesn't is because of the differences between the environment they are running in.
To illustrate this, take this console application, compile it and then run it as a Schedule Task. Set the "path" variable to be a mapped drive that your user can access.
static void Main(string[] args) {
MappedDriveResolver mdr = new MappedDriveResolver();
string logfile;
string path = #"I:\";
string[] files;
// Write out "log" file to where this is running from
logfile = Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location);
logfile = Path.Combine(logfile, "log.txt");
using (StreamWriter sw = new StreamWriter(logfile, true)) {
try {
sw.WriteLine("Checking path " + path);
if (mdr.isNetworkDrive(path)) {
sw.WriteLine("Network Drive: Yes");
} else {
sw.WriteLine("Network Drive: No");
}
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
try {
sw.WriteLine("Resolve path " + path);
string newpath = mdr.ResolveToUNC(path);
sw.WriteLine("Resolved path " + newpath);
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
try {
sw.WriteLine("Get file list from " + path);
files = Directory.GetFiles(path);
if (files == null || files.Length == 0) {
sw.WriteLine("No files found");
} else {
sw.WriteLine(string.Format("Found {0} files.", files.Length));
}
} catch (Exception ex) {
sw.WriteLine("Exception: " + ex.Message);
}
sw.Flush();
sw.Close();
}
}
Note: This is with the Windows 7 Task Scheduler
Test 1: Just run the app by double-clicking on it.
Result: Success
Test 2: Configure scheduled task to run as your user account with "Run only when user is logged on"
Result: Success
Test 3: Configure scheduled task to run as your user account with "Run whether user is logged on or not"
Result: Exceptions
Test 4: Configure schedule task to run as "Local Service" account.
Result: Exceptions
Test 1 & 2 work because they are using the currently logged in user environment including the mapped drives that are part of it.
Test 3 & 4 fail because they have their own user environment created for them, which does not have any mapped drives configured. It escapes me at the moment what the differences there are, but an "interactive" and "non-interactive" environment are different in some significant ways.