Use PInvoke to Capture CD Rom Information of Remote Machine - c#

I'm using C# to call GetVolumeInformation on a remote machine. I can hit the remote harddrives easily as there is a default share setup of c$ or whatever. However, CD/DVD do not have a default setup. How can I read the remote CD/DVD drive using a PInvoke call or something else?
If I can't do it using C#, I could always use PowerShell or WMI.

The WMI allows you to get system information of a remote machine without problems, only you need set the remote WMI access in the machine and use a valid user and password. on this case you can use the Win32_LogicalDisk and Win32_CDROMDrive classes to retrieve the info which you need.
Try this C# sample.
using System;
using System.Collections.Generic;
using System.Management;
using System.Text;
namespace GetWMI_Info
{
class Program
{
static void Main(string[] args)
{
try
{
string ComputerName = "localhost";//set the remote machine name here
ManagementScope Scope;
if (!ComputerName.Equals("localhost", StringComparison.OrdinalIgnoreCase))
{
ConnectionOptions Conn = new ConnectionOptions();
Conn.Username = "";//user
Conn.Password = "";//password
Conn.Authority = "ntlmdomain:DOMAIN";
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), Conn);
}
else
Scope = new ManagementScope(String.Format("\\\\{0}\\root\\CIMV2", ComputerName), null);
Scope.Connect();
ObjectQuery Query = new ObjectQuery("SELECT * FROM Win32_CDROMDrive");
ManagementObjectSearcher Searcher = new ManagementObjectSearcher(Scope, Query);
foreach (ManagementObject WmiObject in Searcher.Get())
{
Console.WriteLine("{0,-35} {1,-40}","DeviceID",WmiObject["DeviceID"]);// String
Console.WriteLine("{0,-35} {1,-40}","Drive",WmiObject["Drive"]);// String
}
}
catch (Exception e)
{
Console.WriteLine(String.Format("Exception {0} Trace {1}",e.Message,e.StackTrace));
}
Console.WriteLine("Press Enter to exit");
Console.Read();
}
}
}

Using Powershell and WMI.
Try this:
Get-WmiObject -computername MyremotePC Win32_CDROMDrive | Format-List *
You need administrative credential on remote computer.
You can P/invoke in powershell the GetVolumeInfomation adding it as type using Add-Type (Some example here).
If you're trying to read data on the disk of a remote CD/DVD that isn't shared I don't know any way to do it.

Related

Telling if a remote server is up or down using C#

I was wondering if it's possible to tell if a remote server is up or down using C#? First I have a method to shut down the server:
private static void RestartSecondServer()
{
Console.WriteLine("Computer details retrieved using Windows Management Instrumentation (WMI)");
//Connect to the remote computer
ConnectionOptions co = new ConnectionOptions();
co.Username = #"***********";
co.Password = "*********";
ManagementScope ms = new ManagementScope("\\\\******\\root\\cimv2", co);
//Query remote computer across the connection
ObjectQuery oq = new System.Management.ObjectQuery("SELECT * FROM Win32_OperatingSystem");
ManagementObjectSearcher query1 = new ManagementObjectSearcher(ms, oq);
ManagementObjectCollection queryCollection1 = query1.Get();
foreach (ManagementObject mo in queryCollection1)
{
string[] ss = {""};
mo.InvokeMethod("Reboot", ss);
Console.WriteLine(mo.ToString());
Console.WriteLine("Reboot complete");
//Process.Start("shutdown", "/r /t 0");
}
}
Now I want to create a method to see if this remote server which is in the process of being restarted is down. I tried a generic pinging method but it was returning true/success.
Can a server be successfully pinged if it's in the process of being restarted? Is it possible to tell if the server is being restarted?

Change service startup type to Delayed (Automatic) in remote machine

