41

I have some utility methods that use Microsoft.Web.Administration.ServerManager that I've been having some issues with. Use the following dead simple code for illustration purposes.

using(var mgr = new ServerManager())
{
    foreach(var site in mgr.Sites)
    {
        Console.WriteLine(site.Name);
    }
}

If I put that code directly in a console application and run it, it will get and list the IIS express websites. If I run that app from an elevated command prompt, it will list the IIS7 websites. A little inconvenient, but so far so good.

If instead I put that code in a class library that is referenced and called by the console app, it will ALWAYS list the IIS Express sites, even if the console app is elevated.

Google has led me to try the following, with no luck.

//This returns IIS express
var mgr = new ServerManager();
//This returns IIS express
var mgr = ServerManager.OpenRemote(Environment.MachineName);
//This throws an exception
var mgr = new  ServerManager(@"%windir%\system32\inetsrv\config\applicationhost.config");

Evidently I've misunderstood something in the way an "elevated" process runs. Shouldn't everything executing in an elevated process, even code from another dll, be run with elevated rights? Evidently not?

Thanks for the help!

Josh
  • 2,740
  • 3
  • 27
  • 41

4 Answers4

64

Make sure you are adding the reference to the correct Microsoft.Web.Administration, should be v7.0.0.0 that is located under c:\windows\system32\inetsrv\ It looks like you are adding a reference to IIS Express's Microsoft.Web.Administraiton which will give you that behavior

Carlos Aguilar Mares
  • 13,411
  • 2
  • 39
  • 36
  • 2
    Carlos. Thanks for the reply! You were right! I double checked and somehow the reference in the class library got screwed up. I would have sworn that it had the right reference, but somehow it was pointing to 7.9.0.0 in the GAC. Thanks! – Josh Dec 13 '11 at 17:05
  • 1
    I had the same problem. I'm also sure i had the right reference. But after moving around on projects it got changed.. – mimo Apr 18 '12 at 05:53
  • 2
    I suspect installing VS 2012 caused me to have this same problem, perhaps it only installed IIS express and wasn't actually a direct cause. – John Nov 10 '12 at 09:50
  • 4
    I also noticed that even if you're running the reference to the assembly in %windir%\system32\inetsrv\ but you are executing the code within an IIS Express process, it only returns IIS Express sites, but when I run it in a console app with admin rights, I get only the IIS 7.5 sites (on Windows 7 x64). – Wade Apr 10 '13 at 14:34
  • 3
    I love you. This was driving me crazy. – mcabral Jun 06 '13 at 16:27
  • 12
    Thank you. I had a reference to 7.0.0.0 (from inetmgr dir) but Visual Studio was silently switching this for 7.9.0.0 (IISExpress) from the GAC instead. Setting ``True`` in the assembly reference in my *.csproj fixed the problem. You can tell if ServerManager is using IIS or IISExpress by firing up your app in a debugger and having a look at ``ServerManager.ApplicationPoolsSection.Configuration.ConfigFile.FilePath`` to see if it contains inetsrv or IISExpress. – Richard Dingwall Jul 10 '13 at 10:13
  • 1
    As @Wade pointed out, this doesn't actually have anything to do with what DLL is being used. – Florian Winter Feb 10 '17 at 08:48
  • Windows Forms application on Windows 10 with IIS 10.0.14393.0, tried all: updated reference, set to specificversion, running elevated, debug/release, with/withot debugger, connecting with `ServerManager.OpenRemote("localhost")`, always connects to IISExpress... – Cee McSharpface Apr 28 '17 at 16:11
12

Your question helped me find the answer for PowerShell, so if the Internet is searching for how to do that:

$assembly = [System.Reflection.Assembly]::LoadFrom("$env:systemroot\system32\inetsrv\Microsoft.Web.Administration.dll")

# load IIS express
$iis = new-object Microsoft.Web.Administration.ServerManager 
$iis.Sites

# load IIS proper
$iis = new-object Microsoft.Web.Administration.ServerManager "$env:systemroot\system32\inetsrv\config\applicationhost.config"  
$iis.Sites
Richard
  • 14,798
  • 21
  • 70
  • 103
  • 1
    Note that the constructor you are using is documented as "Microsoft internal use only": https://msdn.microsoft.com/en-us/library/ms617371(v=vs.90).aspx – Florian Winter Jun 22 '18 at 12:49
5

CAUTION! Using this approach we have seen seemingly random issues such as "unsupported operation" exceptions, failure to add/remove HTTPS bindings, failure to start/stop application pools when running in IIS Express, and other problems. It is unknown whether this is due to IIS being generally buggy or due to the unorthodox approach described here. In general, my impression is that all tools for automating IIS (appcmd, Microsoft.Web.Administration, PowerShell, ...) are wonky and unstable, especially across different OS versions. Good testing is (as always) advisable!

EDIT: Please also see the comments on this answer as to why this approach may be unstable.

The regular Microsoft.Web.Administration package installed from NuGet works fine. No need to copy any system DLLs.

The obvious solution from the official documentation also works fine:

ServerManager iisManager = new ServerManager(Environment.SystemDirectory + @"inetsrv\config\applicationHost.config");

This works even if you execute the above from within the application pool of IIS Express. You will still see the configuration of the "real" IIS. You will even be able to add new sites, as long as your application runs as a user with permission to do so.

Note, however that the constructor above is documented as "Microsoft internal use only":

https://msdn.microsoft.com/en-us/library/ms617371(v=vs.90).aspx

Florian Winter
  • 4,750
  • 1
  • 44
  • 69
  • 2
    I don't think effect is random. there are two version of that dll exists in system, one in GAC and one in ```System32\inetsrv\```. Both have same name for some weird unknown reason. The one in GAC is for IISExpress and the one in inetsrv is for IIS. Neither of those can read the other one's data correctly. Obviously GAC version shouldn't exist in actual webserver since visual studio is not installed. – AaA Apr 20 '21 at 08:14
  • @AaA Thanks for the explanation. You don't happen to know if there is an official/reliable way to link to the correct DLL? The accepted answer is based on version number, which seems unstable, as version numbers change (and a comment on it suggests this has already happened). – Florian Winter Apr 22 '21 at 07:06
  • I'm not sure what do you like to know, IISExpress version normally doesn't exist in production environment. if you don't want to copy the dll in your app folder (obviously from same machine that you are installing your app) then [you can dynamically load the dll on runtime using reflection](https://stackoverflow.com/questions/465488/) – AaA Apr 22 '21 at 08:36
2
var iisManager = new ServerManager(Environment.SystemDirectory + "\\inetsrv\\config\\applicationhost.config");

This works perfectly. No need to change any references

arlak
  • 440
  • 4
  • 5