I'm using Microsoft Visual Studio to make a simple remote task manager for experience purposes.
I want to use Process.GetProcesses(string); but there is an access denied exception that won't allow me to get the remote computer process. In fact it is normal because we should authenticate using a user name and password, but how?
You may try to use WMI for this purpose
/// using System.Management;
// don't forget! in VS you may have to add a new reference to this DLL
ConnectionOptions op = new ConnectionOptions();
op.Username = "REMOTE_USER";
op.Password = "REMOTE_PASSWORD";
ManagementScope sc = new ManagementScope(#"\\REMOTE_COMPUTER_NAME\root\cimv2", op);
ObjectQuery query = new ObjectQuery("Select * from Win32_Process");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(sc, query);
ManagementObjectCollection result = searcher.Get();
foreach (ManagementObject obj in result)
{
if (obj["Caption"] != null) Console.Write(obj["Caption"].ToString() + "\t");
if (obj["CommandLine"] != null) Console.WriteLine(obj["CommandLine"].ToString());
}
For further details on Win32_Process class see MSDN.
hth
EDIT: Just read your post again, the steps described in my post only apply in a domain, I assume you work inside a workgroup. I'm sorry.
I recently ran into a similar issue when running Visual Studio as Administrator on Windows 7. It seems like permissions on remote machines and network shares are dropped (even in a domain!) if you elevate your program to run as local administrator, which will be the case if you run a program out of VS when VS is run as admin. This even happens if you have domain wide admin accounts.
Try the following:
Build the solution
Run it manually with your account which has hopefully
privileges on the remote computer from windows explorer, without elevation
If this helps, you could stop running VS as administrator. It worked out for me.
I'm pretty sure you need elevation to do this, or at least use a stronger user by impersonation
Related
I'm currently trying to launch a process on a remote machine using WMI in C#. The process reads and writes to a file that is stored on a separate server.
When I manually login to the remote machine, I can run the process and it all works fine.
However, when I try to launch the process on the remote from my local machine using WMI, I get the following error:
System.UnauthorizedAccessException: Access to the path '\\server\path\input.txt' is denied.
I've tried multiple connection options, but I'm not sure how to re-create the permissions that I seem to have when I login manually... What do I need to do?
Local machine code
static void LaunchRemoteProcess(string remoteMachine, string command)
{
ConnectionOptions connectionOptions = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
EnablePrivileges = true
};
var managementScope = new ManagementScope(string.Format(#"\\{0}\root\cimv2", remoteMachine), connectionOptions);
managementScope.Connect();
var managementPath = new ManagementPath("Win32_Process");
var objectGetOptions = new ObjectGetOptions();
var managementClass = new ManagementClass(managementScope, managementPath, objectGetOptions);
// Launch the command asynchronously
var inParams = managementClass.GetMethodParameters("Create");
inParams["CommandLine"] = command;
var outParams = managementClass.InvokeMethod("Create", inParams, null);
}
Remote machine code
string networkPath = #"\\server\path";
string inputFile = "input.txt";
string inputText = File.ReadAllText(Path.Combine(networkPath, inputFile));
string outputFile = "output.txt";
File.WriteAllText(Path.Combine(networkPath, outputFile), inputText);
Edit 1
I have already tried using the credentials of the user for which the process works if I log on to the remote machine manually and the process still fails with the same error:
ConnectionOptions connectionOptions = new ConnectionOptions
{
Username = "username",
Password = "password",
Authority = "ntlmdomain:COMPANYNAME.CO.UK,
EnablePrivileges = true
};
Am I missing something with regards to the Authority, Authentication, or Impersonation attributes?
Impersonation vs Delegation
Your WMI code uses impersonation, so the server side runs in the security context of the user who calls the code on the client. But this is only valid on the server itself, not for accessing e.g. a remote CIFS share (as in your case).
You have to use delegation.
First, change
Impersonation = ImpersonationLevel.Impersonate,
to
Impersonation = ImpersonationLevel.Delegate,
If you get an exception then, delegation does not yet work in your environment.
Check:
Calling user account: "Account is sensitive and cannot be delegated" must not be checked in the user properties (Active Directory Users and Computers)
server machine account: "Trust this computer for delegation to any service..." must be checked
local security policy on the server: "Enable computer and user accounts to be trusted for delegation" must include the calling user.
See
https://msdn.microsoft.com/en-us/library/aa389288%28VS.85%29.aspx
for further information on this topic.
Added: (see the comments below):
If Delegate is not an option in your environment (e.g. group policies do not allow for this, and you do not have the rights to change them), you may check some alternative ways.
You probably heard of psexec.
Or, what I did some years ago, and which runs in production in a enterprise environment on a few servers for many years very successfull:
I created a scheduled task which starts a program and set the technical user + password for this task. The task was configured for "run once in year 2200 :-)".
Then I wrote commands in a queue (I used a simple command file) and started the task from a remote machine.
Doing it this way, delegation is not required, since the scheduled task itself logs on as the technical user account ("logon as batch" privs are required).
As the reason states, the user id you are using on your PC does not seem to have access for to another computer's location (though it is a server, it is some other computer).
You may get access for your user id or use Impersonation to use an user id that already has access to the location.
Find more details here: https://msdn.microsoft.com/en-us/library/w070t6ka%28v=vs.110%29.aspx
Edited: Add user name password too. That may help.
I have a virtual machine with Active Directory that I want to connect to using .NET, I've already connected to an ubuntu machine running OpenLDAP but when connecting to AD it's not working smoothly.
The code I'm attempting to connect with is as follows:
var directoryEntry =
new DirectoryEntry("LDAP://192.168.1.1", #"EXAMPLE\Administrator", "Abc1234");
try
{
var test = directoryEntry.NativeObject;
}
catch (Exception e)
{
System.Diagnostics.Debug.WriteLine(e.Message);
}
Watching the locals window the variable directoryEntry's Guid, name etc says "Function evaluation timed out".
Then when it arrives at the try block it simply says "The server is not operational".
I've also tried this code, and it fails at the "ldap.bind" telling me that "the ldap-server is unavailable".
using (var ldap = new LdapConnection("192.168.1.1:389"))
{
ldap.AuthType = AuthType.Basic;
ldap.SessionOptions.ProtocolVersion = 3;
ldap.Bind(new NetworkCredential(#"EXAMPLE\Administrator", "Abc1234"));
}
I know the server is up and running, I know that they have a connection (machines can ping each other) but I can't figure out why it isn't working. Can any of you see if there are any flaws in the code? (and yes I've googled all of the errors and various questions about connecting to AD before asking this question but none of the solutions have worked).
If you domain name is 'example.com' and let say you have an organization unit (OU) called 'users'. This works perfectly fine for me.
However the machine where this code runs, is added to the AD domain and it runs with an AD user account. If you do not have a machine added to the same domain which you are querying, you may try "Run as" option (Shift + Right Click) to launch the program or visual studio.
public static List<string> GetAllUsers()
{
List<string> users = new List<string>();
using (DirectoryEntry de = new DirectoryEntry("LDAP://OU=Users,DC=example,DC=local"))
{
using (DirectorySearcher ds = new DirectorySearcher(de))
{
ds.Filter = "objectClass=user";
SearchResultCollection src = ds.FindAll();
foreach (SearchResult sr in src)
{
using (DirectoryEntry user = new DirectoryEntry(sr.Path))
{
users.Add(new string(user.Properties["sAMAccountName"][0].ToString()));
}
}
}
}
return users;
}
I tested your code (with changed domain / password...) in my own Active Directory test environment, it works. If I use a wrong password intentionally for testing purpose, I get "invalid credentials". Fine.
"The server is not operational" will be returned if LDAP is completely unavailable. So it seems that e.g. port 389 is not reachable.
Firewall ?
LDAP SSL (port 636) ??
If you do not have a machine added to the same domain which you are querying, you may try "Run as" option (Shift + Right Click) to launch the program or visual studio.
Yes, this was my first idea too as I saw this question. However, it seems that you will get another error in this case.
What I suggest: install WireShark, the network analyzer and check what is sent over the wire (assuming your AD is running on another machine).
WireShark helped me more than often to diagnose errors with AD, login, SMB or other protocols.
PS:
The answer from Ravi M Patel is a nice example of searching, I almost do the same in my own code.
Problem solved. I had two network adapters and adapter 1 had dhcp and the static ip I was attempting to connect was running on adapter 2. I simply gave adapter 1 the static adress and was able to connect that way, seemingly the code connects via adapter 1 per default. And Thanks for all the answers guys :)
I am working on doing a check for Firewalls. The following code quite easily checks the status of the default Windows Firewall:
INetFwMgr manager = GetFireWallManager();
bool isFirewallEnabled = manager.LocalPolicy.CurrentProfile.FirewallEnabled;
if (isFirewallEnabled == false)
{
Console.WriteLine("Firewall is not enabled.");
}
else
{
Consoe.WriteLine("Firewall is enabled.");
}
Console.ReadLine();
private static INetFwMgr GetFireWallManager()
{
Type objectType = Type.GetTypeFromCLSID(new Guid(firewallGuid));
return Activator.CreateInstance(objectType) as INetFwMgr;
}
The question then becomes: How do I find the status of a non-Windows Firewall?
If the Firewall is properly integrated, will the above check work just the same or is there a better method for doing this?
I have checked this post: C# Windows Security Center Settings and this post: C# - How to chceck if external firewall is enabled? but both proved relatively unhelpful.
I have been looking into the WMI API but it is pretty confusing so far, and the documentation via MSDN hasn't been too promising.
I have also tried messing around with SelectQuery but so far I have been unsuccessful.
Can anyone assist me in a new starting point or to where I might be able to find better documentation/instructions concerning 3rd Party Firewalls?
EDIT: Currently I am exploring further into WMI, specifically the class FirewallProduct as suggested by a post.
UPDATE 2: I have been testing the following snippet:
string wmiNameSpace = "SecurityCenter2";
ManagementScope scope;
scope = new ManagementScope(String.Format("\\\\{0}\\root\\{1}", "localhost", wmiNameSpace), null);
scope.Connect();
ObjectQuery query = new ObjectQuery("SELECT * FROM FirewallProduct");
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
But running this results in the following error:
Exception Invalid namespace and it points to line 39 (scope.Connect()). I would not be at all surprised if I have simply missed a parameter or formatted something improperly, I just don't know what it is.
UPDATE 3 Switching from SecurityCenter2 to SecurityCenter still yields the same invalid namespace error.
UPDATE 4 I moved the console app over to a different box (win7 not winserver08r2) and it properly reported back as expected. So it may be an issue with the VM that I currently have been testing on. Next step is to parse out active/inactive status
UPDATE 5 It was tested on another Server08 box and the same invalid namespace error appears. Using SecurityCenter instead of SecurityCenter2 does not resolve the issue. Is there some underlying security feature Windows Server OS's use to prevent tampering with Firewalls, or do Server OS's not come with a specific key set of WMI features?
According to Microsoft Q: How does Windows
Security Center detect third-party products and their status?
A:
Windows Security Center uses a two-tiered approach for detection
status. One tier is manual, and the other tier is automatic through
Windows Management Instrumentation (WMI). In manual detection mode,
Windows Security Center searches for registry keys and files that are
provided to Microsoft by independent software manufacturers. These
registry keys and files let Windows Security Center detect the status
of independent software. In WMI mode, software manufacturers determine
their own product status and report that status back to Windows
Security Center through a WMI provider. In both modes, Windows
Security Center tries to determine whether the following is true:
An antivirus program is present.
The antivirus signatures are up-to-date.
Real-time scanning or on-access scanning is turned on for antivirus programs.
For firewalls, Windows Security Center
detects whether a third-party firewall is installed and whether the
firewall is turned on or not.
So you can use the WMI to determine if a third-party firewall is installed, using the FirewallProduct class, sometime ago I wrote an article about this topic which explain how obtain this info using the WMI.
Getting the installed Antivirus, AntiSpyware and Firewall software using Delphi and the WMI.
Try this sample C# to get the current Third-party firewall name and state installed.
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace GetWMI_Info
{
class Program
{
static void Main(string[] args)
{
try
{
//select the proper wmi namespace depending of the windows version
string WMINameSpace = System.Environment.OSVersion.Version.Major > 5 ? "SecurityCenter2" : "SecurityCenter";
ManagementScope Scope;
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\{1}", "localhost", WMINameSpace), null);
Scope.Connect();
ObjectQuery Query = new ObjectQuery("SELECT * FROM FirewallProduct");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
Console.WriteLine("{0,-35} {1,-40}","Firewall Name",WmiObject["displayName"]);
if (System.Environment.OSVersion.Version.Major < 6) //is XP ?
{
Console.WriteLine("{0,-35} {1,-40}","Enabled",WmiObject["enabled"]);
}
else
{
Console.WriteLine("{0,-35} {1,-40}","State",WmiObject["productState"]);
}
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}
I'm using WMI inside c# to get a list of users currently "logged in" to a machine:
ManagementScope ms = new ManagementScope(ManagementPath.DefaultPath);
var q = new SelectQuery("Win32_LoggedOnUser");
using (var query = new ManagementObjectSearcher(ms, q)) {
using (var results = query.Get()) {
foreach (var r in results) {
using (var o = new ManagementObject(r["Dependent"].ToString())) {
var logonType = o["LogonType"];
if (logonType == "2") {
// Interactive user is logged in, retrieve the name
using (var userObj = new ManagementObject(r["Antecedent"].ToString())) {
name = userObj["Name"].ToString();
}
}
...
This works great, but it seems that in some cases even after the user logs out, WMI still reports it as being logged in. One particular case is when that user accesses a network share during the session.
Is there anyway around this? Perhaps a way to test a session to see if it was created as a share or if it's active?
Any tips would be greatly appreciated.
Even though the user has logged off, because you accessed another computer's files remotely, the connection remains open for a period of time.
https://superuser.com/questions/173535/what-are-close-wait-and-time-wait-states
Look under Run > cmd > netstat -a. You should see a connection called microsoft-ds after you have established a connection through Windows Explorer to another computer. This is the service that Microsoft uses for file transfers, among other things. If you see a TIME_WAIT or CLOSE_WAIT, the connection is still open even if window you used to access the files is closed.
You can check this programmatically by using "handle.exe", a tool provided by Microsoft that is a part of Sysinternals, that will be able to provide information on which part of the hive is still active. This should include Registry Keys, ports, the works.
http://technet.microsoft.com/en-us/sysinternals/bb896655.aspx
WMI may be reporting that the user is still logged in because a port or connection has not been closed that was initiated by that user. This type of thing has caused us a few headaches, so we use handle.exe to dump anything keeping the hive open for a user and then systematically kill/close all of it before we do any profile maintenance (as an automation).
Of course, rebooting the computer always works. =)
I am trying to connect to IIS programmatically. I find there are a ton of examples online, but I can't seem to get any to work and have tried quite a few variations
Every time I try the following code the object that is returned has this error for each property: ..."threw an exception of type 'System.Runtime.InteropServices.COMException'"
using System.DirectoryServices;
String serverName = "serverName";
DirectoryEntry IIS = new DirectoryEntry("IIS://" + serverName + "/W3SVC");
IIS = new DirectoryEntry("IIS://" + serverName + "/W3SVC", "administrator", "mypassword");
IIS = new DirectoryEntry("IIS://" + serverName + "/W3SVC/1/ROOT", "administrator", "mypassword");
I am using Windows Directory user accounts and I have a bunch of sites running on IIS. I am trying this code on a windows xp development machine trying to connect to a windows 2008 Server with IIS 7. Anyone know what I am doing wrong?
Your account may not have launch permissions on the COM object wrapping the IIS calls. You may need to try adding yourself to the admin group on the box hosting IIS to get this to work.
Make sure you have the IIS6 management compatibility feature installed on the target server- you can't do remote management via ADSI on IIS7 without it.
Make sure that IIS is installed on your client machine - your program will throw a System.Runtime.InteropServices.COMException if it isn't installed.
This counts when you are looking at IIS on a remote machine too, the machine running your app will need IIS too.
EDIT: Also, I've recently discovered an assembly specifically for connecting to and configuring IIS7 - Microsoft.Web.Administration. Might be worth looking at whether you have access to this (or can get access, it should be on the machine with IIS7 in any case) and see what it can do. I'm afraid I've not used it myself, so I can't tell you if it'll do what you want, but it's another option to look into.
Finally, there's the option of System.Management and WMI scripts.
Dim scope As New Management.ManagementScope("\\" & server & "\root\MicrosoftIISv2")
scope.Connect()
Dim query As New Management.ObjectQuery("select * from IISWebVirtualDirSetting")
Dim searcher As New Management.ManagementObjectSearcher(scope, query)
For Each obj As Management.ManagementObject In searcher.Get()
DoSomethingWith(obj)
Next
The list of properties on obj is at http://msdn.microsoft.com/en-us/library/ms525005.aspx, there's also some more different queries you can run - just dig around on MSDN for more.