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.
Related
We have an application (C#) that up till today has worked fine.
It communicates with a laravel website to manage the sites data.
So there are some validation points that occur, the application does checks with out SSO provider for authentication. Then it passes some of the user's information over to the site so the site can create a user / send back user id for further entry points.
I have literally not touched this in months - and its been working without a problem.
Today I get a message its not working and so I start digging.
Can somebody explain THIS one?
C# Code For Validating User - Notice the response from the site.
The Laravel API Routes File on the route in question.
public function validation(Request $request) {
//Check if user exists if they do then just return. If they dont we need to create them in the system.
$user = User::where('email', $request['Email'])->first();
if($user == null) {
$nuser = new User();
$nuser->first_name = $request['FName'];
$nuser->last_name = $request['LName'];
$nuser->email = $request['Email'];
$nuser->token = $request['Token'];
switch($request['Role']) {
case 1:
$nuser->user_level = 1;
break;
case 2:
$nuser->user_level = 2;
break;
case 3:
$nuser->user_level = 3;
break;
case 4:
$nuser->user_level = 4;
break;
default:
$nuser->user_level = 4;
break;
}
try {
$nuser->save();
return json_encode($nuser);
}catch(\Exception $e) {
Log::error($e->getMessage());
}
}else{
switch($request['Role']) {
case 1:
$user->user_level = 1;
break;
case 2:
$user->user_level = 2;
break;
case 3:
$user->user_level = 3;
break;
case 4:
$user->user_level = 4;
break;
default:
$user->user_level = 4;
break;
}
try {
$user->save();
return json_encode($user);
}catch(\Exception $e) {
Log::error($e->getMessage());
}
}
}
So the end user of the C# application decided to overwrite the ini file with the website in it (for quick swaps between dev and production for the development team)....I noticed new entries in the development server's database from yesterday....end user then tries to put it back to the production server. But left off the s in https - and like any good website - it auto redirects to its https counterpart.
Cue RestClient trying to follow the redirect with a GET.
Updated the INI fixing the typo, tell user to close the application and reopen it to reload the INI data. Have our network team lock down the network folder containing the INI to read only unless its a member of the development team. And we're back rolling.
I am writing a small app that installs IIS and configures a website before deploying the files to it.
On a freshly reset Windows 10, the first attempt always fails with the 0x80040154 COM+ component failure as documented in This question
I looked at the version I am using and it is the latest and correct one for .net standard (4.8) and not the one meant for .net core
When I press the button to rerun the function it always finishes correctly. I tried using a retry routine, and it fails on each retry, yet runs fine again when the button is pressed. The reason for this I assume is that the server manager object isn't disposed when it hits the catch block since its in a using statement.
I can work around that, but I really want to understand the issue and make a permanent fix.
My routine simply creates a website in IIS and creates an app pool to assign to it.
And it is running with elevated privileges
For reference:
Machine is Windows 10 latest from the downloadable media creator.
Microsoft.Web.Administrator version is 7.0.0.0
App is .net 4.8 standard windows forms
using (var serverManager = new ServerManager())
{
string iisrootdir = drive;
//Check for inetpub/wwwroot
if (!Directory.Exists(iisrootdir)) //Check for Drive D
{
iisrootdir = #"C:\";
}
string iiscmsdir = Path.Combine(iisrootdir, "webdir", "appdir");
if (!Directory.Exists(iiscmsdir))
Directory.CreateDirectory(iiscmsdir);
var settings = new ApplicationSettings();
settings.ReadFromFile();
settings.CMSPATH = iiscmsdir;
settings.SaveToFile();
try
{
string poolName = "DefaultAppPool";
if (serverManager.Sites.Count > 0)
{
Site myDefualtWebsite = serverManager.Sites[0];
if (myDefualtWebsite != null)
{
OnRaiseInstallEvent(new InstallEventArgs("CreateWebsite", ProcessState.Started,
"Remove Default Website"));
serverManager.Sites.Remove(myDefualtWebsite);
serverManager.CommitChanges();
}
}
if (!WebsiteExists("sitename"))
{
mySite.ServerAutoStart = true;
}
Site site = serverManager.Sites["sitename"];
if (!AppPoolExists(poolName))
{
serverManager.ApplicationPools.Add(poolName);
}
ApplicationPool apppool = serverManager.ApplicationPools[poolName];
apppool.ManagedPipelineMode = ManagedPipelineMode.Integrated;
apppool.ManagedRuntimeVersion = "";
serverManager.Sites["sitename"].ApplicationDefaults.ApplicationPoolName = poolName;
foreach (var item in serverManager.Sites["sitename"].Applications)
{
item.ApplicationPoolName = poolName;
}
serverManager.CommitChanges();
apppool.Recycle();
serverManager.CommitChanges();
}
catch (Exception ex)
{
if (ex.Message.Contains("80040154") && errorCount < 4)
{
if (serverManager != null)
serverManager.Dispose();
errorCount++;
OnRaiseInstallEvent(new InstallEventArgs("CreateWebsite", ProcessState.Started,
"Error encountered with COM+ object, trying again: " + errorCount));
CreateWebsite(#"D:\");
}
else
{
if (serverManager != null)
serverManager.Dispose();
errorCount = 0;
OnRaiseErrorEvent(new InstallErrorEventArgs("CreateWebsite", ProcessState.Error, ex));
return false;
}
}
finally
{
serverManager?.Dispose();
}
Thanks for the help Guys. I found the problem.
DISM was running in its own thread. The Process object exited the moment it launched. My function was then attempting to configure IIS before it had finished installing.
Im working on the Vsto excel add-in and I'm getting the window rect through CreateWindowRect().
I'm running the application with ISO Office2016 Excel and Office365 excel.
The problem is I'm getting a different window rectangle while running the ISO office2016 excel and I have to get the correct window rect while running the application with office365excel.
So I'm planning to adjust the window rectangle while running application with ISO office2016 excel. To check the condition I'm in need to get whether the excel is standalone or office365 excel.
Is there any way to find whether Excel application is Click-to-Run (Online Office 365 installer) or Windows Installer (ISO file or DVD) using c#?
A computer can have multiples versions of Office.
But, you can discover if the machine has the Office 365 installed doing something like that:
using Microsoft.Win32;
...
private bool Has365Office()
{
RegistryView registryView = RegistryView.Registry32;
string registryKey = "Software\Microsoft\Office\16.0\Common\Licensing\LicensingNext";
using (RegistryKey key = RegistryKey.OpenBaseKey(RegistryHive.CurrentUser, registryView).OpenSubKey(registryKey))
{
foreach (string subkeyName in key.GetValueNames())
{
if (subkeyName.Contains("o365"))
return true;
}
}
return false;
}
...
To know what version is running, or at least will run when the user opens it, you can do something like that:
using Microsoft.Office.Interop;
...
public string GetOfficeVersion()
{
string sVersion = string.Empty;
Microsoft.Office.Interop.Word.Application appVersion = new Microsoft.Office.Interop.Word.Application();
appVersion.Visible = false;
switch (appVersion.Version.ToString())
{
case "7.0":
sVersion = "95";
break;
case "8.0":
sVersion = "97";
break;
case "9.0":
sVersion = "2000";
break;
case "10.0":
sVersion = "2002";
break;
case "11.0":
sVersion = "2003";
break;
case "12.0":
sVersion = "2007";
break;
case "14.0":
sVersion = "2010";
break;
case "16.0":
sVersion = "2016 or 2019 or 365";
break;
default:
sVersion = "Too Old!";
break;
}
return sVersion;
}
You can combine the code above to get what you need. I hope it helps!
both codes were made from this answer: link
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
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)
{...