I would like to know how to programatically restart IIS 6.0 SMTP server.
The SMTP server I have setup crashes every now and then. I don't notice it for a couple days, but that is by far way too late to do anything about it.
I want to set up a scheduled task every 30 minutes or so to test if the SMTP server is running, and if its not, the Scheduled task with automatically start it back up.
I have found a way to check if the SMTP server is up and running, but I have not figured out how to restart the process if it crashes.
That way is posted here: Testing SMTP server is running via C#
Any help would be brilliant!
Thank you.
Im developing the Console application in C# to check if its running or not, so any code examples would be great too.
A ServiceController can help you, as it has start and stop methods. Look at the sample in the msdn page.
Another sample is taken from the ServiceControllerStatus Enumeration is nearly what you need (just replace the service name).
ServiceController sc = new ServiceController("Telnet");
Console.WriteLine("The Telnet service status is currently set to {0}",
sc.Status.ToString());
if ((sc.Status.Equals(ServiceControllerStatus.Stopped)) ||
(sc.Status.Equals(ServiceControllerStatus.StopPending)))
{
// Start the service if the current status is stopped.
Console.WriteLine("Starting the Telnet service...");
sc.Start();
}
else
{
// Stop the service if its status is not set to "Stopped".
Console.WriteLine("Stopping the Telnet service...");
sc.Stop();
}
// Refresh and display the current service status.
sc.Refresh();
Console.WriteLine("The Telnet service status is now set to {0}.",
sc.Status.ToString());
Maybe I'm missing something, or something changed, but when you install SMTP service on Windows 2012R2, there is no dedicated service for it. So, for recent version of Windows the advice above won't work.
Luckily there's a way to do it much easier. Powershell:
([ADSI]'IIS://LOCALHOST/SMTPSVC/1').Start() #to start
([ADSI]'IIS://LOCALHOST/SMTPSVC/1').Stop() #to ... you guess
The weirdest thing is that you control smtp service through AD, but it works.
And of course this should be run elevated.
If you have several virtual SMTP servers, you may need to identify your server by index or by some property (e.g. .ConnectionTimeout) first.
in c# you can write:
enum StatusVirtualServerSMTP
{
Started = 2,
Stopped = 4
}
DirectoryEntry dir = new DirectoryEntry("IIS://localhost/SMTPSVC/1");
if (Convert.ToInt32(dir.Properties["SERVERSTATE"].Value) == (int)StatusVirtualServerSMTP.Stopped)
{
dir.Properties["SERVERSTATE"].Value = (int)StatusVirtualServerSMTP.Started;
dir.CommitChanges();
}
Related
I'm working on an automation process in C# that is going to remotely reboot a Windows (2008/2012/2016) server and I need to wait until that server is back online before proceeding.
I know 'back online' can be ambiguous, so for my requirements, I need the server to be back at the Ctrl-Alt-Del screen.
The reason for this is to have the server in a consistent state before proceeding. In my experience, there are several factors that could prevent the server from reaching this screen, such as installing windows updates that gets stuck in a reboot cycle or getting stuck at 'Waiting for Local Session Manager' etc.
I've spent a few days looking in to this to no avail:
The server obviously starts responding to ping requests before it is available
System Boot Time occurs before the Server reaches the desired state
Any events indicating the system has booted are logged before the desired state
I can't simply poll for an essential service - when Windows is applying computer updates prior to logon these services can be already started. Additionally, sometimes a server will reboot itself whilst installing updates at this stage which could result in false positives.
Polling CPU activity could also produce false positives or introduce delays
Is there anyway to detect a Windows server has finished booting and is available for an interactive logon?
It sounds like you've covered most of the possible ways I know of. Which makes me revert to brute force ideas. I am curious what you're doing where you can't install a windows service on the box (or is that just not very viable because of the number)
First would just be trying to remote login or whatever, and having some way to test if it fails or not, wait 1 minute, try again. But seems like that might cause side-issues for you somehow?
My idea of a brute force method that wouldn't affect state:
Ping every 1-5seconds
Once it starts responding
wait 5 or 10 or even 15 minutes, whilst still pinging it
If pings fail reset that timer (windows updates restart case)
Then be pretty confident you're at the right state.
With potentially thousands of servers, I can't imagine 15 minutes each would be a big deal, especially if it is consistent enough to be able to run in larger batches
So I've been able to accomplish this by using a hacky method put seems to work in my test environment.
Note that the el.Current.Name property will equate to the Ctrl-Alt-Del text, so on 2008R2 this is 'Press CTRL-ALT-DEL to log on' and 'Press CTRL-ALT-DEL to sign in.' on 2012R2
I've built a C# console application that uses UI Automation:
using System;
using System.Windows.Automation;
namespace WorkstationLocked
{
class Program
{
static void Main()
{
AutomationElement el = AutomationUI.FindElementFromAutomationID("LockedMessage");
if (el !=null)
{
Console.WriteLine(el.Current.Name);
}
}
}
class AutomationUI
{
public static AutomationElement FindElementFromAutomationID(string automationID)
{
string className = "AUTHUI.DLL: LogonUI Logon Window";
PropertyCondition condition = new PropertyCondition(AutomationElement.ClassNameProperty, className);
AutomationElement logonui = AutomationElement.RootElement.FindFirst(TreeScope.Children, condition);
if (logonui != null)
{
condition = new PropertyCondition(AutomationElement.AutomationIdProperty, automationID);
return logonui.FindFirst(TreeScope.Descendants, condition);
}
else
{
return null;
}
}
}
}
I can then execute this console application via PsExec, however, because this needs to be launched in the winlogon desktop, which can only be done by running under the local system, PsExec is invoked twice. For example:
psexec.exe \\ServerA -s -d C:\PsTools\PsExec.exe -accepteula -d -x C:\Utils\WorkstationLocked.exe
This is very much a work in progress right now as I can't get the output of the command to pass through to the calling process so I may just look to populate a registry value or write to a file that can be subsequently interrogated.
I have a local service running on my computer and trying to get other computers to be able to read the status of my service (whether it's running, stopped, etc.) However, I am unable to as I get an InvalidOperationException error, saying that I am unable to open Service Control Manager. Locally, I am able to, but on another remote computer I am unable to. The ServiceController (cs) object just returns an object with properties that all have the InvalidOperationException error.
I've tried closing down all the firewalls on the other computers, tried running Visual Studio on Administrator privileges, but nothing seems to be working. I've noticed that others suggested hard coding your admin credentials and using WindowsIdentity and Impersonation but that wouldn't work for my project (as it wouldn't be a viable solution at my workplace - wouldn't make sense with the business logic as don't want to give clients any in-house credentials).
Here's my snippet of code:
public bool CheckServiceStatus()
{
try
{
string machineName = pubSubConfig.MachineName;
string serviceName = pubSubConfig.ServiceName;
System.ServiceProcess.ServiceController cs = new System.ServiceProcess.ServiceController(serviceName, machineName);
if (cs != null && cs.ServiceName == serviceName && cs.Status == System.ServiceProcess.ServiceControllerStatus.Running)
{
return true;
}
}
catch(Exception ex)
{
Trace.TraceError("Unable to check service status: /r/n {0}", ex.Message);
}
return false;
}
The error is this:
System.InvalidOperationException: Cannot open Service Control Manager on computer '___'.
This operation might require other privileges. ---> System.ComponentModel.Win32Exception: Access is denied
Does anyone know any workarounds as to how I can get other computers running my C# program to be able to read the ServiceController object?
Thanks!
So as I said in the comments, I was not able to get around the SCM (Service Control Manager) due to admin privileges when accessing another remote computer (makes sense if you think about security). However, I did find another solution that was more or less a workaround. I'll post the solution here in case anyone finds it helpful.
So to check the status of the Windows Service (like if it's running or not), I added an additional WCF service that is hosted in the Windows Service. So now the service can expose a method that literally just returns true.
Essentially the thought-process around it was that if the WCF service is accessible then that means the Window Service is running, and thus will always return true. If the Windows service is down, the WCF service will also be down and thus making that method not available. You wouldn't get anything to return, so you would know that the service is down and not running.
Hope that helps someone! I know it's not really a direct solution to the problem I had originally asked, but it was a workaround, indirect solution.
I am trying to figure out what clients are connected to my machine using remote desktop.
I read about Cassia and the Cassia.TerminalServicesManager, but I can't wrap my mind around it...
I thought that Cassia.TerminalServicesManager().CurrentSession.ClientName would give me a name of the client, but what if there are more? I looked at the references, but I am still confused. Can someone help me out?
Thanks
It sounds like you're looking for something like this:
var manager = new TerminalServicesManager();
using (var server = manager.GetLocalServer())
{
server.Open();
foreach (var session in server.GetSessions())
{
if (session.ConnectionState == ConnectionState.Active)
{
Console.WriteLine(session.ClientName);
}
}
}
ITerminalServicesManager.CurrentSession returns the session in which the current process is running.
By default If you connect to a windows machine using remote desktop it kicks the local user off, if they log back in it kicks the remote user off. If you have enabled Concurrent Remote Desktop Sessions there can be multiple users connected at once. I am not familiar with Cassia but perhaps you could loop over all of the sessions calling Cassia.TerminalServicesManager().CurrentSession.ClientName each time?
I have a ASP.NET web application running under IIS 6, and another process that is responsible to monitor and report status.
I'd like to sample the web application by the monitoring process in order to check its status by accessing a dedicated handler on the web application, BUT i don't want to "wake up" the web application in case it is not running.
Is there an option to determine whether a specific web application is currently running? if there is such an option, i would be able to first check if the application is running, and only then to access the handler to check its status.
Thanks.
I had to do something similar earlier this year for IIS7, not sure if this would work for IIS6 but here's what I did.
var iis = new DirectoryEntry("IIS://" + Environment.MachineName + "/w3svc");
foreach (DirectoryEntry site in iis.Children)
{
if (site.SchemaClassName.ToLower() == "iiswebserver")
{
Console.WriteLine("Name: " + site.Name);
Console.WriteLine("State: " + site.Properties["ServerState"].Value);
}
}
ServerState returns 2 for started and 4 for stopped.
You can use the HTTP HEAD request to check if the site is up or not. Here is an example to do the same.
http://www.eggheadcafe.com/tutorials/aspnet/2c13cafc-be1c-4dd8-9129-f82f59991517/the-lowly-http-head-reque.aspx
I would include in the ASP.NET website an asmx file, a web service with a simple Ping function, but it will still wake up the application pool of the website.
You could analyse the IIS log file, to see if there are recent entries.
If your application is not used much, it is possible the latest "entry" still needs to be flushed.
Or you could update a file/database to indicate "still active".
If you really do not want a delay, in the Application_Start and Application_End, create and destroy a system mutex.
This is my solution:
try
{
WebRequest request = WebRequest.Create("http://localhost/");
WebResponse response = request.GetResponse();
}
catch (WebException ex)
{
// ex.Status will be WebExceptionStatus.ConnectFailure
// if the site is not currently running
}
We used to use Nagios to monitor our site and it would target the favicon of our website. If it could pull back the icon, we knew the site was up.
I have a small C# solution used to check users credentials. It works fine for two of my teammates, but on my PC I get an exception.
The relevant code:
PrincipalContext context = new PrincipalContext(ContextType.Domain);
if (context.ValidateCredentials(System.Environment.UserDomainName + "\\" + usr, pwd))
return true;
else
return false;
And the exception is:
DirectoryOperationException, "The server cannot handle directory requests.".
I tried creating context with the explicit server name and the 636 port number, but this didn't help as well.
Any ideas?
I had this problem too using IIS Express and VS 2010. What fixed it for me was a comment on another thread.
Validate a username and password against Active Directory?
but i'll save you the click and search... :) Just add ContextOpations.Negotiate to you Validate Credentials call like below.
bool valid = context.ValidateCredentials(user, pass, ***ContextOptions.Negotiate***);
I had this issue: things were working on my dev machine but didn't work on the server. Turned out that IIS on the server was set up to run as LocalMachine. I changed it to NetworkService (the default) and things started working.
So basically check the user of the app pool if this is running on IIS.
I had to just create a new app pool and assign it .NET 2.0, then assign the new app pool to our web app, and it started working. We had .NET 3.5 SP2, so the hotfix wasn't ideal for us. Since the WWW service is usually Local System, I questioned that too. But since it was .NET and security related, I gave a shot at the app pool first and it worked.
Perhaps you need the hotfix?
FIX: DirectoryOperationException exception
And you are an Admin or the id that your service is running under is an Admin on your PC right?
I take it you already looked into this:
System.DirectoryServices.Protocols
"You may receive a less than helpful DirectoryOperationException(“The server cannot handle directory requests.”) what isn’t quite so amusing about this is that it didn’t even try to communicate with the server. The solution was to add the port number to the server. So instead of passing “Server” to open the LdapConnection, I passed “server:636”. By the way, LDAPS is port 636 – rather than the 389 port used by LDAP."
Good point, I wouldn't expect that Win7/.NET 3.5 would need that patch. How about the info provided in this question:
Setting user's password via System.DirectoryServices.Protocols in AD 2008 R2