I am using the below code to change the service start in a remote server up type to manual/automatic using C#.
public static void ChangeServiceStartupType()
{
string query1 = "select * from Win32_Service where name = 'myservice' ";
string server = "servername";
ConnectionOptions connectoptions = new ConnectionOptions();
connectoptions.Username = #"username";
connectoptions.Password = "password";
ManagementScope scope = new ManagementScope(#"\\" + server + #"\root\cimv2");
scope.Options = connectoptions;
scope.Connect();
ObjectQuery query = new ObjectQuery(query1);
ManagementObjectSearcher managementObjectSearcher = new ManagementObjectSearcher(scope, query);
ManagementObjectCollection managementObjectCollection = managementObjectSearcher.Get();
foreach (ManagementObject mo in managementObjectSearcher.Get())
{
string name = mo.Properties["Name"].Value.ToString().Trim().ToLower();
string state = mo.Properties["State"].Value.ToString().Trim();
string startmode = mo.Properties["StartMode"].Value.ToString().Trim();
changemode(mo, "Automatic");
}
}
Here is the changemode method
private static void changemode(ManagementObject mo, string startmode)
{
ManagementBaseObject inParams = mo.GetMethodParameters("ChangeStartMode");
inParams["startmode"] = startmode;
ManagementBaseObject outParams = mo.InvokeMethod("ChangeStartMode", inParams, null);
startmode = mo.Properties["StartMode"].Value.ToString().Trim();
}
When I pass the parameters Manual or Automatic in the changemode(object,startmode parameter) the service start up type changes from automatic to manual and vice-versa. However, I am unable to change it to Automatic(Delayed Start).
I tried Auto-Delayed , Delayed-Auto, Automatic (Delayed Start) How do I achieve this?
If there's a way through ManagementObject than I haven't found it, but it IS possible through the registry:
public void SetDalayedAutoStart(string machineName, string serviceName)
{
using (var regKey = RegistryKey.OpenRemoteBaseKey(RegistryHive.LocalMachine, machineName))
{
using (RegistryKey serviceKey = regKey.OpenSubKey(#"System\CurrentControlSet\Services\" + serviceName, true))
{
serviceKey.SetValue("DelayedAutostart", 1, RegistryValueKind.DWord);
}
}
}
Note 1: This is only relevant for services with the Automatic start type
Note 2: The new state will be visible in the Services control (services.msc) only after a restart (don't ask me why)
Looking at the documentation, it doesn't seem to be possible to make the service start with a delay using the ChangeStartMode Win32 method. Doing what you want is fairly straightforward if you use ServiceInstaller, like so:
myServiceInstaller.StartType = ServiceStartMode.Automatic;
myServiceInstaller.DelayedAutoStart = true;
However I'm guessing that isn't an option, so we will have to dig deeper.
The Service class does have a DelayedAutoStart property, but it is read only. If you want to set it to delayed, you're going to have to mess around with P/Invokes. All information I could find points to ChangeServiceConfig2 and this struct.
Alternatively, you can just execute this command it it will have the same effect. However, it isn't really an answer to your question, just a workaround.
sc.exe config myService start= delayed-auto
Finally, check out this (very) long answer by user Kramii, and this by Peter Kelly. Both of them wrote helper classes to make doing this sort of thing a lot easier. I haven't tested them but they look promising.
Sty's answer lets you set a service to automatic delayed at the time of creation; not post deployment.
There is a command line that can do that
sc \\computername config *servicename* start= delayed-auto
I ran this command line in the remote server using WMI Management Class and it works fine.
More documentation on how to remote start a process here

What to specify for Local ManagementScope

I am trying to connect (locally) to get a list of virtual machines and their properties. I have hacked some code I found, but my code is failing to connect so I can only assume that the connection string is wrong.
Using Server 2012, Hyper-V
private void listVirtualMachines() {
ManagementScope manScope = new ManagementScope(#"\\LOCALHOST\root\cimv2");
if (manScope.IsConnected) {
ObjectQuery queryObj = new ObjectQuery("SELECT * FROM Msvm_ComputerSystem");
// connect and set up our search
ManagementObjectSearcher vmSearcher = new ManagementObjectSearcher(manScope, queryObj);
ManagementObjectCollection vmCollection = vmSearcher.Get();
// loop through the machines
foreach (ManagementObject vm in vmCollection) {
// display VM details
LogString(vm["ElementName"].ToString());
LogString(vm["EnabledState"].ToString());
LogString(vm["Description"].ToString());
}
} else {
//WE END UP HERE EVERY TIME!
LogString("Cannot Connect to ManagementScope!");
}
} //funct
In Server 2012, Msvm_ComputerSystem is in the WMI namespace root\virtualization\v2 so the code should be:
ManagementScope manScope = new ManagementScope(#"\\.\root\virtualization\v2");
manScope.Connect();

Getting system information using c#

I have some problem (c#).
I can retrieve some mainboard info from win32-baseboard but when I want to get Model
but an error accrued.
How can we get a list of installed software on windows (like xp).
How can we get a list of installed Peripheral device on Windows (with detail) (like scanner, webcam).
How to obtain total amount of ram (just) directly.
Use WMI (I suspect you already using it):
Model is blank. Try Manufacturer property. Also get the Product property to get the model.
Installed software: Get the Win32_Product class.
Try Win32_PnPSignedDriver class and iterate through.
Use Win32_ComputerSystem class and get TotalPhysicalMemory property.
Get WMIEXPLORER and play with it. LINK
Sample for C#:
If you require to connect to remote computer with credentials (strUsername and strPassword variables):
private ManagementScope CreateNewManagementScope(string server)
{
string serverString = #"\\" + server + #"\root\cimv2";
ManagementScope scope = new ManagementScope(serverString);
if (!chkUseCurrentUser.Checked)
{
ConnectionOptions options = new ConnectionOptions
{
Username = strUsername,
Password = strPassword,
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.PacketPrivacy
};
scope.Options = options;
}
return scope;
}
Get the services:
private void GetServicesForComputer(string computerName)
{
ManagementScope scope = CreateNewManagementScope(computerName);
SelectQuery query = new SelectQuery("select * from Win32_Service");
try
{
using (ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query))
{
ManagementObjectCollection services = searcher.Get();
List<string> serviceNames =
(from ManagementObject service in services select service["Caption"].ToString()).ToList();
lstServices.DataSource = serviceNames;
}
}
catch (Exception exception)
{
lstServices.DataSource = null;
lstServices.Items.Clear();
lblErrors.Text = exception.Message;
Console.WriteLine(Resources.MainForm_GetServicesForServer_Error__ + exception.Message);
}
}
Some screens from wmiexplorer:

check if a process runs on a remote machine for a certain user

I have to create an executable which checks if a certain process is running for a certain user (a service account) on a remote machine, the input parameters are 3 strings, machine name, user name and process name.
I have the idea to do this using either System.Diagnostics or WMI, just wanted to double check if anybody has another idea like powershell or even a window functionality which could make the task even easier.
since we want to make sure that process is always running on a dedicated server we will configure a scheduled task to execute a small console application which does this check. Not sure if coding it in C# is the best option or am I ignoring a builtin feature of windows server? Thanks!
I'm pretty sure you can accomplish this with tasklist cmd: tasklist /S \\<server> /V > tasklist.txt. this will give you a file you can grep through.
namespace not referenced
using System.Management;
I have ended up by implementing following solution in C#
this retrieves the username without domain name of the user running processName on machineName
public static string GetProcessOwner()
{
try
{
var resultUserName = string.Empty;
ConnectionOptions opt = new ConnectionOptions();
string path = string.Format(#"\\{0}\root\cimv2", machineName);
ManagementScope scope = new ManagementScope(path, opt);
scope.Connect();
var query = new ObjectQuery(string.Format("Select * From Win32_Process Where Name = '{0}'", processName));
ManagementObjectSearcher searcher = new ManagementObjectSearcher(scope, query);
var processList = searcher.Get();
foreach (ManagementObject obj in processList)
{
string[] argList = new string[] { string.Empty, string.Empty };
int returnVal = Convert.ToInt32(obj.InvokeMethod("GetOwner", argList));
if (returnVal == 0)
{
// return DOMAIN\user
//return argList[1] + "\\" + argList[0];
resultUserName = argList[0];
}
}
return resultUserName;
}
catch (Exception exc)
{
Debug.WriteLine(exc.Message);
return string.Empty;
}
}
GetOwner can return empty array for remote comp, so it may not work

Categories

Resources