I have C# WinForm application that needs to set sharing permission to some folder, and specify what users have access read/write/delete.
I was wondering if there is any api or way to call something similar to when you right click on folder select Properties/Sharing/Advanced Sharing and window opens.
If you know of anyway calling this window from c# I would appreciate if you share your knowledge.
I want to call this window.
You can do it through Win32 API:
private static void QshareFolder(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
// Invoke the method on the ManagementClass object
outParams = managementClass.InvokeMethod("Create", inParams, null);
if ((uint)(outParams.Properties["ReturnValue"].Value) != 0)
{
throw new Exception("Unable to share directory.");
}
}
catch (Exception ex)
{
//MessageBox.Show(ex.Message, "error!");
}
}
Usage:
QshareFolder("c:\TestShare", "Test Share", "This is a Test Share");
Source: http://www.codeproject.com/Articles/18624/How-to-Share-Windows-Folders-Using-C
There is no any standart API for this task.
Try this project to implement what you need How to Share Windows Folders Using C# (and here there is another example https://social.msdn.microsoft.com/Forums/windowsdesktop/en-US/de213b61-dc7e-4f33-acdb-893aa96837fa/c-set-directory-sharing-permission-full-control-for-everyone-programmatically-in-windows-7-or?forum=windowssdk)
Notice that your application will need to be running with Administrative access in order to share a folder.
Related
I am trying to create the shared folder in computer management shares with the following code
ManagementClass managementClass = new ManagementClass("Win32_Share");
ManagementBaseObject inParams = managementClass.GetMethodParameters("Create");
ManagementBaseObject outParams;
inParams["Description"] = Description;
inParams["Name"] = ShareName;
inParams["Path"] = FolderPath;
inParams["Type"] = 0x0; // Disk Drive
outParams = managementClass.InvokeMethod("Create", inParams, null);
var res = (uint)(outParams.Properties["ReturnValue"].Value);
res always returns 2.
Can anyone be of help in this regard?
What does it 2 mean and what are all the other output parameters?
Based on Create method of Win32_Share documentation , possible return values are :
Success (0)
Access denied (2)
Unknown failure (8)
Invalid name (9)
Invalid level (10)
Invalid parameter (21)
Duplicate share (22)
Redirected path (23)
Unknown device or directory (24)
Net name not found (25)
Other (26–4294967295)
I've seen many ways in powershell to force a computer to do a client action from the configuration manager.
Where I do work, it is not possible because we can't invoke commands on distant computer because it is blocked and the senior IT do not want to unlock it.
I did find a library in c# that allow me to do some action in sccm :
AdminUI.SmsTraceListener.dll
AdminUI.WqlQueryEngine.dll
I can add/remove computer to a collections, make queries and get the data, but I didn't find the way to force a computer to make an action from the configuration manager.
Is there someone here that knows if it is possible and how?
Thanks.
Edit 1: While searching in the MSDN documentation, I did find the TriggerSchedule Method in Class SMS_Client but I don't find the way to use it correctly. I think it might be the way to go, but i'm still stuck on this.
It is possible to trigger an Machine Policy Update via TriggerSchedule like this
ManagementScope scope = new ManagementScope(#"\\.\root\ccm");
ManagementClass cls = new ManagementClass(scope.Path.Path, "SMS_Client", null);
ManagementBaseObject inParams = cls.GetMethodParameters("TriggerSchedule");
inParams["sScheduleID"] = "{00000000-0000-0000-0000-000000000021}";
ManagementBaseObject outMPParams = cls.InvokeMethod("TriggerSchedule", inParams, null);
You already found the other Parameters for the sScheduleID in the link you posted. This uses standard WMI. With WqlQueryEngine you would get access to some WMI wrappers that can basically do the same thing. I do not see many advantages however.
Using the scope like this
\\.\root\ccm
makes the whole thing only work locally which is what you want if I understood you correctly. Otherwise replacing the . With a hostname or IP would make it work remotely. Only thing I found a bit strange is that it needs administrative rights, which should in theory not be necessary for a policy update request.
if someone is having the issue that nothing is happening, it is because WMI required higher rights. To leave triggering the actions also by the user, I switched to use the CPApplet:
TriggerSccmActions("Request & Evaluate", true);
private static List<string> TriggerSccmActions(string stringActions, bool boolContains)
{
List<string> actionName = new List<string>();
try {
const string ProgID = "CPApplet.CPAppletMgr";
Type foo = Type.GetTypeFromProgID(ProgID);
dynamic COMobject = Activator.CreateInstance(foo);
var oClientActions = COMobject.GetClientActions;
foreach (var oClientAction in oClientActions)
{
if (oClientAction.Name.ToString().Contains(stringActions) && boolContains)
{
var result = oClientAction.PerformAction();
actionName.Add(oClientAction.Name.ToString());
}
else if (!(oClientAction.Name.ToString().Contains(stringActions)) && !(boolContains))
{
var result = oClientAction.PerformAction();
actionName.Add(oClientAction.Name.ToString());
}
}
} catch(Exception e)
{
actionName.Add("Error: " + e.Message.ToString());
}
return actionName;
}
For me, EvaluateMachinePolicy Method in Class SMS_Client class worked. Here is the code:
public static void RefreshMachinePolicy(string machineName)
{
ManagementScope scope = new ManagementScope(string.Format(#"\\{0}\root\ccm", machineName));
ManagementClass cls = new ManagementClass(scope.Path.Path, "SMS_Client", null);
ManagementBaseObject inParams = cls.GetMethodParameters("EvaluateMachinePolicy");
ManagementBaseObject outMPParams = cls.InvokeMethod("EvaluateMachinePolicy", inParams, null);
Console.WriteLine("Policy refreshed successfully by EvaluateMachinePolicy method");
}
Here is the MSDN link for method details. Please include below namespace at the top of your source code file:
using System.Management;
I am trying to create a VM in Hyper-V with WMI.
ManagementClass virtualSystemManagementService =
new ManagementClass(#"root\virtualization\v2:Msvm_VirtualSystemManagementService");
ManagementBaseObject inParams =
virtualSystemManagementService
.GetMethodParameters("DefineSystem");
// Add the input parameters.
ManagementClass virtualSystemSettingData =
new ManagementClass(#"root\virtualization\v2:Msvm_VirtualSystemSettingData")
{
["ElementName"] = "Test"
};
inParams["SystemSettings"] =
virtualSystemSettingData.GetText(TextFormat.CimDtd20);
// Execute the method and obtain the return values.
ManagementBaseObject outParams =
virtualSystemManagementService
.InvokeMethod("DefineSystem", inParams, null);
The call to InvokeMethod throws an System.Management.MangementException - "Invalid method Parameter(s).
I am basing this code on https://blogs.msdn.microsoft.com/virtual_pc_guy/2013/06/20/creating-a-virtual-machine-with-wmi-v2/
I do realize that this is really easy with powershell, but I am trying to understand how the WMI side of things works.
Basic workflow For Virtual Machine Creation using WMI with C#:
You missed creating an instance of VirtualSystemSettingData and getting an instance of VirtualSystemManagment Service.
The exception System.Management.MangementException - "Invalid method Parameter(s) is thrown when you call invoke method on a class not an object!
Create VirtualSystemSettingData class
Add Properties
Create new VirtualSystemSettingData instance
Convert to text
Pass to params
Create VirtualSystemManagementService class
Get existing VirtualSystemManagementService instance
Invoke Method
Example:
ManagementClass virtualSystemManagementServiceClass =
new ManagementClass(#"root\virtualization\v2:Msvm_VirtualSystemManagementService");
ManagementBaseObject inParams =
virtualSystemManagementServiceClass
.GetMethodParameters("DefineSystem");
// Add the input parameters.
ManagementClass virtualSystemSettingDataClass =
new ManagementClass(#"root\virtualization\v2:Msvm_VirtualSystemSettingData")
{
["ElementName"] = "Test"
};
// Create Instance of VirtualSystemSettingData
ManagementObject virtualSystemSettingData = virtualSystemSettingDataClass.CreateInstance();
inParams["SystemSettings"] =
virtualSystemSettingData.GetText(TextFormat.CimDtd20);
// Get Instance of VirtualSystemManagmentService
ManagementObject virtualSystemManagementService = null;
foreach (ManagementObject instance in virtualSystemManagementServiceClass.GetInstances())
{
virtualSystemManagementService = instance;
break;
}
// Execute the method and obtain the return values.
ManagementBaseObject outParams = virtualSystemManagementService.InvokeMethod("DefineSystem", inParams, null);
You need to create an instance of msvm_VirtualSystemSettingData.
ManagementObject newInstance = new ManagementClass(scope, new ManagementPath("Msvm_VirtualSystemSettingData"), null).CreateInstance();
newInstance["ElementName"] = vmName;
inParameters["SystemSettings"] = newInstance.GetText(TextFormat.CimDtd20);
Story time! One of our more disgruntled employees decided to upgrade visual svn and modify our web interface a day before his last day. We had the old authentication set up, and it was all working fine. Give this particular applications footprint in the grand scheme we followed the 'if it ain't broke, don't fix it' mantra.
It wasn't broke, and he fixed it...
SO here we are. I found This Question regarding interfacing with Visual SVN with C#, and it looks like he had just copied and pasted the code verbatim from there.
The interface we have is very simple. There is an input box that the user types in the name of there desired repo. Below that is a text area where he/she can add users to have access to the repo. The user lookup is done based off of email address and it hits our active directory. The end result of this is I have the name of the repo I need to create, and the users/SIDs of the people I need to give read/write access to.
Testing this code he pasted in, it seems like the repositories are getting created fine (they show up when I log into the server as an admin). Here is the repo creation code:
static public bool CreateRepository(repository r)
{
ManagementClass repoClass = new ManagementClass("root\\VisualSVN", "VisualSVN_Repository", null);
// Obtain in-parameters for the method
ManagementBaseObject inParams = repoClass.GetMethodParameters("Create");
// Add the input parameters.
inParams["Name"] = r.name;
// Execute the method and obtain the return values.
ManagementBaseObject outParams =
repoClass.InvokeMethod("Create", inParams, null);
return true;
}
'repository r' in the method parameters, repository is a class with the following properties:
private int _id;
private string _name;
private System.Nullable<System.DateTime> _deleteAfter;
private EntitySet<UserRepositoryRight> _UserRepositoryRights;
with all the public getters and setters you would expect from a linq to sql generated file.
UserRepositoryRight is a table that holds the one (repo) to many (users) relationships.
Like I said, I think this code is fine, since I am seeing the repositories being created.
The next copypasta code is the UpdatePermissions method
static public void UpdatePermissions(string sid, string repository, AccessLevel level, bool isAdmin = false)
{
//Update SVN
ManagementClass userClass = new ManagementClass("root\\VisualSVN", "VisualSVN_WindowsAccount", null);
ManagementClass permClass = new ManagementClass("root\\VisualSVN", "VisualSVN_PermissionEntry", null);
ManagementClass repoClass = new ManagementClass("root\\VisualSVN", "VisualSVN_Repository", null);
ManagementObject userObject = userClass.CreateInstance();
userObject.SetPropertyValue("SID", sid);
ManagementObject permObject = permClass.CreateInstance();
permObject.SetPropertyValue("Account", userObject);
permObject.SetPropertyValue("AccessLevel", level);
ManagementObject repoObject = repoClass.CreateInstance();
repoObject.SetPropertyValue("Name", repository);
ManagementBaseObject inParams =
repoClass.GetMethodParameters("SetSecurity");
inParams["Path"] = "/trunk";
inParams["Permissions"] = new object[] { permObject };
ManagementBaseObject outParams =
repoObject.InvokeMethod("SetSecurity", inParams, null);
//Update in DB
var db = new DataMapSVNServiceDataContext();
if (level == AccessLevel.NoAccess) //If we are removing the user
{
var output = (db.repositories.Single(r => r.name == repository)).UserRepositoryRights.Single(u => u.User.Sid == sid);
if (output.isAdmin != null && !((bool)output.isAdmin)) //making sure DB owner isn't ever removed
db.UserRepositoryRights.DeleteOnSubmit(output);
}
if (level == AccessLevel.ReadWrite) //if we are adding the user
{
var add = new UserRepositoryRight
{
isAdmin = isAdmin,
User = db.Users.Single(u => u.Sid == sid),
repository = db.repositories.Single(r => r.name == repository)
};
db.UserRepositoryRights.InsertOnSubmit(add);
}
db.SubmitChanges();
}
Here everything looks ok, but it does not seem to be carrying over to the repo and adding the user to have ReadWrite (key value is 2) permissions on the created repo. The tail end of the method just saves the data to our websites databases to allow us to interface with it.
So, the root problem is if I create a repo via the web interface here, I get a 403 Forbidden error when trying to access it, but NO errors when creating and deleting it. Can anyone point me in the right direction here?
You should use VisualSVN Server PowerShell cmdlets instead of using the server's WMI provider. The WMI provider of VisualSVN Server can be considered as an internal API. It is not documented and is not intended to be used to build custom applications.
Old answer
If you don't get any errors when running the code, I guess that the access rule is set on path <repo>/trunk which simply does not exist in the youngest revision. You can try the script on some fresh testing repository which contains "/trunk" in it's root. Otherwise, you can simply change change the code string inParams["Path"] = "/trunk"; to inParams["Path"] = "/";.
VisualSVN Server allows you to setup path-based authorization rules on items (files and folders) that don't exist in youngest revision because these items can exist in earlier and newer revisions.
I want to create an alias record in Microsoft's DNS server to point AliasA to ComputerA. How can I do this programmatically?
I used WMI to do this, found an example on the web, and this is what it looked like.
private ManagementScope _session = null;
public ManagementPath CreateCNameRecord(string DnsServerName, string ContainerName, string OwnerName, string PrimaryName)
{
_session = new ManagementScope("\\\\" + DnsServerName+ "\\root\\MicrosoftDNS", con);
_session.Connect();
ManagementClass zoneObj = new ManagementClass(_session, new ManagementPath("MicrosoftDNS_CNAMEType"), null);
ManagementBaseObject inParams = zoneObj.GetMethodParameters("CreateInstanceFromPropertyData");
inParams["DnsServerName"] = ((System.String)(DnsServerName));
inParams["ContainerName"] = ((System.String)(ContainerName));
inParams["OwnerName"] = ((System.String)(OwnerName));
inParams["PrimaryName"] = ((System.String)(PrimaryName));
ManagementBaseObject outParams = zoneObj.InvokeMethod("CreateInstanceFromPropertyData", inParams, null);
if ((outParams.Properties["RR"] != null))
{
return new ManagementPath(outParams["RR"].ToString());
}
return null;
}
I don't think .NET has anything to provide access to these (all I can find in a bit of quick searching is references to proprietary libraries, controls, etc.), so you'll probably have to use the Win32 API via P/Invoke (though another possibility would be to do the job via WMI).
You'd start with DnsAcquireContextHandle, then (probably) DnsQuery to get a current record set, modify its contents to add your new alias, DnsReplaceRecordSet to have the DNS server use the new set of records, and finally DnsReleaseContextHandle to shut things down.
Of course, you'll need the right permissions on the server or none of this will work at all.