How to get the process path using PowerShell.Create()? - c#

I am studying this and I have a question, how to extract the path of the process executable?
using System;
using System.Management.Automation;
namespace GetProcess
{
internal class FileName
{
private static void Main()
{
PowerShell ps = PowerShell.Create().AddCommand("Get-Process");
foreach (PSObject result in ps.Invoke())
{
Console.WriteLine("{0,-30}{1,-30}{2,-30}", result.Members["ProcessName"].Value, result.Members["Id"].Value, "How to get the file path?");
// How to get the process path (Mainmodule.FileName) using PowerShell.Create()?
}
ps.Commands.Clear();
Console.ReadKey();
}
}
}
I can get the paths like this:
using (var PSPath = PowerShell.Create().AddScript("Get-Process | Where-Object {$_.Path} | Dir"))
{
foreach (PSObject p in PSPath.Invoke()) Console.WriteLine(p);
}
However, I want to find a method to get the path from PowerShell ps = PowerShell.Create().AddCommand("Get-Process"); where ps is used several times.
Thanks

Related

Get Absolute Path of file in C# from file name [duplicate]

This question already has answers here:
How to get a path to the desktop for current user in C#?
(2 answers)
Closed 3 years ago.
I have a File on my Desktop and I want to get the full Path of the File in my code, should it be on my Desktop or anywhere
My code is looking like this
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GetFullPath
{
class Program
{
static void Main(string[] args)
{
string filename = "eMemoExpenseApproval.docx";
string fullFilePath = Path.Combine(Directory.GetCurrentDirectory(), filename);
Console.Write("Path : " + fullFilePath);
Console.Read();
}
}
}
Rather than get the full path from Desktop it shows the Path from Visual Studio, which is not suppose to be so, but i get this instead
Path : C:\Users\Administrator\Documents\Visual Studio 2017\Projects\GetFullPath\GetFullPath\bin\Debug\eMemoExpenseApproval.docx
Edit:
this works to get the Path of the file on Desktop
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GetFullPath
{
class Program
{
static void Main(string[] args)
{
string filename = "eMemoExpenseApproval.docx";
string path = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string fullFilePath = path +"/"+ filename;
Console.Write("Path : " + fullFilePath);
Console.Read();
}
}
}
Fine but How about other directories?
Directory.GetCurrentDirectory() actually returns the directory in which the application is executed.
If you know that the file is located in your Desktop, you can instead do something like this :
string fullFilePath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop, filename));
As I understand you want to search a limited set of folders for a named file. To do that declare a function like this:
IEnumerable<string> FindInMultipleFolders(string[] folders, string filename)
{
var result = new List<string>();
foreach (var folder in folders)
{
var dirs = Directory.GetFiles(folder, filename);
foreach (String dir in dirs)
{
result.Add(dir);
}
}
return result;
}
And call it with the file name and the folders to search like this:
FindInMultipleFolders(
new string[]
{
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
Environment.GetFolderPath(Environment.SpecialFolder.MyDocuments),
#"C:\Some\Other\Folder\I\Would\Like\Searched"
},
"eMemoExpenseApproval.docx");
}
The file might be in multiple folders, so the function returns an IEnumerable<string>. FindInMultipleFolders only searches the passed folders, not subfolders. If you want subfolders to be searched you should add SearchOption.AllDirectories as a third parameter to GetFiles. Then you could search the whole hard drive with:
FindInMultipleFolders(
new string[]
{
#"C:\"
},
"eMemoExpenseApproval.docx");
}

Add recursive command to set sub directory permissions in C#

