How to close Apps only in windows by C#? - c#

I try to close running user apps (Application Programs) in windows by C# like word, forxitReader, whatsApp , etc.
I try to make a desktop App to secure an online exam like Safe Exam Browser.
My senario is:
1 - get the process of them only as a list (not System programs.)
2 - Kill them by Process.kill();
But I don't know how to do the first step.
How can I get a list of these programs only?

I understand you need to check the process owner to know if its a system or non-system process, and to my knowledge there is no way to get the process owner via .NET api, but you can get active process and their owner in powershell via
Get-Process -IncludeUserName
Now doing this in C# is a bit tricky because out of the box, the Process class is lacking and making CLI calls is complicated, but I was able to write this solution with only Cake.Powershell nuget package.
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Management.Automation;
using (var powershell = PowerShell.Create())
{
List<string> illegalProcesses = new List<string>() { "dota2" };
powershell.AddScript("Get-Process -IncludeUserName");
var results = powershell.Invoke();
var nonSystemResults = results.Where(x => !x.Properties["Username"].Value.ToString().StartsWith("NT AUTHORITY"));
foreach (var result in results)
{
var processOwner = result.Properties["Username"].Value as string;
if (processOwner != null && !processOwner.StartsWith("NT AUTHORITY"))
{
var processName = result.Properties["Name"].Value as string;
if (illegalProcesses.Contains(processName))
{
var processID = result.Properties["ID"].Value as int?;
var doomedProcess = Process.GetProcessById(processID.Value);
doomedProcess?.Kill();
}
}
}
}
I've made the assumption that system processes are the ones owned by users that start with NT AUTHORITY but you might find for your particular use case you want different filters. That said there are tons of properties you can get on processes that should allow you to write your own filters.

Related

How to check a unit (C:) dirty bit using C#

I know it is possible to check the dirty bit status of a unit by running the command fsutil dirty query c: from an elevated prompt. On windows 10 it is also possible to know if C: dirty bit is set without the need of admin privileges simply going into the System and Maintenance page, if dirty bit is set there will be an advice telling it is necessary to reboot in order to repair a damage in the file sistem. How could the dirty bit status (of any unit or even only C:) be checked from a C# program?
Thanks in Advance to anyone will answer
You can get this information using a WMI query
var q = new ObjectQuery("Select * FROM Win32_Volume");
using (var searcher = new ManagementObjectSearcher(q))
using (var moc = searcher.Get())
{
foreach (ManagementObject volume in moc)
{
String label = (String)volume["Label"];
Boolean dirtyBitSet = (Boolean)(volume["DirtyBitSet"] ?? false);
Console.WriteLine($"{label} => {dirtyBitSet}");
}
}
You should add a reference to the System.Management assembly and also run your program using an elevated prompt

C# - How do I find the process id of a separate program?

