c# - sharing a folder on local network - c#

I try to share a folder on local network for a special group.
I create the group, then I add the current user to this group. After this I share the folder on the local network with all the permisson to access to this for the group. In network I see the folder, all the permissons is granted for the group, it seems everything fine, but I can't access the folder on the local network.
I use this code:
string ShareName = "SpecialShare";
string Description = "This is a test";
string folderPath = #"c:\ApplicationFolder\AppData";
try
{
NTAccount ntAccount = new NTAccount("SpecialGroup");
SecurityIdentifier oGroupSID = (SecurityIdentifier)ntAccount.Translate(typeof(SecurityIdentifier));
byte[] utenteSIDArray = new byte[oGroupSID.BinaryLength];
oGroupSID.GetBinaryForm(utenteSIDArray, 0);
ManagementClass oGroupTrustee = new ManagementClass(new ManagementPath("Win32_Trustee"), null);
oGroupTrustee["Name"] = "SpecialGroup";
oGroupTrustee["SID"] = utenteSIDArray;
ManagementClass oGroupACE = new ManagementClass(new ManagementPath("Win32_ACE"), null);
oGroupACE["AccessMask"] = 2032127; //full access
oGroupACE["AceFlags"] = AceFlags.ObjectInherit | AceFlags.ContainerInherit;
oGroupACE["AceType"] = AceType.AccessAllowed;
oGroupACE["Trustee"] = oGroupTrustee;
ManagementObject oGroupSecurityDescriptor = new ManagementClass(new ManagementPath("Win32_SecurityDescriptor"), null);
oGroupSecurityDescriptor["ControlFlags"] = 4;
oGroupSecurityDescriptor["DACL"] = new object[] { oGroupACE };
DirectoryInfo dInfo = new DirectoryInfo(folderPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.AddAccessRule(new FileSystemAccessRule("SpecialGroup", FileSystemRights.FullControl, InheritanceFlags.ObjectInherit | InheritanceFlags.ContainerInherit, PropagationFlags.InheritOnly, AccessControlType.Allow));
dInfo.SetAccessControl(dSecurity);
ManagementClass managementClass = new ManagementClass("Win32_Share");
ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
//MessageBox.Show(managementClass.Derivation[0]);
inParams["Description"] = Description;
inParams["Name"] = ShareName;
inParams["Path"] = folderPath;
inParams["Type"] = 0; //Disk Drive
inParams["MaximumAllowed"] = null;
inParams["Password"] = null;
inParams["Access"] = oGroupSecurityDescriptor;
ManagementBaseObject outParams;
outParams = managementClass.InvokeMethod("Create", inParams, null);
if ((uint)(outParams.Properties["ReturnValue"].Value) != 0)
throw new Exception();
ManagementObject share = new ManagementObject(managementClass.Path + ".Name='" + ShareName + "'");
share.InvokeMethod("SetShareInfo", new object[] { Int32.MaxValue, Description, oGroupSecurityDescriptor });
dInfo.Refresh();
}
catch (Exception ex)
{
MessageBox.Show(ex.ToString());
}

Related

Getting the name of the installed program, its version and installation date WMI C#

I'm trying to get information about the programs installed on remote devices. At the moment, I found a way to output all installed programs. Is there a way to get the version and date of installation?
List<string> programs = new List<string>();
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Username = "USERNAME";
connectionOptions.Password = "USERPASS";
//connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
string devicename = textBox8.Text;
ManagementScope scope = new ManagementScope("\\\\" + devicename + "\\root\\CIMV2", connectionOptions);
scope.Connect();
string softwareRegLoc = #"Software\Microsoft\Windows\CurrentVersion\Uninstall";
ManagementClass registry = new ManagementClass(scope, new ManagementPath("StdRegProv"), null);
ManagementBaseObject inParams = registry.GetMethodParameters("EnumKey");
inParams["hDefKey"] = 0x80000002;//HKEY_LOCAL_MACHINE
inParams["sSubKeyName"] = softwareRegLoc;
// Read Registry Key Names
ManagementBaseObject outParams = registry.InvokeMethod("EnumKey", inParams, null);
string[] programGuids = outParams["sNames"] as string[];
foreach (string subKeyName in programGuids)
{
inParams = registry.GetMethodParameters("GetStringValue");
inParams["hDefKey"] = 0x80000002;//HKEY_LOCAL_MACHINE
inParams["sSubKeyName"] = softwareRegLoc + #"\" + subKeyName;
inParams["sValueName"] = "DisplayName";
// Read Registry Value
outParams = registry.InvokeMethod("GetStringValue", inParams, null);
if (outParams.Properties["sValue"].Value != null)
{
string softwareName = outParams.Properties["sValue"].Value.ToString();
programs.Add(softwareName);
}
}
foreach (string softwareName in programs)
{
int n = dataGridView8.Rows.Add();
dataGridView8.Rows[n].DefaultCellStyle.BackColor = Color.LightGreen;
dataGridView8.Rows[n].Cells[0].Value = devicename;
dataGridView8.Rows[n].Cells[1].Value = softwareName;
dataGridView8.FirstDisplayedScrollingRowIndex = dataGridView8.RowCount - 1;
}
}
catch
{
MessageBox.Show("Something went wrong");
}
}
Welcome to Stack Overflow. Use ORMi library to get that information easily:
1) Install via NuGet:
Install-Package ORMi
2) Use the library:
using ORMi;
3) Instanciate and use:
WMIHelper helper = new WMIHelper("root\CimV2");
var programs = helper.Query("SELECT Name, Version, InstallDate FROM Win32_Product").ToList();
foreach(var p in programs)
{
Console.WriteLine(p.Name);
}
And that´s it. Then if you want to do some more advanced working you can define your model classes and query in a simpler way. You can read the docs on GitHub.

