How can I retrieve the machine name from a remote Windows computer? - c#

I am trying to find a way to retrieve Computer name from an IP address in C#, but all of the answers marked online as retrieving machine name or computer name actually get the hostname, not the Computer Name. If you go to Control panel > system, there is a property in that menu "Computer name" ... I'm looking for this value on a remote machine. AFAIK, the HOSTNAME will = the full computer name IF there is no DNS mapping. The problem is that these servers I'm working on do have DNS mapping so the hostname returns their DNS address.
Feel free to correct me on the technical details of that if I said anything wrong, but the question will remain.
I've tried this:
IPHostEntry hostEntry = Dns.GetHostEntry(_ip);
_hostname = hostEntry.HostName;
but obviously returns the HostName, not the Computer name. I could also settle for the "Full computer name" property being returned, and then simply strip the unneeded parts of the string off to reveal the "Computer name."
Also, if you know how to do this with PowerShell, I could use your help as-well. I am hosting the PowerShell engine in my app anyway... so could simply pass your command into PowerShellInstance.AddScript(_yourCommandHere); and pipe its return back into my app.
Please advise if this is possible to do.
#DanielAWhite
EDIT: How is this a duplicate of the listed answer? The answer in that post says exactly what I posted as being the problem to this question. No, that's not a duplicate, because I'm NOT looking for the hostname. I specifically told you in my OP that I wasn't looking for that, and they're not asking what I'm asking. If there is no way to get the computer name from the IP in .NET then just answer the question with that.
From the "duplicate":
Well, not every IP address has a name. However, given the IPAddress you can use >Dns.GetHostEntry to try to resolve it. Also note that if it's being a NAT >router, you'll be getting the router's IP address rather than their actual >machine.
look at my OP... .GetHostEntry DOESN'T work. that's the whole reason I took the time to type this up.
thanks
DOUBLE EDIT: BACON has an answer for how to do this; this post was locked because someone didn't take the time to actually read what I wrote. Since it's locked, you also can't give a better answer. But here's how I did it, saving this here for future reference:
//declare a string to be our machinename
string machineName;
//declare a string which we will pass into powershell later as script
//assigns the hostname or IP
string getComputer = "$ip = " + "\"" + ip + "\"" + "\r\n";
//add to the string this, which gets the Win32_ComputerSystem.. #BACON knew what I was after
//we pipe that back using |select -expand Name
getComputer += "get-wmiobject -class Win32_ComputerSystem -property Name -ComputerName " + "$ip " +
"|select -expand Name";
//create a powershell instance using
using (PowerShell PowerShellInstance = PowerShell.Create())
{
//add the script into our instance of ps
PowerShellInstance.AddScript(getComputer);
//instantiate a collection to house our output from PS
//you could also probably just instantiate a PSObject instead of a collection.. but this might be useful if modified to get an array of computer names... and this is how I did it so can't verify
Collection<PSObject> psOutput;
//assign psOutput from .Invoke() method
psOutput = PowerShellInstance.Invoke();
//you could trim this loop and get rid of it for only one IP
foreach (var item in psOutput)
{
//machineName = MachineName||ComputerName string NOT hostname
machineName = item.BaseObject.ToString();
}
}
Oh, and per bacon in the comments, you have to have WMI allowed through windows firewall for this to work. It worked perfectly for me.