I need the process ID for a program that is already running on the computer. How would I go about doing this? (The process isn't started from Process.Start())
Use GetProcessesByName or just GetProcesses with a bit of LINQ, depending on how you intend to identify the program.
using System;
using System.Diagnostics;
using System.ComponentModel;
void Example()
{
// Get all processes running on the local computer.
var localProcesses = Process.GetProcesses();
//Get all processes with a name that contain "Foo" in the title
var fooProcess = localProcesses.Where(p => p.MainWindowTitle.Contains("Foo"));
// Get all instances of Notepad running on the local computer.
var notepad = Process.GetProcessesByName("notepad").Single();
}
Once you have the Process object, you can get its ID with the Id property.
var id = process.Id;

TestStack/White API

I'm trying to automate an application using TestStack/White API (Which is based on Microsoft's UI Automation library).
The problem is the following:
At a certain point of automation, I have to deal with an "Dialog" window, which looks to be a separate process, if i look at "Windows Task Manager". But no matter how i try to access the "Dialog Window" (Class, ID, Text, ControlType, etc.) I'm not able to access it.
You can find the UISpy image and code below...
Using UISpy - Dialog Information
using (var DISCLAIMER_App = Application.Attach(#"PathToExecutable"))
using (var DISCLAIMER_Window = DISCLAIMER_App.GetWindow(SearchCriteria.ByClassName("#32770"), InitializeOption.NoCache))
{
var IAccept_button = DISCLAIMER_Window.Get<Button>(SearchCriteria.ByText("I accept"));
IAccept_button.Click();
}
# I've tried also Application.Launch, Application.AttachOrLaunch.
# I also looked to be sure that the Dialog window is a separated process and doesn't belong to any parent window.
Any suggestions?
Found the Solution, had to use "ProcessStartInfo()" and pass the return data to "Application.AttachOrLaunch()":
var psi = new ProcessStartInfo(#"PathToExecutable");
using (var DISCLAIMER_App = Application.AttachOrLaunch(psi))
Source: http://techqa.info/programming/tag/white?after=24806697

How to change DCOM config identity programmatically

Is there any way to get the information about Launching identity of DCOM application programmatically. See the picture attached to understand what i mean.
I tried to use WMI
ManagementObjectSearcher s = new ManagementObjectSearcher(new ManagementScope(#"\\.\root\cimv2"), new ObjectQuery(
"select * from Win32_DCOMApplicationSetting where AppID='{048EB43E-2059-422F-95E0-557DA96038AF}'"))
ManagementObjectCollection dcomSett = s.Get();
var value = dcomSett.Cast<ManagementObject>().ToArray()
[0].Properties["RunAsUser"].Value;
but "RunAsUser" property was empty.
Also tried Interop.COMAdmin
COMAdmin.COMAdminCatalogClass catalog = (COMAdmin.COMAdminCatalogClass)new COMAdmin.COMAdminCatalog();
(COMAdmin.COMAdminCatalogCollection)catalog.GetCollection("Applications")
in this way i managed to get applications which are listed under the "COM+ Applications" node in the "Component Services" snap-in of MMC:
I'm new in COM, DCOM, COM+ stuff and sure that i missed something important.
After a while i found out why i used to get NULL in the first approach (ManagementObject).
You will receive:
NULL if identity is currently set to The launching user
"Interactive User" in case of "The interactive user"
some string with username in case of third option (see the first picture)
But still i need a way to change identity for items like Microsoft PowerPoint Slide under DCOM Config node in MMC.
In the DCOM config, if you are using a specific user for the identity and you want to update the password via code, you need to update it in the Local Security Authority (LSA). This is possible with Windows API calls. MS has some sample code for a utility called dcomperm that does it, and you can see how they implemented in C++. You could make the same calls in C#. See the SetRunAsPassword method here. They are using the method LsaOpenPolicy to get a handle to the policy and calling LsaStorePrivateData to update the password. Then they are adding "login as a batch job" access to the account (but that shouldn't be necessary if you are only changing the password).
This sample code on pinvoke.net looks like it is making the requisite calls, except for the optional part about granting the login as a batch job permission. Note the "key" in the LSA is in the format SCM:{GUID-of-DCOM-object} Example: SCM:{00000000-0000-0000-0000-000000000000}
Oh, and I should mention as an aside that if you wanted to change the RunAs user itself (i.e. the username), you'd need to also update that in the windows registry directly (AFAIK that's the only way to do it). DCOM entries are stored under HKLM\SOFTWARE\Classes\AppID. You can do that with WMI or just use the Registry classes in .NET.
This is very simple , you can get APPId from
Computer\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\AppID\{048EB43E-2059-422F-95E0-557DA96038AF}
using
(RegistryKey dcomPPTIdentity = Registry.LocalMachine.OpenSubKey("Software\\Classes\\AppID\\{048EB43E-2059-422F-95E0-557DA96038AF}"))
{
if (dcomPPTIdentity != null)
{
Registry.SetValue(dcomPPTIdentity.ToString(), "RunAs", "userName");
}
}
I am using COMAdmin DLL successfully. Try something like this:
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = COMAppCollectionInUse.Item[i];
if (application.Name == "Your COM+ application name")
{
application.Value["Identity"] = "nt authority\\localservice"; // for example
}
}
This works for me on my development server. Keep in mind, it is run against the server directly on the server
using COMAdmin;
using System;
namespace ComComponents
{
class Program
{
static void Main(string[] args)
{
COMAdminCatalog catalog = new COMAdminCatalog();
COMAdminCatalogCollection applications = catalog.GetCollection("Applications");
applications.Populate();
for (int i = 0; i < applications.Count; i++)
{
COMAdminCatalogObject application = applications.Item[i];
Console.WriteLine(application.Name);
Console.WriteLine(application.Value["Identity"]);
}
Console.WriteLine("Press any key to continue...");
Console.ReadKey();
}
}
}

Get install date of a ClickOnce program?

I'm building an asset tracker of sorts. I'm already searching the registry to get a list of all software titles, publishers, install dates and it's working great. However, programs installed with ClickOnce don't store the install date in the registry(at least not that I can find).
I know I should eb able to use WMI to get the install date, but this is very slow. Also, per this post: Get installed applications in a system
"using the WMI Win32_Product class is a bad idea if you plan to run this query repeatedly"
So, without using WMI, how can I get the install date of ClickOnce programs? I know the information is available somehow because the date is inside of Add/Remove programs.
As ClickOnce application installs per user, you can find uninstall information (what app wizard shows you) by follwing path in registry:
HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Uninstall\5f7eb300e2ea4ebf
This 'Uninstall' has unique hash subkeys, to find your app you can iterate through these keys and filter for example by DisplayName like this:
private RegistryKey GetUninstallRegistryKeyByProductName(string productName)
{
var subKey = Registry.CurrentUser.OpenSubKey(#"Software\Microsoft\Windows\CurrentVersion\Uninstall");
if (subKey == null)
return null;
foreach (var name in subKey.GetSubKeyNames())
{
var application = subKey.OpenSubKey(name, RegistryKeyPermissionCheck.ReadWriteSubTree, RegistryRights.QueryValues | RegistryRights.ReadKey | RegistryRights.SetValue);
if (application == null)
continue;
foreach (var appKey in application.GetValueNames().Where(appKey => appKey.Equals("DisplayName")))
{
if (application.GetValue(appKey).Equals(productName))
return application;
break;
}
}
return null;
}
This method returns RegistryKey, then you can get 'DisplayVersion' key value:
var key = GetUninstallRegistryKeyByProductName("myApp");
var version = key.GetValue("DisplayVersion");
Update
Regarding Install date, Try getting last write time of registry key (Getting last write time of "DisplayVersion" is what you need). It looks like there's no managed wrapper for getting this, so use P/Invoke. You need to call RegQueryInfoKey.

Categories

Resources