Invoke Application (Custom application which has arguments) on Remote System using WMI - c#

I have one custom application which install or other system & I want to call that from this system using WMI C# without any batch file.
Moreover that application has command arguments to run. So, can anyone guide me what I suppose to code ?
I already tried few things which I am pasting here (code snippet) for your reference which works fine in case of Notepad.exe or Calc.exe to run.
In fact, It also works for me in my custom application without arguments but not with arguments. When I passed with arguments it start & kill after 2 seconds. Which means it doesn't pass arguments in well/ proper format.
private static uint CreateProcess(ManagementScope connectionScope, string exeWithPathAndArguments)
{
try
{
var objectGetOptions = new ObjectGetOptions();
ManagementPath processPath = new ManagementPath("Win32_Process");
using (var processTask = new ManagementClass(connectionScope, processPath, objectGetOptions))
{
using (var methodInParams = processTask.GetMethodParameters("Create"))
{
methodInParams["CommandLine"] = exeWithPathAndArguments;
using (var methodOutParams = processTask.InvokeMethod("Create", methodInParams, null))
{
var err = (uint)methodOutParams["returnValue"];
if (err != 0)
{
var info = "see http://msdn.microsoft.com/en-us/library/windows/desktop/aa389388(v=vs.85).aspx";
switch (err)
{
case 2: info = "Access Denied"; break;
case 3: info = "Insufficient Privilege"; break;
case 8: info = "Unknown failure"; break;
case 9: info = "Path Not Found"; break;
case 21: info = "Invalid Parameter"; break;
default: info = "Unknown(Code)"; break;
}
var msg = "Failed to Start the Process, error = " + methodOutParams["returnValue"] + " (" + info + ")";
throw new Exception(msg);
}
return (uint)methodOutParams["processId"];
}
}
}
}
catch (Exception ex)
{
throw ex;
}
}
I already aware with PSExec but I don't want to use that. Same time I don't want to use Batch File to run my command. Just want to use direct command passing way to run the application.
My Application location is not in PATH Directory. so, obviously I need to supply a full path like...
CreateProcess(connectionScope, exeWithPathAndArguments.Trim());
where exeWithPathAndArguments would be "/"C:\Program files (x86)\Company\Application Folder\app.exe/" -argsName argvalue"

Add methodInParams["CurrentDirectory"] = wheretostartapp; and delete -argsName
So your exeWithPathAndArguments will be:
\"C:\\\\Program files (x86)\\\\Company\\\\Application Folder\\\\app.exe\" argvalue

Related

Cmdlet is working on Powershell but it is not working through C#

I want to use a Invoke-RDUserLogoff cmdlet to logoff users on remote computer. This cmdlet works well when is submitted using PowerShell. However, every time I try to execute it using the below code I get a "Invoke-RDUserLogoff is not recognized as the name of a cmdlet.....". Any clue or help will be appreciate it. Thanks!
System.Management.Automation.PowerShell psinstance = System.Management.Automation.PowerShell.Create();
string errorMesg = string.Empty;
//string result = string.Empty;
string command = "";
command = #"Invoke-RDUserLogoff -HostServer " + computerNameTB.Text + " -UnifiedSessionID " + sessionIDTB.Text + " -Force";
psinstance.AddCommand(command);
//Make sure return values are outputted to the stream captured by C#
psinstance.AddCommand("out-string");
PSDataCollection<PSObject> outputCollection = new PSDataCollection<PSObject>();
psinstance.Streams.Error.DataAdded += (object sender1, DataAddedEventArgs e1) =>
{
errorMesg = ((PSDataCollection<ErrorRecord>)sender1)[e1.Index].ToString();
};
//IAsyncResult result = psinstance.BeginInvoke<PSObject, PSObject>(null, outputCollection);
IAsyncResult result = psinstance.BeginInvoke();
//wait for powershell command/script to finish executing
psinstance.EndInvoke(result);
StringBuilder sb = new StringBuilder();
foreach (var outputItem in outputCollection)
{
sb.AppendLine(outputItem.BaseObject.ToString());
}
if (!string.IsNullOrEmpty(errorMesg))
{
MessageBox.Show(errorMesg, "Logoff Users");
}
else
{
MessageBox.Show(sb.ToString(), "LogoffUsers app");
}
A hint I think worth trying is checking the project settings: found few claims that changing the target platform cpu to x64 from x86 might fix locating the proper modules please see: Import-Module does not work in c# powershell command
Good luck!🤞

