How to add a DNS alias programmatically? - c#

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.

Related

C# SCCM - Client Action

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;

Sharing Folder API

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.

Check service status remotely

I need to grab the service status (running, stopped) remotely using the credentials of the user running my executable(winform).
Would WMI be the best method?
I need this query to work on windows(7,2003,2008,2012).Can someone point me in the right direction.
if (RemoteOSversion.Contains("Windows 7"))
{
var Windows7Query = xdoc.Elements("OS").Elements("Windows7");
foreach (var myServices in Windows7Query)
{
var ServicesQuery = myServices.Elements("Services");
foreach (var ServiceName in ServicesQuery)
{
var ServiceOutput = ServiceName.Value;
}
}
}
ServiceOutput is the service name. I need to check if this service is running/stopped remotely using the same credentials of the user running my exe
It's REALLY straightforward with WMI
var sc = new ServiceController(ServiceName, MachineName);
string result = sc.Status.ToString();
Yes, use WMI.
WMI has a query language called WQL, which is similar to to SQL. You can execute these in C# using the System.Management classes.
To work with WMI you need to add a reference to the System.Management assembly. Then you can set up a connection (i.e. ManagementScope) to the WMI Provider as follows:
ConnectionOptions options = new ConnectionOptions();
// If we are connecting to a remote host and want to
// connect as a different user, we need to set some options
//options.Username =
//options.Password =
//options.Authority =
//options.EnablePrivileges =
// If we are connecting to a remote host, we need to specify the hostname:
//string providerPath = #"\\Hostname\root\CIMv2";
string providerPath = #"root\CIMv2";
ManagementScope scope = new ManagementScope(providerPath, options);
scope.Connect();
You can read more about WMI at Microsoft Docs and work around at working-with-windows-services-using-csharp-and-wmi.

Visual-SVN Server C# code not properly adding user permissions (version 2.7.2)

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.

what are registry settings to enable TCP on SQL Server 2005 and 2008?

I want to programatically enable TCP connections on SQL Server. I believe we can achieve this by modifying registry entries and restarting SQL Server service. What registry should I edit?
Unless you have a good reason for modifying the registry directly, I suggest you consider using WMI. WMI will provide you with a more version agnostic implementation. WMI can be accessed through the System.Management namespace. You could have code that looks something like this.
public void EnableSqlServerTcp(string serverName, string instanceName)
{
ManagementScope scope =
new ManagementScope(#"\\" + serverName +
#"\root\Microsoft\SqlServer\ComputerManagement");
ManagementClass sqlService =
new ManagementClass(scope,
new ManagementPath("SqlService"), null);
ManagementClass serverProtocol =
new ManagementClass(scope,
new ManagementPath("ServerNetworkProtocol"), null);
sqlService.Get();
serverProtocol.Get();
foreach (ManagementObject prot in serverProtocol.GetInstances())
{
prot.Get();
if ((string)prot.GetPropertyValue("ProtocolName") == "Tcp" &&
(string)prot.GetPropertyValue("InstanceName") == instanceName)
{
prot.InvokeMethod("SetEnable", null);
}
}
uint sqlServerService = 1;
uint sqlServiceStopped = 1;
foreach (ManagementObject instance in sqlService.GetInstances())
{
if ((uint)instance.GetPropertyValue("SqlServiceType") == sqlServerService &&
(string)instance.GetPropertyValue("ServiceName") == instanceName)
{
instance.Get();
if ((uint)instance.GetPropertyValue("State") != sqlServiceStopped)
{
instance.InvokeMethod("StopService", null);
}
instance.InvokeMethod("StartService", null);
}
}
}
This code assumes a project reference to System.Management.dll and the following using statement:
using System.Management;
The Sql Protocols blog has an article that goes into some detail as to what the above code is doing.
Note: If a firewall is blocking the port(s) you will still be unable to access the server via TCP.
Take a look at HKLM\SOFTWARE\Microsoft\Microsoft SQL Server\MSSQL10.MSSQLSERVER\MSSQLServer\SuperSocketNetLib\Tcp hive. There are keys like Enabled, ListenOnAllIPs and a list of IP addresses to listen on.

Categories