Remotely Install an Application from a FileShare using WMI

So far my code will start a process (Install an application) with command line arguments on a target computer and wait for the process to finish, IF I copy the install files to that computer.
My goal now is to:
Start a process with command line arguments (Install an application) on the remote computer.
NOT copy the files to the remote computer. The installer files will be located on a network share that both the sender computer and the remote computer have access to.
Wait for the process to finish.
Any help is much appreciated!
private void StartAppAction(string PCName, string Params)
{
//Example of Params \\Server\Folder\Application.EXE /s
ConnectionOptions conn = new ConnectionOptions();
conn.Impersonation = ImpersonationLevel.Impersonate;
conn.Authentication = AuthenticationLevel.Default;
conn.EnablePrivileges = true;
ManagementScope manScope = new ManagementScope(String.Format(#"\\{0}\ROOT\CIMV2", PCName), conn);
try
{
manScope.Connect();
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
ObjectGetOptions objOpt = new ObjectGetOptions();
ManagementPath manPath = new ManagementPath("Win32_Process");
ManagementClass manClass = new ManagementClass(manScope, manPath, objOpt);
ManagementBaseObject inParams = manClass.GetMethodParameters("Create");
inParams["CommandLine"] = Params;
ManagementBaseObject outParams = manClass.InvokeMethod("Create", inParams, null);
string query = String.Format("SELECT * FROM __InstanceDeletionEvent WITHIN 3 WHERE TargetInstance ISA 'Win32_Process' AND TargetInstance.ProcessID = '{0}'", outParams["ProcessId"].ToString());
string scope = #"\\" + PCName + #"\root\CIMV2";
EventWatcherOptions evOp = new EventWatcherOptions(null, new TimeSpan(1, 0, 0), 1);
ManagementEventWatcher manWatch = new ManagementEventWatcher(scope, query, evOp);
try
{
ManagementBaseObject watcher = manWatch.WaitForNextEvent();
var ID = ((ManagementBaseObject)watcher["TargetInstance"]);
//Process Ended
}
catch
{
MessageBox.Show("Unable to watch for the remote process to finish");
}
}

List all network printers per user

at my work, we install printers on the per user basis. I'm trying to write a backup program that would list all networked printers given a username. Is that at all possible ? via WMI or System.IO would be OK. Here is the code that lists all the machines networked printers but not per user.
private void Button_Click(object sender, EventArgs e)
{
ConnectionOptions objConnection = new ConnectionOptions();
objConnection.Impersonation = ImpersonationLevel.Impersonate;
objConnection.EnablePrivileges = true;
string backupselectedcomputer = "Some Computer Name"
ManagementScope objScope = new ManagementScope("\\\\" + backupselectedcomputer +"\\root\\cimv2",objConnection);
objScope.Connect();
SelectQuery selectQuery = new SelectQuery();
selectQuery.QueryString = "Select * from win32_Printer Where Local = FALSE";
ManagementObjectSearcher MOS = new ManagementObjectSearcher(objScope, selectQuery);
ManagementObjectCollection MOC = MOS.Get();
foreach (ManagementObject mo in MOC)
{
//lbBackupprinters is a list box
lbBackupprinters.Items.Add(mo["Name"].ToString().ToUpper());
}
}
Figured out a way. Here is the code for anyone that comes across this issue.
private void ddlBackupselectuser_SelectionChangeCommitted(object sender, EventArgs e)
{
lbBackupprinters.Items.Clear();
string selecteduser = ddlBackupselectuser.Text;
string computer = ddlBackupselectcomp.Text;
string sid;
lblBackuppwd.Visible = true;
txtBackuppwd.Visible = true;
cboBackuppwdshow.Visible = true;
//BEGIN GRAB PRINTERS FROM REGISTRY
try
{
NTAccount ntuser = new NTAccount(selecteduser);
SecurityIdentifier sID = (SecurityIdentifier)ntuser.Translate(typeof(SecurityIdentifier));
lblBackupStatus.Text = sID.ToString();
sid = sID.ToString();
}
catch (IdentityNotMappedException)
{
lblBackupStatus.Text = "ERROR "+ ddlBackupselectuser.Text.ToString() + " contains no profile information";
lbBackupprinters.Items.Add("No Printers Found");
return;
}
ConnectionOptions co = new ConnectionOptions();
co.EnablePrivileges = true;
co.Impersonation = ImpersonationLevel.Impersonate;
System.Net.IPHostEntry h = System.Net.Dns.GetHostEntry(System.Net.Dns.GetHostName());
string IPAddress = h.AddressList.GetValue(0).ToString();
string lm = System.Net.Dns.GetHostName().ToString();
try
{
ManagementScope myScope = new ManagementScope("\\\\" + computer + "\\root\\default", co);
ManagementPath mypath = new ManagementPath("StdRegProv");
ManagementClass wmiRegistry = new ManagementClass(myScope, mypath, null);
const uint HKEY_LOCAL_MACHINE = unchecked((uint)0x80000002);
//ManagementClass wmiRegistry = new ManagementClass("root/default",
//"StdRegProv",null);
string keyPath = #"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Providers\\Client Side Rendering Print Provider\\" + sid + "\\Printers\\Connections";
object[] methodArgs = new object[] { HKEY_LOCAL_MACHINE, keyPath, null };
uint returnValue = (uint)wmiRegistry.InvokeMethod("EnumKey", methodArgs);
if (null != methodArgs[2])
{
string[] subKeys = methodArgs[2] as String[];
if (subKeys == null)
{
lbBackupprinters.Items.Add("No Printers Found");
return;
}
ManagementBaseObject inParam = wmiRegistry.GetMethodParameters("GetStringValue");
inParam["hDefKey"] = HKEY_LOCAL_MACHINE;
string keyName = "";
foreach (string subKey in subKeys)
{
//Display application name
keyPath = #"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Print\\Providers\\Client Side Rendering Print Provider\\" + sid + "\\Printers\\Connections" + subKey;
keyName = "DisplayName";
inParam["sSubKeyName"] = keyPath;
inParam["sValueName"] = keyName;
ManagementBaseObject outParam = wmiRegistry.InvokeMethod("GetStringValue", inParam, null);
lbBackupprinters.Items.Add(subKey);
}
}
else
{
lbBackupprinters.Items.Add("No Printers Found");
}
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.Message);
}

Get a list of all UNC shared folders on a local network server

I'm trying to get a list of all shared folders available on a local intranet server.
The System.IO.Directory.GetDirectories() works fine for a path like \\myServer\myShare, however I'm getting an exception for a path like \\myServer:
Unhandled Exception: System.ArgumentException: The UNC path should be of the form \server\share.
Is there a way to get a list all shared folders for a server? Ultimately I'm looking for a method that can handle both scenarios based on a given path - returning a list of all shares for a given server and returning a list of all subdirectories for a given network shared folder.
Here's a technique that uses System.Management (add a reference to this assembly):
using (ManagementClass shares = new ManagementClass(#"\\NameOfTheRemoteComputer\root\cimv2", "Win32_Share", new ObjectGetOptions())) {
foreach (ManagementObject share in shares.GetInstances()) {
Console.WriteLine(share["Name"]);
}
}
Appropriate permissions are required.
I think this is what you are looking for http://www.codeproject.com/KB/IP/networkshares.aspx
private DataTable GetSharedFolderAccessRule()
{
DataTable DT = new DataTable();
try
{
DT.Columns.Add("ShareName");
DT.Columns.Add("Caption");
DT.Columns.Add("Path");
DT.Columns.Add("Domain");
DT.Columns.Add("User");
DT.Columns.Add("AccessMask");
DT.Columns.Add("AceType");
ManagementScope Scope = new ManagementScope(#"\\.\root\cimv2");
Scope.Connect();
ObjectQuery Query = new ObjectQuery("SELECT * FROM Win32_LogicalShareSecuritySetting");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
ManagementObjectCollection QueryCollection = Searcher.Get();
foreach (ManagementObject SharedFolder in QueryCollection)
{
{
String ShareName = (String) SharedFolder["Name"];
String Caption = (String)SharedFolder["Caption"];
String LocalPath = String.Empty;
ManagementObjectSearcher Win32Share = new ManagementObjectSearcher("SELECT Path FROM Win32_share WHERE Name = '" + ShareName + "'");
foreach (ManagementObject ShareData in Win32Share.Get())
{
LocalPath = (String) ShareData["Path"];
}
ManagementBaseObject Method = SharedFolder.InvokeMethod("GetSecurityDescriptor", null, new InvokeMethodOptions());
ManagementBaseObject Descriptor = (ManagementBaseObject)Method["Descriptor"];
ManagementBaseObject[] DACL = (ManagementBaseObject[])Descriptor["DACL"];
foreach (ManagementBaseObject ACE in DACL)
{
ManagementBaseObject Trustee = (ManagementBaseObject)ACE["Trustee"];
// Full Access = 2032127, Modify = 1245631, Read Write = 118009, Read Only = 1179817
DataRow Row = DT.NewRow();
Row["ShareName"] = ShareName;
Row["Caption"] = Caption;
Row["Path"] = LocalPath;
Row["Domain"] = (String) Trustee["Domain"];
Row["User"] = (String) Trustee["Name"];
Row["AccessMask"] = (UInt32) ACE["AccessMask"];
Row["AceType"] = (UInt32) ACE["AceType"];
DT.Rows.Add(Row);
DT.AcceptChanges();
}
}
}
}
catch (Exception ex)
{
MessageBox.Show(ex.StackTrace, ex.Message);
}
return DT;
}

Create and set permissions on new home folder programmatically

I have created an app to standardize user creation for our AD domain. Now I would like to be able to create, share and set permissions on the folder. I know how to create a remote folder, but I am unclear on the best way to go about sharing and setting permissions in VB08.
Thanks in advance,
Christopher
Just so people know what I ended up going with, here is the final successful code to create a remote folder, set NTFS permissions on the folder to full control for the selected user and then create a share on the new folder with full permissions for everyone.
using System.IO;
using System.Management;
using System.Security.AccessControl;
public static void CreateFolder(String accountName, String homeFolder)
{
String folderName;
String localfolderpath;
String shareName;
try
{
folderName = "\\\\server\\c$\\Home\\" + homeFolder + "\\" + accountName;
Directory.CreateDirectory(folderName);
localfolderpath = "C:\\Home\\" + homeFolder + "\\" + accountName;
shareName = accountName + "$";
FolderACL(accountName, folderName);
makeShare(localfolderpath, shareName);
}
catch (Exception ex)
{
MessageBox.Show("Error: " + ex.ToString());
}
}
public static void FolderACL(String accountName, String folderPath)
{
FileSystemRights Rights;
//What rights are we setting?
Rights = FileSystemRights.FullControl;
bool modified;
InheritanceFlags none = new InheritanceFlags();
none = InheritanceFlags.None;
//set on dir itself
FileSystemAccessRule accessRule = new FileSystemAccessRule(accountName, Rights, none, PropagationFlags.NoPropagateInherit, AccessControlType.Allow);
DirectoryInfo dInfo = new DirectoryInfo(folderPath);
DirectorySecurity dSecurity = dInfo.GetAccessControl();
dSecurity.ModifyAccessRule(AccessControlModification.Set, accessRule, out modified);
//Always allow objects to inherit on a directory
InheritanceFlags iFlags = new InheritanceFlags();
iFlags = InheritanceFlags.ContainerInherit | InheritanceFlags.ObjectInherit;
//Add Access rule for the inheritance
FileSystemAccessRule accessRule2 = new FileSystemAccessRule(accountName, Rights, iFlags, PropagationFlags.InheritOnly, AccessControlType.Allow);
dSecurity.ModifyAccessRule(AccessControlModification.Add, accessRule2, out modified);
dInfo.SetAccessControl(dSecurity);
}
private static void makeShare(string filepath, string sharename)
{
try
{
String servername = "server";
// assemble the string so the scope represents the remote server
string scope = string.Format("\\\\{0}\\root\\cimv2", servername);
// connect to WMI on the remote server
ManagementScope ms = new ManagementScope(scope);
// create a new instance of the Win32_Share WMI object
ManagementClass cls = new ManagementClass("Win32_Share");
// set the scope of the new instance to that created above
cls.Scope = ms;
// assemble the arguments to be passed to the Create method
object[] methodargs = { filepath, sharename, "0" };
// invoke the Create method to create the share
object result = cls.InvokeMethod("Create", methodargs);
MessageBox.Show(result.ToString());
}
catch (SystemException e)
{
Console.WriteLine("Error attempting to create share {0}:", sharename);
Console.WriteLine(e.Message);
}
}
here is nice tutorial http://weblogs.asp.net/cumpsd/archive/2004/02/08/69403.aspx
and home path you can get from %HOMEPATH% env. variable

Categories