Hi i've wrote this method in C# that checks all windows processes for digital signatures. Howver, it tells me that File doesn't contain a definiton for GetDigitalSignatures.
void DriverCheck()
{
Process[] processes = Process.GetProcesses();
foreach (Process process in processes)
{
try
{
// Check if the process has a main module
if (process.MainModule != null)
{
// Check if the main module has a digital signature
bool isSigned = File.GetDigitalSignatures(process.MainModule.FileName).Length > 0;
if (isSigned)
{
// The main module is signed
// You can also get the certificate that was used to sign the file using the following code:
}
else
{
// The main module is not signed
}
}
}
catch (System.ComponentModel.Win32Exception)
{
// The process does not have a main module
}
}
}
can someone help me?
I tried finding a namespace that contains those but didn't suceed.
You can try something like this.
using System;
using System.IO;
using System.Windows.Forms; // I have this here, because I wanted to make a WinForm app
using System.Security.Cryptography.X509Certificates;
// rest of the code - form.load, checking the signature
// on button click, displaying the info in a multiline textbox, etc
string curFile = txtPath.Text.Trim(); // I'm reading the path from a textbox
if(File.Exists(curFile))
{
try
{
byte[] fileBytes = File.ReadAllBytes(curFile);
X509Certificate cert = new X509Certificate(fileBytes);
byte[] signature = cert.GetRawCertData();
string extraInfo = "Subject: " + cert.Subject + "\r\n------\r\nIssuer: " + cert.Issuer;
txtResult.Text = extraInfo;
} catch (Exception ex)
{
txtResult.Text = DateTime.Now.ToString("HH:mm:ss") + "\r\nException: " + ex.Message;
}
} else
{
txtResult.Text = "Signature not found";
}
This is how it would look in a tiny WinForm app, made just for this.
The case when the file doesn't have a digital signature is handled in the Exception. You might want to change that for your specific use case, as you would for the way you get the file path (get all the processes, loop through them, check them individually, do something if a signature is not found, etc). For simplicity's sake, I went with a textbox solution and a GUI.
You could call signtool as external tool to validate the process signatures.
// Compile as x64 executable to be able to access 64-bit processes.
// Execute tool as Administrator to get access to more processes.
[DllImport("Kernel32.dll")]
static extern uint QueryFullProcessImageName(IntPtr hProcess, uint flags, StringBuilder text, out uint size);
// Get the path to a process excutable
// https://stackoverflow.com/a/46671939/1911064
private static string GetPathToApp(Process process)
{
string pathToExe = string.Empty;
if (null != process)
{
uint nChars = 256;
StringBuilder Buff = new StringBuilder((int)nChars);
uint success = QueryFullProcessImageName(process.Handle, 0, Buff, out nChars);
if (0 != success)
{
pathToExe = Buff.ToString();
}
else
{
int error = Marshal.GetLastWin32Error();
pathToExe = ("Error = " + error + " when calling GetProcessImageFileName");
}
}
return pathToExe;
}
static bool CheckIfSigned(string fileName)
{
bool ret = false;
if (File.Exists(fileName))
{
// https://learn.microsoft.com/en-us/windows/win32/seccrypto/signtool
// https://developer.microsoft.com/en-us/windows/downloads/windows-10-sdk
// signtool.exe is part of Windows 10 SDK
var process = new Process
{
StartInfo = new ProcessStartInfo
{
FileName = "signtool.exe",
Arguments = $"verify /all /pa /v {fileName}",
UseShellExecute = false,
RedirectStandardOutput = true,
CreateNoWindow = true
}
};
process.Start();
while (!process.StandardOutput.EndOfStream)
{
var line = process.StandardOutput.ReadLine();
// Console.WriteLine(line);
if (line.StartsWith("Successfully verified:"))
{
Console.WriteLine("success!");
return true;
}
if (line.StartsWith("SignTool Error:"))
{
Console.WriteLine("error!");
return false;
}
if (line.StartsWith("Number of errors: 0"))
{
Console.WriteLine("should have announced success!");
return false;
}
if (line.StartsWith("Number of errors:"))
{
Console.WriteLine("Signtool found errors!");
return false;
}
}
Console.WriteLine($"Could not recognized signtool output for {fileName}");
}
else
{
Console.WriteLine($"File not found: {fileName}");
}
return ret;
}
static void DriverCheck()
{
Process[] processes = Process.GetProcesses();
foreach (Process process in processes)
{
try
{
if (!process.HasExited)
{
string processPath = GetPathToApp(process);
// Check if the process has a main module
if (null != processPath)
{
// Check if the main module has a digital signature
bool isSigned = CheckIfSigned(processPath);
if (isSigned)
{
Console.WriteLine($"signed: {process.MainModule.FileName}");
}
else
{
Console.WriteLine($"**NOT** signed: {process.MainModule.FileName}");
}
}
}
}
catch (System.ComponentModel.Win32Exception ex)
{
// The process does not have a main module?
Console.WriteLine($"Win32Exception for ID={process.Id} {process.ProcessName}: {ex.Message}");
}
catch(Exception ex)
{
Console.WriteLine($"Exception for ID={process.Id} {process.ProcessName}: {ex.Message}");
}
}
}
I would like to run all the .exe files in a certain directory from my winform application.
Is there a way not to hard code the file path of each exe and be not dependent on knowing beforehand how many exe I have to run?
DirectoryInfo d = new DirectoryInfo(filepath);
foreach (var file in d.GetFiles("*.exe"))
{
Process.Start(file.FullName);
}
You can get all executable files using:
static public List<string> GetAllExecutables(string path)
{
return Directory.Exists(path)
? Directory.GetFiles(path, "*.exe").ToList()
: return new List<string>(); // or null
}
You can run one with:
static public Process RunShell(string filePath, string arguments = "")
{
try
{
var process = new Process();
process.StartInfo.FileName = filePath;
process.StartInfo.Arguments = arguments;
process.Start();
return process;
}
catch ( Exception ex )
{
Console.WriteLine($"Can''t run: {filePath}{Environment.NewLine}{Environment.NewLine}" +
ex.Message);
return null;
}
}
Thus you can write:
foreach ( string item in GetAllExecutables(#"c:\MyPath") )
RunShell(item);
//get exe files included in the directory
var files = Directory.GetFiles("<target-directory>", "*.exe");
Console.WriteLine("Number of exe:" + files.Count());
foreach (var file in files)
{
// start each process
Process.Start(file);
}
I am creating a program which converts Msg outlook file into pdf. What I did was export the Msg file into Html then convert the Html output to pdf. This is my code:
Microsoft.Office.Interop.Outlook.Application app = new Microsoft.Office.Interop.Outlook.Application();
string filename = System.IO.Path.GetFileNameWithoutExtension(msgLocation) + ".html";
string attachmentFiles = System.IO.Path.Combine(System.IO.Path.GetTempPath(), System.IO.Path.GetFileNameWithoutExtension(msgLocation) + "_files");
string extractLocation = System.IO.Path.Combine(System.IO.Path.GetTempPath(), filename);
Console.WriteLine(filename);
Console.WriteLine(attachmentFiles);
Console.WriteLine(extractLocation);
var item = app.Session.OpenSharedItem(msgLocation) as Microsoft.Office.Interop.Outlook.MailItem;
item.SaveAs(extractLocation, Microsoft.Office.Interop.Outlook.OlSaveAsType.olHTML);
int att = item.Attachments.Count;
if (att > 0)
{
for (int i = 1; i <= att; i++)
{
item.Attachments[i].SaveAsFile(System.IO.Path.Combine(attachmentFiles, item.Attachments[i].FileName));
}
}
app.Quit();
System.Runtime.InteropServices.Marshal.ReleaseComObject(app);
The MSG file convertion to HTML is working perfectly, but why is outlook.exe is still running? I want to close it, but app.Quit() doesn't close the app.
The issue is that the outlook com object is holding on to references and stopping the app from closing. Use the following function and pass your "app" object to it:
private void ReleaseObj(object obj)
{
try
{
System.Runtime.InteropServices.Marshal.ReleaseComObject(obj);
}
finally
{
obj = null;
}
}
See https://blogs.msdn.microsoft.com/deva/2010/01/07/best-practices-how-to-quit-outlook-application-after-automation-from-visual-studio-net-client/
This should work for any and App by referencing the App Name and it will kill all instances of the application. For instance if you have 5 instances of Notepad, it will kill them all...
To Kill the app, use the following:
KillProcessByPID.KillProcessByName("OUTLOOK");
Create the following static class (c# .net Core 6.0 is my weapon of choice in this case, but it should be fairly universal).
using System.Management;
using System.Diagnostics;
public static class KillProcessByPID
{
public static void KillProcessByName(string ProcessName)
{
string OutlookProcessName = "";
foreach (Process otlk in Process.GetProcesses())
{
if (otlk.ProcessName.ToLower().Contains(ProcessName.ToLower())) //OUTLOOK is the one I am seeking - yours may vary
{
OutlookProcessName = otlk.ProcessName;
}
}
//Get process ID by Name
var processes = Process.GetProcessesByName(OutlookProcessName);
foreach (var process in processes)
{
Console.WriteLine("PID={0}", process.Id);
Console.WriteLine("Process Handle={0}", process.Handle);
PortfolioTrackerXML.KillProcessByPID.KillProcessAndChildren(process.Id);
}
}
/// <summary>
/// Kill a process, and all of its children, grandchildren, etc.
/// </summary>
/// <param name="pid">Process ID.</param>
public static void KillProcessAndChildren(int pid)
{
// Cannot close 'system idle process'.
if (pid == 0)
{
return;
}
ManagementObjectSearcher searcher = new ManagementObjectSearcher
("Select * From Win32_Process Where ParentProcessID=" + pid);
ManagementObjectCollection moc = searcher.Get();
foreach (ManagementObject mo in moc)
{
KillProcessAndChildren(Convert.ToInt32(mo["ProcessID"]));
}
try
{
Process proc = Process.GetProcessById(pid);
proc.Kill();
}
catch (ArgumentException)
{
// Process already exited.
}
}
}
I borrowed from many and I'm not sure where, but I thank you all and give you all credit... apologies for not referencing you directly, but this was instrumental.
I want to find the pah for the currently opened file which is either currently active in the windows Explorer . i have got the location for the folder while the folder is being clicked but how do we get the path of the file like a text file or word or something like that
private string GetActiveWindowPath()
{
const int nChars = 256;
StringBuilder Buff = new StringBuilder(nChars);
IntPtr handle = GetForegroundWindow();
int handleint = int.Parse(handle + "");
SHDocVw.ShellWindows explorer = new SHDocVw.ShellWindows();
//var xy = new SHDocVw.InternetExplorerMedium();
var xpl = explorer.Cast<SHDocVw.InternetExplorerMedium>().Where(hwnd => hwnd.HWND == handleint).FirstOrDefault();
if (xpl != null)
{
// this will get the folder location
string path = new Uri(xpl.LocationURL).LocalPath;
return ("location:" + xpl.LocationName + " path:" + path );
}
return "HWND" + handleint ;
}
i ma getting the path of the opened window as you see but not the text file
private string GetMainModuleFilepath(int processId)
{
string wmiQueryString = "SELECT * FROM Win32_Process WHERE ProcessId = " + processId;
using (var searcher = new ManagementObjectSearcher(wmiQueryString))
{
using (var results = searcher.Get())
{
ManagementObject mo = results.Cast<ManagementObject>().FirstOrDefault();
if (mo != null)
{
return (string)mo["CommandLine"];
}
}
}
Process testProcess = Process.GetProcessById(processId);
return null;
}
After that you will get Executable file name with your file name like
"c:..\notepade.exe" D:\New Folder\sampleFile.txt" after that split as you like to get the path.
I am having an application that is changing some settings of another application (it is a simple C# application that run by double clicking (no setup required)).
After changing the settings I need to restart the other application so that it reflects the changed settings.
So to do, I have to kill the running process and start the process again, But the problem is after killing I am not able to find the process. (Reason is system do not know where the exe file is..)
Is there any way to find out the path of running process or exe, if it is running?
I do not want to give path manually, i.e. if it is running get the path, kill the process and start again else .... I will handle later
using System.Diagnostics;
var process = Process.GetCurrentProcess(); // Or whatever method you are using
string fullPath = process.MainModule.FileName;
//fullPath has the path to exe.
There is one catch with this API, if you are running this code in 32 bit application, you'll not be able to access 64-bit application paths, so you'd have to compile and run you app as 64-bit application (Project Properties → Build → Platform Target → x64).
What you can do is use WMI to get the paths. This will allow you to get the path regardless it's a 32-bit or 64-bit application. Here's an example demonstrating how you can get it:
// include the namespace
using System.Management;
var wmiQueryString = "SELECT ProcessId, ExecutablePath, CommandLine FROM Win32_Process";
using (var searcher = new ManagementObjectSearcher(wmiQueryString))
using (var results = searcher.Get())
{
var query = from p in Process.GetProcesses()
join mo in results.Cast<ManagementObject>()
on p.Id equals (int)(uint)mo["ProcessId"]
select new
{
Process = p,
Path = (string)mo["ExecutablePath"],
CommandLine = (string)mo["CommandLine"],
};
foreach (var item in query)
{
// Do what you want with the Process, Path, and CommandLine
}
}
Note that you'll have to reference the System.Management.dll assembly and use the System.Management namespace.
For more info on what other information you can grab out of these processes such as the command line used to start the program (CommandLine), see the Win32_Process class and WMI .NET for for more information.
A solution for:
Both 32-bit AND 64-bit processes
System.Diagnostics only (no System.Management)
I used the solution from Russell Gantman and rewritten it as an extension method you can use like this:
var process = Process.GetProcessesByName("explorer").First();
string path = process.GetMainModuleFileName();
// C:\Windows\explorer.exe
With this implementation:
internal static class Extensions {
[DllImport("Kernel32.dll")]
private static extern bool QueryFullProcessImageName([In] IntPtr hProcess, [In] uint dwFlags, [Out] StringBuilder lpExeName, [In, Out] ref uint lpdwSize);
public static string GetMainModuleFileName(this Process process, int buffer = 1024) {
var fileNameBuilder = new StringBuilder(buffer);
uint bufferLength = (uint)fileNameBuilder.Capacity + 1;
return QueryFullProcessImageName(process.Handle, 0, fileNameBuilder, ref bufferLength) ?
fileNameBuilder.ToString() :
null;
}
}
I guess you already have the process object of the running process (e.g. by GetProcessesByName()).
You can then get the executable file name by using:
Process p;
string filename = p.MainModule.FileName;
By combining Sanjeevakumar Hiremath's and Jeff Mercado's answers you can actually in a way get around the problem when retrieving the icon from a 64-bit process in a 32-bit process.
using System;
using System.Management;
using System.Diagnostics;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
int processID = 6680; // Change for the process you would like to use
Process process = Process.GetProcessById(processID);
string path = ProcessExecutablePath(process);
}
static private string ProcessExecutablePath(Process process)
{
try
{
return process.MainModule.FileName;
}
catch
{
string query = "SELECT ExecutablePath, ProcessID FROM Win32_Process";
ManagementObjectSearcher searcher = new ManagementObjectSearcher(query);
foreach (ManagementObject item in searcher.Get())
{
object id = item["ProcessID"];
object path = item["ExecutablePath"];
if (path != null && id.ToString() == process.Id.ToString())
{
return path.ToString();
}
}
}
return "";
}
}
}
This may be a bit slow and doesn't work on every process which lacks a "valid" icon.
Here is a reliable solution that works with both 32bit and 64bit applications.
Add these references:
using System.Diagnostics;
using System.Management;
Add this method to your project:
public static string GetProcessPath(int processId)
{
string MethodResult = "";
try
{
string Query = "SELECT ExecutablePath FROM Win32_Process WHERE ProcessId = " + processId;
using (ManagementObjectSearcher mos = new ManagementObjectSearcher(Query))
{
using (ManagementObjectCollection moc = mos.Get())
{
string ExecutablePath = (from mo in moc.Cast<ManagementObject>() select mo["ExecutablePath"]).First().ToString();
MethodResult = ExecutablePath;
}
}
}
catch //(Exception ex)
{
//ex.HandleException();
}
return MethodResult;
}
Now use it like so:
int RootProcessId = Process.GetCurrentProcess().Id;
GetProcessPath(RootProcessId);
Notice that if you know the id of the process, then this method will return the corresponding ExecutePath.
Extra, for those interested:
Process.GetProcesses()
...will give you an array of all the currently running processes, and...
Process.GetCurrentProcess()
...will give you the current process, along with their information e.g. Id, etc. and also limited control e.g. Kill, etc.*
You can use pInvoke and a native call such as the following. This doesn't seem to have the 32 / 64 bit limitation (at least in my testing)
Here is the code
using System.Runtime.InteropServices;
[DllImport("Kernel32.dll")]
static extern uint QueryFullProcessImageName(IntPtr hProcess, uint flags, StringBuilder text, out uint size);
//Get the path to a process
//proc = the process desired
private string GetPathToApp (Process proc)
{
string pathToExe = string.Empty;
if (null != proc)
{
uint nChars = 256;
StringBuilder Buff = new StringBuilder((int)nChars);
uint success = QueryFullProcessImageName(proc.Handle, 0, Buff, out nChars);
if (0 != success)
{
pathToExe = Buff.ToString();
}
else
{
int error = Marshal.GetLastWin32Error();
pathToExe = ("Error = " + error + " when calling GetProcessImageFileName");
}
}
return pathToExe;
}
private void Test_Click(object sender, System.EventArgs e){
string path;
path = System.IO.Path.GetDirectoryName(
System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase );
Console.WriiteLine( path );
}
Try:
using System.Diagnostics;
ProcessModuleCollection modules = Process.GetCurrentProcess().Modules;
string processpathfilename;
string processmodulename;
if (modules.Count > 0) {
processpathfilename = modules[0].FileName;
processmodulename= modules[0].ModuleName;
} else {
throw new ExecutionEngineException("Something critical occurred with the running process.");
}
using System;
using System.Diagnostics;
class Program
{
public static void printAllprocesses()
{
Process[] processlist = Process.GetProcesses();
foreach (Process process in processlist)
{
try
{
String fileName = process.MainModule.FileName;
String processName = process.ProcessName;
Console.WriteLine("processName : {0}, fileName : {1}", processName, fileName);
}catch(Exception e)
{
/* You will get access denied exception for system processes, We are skiping the system processes here */
}
}
}
static void Main()
{
printAllprocesses();
}
}
For others, if you want to find another process of the same executable, you can use:
public bool tryFindAnotherInstance(out Process process) {
Process thisProcess = Process.GetCurrentProcess();
string thisFilename = thisProcess.MainModule.FileName;
int thisPId = thisProcess.Id;
foreach (Process p in Process.GetProcesses())
{
try
{
if (p.MainModule.FileName == thisFilename && thisPId != p.Id)
{
process = p;
return true;
}
}
catch (Exception)
{
}
}
process = default;
return false;
}
As of .NET 6, you can use Environment.ProcessPath.
In a test, you can see that it gives the same result as Process.GetCurrentProcess().MainModule.FileName:
It's possible to implement process query path using PInvoke on OpenProcess, GetModuleFileNameEx.
See full answer in here.
using System.Management;
ManagementObjectSearcher search = new ManagementObjectSearcher("SELECT * FROM
Win32_Process");
foreach (ManagementObject currentObj in search.Get())
{
if (currentObj["Caption"].ToString() == "sqlservr.exe")
MessageBox.Show(currentObj["ExecutablePath"].ToString());
}
The Process class has a member StartInfo that you should check out:
http://msdn.microsoft.com/en-us/library/system.diagnostics.processstartinfo_members(v=VS.71).aspx
I got to this thread while looking for the current directory of an executing process. In .net 1.1 Microsoft introduced:
Directory.GetCurrentDirectory();
Seems to work well (but doesn't return the name of the process itself).