Reconstituting my comments as an answer...
Imagine we had an interface like this...
namespace SO56585341
{
public interface IComputerInfoSource
{
string GetComputerName();
}
}
There are a handful of ways to implement this to get the machine name of the local computer. The simplest is to return the value of the Environment.MachineName property...
namespace SO56585341
{
public class EnvironmentClassComputerInfoSource : IComputerInfoSource
{
public string GetComputerName()
{
return System.Environment.MachineName;
}
}
}
You can also use the Environment.GetEnvironmentVariable() method to retrieve the value of the %ComputerName% environment variable...
namespace SO56585341
{
public class EnvironmentVariableComputerInfoSource : IComputerInfoSource
{
public string GetComputerName()
{
return System.Environment.GetEnvironmentVariable("ComputerName");
}
}
}
You can p/invoke the GetComputerName() Windows API function, which is what Environment.MachineName does behind the scenes...
using System.Runtime.InteropServices;
using System.Text;
namespace SO56585341
{
public class WinApiComputerInfoSource : IComputerInfoSource
{
private const int MAX_COMPUTERNAME_LENGTH = 15;
[DllImport("Kernel32.dll", CallingConvention = CallingConvention.Winapi, CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetComputerName(
StringBuilder lpBuffer,
ref int nSize
);
public string GetComputerName()
{
int maxCapacity = MAX_COMPUTERNAME_LENGTH + 1;
StringBuilder nameBuilder = new StringBuilder(maxCapacity, maxCapacity);
if (!GetComputerName(nameBuilder, ref maxCapacity))
{
// TODO: Error handling...
throw new System.ComponentModel.Win32Exception();
}
return nameBuilder.ToString();
}
}
}
You can use WMI to retrieve the Name property of the singleton Win32_ComputerSystem class. You can do this by instantiating a ManagementClass instance for the Win32_ComputerSystem class and calling GetInstances() on it to retrieve an array containing the sole instance...
using System.Linq;
using System.Management;
namespace SO56585341
{
public class WmiClassComputerInfoSource : IComputerInfoSource
{
public string GetComputerName()
{
using (ManagementClass computerSystemClass = new ManagementClass("Win32_ComputerSystem"))
using (ManagementObjectCollection computerSystemCollection = computerSystemClass.GetInstances())
using (ManagementObject computerSystem = computerSystemCollection.Cast<ManagementObject>().Single())
return (string) computerSystem["Name"];
}
}
}
...or by creating a ManagementObjectSearcher and using that to Get() the lone Win32_ComputerSystem instance...
using System.Linq;
using System.Management;
namespace SO56585341
{
public class WmiSearcherComputerInfoSource : IComputerInfoSource
{
public string GetComputerName()
{
ObjectQuery computerSystemQuery = new SelectQuery("Win32_ComputerSystem");
using (ManagementObjectSearcher computerSystemSearcher = new ManagementObjectSearcher(computerSystemQuery))
using (ManagementObjectCollection computerSystemCollection = computerSystemSearcher.Get())
using (ManagementObject computerSystem = computerSystemCollection.Cast<ManagementObject>().Single())
return (string) computerSystem["Name"];
}
}
}
Finally, the value returned by all of the methods above seems to ultimately be stored in the registry, so if you don't mind relying on that implementation detail you can retrieve it from there directly...
using Microsoft.Win32;
namespace SO56585341
{
public class RegistryComputerInfoSource : IComputerInfoSource
{
public string GetComputerName()
{
// See also #"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\"
// https://www.oreilly.com/library/view/windows-nt-workstation/9781565926134/10_chapter-07.html
const string valueParentKeyPath = #"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\";
using (RegistryKey parentKey = Registry.LocalMachine.OpenSubKey(valueParentKeyPath, false))
return (string) parentKey.GetValue("ComputerName");
}
}
}
As for getting the same value from a remote computer only the last three implementations above will work, though with minimal tweaking required. First, just to complete this IComputerInfoSource example, let's create an abstract class to hold the remote machine name/address "parameter"...
namespace SO56585341
{
public abstract class RemoteComputerInfoSource : IComputerInfoSource
{
public string RemoteNameOrIp
{
get;
}
protected RemoteComputerInfoSource(string nameOrIp)
{
RemoteNameOrIp = nameOrIp ?? throw new System.ArgumentNullException(nameof(nameOrIp));
}
public abstract string GetComputerName();
}
}
Retrieving the Win32_ComputerSystem instance via a ManagementClass just becomes a matter of explicitly passing it a ManagementPath that also specifies the NamespacePath and Server...
using System.Linq;
using System.Management;
namespace SO56585341
{
public class RemoteWmiClassComputerInfoSource : RemoteComputerInfoSource
{
public RemoteWmiClassComputerInfoSource(string nameOrIp)
: base(nameOrIp)
{
}
public override string GetComputerName()
{
ManagementPath computerSystemPath = new ManagementPath() {
ClassName = "Win32_ComputerSystem",
NamespacePath = #"root\cimv2",
Server = RemoteNameOrIp
};
using (ManagementClass computerSystemClass = new ManagementClass(computerSystemPath))
using (ManagementObjectCollection computerSystemCollection = computerSystemClass.GetInstances())
using (ManagementObject computerSystem = computerSystemCollection.Cast<ManagementObject>().Single())
return (string) computerSystem["Name"];
}
}
}
A ManagementObjectSearcher can be used by passing a similar ManagementPath wrapped in a ManagementScope...
using System.Linq;
using System.Management;
namespace SO56585341
{
public class RemoteWmiSearcherComputerInfoSource : RemoteComputerInfoSource
{
public RemoteWmiSearcherComputerInfoSource(string nameOrIp)
: base(nameOrIp)
{
}
public override string GetComputerName()
{
ManagementScope computerSystemScope = new ManagementScope(
new ManagementPath() {
NamespacePath = #"root\cimv2",
Server = RemoteNameOrIp
}
);
ObjectQuery computerSystemQuery = new SelectQuery("Win32_ComputerSystem");
using (ManagementObjectSearcher computerSystemSearcher = new ManagementObjectSearcher(computerSystemScope, computerSystemQuery))
using (ManagementObjectCollection computerSystemCollection = computerSystemSearcher.Get())
using (ManagementObject computerSystem = computerSystemCollection.Cast<ManagementObject>().Single())
return (string) computerSystem["Name"];
}
}
}
Querying a remote registry just requires an additional call to OpenRemoteBaseKey() to get a handle to the root of the remote hive...
using Microsoft.Win32;
namespace SO56585341
{
public class RemoteRegistryComputerInfoSource : RemoteComputerInfoSource
{
public RemoteRegistryComputerInfoSource(string nameOrIp)
: base(nameOrIp)
{
}
public override string GetComputerName()
{
// See also #"SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\"
// https://www.oreilly.com/library/view/windows-nt-workstation/9781565926134/10_chapter-07.html
const string valueParentKeyPath = #"SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\";
using (RegistryKey baseKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, RemoteNameOrIp))
using (RegistryKey parentKey = baseKey.OpenSubKey(valueParentKeyPath, false))
return (string) parentKey.GetValue("ComputerName");
}
}
}
If you compile all of the above code into a project you can use the following Program class to test it...
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace SO56585341
{
public static class Program
{
private const string TestHost = "127.0.0.1";
public static void Main()
{
// Get all non-abstract classes in the executing assembly that implement IComputerInfoSource
IEnumerable<Type> computerInfoSourceTypes = Assembly.GetExecutingAssembly().GetTypes()
.Where(type => type.IsClass && !type.IsAbstract && typeof(IComputerInfoSource).IsAssignableFrom(type));
// For each constructor in each candidate class...
foreach (Type computerInfoSourceType in computerInfoSourceTypes)
foreach (ConstructorInfo constructor in computerInfoSourceType.GetConstructors())
{
ParameterInfo[] constructorParameters = constructor.GetParameters();
object[] instanceParameters;
// If the constructor takes no parameters...
if (!constructorParameters.Any())
instanceParameters = Array.Empty<object>();
// ...or a single string parameter...
else if (constructorParameters.Length == 1 && constructorParameters[0].ParameterType == typeof(string))
instanceParameters = new object[1] { TestHost };
// ...otherwise skip this constructor
else
continue;
// Instantiate the class using the constructor parameters specified above
IComputerInfoSource computerInfoSource = (IComputerInfoSource) constructor.Invoke(instanceParameters);
string result;
try
{
result = computerInfoSource.GetComputerName();
}
catch (Exception ex)
{
result = ex.ToString();
}
Console.WriteLine(
"new {0}({1}).{2}(): \"{3}\"",
computerInfoSourceType.Name,
string.Join(
", ",
instanceParameters.Select(value => $"\"{value}\"")
),
nameof(IComputerInfoSource.GetComputerName),
result
);
}
}
}
}
I found this code to work whether TestHost was set to a machine name, CNAME, or IP address. Note that the Remote*ComputerInfoSource classes will fail if...
The appropriate service (RemoteRegistry or Winmgmt) is not running on the remote machine, or...
The appropriate firewall rule (e.g. WMI-WINMGMT-In-TCP) is not enabled on the remote machine, or...
The code is not run as a user with privileges to access the remote service.
As for PowerShell, one should be able to port the code of any of the above methods from C# (either a direct translation or using PowerShell's conveniences) and wrap them in a call to Invoke-Command since that code will be executed local to the remote machine. For example...
Invoke-Command -ComputerName $nameOrIp -ScriptBlock { $Env:COMPUTERNAME }
...or...
Invoke-Command -ComputerName $nameOrIp -ScriptBlock {
# See also 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ActiveComputerName\'
# https://www.oreilly.com/library/view/windows-nt-workstation/9781565926134/10_chapter-07.html
Get-ItemProperty -Path 'HKLM:\SYSTEM\CurrentControlSet\Control\ComputerName\ComputerName\' -Name 'ComputerName'
}
PowerShell also has the Get-WmiObject...
Get-WmiObject -Class 'Win32_ComputerSystem' -ComputerName $nameOrIp -Property 'Name'
...and Get-CimInstance cmdlets...
Get-CimInstance -Class 'Win32_ComputerSystem' -ComputerName $nameOrIp -Property 'Name'
...that make working with WMI much easier. In general, I would recommend using WMI since it is pretty easy to use from C# and PowerShell for both local and remote queries, and it exists for exactly this purpose of retrieving system details without having to know about the underlying API calls or data representation.
Note that when using the Invoke-Command or Get-CimInstance cmdlets that the WinRM service must be running on the remote machine and the appropriate firewall rule (e.g. WINRM-HTTP-In-TCP-NoScope) must be enabled. Also, when passing an IP address to the -ComputerName parameter of either of those cmdlets that address must be matched by the value of WSMan:\localhost\Client\TrustedHosts. If you need to scan an entire network by IP address I tested and found that TrustedHosts accepts the * wildcard but not subnet masks, CIDR notation, or the ? wildcard.

Related

Querying AllegroGraph using dotNetRDF

I've got a AllegroGraph server running and have trouble querying remote datastore, there's very little information on documentation.
Here's my lil piece of code:
using System;
using VDS.RDF;
using VDS.RDF.Storage;
namespace PoC {
class Program {
static void Main(string[] args) {
string server = "http://server";
string repo = "repo";
string username = "username";
string password = "password";
AllegroGraphConnector agraph = new AllegroGraphConnector(server, repo, username, password);
Options.HttpDebugging = true;
Options.HttpFullDebugging = true;
agraph.Query("SELECT * WHERE { emid:_PCAT_0001 ?p ?o }");
Console.ReadLine();
}
}
}
MALFORMED QUERY: Parse error: namespace mapping for "emid" not defined
when expanding QName "emid:_PCAT_0001".
Although in AllegroGraph WebView I can run exactly the same query and namespace is loaded into repository.
How do I resolve that?
You will need to declare the prefix emid: in your query. Presumably the AllegroGraph WebView UI is doing that automatically for you, but the plain SPARQL endpoint won't.
Try using something like this:
agraph.Query("PREFIX emid: <http://your.uri.goes/here> SELECT * WHERE { emid:_PCAT_0001 ?p ?o }");
Obviously you should replace that fake URI with the real URI that your emid: prefix maps to!

Submit C# MapReduce Job Windows Azure HDInsight - Response status code does not indicate success: 500 (Server Error)

I'm trying to submit a MapReduce job to HDInsight cluster. In my job I didn't write reduce portion because I don't want to reduce anything. All I want to do is to parse the each filename and append the values to every line in the file. So that I will have all the data needed inside the file.
My code is
using Microsoft.Hadoop.MapReduce;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace GetMetaDataFromFileName
{
class Program
{
static void Main(string[] args)
{
var hadoop = connectAzure();
//Temp Workaround to Env Variables
Environment.SetEnvironmentVariable("HADOOP_HOME", #"c:\hadoop");
Environment.SetEnvironmentVariable("Java_HOME", #"c:\hadoop\jvm");
var result = hadoop.MapReduceJob.ExecuteJob<MetaDataGetterJob>();
}
static IHadoop connectAzure()
{
//TODO: Update credentials and other information
return Hadoop.Connect(
new Uri("https://sampleclustername.azurehdinsight.net//"),
"admin",
"Hadoop",
"password",
"blobstoragename.blob.core.windows.net", //Storage Account that Log files exists
"AccessKeySample", //Storage Account Access Key
"logs", //Container Name
true
);
}
//Hadoop Mapper
public class MetaDataGetter : MapperBase
{
public override void Map(string inputLine, MapperContext context)
{
try
{
//Get the meta data from name of the file
string[] _fileMetaData = context.InputFilename.Split('_');
string _PublicIP = _fileMetaData[0].Trim();
string _PhysicalAdapterMAC = _fileMetaData[1].Trim();
string _BootID = _fileMetaData[2].Trim();
string _ServerUploadTime = _fileMetaData[3].Trim();
string _LogType = _fileMetaData[4].Trim();
string _MachineUpTime = _fileMetaData[5].Trim();
//Generate CSV portion
string _RowHeader = string.Format("{0},{1},{2},{3},{4},{5},", _PublicIP, _PhysicalAdapterMAC, _BootID, _ServerUploadTime, _LogType, _MachineUpTime);
//TODO: Append _RowHeader to every row in the file.
context.EmitLine(_RowHeader + inputLine);
}
catch(ArgumentException ex)
{
return;
}
}
}
//Hadoop Job Definition
public class MetaDataGetterJob : HadoopJob<MetaDataGetter>
{
public override HadoopJobConfiguration Configure(ExecutorContext context)
{
//Initiate the job config
HadoopJobConfiguration config = new HadoopJobConfiguration();
config.InputPath = "asv://logs#sample.blob.core.windows.net/Input";
config.OutputFolder = "asv://logs#sample.blob.core.windows.net/Output";
config.DeleteOutputFolder = true;
return config;
}
}
}
}
Usually what do you thing the reason of 500 (Server Error) ? Am I suppling to wrong credentials ? Actually I didn't really understand the difference between Username and HadoopUser parameters in Hadoop.Connect method ?
Thank you,
I had approximately same issue in the past (was unable to submit hive job to the cluster with BadGateway response). I have contacted the support team and in my case the problem was in memory leakage at the head node, what means that the problem was not at client's side and it seems to be inherited hadoop problem.
I've solved that stuff by redeploying the cluster.
Have you tried to submit other jobs (simple ones)? If so, than I suggest to have a contact with azure support team or just redeploy the cluster if it's not painful for you.

.NET reference design for GUI app with built-in interactive terminal console (e.g. SublimeText, Visual Studio)

I'm trying to build a GUI app that has an interactive console, much like the one found in SublimeText.
I hope it is a valid question because it seems to be "a practical, answerable problem that is unique to software development".
In short, I see huge benefits having an interactive console inside a GUI app for
debugging, probing internal variables at runtime
logging
quick configuration changes
However, I have not come across any existing open-source applications that uses such a design.
I'm hoping someone has done it before and can share his/her design approach.
While I do have a semi-working solution using reflection and invoke in .NET, it is limited to only function calls and I'm not able to probe into nested internal variables (e.g. object.property.property).
To make the question more specific, these are the problems I'm facing:
Not easily extensible (Need to wire every new GUI command to a console command, vice-versa), any design tips? Routed commands (I could not find a useful example either)?
How to execute dynamic code that can access all existing object instances in the entire .NET app?
Thank you.
So here comes the code which worked for me:
namespace ReflectionsTest
{
public partial class MainForm : Form
{
public MainForm()
{
InitializeComponent();
}
//Events excluded
private void ExecuteCommand(string command)
{
string cmd = "";
cmd += #"using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Linq;
using Microsoft.CSharp;
using System.Reflection;
using ReflectionsTest;";
// i included a using statement for every namespace i want to adress direct
cmd += #"namespace ReflectionConsole
{
public class RuntimeExecution
{
public static void Main(MainForm parent, TextBox output, FieldInfo[] privateFields)
{
try {";
//the code in a trycatch because i can send every error to a specific output defined as output parameter
cmd += command;
cmd += "}catch (Exception ex) { if(output != null){" +
"output.Text += ex.Message + \"\\n\\r\";"
+"}else{MessageBox.Show(ex.Message);}}}}}";
try {
ExecuteCSharp(cmd);
}
catch (Exception ex) {
textBox2.Text += ex.Message + "\n\r";
}
}
private void ExecuteCSharp(string code)
{
CSharpCodeProvider provider = new CSharpCodeProvider();
CompilerParameters parameters = new CompilerParameters();
List<AssemblyName> assemblys = (Assembly.GetExecutingAssembly().GetReferencedAssemblies()).ToList<AssemblyName>();
foreach (var item in assemblys) {
parameters.ReferencedAssemblies.Add(item.Name + ".dll");
}
string t = Assembly.GetExecutingAssembly().GetName().Name;
parameters.ReferencedAssemblies.Add(t + ".exe");
//Here you have to reference every assembly the console wants access
parameters.GenerateInMemory = true;
parameters.GenerateExecutable = false;
CompilerResults results = provider.CompileAssemblyFromSource(parameters, code);
if (results.Errors.HasErrors) {
StringBuilder sb = new StringBuilder();
foreach (CompilerError error in results.Errors) {
sb.AppendLine(String.Format("Error ({0}): {1}", error.ErrorNumber, error.ErrorText));
}
throw new InvalidOperationException(sb.ToString());
}
else {
Assembly assembly = results.CompiledAssembly;
Type program = assembly.GetType("ReflectionConsole.RuntimeExecution");
MethodInfo main = program.GetMethod("Main");
FieldInfo[] fields = this.GetType().GetFields(
BindingFlags.NonPublic |
BindingFlags.Instance);
//if everything is correct start the method with some arguments:
// containing class, output, private fields of the containing class for easier access
main.Invoke(null, new object[]{this, textBox2, fields});
}
}
}
}
Some Explanations:
You have pass the highest class of your program which contains everything else, because it is easier to access members than parent objects.
public objects you can access like parent.obect1.Text = "textXYZ";
private objects you can access by name. These objects are listed in privateFields.
for the subclasses you have two options:
change the first and third parameter when calling main.Invoke([...])
or
recollect the private fields.
as Suggestion you could include a .dll in the command which already gives you methods to achieve this much faster.
For example GetValueFromFieldByName(object class, string name, Type resultType)
I hope that is what you've hoped for ^^

C# cannot connect to vmware

I have a project where i will have to build dual stacked virtual machines. I usually work with powershell but it does not appear to be able to do that. I may have to use C#. I am kinda rusty on this but for some reason this code give me an error "Cannot create an instance of the abstract class or interface 'VMware.Vim.VimClient'".
using System.Text;
using VMware.Vim;
namespace Vimfunctions
{
public class VimFunctions
{
protected VimClient ConnectServer(string viServer, string viUser, string viPassword)
{
**VimClient vClient = new VimClient();**
ServiceContent vimServiceContent = new ServiceContent();
UserSession vimSession = new UserSession();
vClient.Connect("https://" + viServer.Trim() + "/sdk");
vimSession = vClient.Login(viUser, viPassword);
vimServiceContent = vClient.ServiceContent;
return vClient;
}
I added the reference to the project. I must have forgot to do something.
As per https://communities.vmware.com/thread/478700:
"either stick with the PowerCLI 5.5 release as mentioned or to modify your code to use the VimClientImpl class instead of VimClient (which is now an interface)."
A complete simple example I used:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using VMware.Vim;
namespace vSphereCli
{
class Program
{
static void Main(string[] args)
{
VMware.Vim.VimClientImpl c = new VimClientImpl();
ServiceContent sc = c.Connect("https://HOSTNAME/sdk");
UserSession us = c.Login("admin#vsphere.local", "password");
IList<VMware.Vim.EntityViewBase> vms = c.FindEntityViews(typeof(VMware.Vim.VirtualMachine), null, null, null);
foreach (VMware.Vim.EntityViewBase tmp in vms)
{
VMware.Vim.VirtualMachine vm = (VMware.Vim.VirtualMachine)tmp;
Console.WriteLine((bool)(vm.Guest.GuestState.Equals("running") ? true : false));
Console.WriteLine(vm.Guest.HostName != null ? (string)vm.Guest.HostName : "");
Console.WriteLine("");
}
Console.ReadLine();
}
}
}
Add a reference to "C:\Program Files (x86)\VMware\Infrastructure\vSphere PowerCLI\VMware.Vim.dll". Update the hostname, password; and volia!

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

Categories