c# adobe acrobat SDK: file is still locked after SDK quit

I'm working with C# and adobe acrobat SDK.
When the program throws an error due to the pdf already being compressed I want to move the pdf.
However, C# complains that the file is being used by another process and I know it has to do with the SDK and not another program.
After some debugging I found out that compressPDFOperation.Execute is the culprit.
How can I close it so that I can move the file?
try {
// Initial setup, create credentials instance.
Console.WriteLine(".json: " + Directory.GetCurrentDirectory() + "/pdftools-api-credentials.json");
Credentials credentials = Credentials.ServiceAccountCredentialsBuilder()
.FromFile(Directory.GetCurrentDirectory() + "/pdftools-api-credentials.json")
.Build();
// Create an ExecutionContext using credentials and create a new operation instance.
ExecutionContext executionContext = ExecutionContext.Create(credentials);
CompressPDFOperation compressPDFOperation = CompressPDFOperation.CreateNew();
// Set operation input from a source file.
FileRef sourceFileRef = FileRef.CreateFromLocalFile(directory + #"\" + pdfname);
compressPDFOperation.SetInput(sourceFileRef);
// Execute the operation.
FileRef result = compressPDFOperation.Execute(executionContext);
// Save the result to the specified location.
//if pdf is part of a group, the group directory name will be stored in fileGroupDirectory
string fileGroupDirectory = directory.Replace(sourceDir, "");
result.SaveAs(finishedDir + fileGroupDirectory + pdfname);
}
catch (ServiceApiException ex)
{
Console.WriteLine("Exception encountered while executing operation", ex.Message);
if (ex.Message.Contains("The input file is already compressed"))
{
File.Move(file, finishedDir + fileGroupDirectory + fileName);
}
}
I've found a solution , it's not best practice but I don't know an other way to do it.
I've declared all the variables used to execute the compression (sourceFileRef, compressPdfOperation, ...) before the try catch statement and after result.SaveAs(...) I set those variables to null and run the garbage collection.
compressPDFOperation = null;
result = null;
sourceFileRef = null;
executionContext = null;
credentials = null;
GC.Collect();

MSFT_Volume Format Method, in WinPE

I hope there may be some insight and maybe help in relation to my query.
I am trying to write the last module to a customised Windows Recovery environment, based on WinPE for Windows 10.
The solution currently utilises DiskPart to create the Disk Partitions (inline with Microsoft advice here), with the change of not providing for the WinRE partition.
After a fair amount of research and tinkering with a project found on MSDN, I managed to get a working project that would clear/partition and format a disk using WMI (MSFT_Disk,MSFT_Partition & MSFT_Volume). That is fully working within Windows 10 on a virtual disk of 15 GiB size.
When I tried it in WinPE (as this will be the OS that it will be used on), it failed on multiple elements, even though the Methods were reported as there). (MSFT_Disk::Clear, MSFT_Volume::Format).
On inspecting the result of my work in DiskPart, I noticed that even though MSFT_Volume::Format had a return value of 2 "Unknown Error" it had actually formatted the data partition (NTFS, ClusterSize 4096). However, when when the Format method is applied to the ESP (FAT32, cluster size 512/1024/4096)it fails fully, with the FileSystem still being reported as RAW, but will apply an AccessPath. "ExtendedStatus" only returns Error 2 (unless I am not accessing it correctly).
Has anyone else had this problem and managed to rectify the problem? Multiple Google searches have thrown out the idea that there maybe a WMI error, but within PowerShell, not as coded in C#/C++. Below are some code snippets and screen shots:
Creating the Partition:
try
{
parameters = disk.GetMethodParameters("CreatePartition");
}
catch (Exception e)
{
Console.WriteLine("Exception in Line 88: " + e.Message);
}
if (PartitionType != "PRIMARY")
{
FillInvocationParameters(parameters, new Dictionary<string, object> { { "Size", _partitionSize.ToString() },
{ "AssignDriveLetter", false },
{ "GpTType", _partitionType} });
}
else
{
FillInvocationParameters(parameters, new Dictionary<string, object> { { "UseMaximumSize", true },
{ "AssignDriveLetter", false },
{ "GpTType", _partitionType} });
}
try
{
res = disk.InvokeMethod("CreatePartition", parameters, null);
objresult = res["ReturnValue"]; //write error handliong routine for the objResult.
Int32.TryParse(objresult.ToString(), out intRes);
}
catch (Exception e)
{
Console.WriteLine("Exception in Line 146: " + e.Message);
ErrorID = Marshal.GetLastWin32Error();
return false;
}
if (intRes != 0)
{
Console.Write("CreatePartition {0} failed with the result: {1} Line 111.", PartitionType, objresult.ToString());
Console.ReadKey();
ErrorID = Marshal.GetLastWin32Error();
return false;
}
//this is the format point for EFI System Disk.. MSFTPARTITIONtoVOLUME MSFT VOLUME::FORMAT
Console.Write($"{PartitionType} Partition has been created\r\n");
string partition = ((ManagementBaseObject)res["CreatedPartition"])["__PATH"] as string;
var MSFT_Partition = new ManagementObject(#"root\Microsoft\Windows\Storage", partition, null);
var partitionIndex = partition.IndexOf(#"ObjectId=\");
partition = partition.Substring(partitionIndex);
partitionIndex = partition.IndexOf(#"}\\");
partitionIndex = partitionIndex + 1;
partition = partition.Substring(0, partitionIndex);
var strMSFTPartition = partition;
partition = partition.Replace("root", "ROOT");
var partitionGuid = MSFT_Partition["Guid"] as string;
Console.WriteLine("Line 138: New Partition GUID: " + partitionGuid);
Parameters is declared as:
ManagementBaseObject parameters = null;
FillInvokationParamters:
private static void FillInvocationParameters(ManagementBaseObject InvocationParameters, IDictionary<string, object> parameters)
{
foreach (var pair in parameters)
{
string stringParamValue;
var managementObjectParam = pair.Value as ManagementObject;
var arrayParam = pair.Value as string;
if (managementObjectParam != null)
{
stringParamValue = managementObjectParam.GetText(TextFormat.CimDtd20);
InvocationParameters[pair.Key] = stringParamValue;
}
else if (arrayParam != null)
InvocationParameters[pair.Key] = arrayParam;
else if (pair.Value != null)
{
stringParamValue = pair.Value.ToString();
InvocationParameters[pair.Key] = stringParamValue;
}
}
}
And the Format Method call:
try
{
Console.Write("Line 174: Attempting to Format with MSFT_Volume::Format FileSystem {0}, Label: {1}, ClusterSize: {2}\r\n", _FileSystem, _VolumeLable, _allocationUnit.ToString());
parameters = MSFTVolume.GetMethodParameters("Format");
FillInvocationParameters(parameters, new Dictionary<string, object>{ { "FileSystem", _FileSystem },
{ "AllocationUnitSize", _allocationUnit },
{ "FileSystemLabel", _VolumeLable },
{ "Full", false} });
res = MSFTVolume.InvokeMethod("Format", parameters, null);
objresult = res["ReturnValue"];
Int32.TryParse(objresult.ToString(), out intReslt);
}
catch (Exception e)
{
Console.WriteLine("Line: 189 The Following error occured while attmpeting to Format the Volume: " + e.Message);
ErrorID = Marshal.GetLastWin32Error();
return false;
}
For the ESP the following applies:
switch(PartitionType)
{
case "EFI":
{
_partitionType = "{c12a7328-f81f-11d2-ba4b-00a0c93ec93b}";
_partitionSize = 260 /*bytes*/ *1024 /*Kilobytes*/ *1024 /*Megabytes*/;
_FileSystem = "FAT32";
_allocationUnit = 1024;
_VolumeLable = "System";
break;
}
}
Screenshots of my console app and diskpart results:
Format Disk Console output
DiskPart Results
Any help/insights will be gratefully appreciated.
Regards
Richie
Note that there are several builds of the ADK for newer builds of Windows 10...be sure to use the latest and greatest. We had issues similar to yours with both dism.exe and diskpart.exe. At one point, (on early win 10 adks) we got dism.exe and diskpart.exe from an 8.1 adk. Hacky as heck, but you gotta do what you gotta do :-)
Update:
Checked with the support group...turns out, I got the versions mixed up. The very first win 10 adk had a working dism and diskpart (adk for windows 10 1503)...and we've been unable to use newer ones from within PE since...and so we're still deploying a new winpe from new ADK - but copying in the diskpart and dism saved off from the 1503 adk. We never deployed 8.1 versions - my bad. Still - hacky as all git out.
Best we can recollect, it only presented a problem in one side of the house...either BIOS+MBR or UEFI+GPT...but none of us remember which.

Renaming Printer using C# and WMI

I have created a C# application to rename printers on a Citrix server (Server 2008 R2).
The reason for this is because every time a user logs on the printer gets forwarded to the server and gets a unique name(For example Microsoft XPS Document Writer (from WI_UFivcBY4-wgoYOdlQ) in session 3) and from within some applications thats an issue since the printer is pointed to the name and by that you need to change the printer setting everytime you logon a session.
The program itself works like a charm and the printer gets the names I desire.
However the issue is after that the printers have been renamed Windows does not seem to be able to identify them anymore. For example if I try to change default printer i get an error saying "Error 0x00000709 Double check the printer name and make sure that the printer is connected to the network."
var query = new ManagementObjectSearcher("SELECT * FROM Win32_Printer where name like '%(%'");
ManagementObjectCollection result = query.Get();
foreach (ManagementObject printer in result)
{
string printerName = printer["name"].ToString();
if (printerName.IndexOf('(') > 0)
{
printer.InvokeMethod("RenamePrinter", new object[] { printerName.Substring(0, printerName.IndexOf('(')).Trim() + " " + userName }); //userName is provided as an inputparameter when running the application
}
}
Am I missing anything? Are there anything else i need to do when renaming?
I cant seem to find any info regarding this case at all.
i thing this codeproject is what your looking for. But after some own experiences with the printers in C# i can only say it does not make fun and it can be really frustrating
Code with small modifications:
//Renames the printer
public static void RenamePrinter(string sPrinterName, string newName)
{
ManagementScope oManagementScope = new ManagementScope(ManagementPath.DefaultPath);
oManagementScope.Connect();
SelectQuery oSelectQuery = new SelectQuery();
oSelectQuery.QueryString = #"SELECT * FROM Win32_Printer WHERE Name = '" + sPrinterName.Replace("\\", "\\\\") + "'";
ManagementObjectSearcher oObjectSearcher =
new ManagementObjectSearcher(oManagementScope, oSelectQuery);
ManagementObjectCollection oObjectCollection = oObjectSearcher.Get();
if (oObjectCollection.Count == 0)
return;
foreach (ManagementObject oItem in oObjectCollection)
{
int state = (int)oItem.InvokeMethod("RenamePrinter", new object[] { newName });
switch (state)
{
case 0:
//Success do noting else
return;
case 1:
throw new AccessViolationException("Access Denied");
case 1801:
throw new ArgumentException("Invalid Printer Name");
default:
break;
}
}
}
Still works great in 2022, thank you. Just had to change type
int
to
UInt32
to avoid new Exception:
UInt32 state = (UInt32)oItem.InvokeMethod("RenamePrinter", new object[] { newName });
switch (state)
{...

Check the status of an application pool (IIS 6) with C#

How can I check the status of an IIS6 application pool with C# ?
For example, I want to know if it is running or not !
Thank's in advance for your help !
http://msdn.microsoft.com/en-us/library/ms524962.aspx
You can do this checking the AppPoolState Property:
protected void status()
{
string appPoolName = "dev.somesite.com";
string appPoolPath = #"IIS://" + System.Environment.MachineName + "/W3SVC/AppPools/" + appPoolName;
int intStatus = 0;
try
{
DirectoryEntry w3svc = new DirectoryEntry(appPoolPath);
intStatus = (int)w3svc.InvokeGet("AppPoolState");
switch (intStatus)
{
case 2:
lblStatus.Text = "Running";
break;
case 4:
lblStatus.Text = "Stopped";
break;
default:
lblStatus.Text = "Unknown";
break;
}
}
I think you need the services of WMI (
Windows Management Instrumentation)
There are several articles around on how to manage IIS using WMI via vbscript, e.g.
http://learn.iis.net/page.aspx/163/managing-applications-and-application-pools-on-iis-70-with-wmi/
If you take one of those articles you should be able to adapt it to C# easily enough.

Categories