I would like to add a recursive command to this script that allows it to loop through a current direcotries sub directory/files and set the permissions on the subfolders/files to whatever I would like. Here is what I have so far which allows for the permissions to be changed on the first set of subdirectories. Obviously, I can add the samecode in to keep diving down through the folder structure, but not every root folder will have the same amount of sub folders within it. I want to add the recursive command to loop through all subdirectories and when there are no more, move on to the next root folder.
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.IO;
using System.Security.AccessControl;
using System.Management;
using System.Management.Instrumentation;
namespace ApplyPermissions
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
private void Form1_Load(object sender, EventArgs e)
{
}
private void label1_Click(object sender, EventArgs e)
{
}
private void selectDirectoryBtn_Click(object sender, EventArgs e)
{
FolderBrowserDialog myFolderBrowserDialog = new FolderBrowserDialog();
myFolderBrowserDialog.ShowDialog();
selectedDirBox.Text = myFolderBrowserDialog.SelectedPath.ToString();
try
{
DirectoryInfo myDirectoryInfo = new DirectoryInfo(selectedDirBox.Text);
foreach (DirectoryInfo currentDir in myDirectoryInfo.GetDirectories())
{
toolStripStatusLabel1.Text = currentDir.Name;
DirectorySecurity DirSecurity = currentDir.GetAccessControl();
DirSecurity.AddAccessRule(new FileSystemAccessRule(“Whatever permissions group I choose”, FileSystemRights.CreateFiles, AccessControlType.Allow));
currentDir.SetAccessControl(DirSecurity);
// Step thru each file within current Directory and assign access
foreach (FileInfo currentFile in currentDir.GetFiles())
{
FileSecurity fileSecurity = currentFile.GetAccessControl();
fileSecurity.AddAccessRule(new FileSystemAccessRule("Whatever permissions group I choose", FileSystemRights.FullControl, AccessControlType.Allow));
currentFile.SetAccessControl(fileSecurity);
}
foreach (DirectoryInfo subDir in currentDir.GetDirectories ())
{
toolStripStatusLabel1.Text = currentDir.Name + "/" + subDir.Name;
DirectorySecurity allsubDirSecurity = subDir.GetAccessControl();
allsubDirSecurity.AddAccessRule(new FileSystemAccessRule("Whatever permissions group I choose ", FileSystemRights.FullControl, AccessControlType.Allow));
subDir.SetAccessControl(allsubDirSecurity);
// Step thru each file within current SubDirectory and assign access
foreach (FileInfo currentFile in subDir.GetFiles())
{
FileSecurity fileSecurity = currentFile.GetAccessControl();
fileSecurity.AddAccessRule(new FileSystemAccessRule("Whatever permissions group I choose", FileSystemRights.FullControl, AccessControlType.Allow));
currentFile.SetAccessControl(fileSecurity);
}
}
}
labelFinished.Text = "Completed Successfully";
}
catch (Exception ex)
{
MessageBox.Show(ex.Message + "/////////////////" + ex.StackTrace);
}
}
}
}
First, if your target framework is 4.0, recommend that you use the Directory.EnumerateFiles method (you can also find 3rd code that does the same thing.)
Assuming this is a no-go, you can simplify your recursive processing by using the yield keyword, e.g. make a traverse method based on yield -- I'm showing this with a filter function to since it would often be useful in directory traversal ad should give you ideas.
static IEnumerable<string> traverse(string path, Func<string, bool> filter)
{
foreach (string f in Directory.GetFiles(path).Where(filter))
{
yield return f;
}
foreach (string d in Directory.GetDirectories(path))
{
foreach (string f in traverse(d, filter))
{
yield return f;
}
}
}
Then you use traversal() this way
var files = traverse(PATH, WHERE);
foreach (string f in files) { DoWhatever; }
You will have a more easily reusable directory traversal at your fingertips. I know that I am not yielding directories in the snippet above, but if I wanted to process both files and directory, I would base this on the DirectoryInfo.GetFileSystemInfos method instead.
I forget when the yield feature was added, but it has been available for quite a while.

Opening mp3 by not-default program C sharp

