Find Terminal Services user's document folder - c#

I'm trying to allow users to use their local scanners with a Terminal Server via an IIS aspx page containing a browser plugin. The plugin can scan files and pass the data to an aspx page which uploads files to the server.
I'm using HttpContext.Current.User.Identity.Name to get a string containing the name of the remote user. How can I find the user's documents folder on the terminal server?

Made a bit of progress. Here's a way to find a the path for a known username using Powershell:
$user = Get-WmiObject Win32_UserAccount | Where-Object { $_.Name -eq 'known_username' }
cd 'HKLM:\software\Microsoft\Windows NT\CurrentVersion\ProfileList'
$key = Get-Item $user.SID
$saveLocation = $key.GetValue("ProfileImagePath")
Here's the C# version:
string loginName = HttpContext.Current.User.Identity.Name;
Regex r = new Regex(#"\w+[\\]");
string userName = r.Replace(loginName, "");
throw new System.ArgumentException("Debug: '" + HttpContext.Current.User.Identity.IsAuthenticated.ToString() +"'", "userName");
SelectQuery sQuery = new SelectQuery("Win32_UserAccount", "name='" + userName + "'");
ManagementObjectSearcher mSearcher = new ManagementObjectSearcher(sQuery);
string sid = "";
foreach (ManagementObject mObject in mSearcher.Get())
{
sid = mObject["SID"].ToString();
break; //mSearcher.Get() is not indexable. Behold the hackyness!
}
string saveLocation = Microsoft.Win32.Registry.GetValue(
"HKEY_LOCAL_MACHINE\\Software\\Microsoft\\Windows NT\\CurrentVersion\\ProfileList\\" + sid,
"ProfileImagePath", null).ToString();
C# is not my native tongue; there are probably methods of accomplishing this that are less blunt. But it does work.

Related

Connecting to WMI Remotely with C# to a non-domain PC not working

I use the Microsoft.Management.Infrastructure namespace to connect to remote computers to get WMI information and it works. But when I try to connect to a non-domain PC it does not work. Can anyone pinpoint what I am doing wrong.
Here is the code:
string computer = "Computer_B";
string domain = "WORKGROUP";
string username = ".\\LocalAdminUserName";
string plaintextpassword;
Console.WriteLine("Enter password:");
plaintextpassword = Console.ReadLine();
SecureString securepassword = new SecureString();
foreach (char c in plaintextpassword)
{
securepassword.AppendChar(c);
}
CimCredential Credentials = new
CimCredential(PasswordAuthenticationMechanism.Default, domain,
username,securepassword);
WSManSessionOptions SessionOptions = new WSManSessionOptions();
SessionOptions.AddDestinationCredentials(Credentials);
CimSession Session = CimSession.Create(computer, SessionOptions);
var allVolumes = Session.QueryInstances(#"root\cimv2", "WQL", "SELECT * FROM Win32_LogicalDisk");
// Loop through all volumes
foreach (CimInstance oneVolume in allVolumes)
{
Console.Writeline(oneVolume.CimInstanceProperties["SystemName"].Value.ToString());
}
I am not sure what to take as paramaters for domain and username for a local computer. I have already done/tryed the following:
run winrm quickconfig on the remote local computer
use PasswordAuthenticationMechanism.Negotiate cause I have read Kerberos only
works for domain users and password
added the computer I run the code on to the TrustedHosts on the local computer with winrm config. Also tryed adding * to the TrustedHosts
Used for username="computer_B\LocalAdminUserName". I have also tryed with domain=""
Any suggestions what I am doing wrong?
The error I keep getting is: WinRM cannot process the request. The following error with error code 0x8009030e occurred while using Negotiate authentication: A specified logon session does not exist. It may already have been terminated.
This can occur if the provided credentials are not valid on the target server, or if the server identity could not be verified. If you trust the server identity, add the server name to the TrustedHosts list, and then retry the request. Use winrm.cmd to view or edit the TrustedHosts list. Note that computers in the TrustedHosts list might not be authenticated. For more information about how to edit the TrustedHosts list, run the following command: winrm help config.
Try out the code below, this is working on impersonation logic.
ConnectionOptions cOption = new ConnectionOptions();
ManagementScope scope = null;
Boolean isLocalConnection = isLocalhost(machine);
if (isLocalConnection)
{
scope = new ManagementScope(nameSpaceRoot + "\\" + managementScope, cOption);
}
else
{
scope = new ManagementScope("\\\\" + machine + "\\" + nameSpaceRoot + "\\" + managementScope, cOption);
}
if (!String.IsNullOrEmpty(ACTIVE_DIRECTORY_USERNAME) && !String.IsNullOrEmpty(ACTIVE_DIRECTORY_PASSWORD) && !isLocalConnection)
{
scope.Options.Username = ACTIVE_DIRECTORY_USERNAME;
scope.Options.Password = ACTIVE_DIRECTORY_PASSWORD;
}
scope.Options.EnablePrivileges = true;
scope.Options.Authentication = AuthenticationLevel.PacketPrivacy;
scope.Options.Impersonation = ImpersonationLevel.Impersonate;
scope.Connect();

Invoke RenamePrinter as a non-administrator user

I'm trying to rename a printer using WMI in C#. I can run queries to select printers, but when I try to invoke the RenamePrinter method, I get an Access Denied result. I've tried running this application as administrator and creating a manifest, but I can't seem to invoke this method unless I'm actually running under the administrator account.
var oSearcher = new ManagementObjectSearcher(oMs, oQuery);
ManagementObjectCollection oReturnCollection = oSearcher.Get();
foreach (ManagementObject oReturn in oReturnCollection)
{
var objectClass = new ManagementClass("Win32_Printer");
var inParams = objectClass.GetMethodParameters("RenamePrinter");
inParams["NewPrinterName"] = "..."; // something
ManagementBaseObject oResult = oReturn.InvokeMethod("RenamePrinter", inParams, null);
var result = oResult["returnValue"]; // 5 = Access Denied
Is there some way I can invoke RenamePrinter under a normal user's account -- even if it means running as administrator?
I've been trying to do this, and I've found that I can't do this with certain network printers, but with local printers it works.
What I did was launch PowerShell as local admin and run it from there:
public void RenamePrinter(string strCurrentName, string strNewPrinterName)
{
var newProcessInfo = new System.Diagnostics.ProcessStartInfo
{
FileName = #"C:\Windows\SysWOW64\WindowsPowerShell\v1.0\powershell.exe",
Verb = "runas",
CreateNoWindow = true,
Arguments = "-Command \"$printer = get-wmiobject win32_printer | where { $_.Name -eq '" + strCurrentName + "' }; $printer.RenamePrinter('" + strNewPrinterName + "')\""
};
System.Diagnostics.Process.Start(newProcessInfo);
}
I receive the same "Access Denied" error when I attempt this with network printers (maybe it's a driver thing? I don't know) but this works for local printers.

Get Mapped Network drives from remote machine in C#

I want to list mapped network drives in remote machine using WMI C#.. I am using following code
ConnectionOptions connectionOptions = new ConnectionOptions();
connectionOptions.Username = "myAdminUser";
connectionOptions.Password = "Password";
connectionOptions.Impersonation = ImpersonationLevel.Impersonate;
ManagementScope Scope = new ManagementScope(#"\\" + "myClientMachine" + #"\root\cimv2", connectionOptions);
Scope.Connect();
ManagementObjectSearcher win32Drives = new ManagementObjectSearcher(Scope,
new ObjectQuery(#"SELECT Name,UserName FROM Win32_NetworkConnection'"));
foreach (ManagementObject DriveData in win32Drives.Get())
{
string drivePath = (string)DriveData["Name"];
string userName = (string)DriveData["UserName"];
}
I am running this code in my Server Machine with Admin Credentials to get mapped drives from
my Client Machine... this code returns 0 results when I use Admin credentials .. but at the same time when I use my client user credentials it returns mapped drives for the client user.
Here, my question is, is there any way to get all the mapped drives in client Machine for the all the users?
Yes you can utilize the winmgmts queries and retrieve them from a scripted scan of the computer via vbscript
'Define variables, constants and objects
strComputer="<remote machine here>"
Const HKEY_USERS = &H80000003
Set objWbem = GetObject("winmgmts:")
Set objRegistry = GetObject("winmgmts://" & strComputer & "/root/default:StdRegProv")
Set objWMIService = GetObject("winmgmts:" & "{impersonationLevel=impersonate}!\\" & strComputer & "\root\cimv2")
'Go and get the currently logged on user by checking the owner of the Explorer.exe process.
Set colProc = objWmiService.ExecQuery("Select Name from Win32_Process" & " Where Name='explorer.exe' and SessionID=0")
If colProc.Count > 0 Then
For Each oProcess In colProc
oProcess.GetOwner sUser, sDomain
Next
End If
'Loop through the HKEY_USERS hive until (ignoring the .DEFAULT and _CLASSES trees) until we find the tree that
'corresponds to the currently logged on user.
lngRtn = objRegistry.EnumKey(HKEY_USERS, "", arrRegKeys)
For Each strKey In arrRegKeys
If UCase(strKey) = ".DEFAULT" Or UCase(Right(strKey, 8)) = "_CLASSES" Then
Else
Set objSID = objWbem.Get("Win32_SID.SID='" & strKey & "'")
'If the account name of the current sid we're checking matches the accountname we're looking for Then
'enumerate the Network subtree
If objSID.accountname = sUser Then
regpath2enumerate = strkey & "\Network" 'strkey is the SID
objRegistry.enumkey hkey_users, regpath2enumerate, arrkeynames
'If the array has elements, go and get the drives info from the registry
If Not (IsEmpty(arrkeynames)) Then
For Each subkey In arrkeynames
regpath = strkey & "\Network\" & subkey
regentry = "RemotePath"
objRegistry.getstringvalue hkey_users, regpath, regentry, dapath
wscript.echo subkey & ":" & vbTab & dapath
Next
End If
End If
End If
Next
http://gallery.technet.microsoft.com/scriptcenter/3dd6af3e-edfa-4581-bc35-805314f26bb8
Or you can utilize the C# version:
http://bytes.com/topic/net/answers/170583-list-mapped-drives-remote-machine

Execute a process in a remote machine using WMI

I want to open process pon remote machine, this remote machine is inside local network.
I try this command and in the remote machine nothing happen, this user that i connect with have administrators rights.
Both machines running Windows 7
static void Main(string[] args)
{
try
{
//Assign the name of the process you want to kill on the remote machine
string processName = "notepad.exe";
//Assign the user name and password of the account to ConnectionOptions object
//which have administrative privilege on the remote machine.
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = #"MyDomain\MyUser";
connectoptions.Password = "12345678";
//IP Address of the remote machine
string ipAddress = "192.168.0.100";
ManagementScope scope = new ManagementScope(#"\\" + ipAddress + #"\root\cimv2", connectoptions);
//Define the WMI query to be executed on the remote machine
SelectQuery query = new SelectQuery("select * from Win32_process where name = '" + processName + "'");
object[] methodArgs = { "notepad.exe", null, null, 0 };
using (ManagementObjectSearcher searcher = new
ManagementObjectSearcher(scope, query))
{
foreach (ManagementObject process in searcher.Get())
{
//process.InvokeMethod("Terminate", null);
process.InvokeMethod("Create", methodArgs);
}
}
Console.ReadLine();
}
catch (Exception ex)
{
//Log exception in exception log.
//Logger.WriteEntry(ex.StackTrace);
Console.WriteLine(ex.StackTrace);
}
}
you are not opening a process with that code but you are enumerating all the running process named "iexplore.exe" and close them.
I think an easier, better way is to use SysInternals PsExec or the Task Scheduler API
If you want to use WMI your code should look like this:
object theProcessToRun = { "YourFileHere" };
ManagementClass theClass = new ManagementClass(#"\\server\root\cimv2:Win32_Process");
theClass.InvokeMethod("Create", theProcessToRun);
----------In reply to your comment------------------
First of all you need to change your attitude and approach to coding and read the code that your are copy/pasting.
Then you should study a little more about programming languages.
No I will not write the code for you. I gave you an hint to point to the right direction. now it is your turn to develop it. Have fun!!
This is script that i did for my company before this using vbs script. can search the net to convert it to C# or etc. Fundamental of the steps and how to start a service using WMI. Have a nice coding and have fun.
sUser = "TESTDomain\T-CL-S"
sPass = "Temp1234"
Set ServiceSet = GetObject("winmgmts:").ExecQuery("Select * from Win32_Service where Name = 'netlogon'")
For Each Service In ServiceSet
Service.StopService
Service.Change "netlogon",Service.PathName, , ,"Automatic",false,sUser,sPass
Service.StartService
Next
Set Service = Nothing
Set ServiceSet = Nothing

wmi c#. copy file from remote machine

I use mgmtclassgen.exe and get wrapper(DataFile.cs) class for CIM_DataFile wmi class. Code below works perfect on localhost (without filling credentionals), but when I connect to remote machine variable returnResult=9 (Invalid object). But size of variable dataFileCollection=1
var _connectionOptions = new ConnectionOptions();
_connectionOptions.Username = "username";
_connectionOptions.Password = "password";
_connectionOptions.Authority = String.Format("ntlmdomain:{0}", "DOMAIN");
var _managementScope = new ManagementScope(String.Format("\\\\{0}\\root\\cimv2",
"RemotePCName"), _connectionOptions);
var dataFileCollection = DataFile.GetInstances(_managementScope,
#"Name = 'C:\\Windows\\System32\\mapisvc.inf'";
var tempFilePath = "c:\\temp.txt");
if (dataFileCollection.Count > 0)
{
foreach (var dataFile in dataFileCollection.Cast<DataFile>())
{
var returnResult = dataFile.Copy(tempFilePath);
if (File.Exists(tempFilePath))
{
List<string> lines = File.ReadAllLines(tempFilePath).ToList();
File.Delete(tempFilePath);
}
}
}
try adjusting your management scope differently
Maybe you could try it like:
ManagementObjectSearcher searcher =
new ManagementObjectSearcher(
"\\\\" + strComputer + "\\root\\CIMV2",
"SELECT * FROM Win32_PerfFormattedData_MSSQLSERVER_SQLServerDatabases");
where strComputer is the name of the remote pc and Win32_Perf... the class you're trying to query. This works for me, as it is in a local network, though I am not certain where your remote machine is located.
You could as well to go http://www.microsoft.com/en-us/download/details.aspx?id=8572 which is a WMI-query generator by Microsoft. This allows you to generate query's in either C#, VB, and VB scripts. While setting the connection properties.
Might be worth a shot.

Categories