How can I open mp3 file with RealPlayer while the default is MediaPlayer
I know Process and ProcessStartInfo method, but I would like to know how to "open program with..."
Can you help me, plz?
Okay, so thought I'd make this possible for you before I clock off for the night. I have thrown together a working console application which loads (known) installed programs from the registry's App Path key. The solution is far from perfect, won't be the safest, fastest, or most reliable solution, and it certainly shouldn't be seen amongst any production code, but it is more than enough to aid you, hopefully, in developing what it is you need:
So, here is the code, minus the namespace...
using System;
using System.IO;
using Microsoft.Win32;
using System.Diagnostics;
using System.Collections.Generic;
class Program
{
static void Main(string[] args)
{
if (args.Length >= 0 && !string.IsNullOrEmpty(args[0]) && File.Exists(args[0]))
{
var programs = new InstalledPrograms();
var programKey = "RealPlay.exe".ToLowerInvariant();
if (programs.ContainsKey(programKey))
{
var programPath = programs[programKey];
if (!string.IsNullOrEmpty(programPath) && File.Exists(programPath))
{
var process = new Process();
process.StartInfo = new ProcessStartInfo(programPath);
process.StartInfo.Arguments = args[0];
if (process.Start())
{
Console.WriteLine("That was easy!");
}
else
{
Console.WriteLine("Hell's bells and buckets of blood, we seem to have hit a snag!");
}
}
}
}
else
{
Console.WriteLine("Specify a file as an argument, silly!");
}
Console.WriteLine();
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
class InstalledPrograms : Dictionary<string, string>
{
static string PathKeyName = "Path";
static string RegistryKeyToAppPaths = #"SOFTWARE\Microsoft\Windows\CurrentVersion\App Paths";
public InstalledPrograms()
{
Refresh();
}
public void Refresh()
{
Clear();
using (var registryKey = Registry.LocalMachine.OpenSubKey(RegistryKeyToAppPaths))
{
var executableFullPath = string.Empty;
foreach (var registrySubKeyName in registryKey.GetSubKeyNames())
{
using (var registrySubKey = registryKey.OpenSubKey(registrySubKeyName))
{
executableFullPath = registrySubKey.GetValue(string.Empty) as string;
Add(registrySubKeyName.ToLowerInvariant(), executableFullPath);
}
}
}
}
}
}
Though we check for file existence, and other minor but necessary checks are made, you would still need to tighten this up further when plugged into the environment of your own code, including, among other things, exception handling for, but not limited to, registry access issues.

Powershell Command in C#

I am trying to query the names all of the WMI classes within the root\CIMV2 namespace. Is there a way to use a powershell command to retrieve this information in C# ?
Along the lines of Keith's approach
using System;
using System.Management.Automation;
namespace ConsoleApplication1
{
class Program
{
static void Main(string[] args)
{
var script = #"
Get-WmiObject -list -namespace root\cimv2 | Foreach {$_.Name}
";
var powerShell = PowerShell.Create();
powerShell.AddScript(script);
foreach (var className in powerShell.Invoke())
{
Console.WriteLine(className);
}
}
}
}
I'm not sure why you mentioned PowerShell; you can do this in pure C# and WMI (the System.Management namespace, that is).
To get a list of all WMI classes, use the SELECT * FROM Meta_Class query:
using System.Management;
...
try
{
EnumerationOptions options = new EnumerationOptions();
options.ReturnImmediately = true;
options.Rewindable = false;
ManagementObjectSearcher searcher =
new ManagementObjectSearcher("root\\cimv2", "SELECT * FROM Meta_Class", options);
ManagementObjectCollection classes = searcher.Get();
foreach (ManagementClass cls in classes)
{
Console.WriteLine(cls.ClassPath.ClassName);
}
}
catch (ManagementException exception)
{
Console.WriteLine(exception.Message);
}
Personally I would go with Helen's approach and eliminate taking a dependency on PowerShell. That said, here's how you would code this in C# to use PowerShell to retrieve the desired info:
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Management.Automation;
namespace RunspaceInvokeExp
{
class Program
{
static void Main()
{
using (var invoker = new RunspaceInvoke())
{
string command = #"Get-WmiObject -list -namespace root\cimv2" +
" | Foreach {$_.Name}";
Collection<PSObject> results = invoker.Invoke(command);
var classNames = results.Select(ps => (string)ps.BaseObject);
foreach (var name in classNames)
{
Console.WriteLine(name);
}
}
}
}
}
Just to note that there is a tool available that allows you to create, run, and save WMI scripts written in PowerShell, the PowerShell Scriptomatic tool, available for download from the Microsoft TechNet site.
Using this tool, you could explore all of the WMI classes within the root\CIMV2 or any other WMI namespace.
You'd probably want to just use the System.Management namespace like Helen answered, but you can also host powershell within your application. See http://www.codeproject.com/KB/cs/HowToRunPowerShell.aspx

Retrieving Process Description Information

I am trying to retrieve process information and I'm aware that I can use:
Process[] myProcesses = Process.GetProcesses();
but how do I retrieve the process description? Is it via some Win32 API call? I'm running Vista and when I click under the Processes tab in Task Manager, I see the description.
What you see in Task Manager is actually the Description field of the executable image.
You can use the GetFileVersionInfo() and VerQueryValue() WinAPI calls to access various version informations, e.g. CompanyName or FileDescription.
For .Net way, use the FileDescription member of FileVersionInfo, instantiated with the executable name got via Process.MainModule.FileName.
Another way would be through Assembly. Load the Assembly from the executable image, then query the AssemblyDescriptionAttribute custom attribute.
You just have to go a bit further down the properties.
Suppose you have an instance of notepad running.
Process[] proc = Process.GetProcessesByName("notepad");
Console.WriteLine("Process version- " + proc[0].MainModule.FileVersionInfo.FileVersion);
Console.WriteLine("Process description- " + proc[0].MainModule.FileVersionInfo.FileDescription);
There you go !
This is the only way I could see to do it. I tried Process and Win32_Process, but no go.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Management;
using System.Diagnostics;
namespace Management
{
class Program
{
static void Main(string[] args)
{
var ps = Process.GetProcesses();
foreach (var p in ps)
{
try
{
var desc = FileVersionInfo.GetVersionInfo(p.MainModule.FileName);
Console.WriteLine(desc.FileDescription);
}
catch
{
Console.WriteLine("Access Denied");
}
}
Console.ReadLine();
}
}
}

Categories