Programmatically creating a remote site in IIS7 using Microsoft.Web.Administration: Invalid index. (Exception from HRESULT: 0x80070585) - c#

I'm trying to write a provisioning tool for our web application. I am attempting to create a web site remotely in IIS7.5 using Microsoft.Web.Administration.ServerManager.
CODE:
using (ServerManager serverManager = ServerManager.OpenRemote("MyRemoteHost")) {
serverManager.Sites.Add("Contoso", "http", "*:80:www.contoso.com", #"C:\inetpub\wwwroot\Contoso");
serverManager.CommitChanges();
}
The above code continuously fails with error: Invalid index. (Exception from HRESULT: 0x80070585)
NOTES:
If I run this code locally on the host, I do not encounter the error and the web site is created successfully.
My user has administrative privileges on the remote host.
I am able to perform other operations on the remote host such as reading the listing of sites.
My workstation is running Windows 8
I've managed to successfully execute the above mentioned code against a Server 2012 host. There appears to be some sort of incompatibility when running this code on a Windows 8 client against a Server 2008R2 host.
I'm using Microsoft.Web.Administration.7.0.0.0.
Any help in resolving this issue would be greatly appreciated.
Thank you

I was having the same issue too by using a remote serverManager object connected to my target server on a very large, heavily regulated corporate network.
After some investigation however, it turned out that the website WAS being created on that specific instance of server manager and, despite the error comming back, using the .CommitChanges(); method on that serverManager object would succesfully save the new website.
var serverManager = ServerManager.OpenRemote("ServerName");
var sites = string.Join(";", serverManager.Sites.Select(o => o.ToString()));
Console.WriteLine(sites);
try
{
serverManager.Sites.Add("newWebSite", #"D:\TestSite", 80);
}
catch ( Exception e )
{
Console.WriteLine(e);
}
Console.WriteLine(string.Join(";", serverManager.Sites.Select(o => o.ToString())));
Console.WriteLine(string.Join(";", ServerManager.OpenRemote("ServerName").Sites.Select(o => o.ToString())));
serverManager.CommitChanges();
Console.WriteLine(string.Join(";", ServerManager.OpenRemote("ServerName").Sites.Select(o => o.ToString())));
Console.ReadLine();
Using this sample code, the catch was not hit, indicating that the program still worked and I can clearly see the website added to the remote server in both the original instance of the serverManager and the new one I created.
The Console returned this:
CopyOfLive;Default Web Site
CopyOfLive;Default Web Site;newWebSite
CopyOfLive;Default Web Site
CopyOfLive;Default Web Site;newWebSite
Furthermore, checking IIS on the server proved that the website had been created.
I hope this helps!

Related

WebClient.UploadString Returns 500 Submitting to Web Service Running On IIS Express

I'm using .NET Framework 4.5.1 WebClient and posting to a *.ashx that I have running locally so I can debug. The client site uses code like this:
var cli = new WebClient();
cli.Headers[ HttpRequestHeader.ContentType ] = "application/json";
var job = new
{
Inputs = inputs,
InputTables = inputTables,
...
};
var configuration = Newtonsoft.Json.JsonConvert.SerializeObject( job );
var response = cli.UploadString(
serviceUrl,
configuration
);
The serviceUrl is http://localhost:54300/Calculation.ashx and is running under IIS Express.
The web service returns the result via:
private void ReturnResponse( HttpContext context, JObject result )
{
using ( var textWriter = new StreamWriter( context.Response.OutputStream ) )
{
context.Response.ContentType = "application/json";
using ( var jsonWriter = new JsonTextWriter( textWriter ) )
{
result.WriteTo( jsonWriter );
}
}
}
This all works on my own personal computer, but on my company issued computer, it doesn't work and I'm at a loss of where to look. I assume it is some sort of security setting, or at least I'm hoping.
On my company computer, the client site successfully submits to the web service, I've stepped through the web service code and all works there and it returns the result via ReturnResponse and all looks correct. But, the client site then throws an 500 error 'The remote server returned an error: (500) Internal Server Error.' without much info to go on.
Additionally: This code works fine if the client site (running on my company computer) submits to the web service when the web service is hosted on the web (obviously running under IIS). So the code is fine - in my opinion :) - but only presents problem when web service is running locally.
Anyone know of some sort security/configuration setting that might be causing this? As I said, it worked fine on multiple personal machines without issue.
The 500 exception thrown was of type HttpException, so I read the response and discovered this error message:
Unable to make the session state request to the session state server.
Please ensure that the ASP.NET State service is started and that the
client and server ports are the same. If the server is on a remote
machine, please ensure that it accepts remote requests by checking the
value of
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\aspnet_state\Parameters\AllowRemoteConnection.
If the server is on the local machine, and if the before mentioned
registry value does not exist or is set to 0, then the state server
connection string must use either 'localhost' or
'127.0.0.1' as the server name.
So I simply had to turn on ASP.NET State Service. I could make a web.config transform to have debug/local simply run in regular inproc session, and then have the release build use the State Service (which is required in our case), but turning it on locally is good enough for now.

Xero API Integration - Program does not communicate with Xero after VS publish

I have developed a program that talks with Xero in .NET. When I run the program from VS, it communicates with Xero and works without a problem but when I publish the web application, it cannot make communication with Xero.
The error I get is 'An Internal Error Occurred' relating to the Xero Certificate yet when I run it from VS it does work without a problem.
The certificate are inside a folder.
X509Certificate2 privateCertificate = new X509Certificate2(#"C:\SSLCertificate\\public_privatekey.pfx", "XXXXXX");
IOAuthSession consumerSession = new XeroApiPrivateSession("MyAPITestSoftware", "XXXXXXXXXXXXXXXXXXXXXXX", privateCertificate);
consumerSession.MessageLogger = new DebugMessageLogger();
Thanks
Saj
More than likely the user the web app is executing under doesn't have access to that directory.
Look at your IIS configuration then give the application pool identity read access to the C:\SSLCertificate\ directory.

Adding a website to IIS7 on remote machine C#

I currently have an application written in C# that adds a website to IIS7 on the current machine and it works perfectly, the code is as follows
var iisManager = new ServerManager();
var sites = iisManager.Sites;
var site = sites.Add("WebsiteName", "C:\Website", 80);
var application = site.Applications[0];
application.ApplicationPoolName = appPool;
iisManager.CommitChanges();
I have to create a version of this code that will add a website to IIS on a remote machine located on the same network. That code is as follows.
var iisManager= ServerManager.OpenRemote("machineName"); //I've also tried machines IP
var sites = iisManager.Sites["Default Web Site"];
var site = Sites.Applications.Add("WebsiteName", "C:\Website", 80);
site.ApplicationPoolName = appPool;
iisManager.CommitChanges();
When machineName is the machine executing the code, it adds the website to IIS. However when machineName is the remote machine, I get the following exception
Retrieving the COM class factory for remote component with CLSID {2B72138B-3F5E-4502-8052-803546CE3364} from "remote machine name" failed due to the following error: 80070005 "remote machine"
The exception occurs when executing
var iisManager= ServerManager.OpenRemote("machineName");
Before executing the above code I use impersonation to impersonate an Administrator.
I can remote into the machine and even create a file on the machine using C# code.
I assume there is an issue with permissions on the remote machine or it could be because it's a VM, I'm really not sure.
The code 80070005, is fairly general and represents restricted access but I don't understand why considering I am impersonating an Admin.
I am executing the code on a Windows 7 sp1 x64 machine and the remote VM is running Windows Server 2008 sp2 x64.
If anyone has any ideas how to fix this issue or another way to add a website to IIS on a remote machine, I'd love to hear them.
Thanks
First of all you run your visual studio as administrator and OFF windows firewall of server then see it will work for Remote server

Control IIS 7 server from Windows 2003 server programmatically

We run various jobs using a Windows 2003 server. Some of these jobs send app pool commands to web servers running IIS 6 (recycle, start, stop). Now we have a Windows 2008 web server running IIS 7, and we want to send the same commands. This is all done using C#.
This is the code we use to send commands for IIS 6:
var methodToInvoke = "Stop"; // could be "Stop", "Start", or "Recycle"
var co = new ConnectionOptions
{
Impersonation = ImpersonationLevel.Impersonate,
Authentication = AuthenticationLevel.PacketPrivacy
};
var objPath = string.Format("IISApplicationPool.Name='W3SVC/AppPools/{0}'", appPoolName);
var scope = new ManagementScope(string.Format(#"\\{0}\root\MicrosoftIISV2", machineName), co);
using (var mc = new ManagementObject(objPath))
{
mc.Scope = scope;
mc.InvokeMethod(methodToInvoke, null, null);
}
This code doesn't work for IIS 7 due to underlying changes, so we're currently trying this:
using (ServerManager serverManager = ServerManager.OpenRemote(machineName))
{
var appPool = serverManager.ApplicationPools[appPoolName];
if (appPool != null)
{
appPool.Stop(); // or app.Start() or app.Recycle()
serverManager.CommitChanges();
}
}
The above code works fine on my workstation, which runs Windows 7 (and, thus, IIS 7.5). However, it does not work when I deploy this code to our application server. It get this error:
System.InvalidCastException:
Unable to cast COM object of type 'System.__ComObject' to interface type
'Microsoft.Web.Administration.Interop.IAppHostWritableAdminManager'.
This operation failed because the QueryInterface call on the COM component for the
interface with IID '{FA7660F6-7B3F-4237-A8BF-ED0AD0DCBBD9}' failed due to the following error:
Interface not registered (Exception from HRESULT: 0x80040155).
From my research, this is due to the fact that IIS 7 is not available on the Windows Server 2003 server. (I did include the Microsoft.Web.Administration.dll file.)
So my questions are:
Is it possible for the above code for IIS 7 to work at all from a Windows 2003 server?
If no to #1, is there a better way of doing this?
From reading around it doesn't appear to be possible to do what you're looking for. It's not enough to include the dll files.
According to http://forums.iis.net/t/1149274.aspx..
In order to use Microsoft.Web.Administration you need to have IIS installed, at the bare minimum you need to install the Configuration API's which are brought through installing the Management Tools.
Unfortunately there is no SDK that enables this and it has several dependencies on other components that wouldn't let you just take it to another machine and make it work (such as COM objects, DLL's, etc).
I'd be interested in knowing if you've found a way round this.
Thanks
Try controlling the IIS pool with DirectoryEntry instead.
See this topic:
Check the status of an application pool (IIS 6) with C#
Microsoft.Web.Administration, it relies on System.Web.dll which was provided by framework 4, not client profile.

"Access Denied" when trying to connect to remote IIS server - C#

I receive an "Access Deined" COMException when I try to connect to a remote IIS 6 server from my C# application that is running under IIS 5.1.
Any ideas? I am experiencing all the same issues with the original questions.
Update - 4/1/09
I found this solution (http://www.codeproject.com/KB/cs/Start_Stop_IIS_Website.aspx) that consists of a window application connecting to an IIS server to start and stop web sites. I am able to run it on my workstation and connect to the IIS server.
Ugh....why can I run this stand alone application but not my ASP.NET application?
Original
I receive an "Access Denied" COMException when I try to connect to IIS from a remote machine using the DirectoryEntry.Exist method to check to see if the IIS server is valid.
string path = string.Format("IIS://{0}/W3SVC", server);
if(DirectoryEntry.Exist(path))
{
//do something is valid....
}
I am a member of an active directory group that has been added to the Administrators groups to the IIS server I am trying to connect to.
Has anyone experience this issue and know how to resolve it?
UPDATE:
#Kev - It is an ASP.NET application. Also, I can connect without an username and password to the remote server through IIS6 Manager.
#Chris - I am trying to connect to the remote server to display the number of virtual directorys and determine the .NET framework version of each directory. See this SO question.
#dautzenb - My ASP.NET application is running under IIS 5.1 trying to connect to an IIS 6 server. I can see fault audits in the security log for my local ASPNET account on the remote server. When I try to debug the application, I am running under my domain account and still get the Access is denied.
UPDATE 2:
#Kev - I was able to establish to create a DirectoryEntry object using the following overload:
public DirectoryEntry
(
string path,
string username,
string password
)
But, all of the properties contain a " threw an exception of type 'System.Runtime.InteropServices.COMException'" while I debug the app.
Also, the AuthenticationType property is set to Secure.
UPDATE 3:
The following two failure audit entries were in the remote IIS server's security event log every time I tried to establish a connection:
First event:
Event Category: Account Logon
Event ID: 680
Log attempt by: MICROSOFT_AUTHENTICATION_PACKAGE_V1_0
Logon account: ASPNET
Source Workstation:
Error Code: 0xC0000234
Second event:
Event Category: Logon/Logoff
Event ID: 529
Logon Failure:
Reason: Unknown user name or bad password
User Name: ASPNET
Domain: (MyDomain)
Logon Type: 3
Logon Process: NtLmSsp
Authentication Package: NTLM
Workstation Name: (MyWorkstationId)
Caller User Name: -
Caller Domain: -
Caller Logon ID: -
Caller Process ID: -
Transited Services: -
Source Network Address: 10.12.13.35
Source Port: 1708
Impersonation is set to true and the username and password are blank. It is using the ASPNET account on the remote IIS server.
If it is an identity problem, you could try setting your IIS 5.1 application to use Integrated Windows Authentication, and then add the following to you web.config on your IIS5.1 web site under system.web to enable impersonation.
<identity impersonate="true"/>
<authentication mode="Windows" />
Since this is an ASP.NET application, it runs in an Application Pool of IIS. This Application Pool runs using a specific user("Local System", "Network Service" or another user).
Does this user have enough rights to connect to a remote server ?
See MSDN for more info.
This looks like it may be a double-hop issue. If you are impersonating the current user of a website using NTLM, that impersonation is only valid on that server (your IIS 5.1 server in this case). If you try to connect to another server using the web site, you are actually going to have issues as it cannot pass the token to another server that was used during impersonation. The same is true if you are debugging your site through your machine, going to another box. Your local machine is authenticating you, but it cannot impersonate you to another server.
All of the solutions I have used in the past require you to hard code the app pool to use an account that has permissions, set the annony. account to a domain account with permissions on the other machine, or use a windows service running on the IIS 5.1 machine, under a domain account, to connect to the other server.
If you are using Kerberos, this wouldn't apply, but AD uses NTLM by default.
Where exactly are you trying to read too? Is it in under the same path as your application?
When I had this problem, I found that simply authenticating my self on a Windows file share solved the problem. From experience, I think that WMI/ADSI/COM doesn't have great support for not-already-authenticated users. I believe this issue occurs when you're not associated with a Windows domain.
If it is indeed a NTLM doublehop issue you could use the SETSPN utility to create service principal named instances for your target IIS servers.
Then you could go into Active Directory, and then allow the computer object (basically the NETWORK SERVICE or LOCAL SERVICE principals) to delegate its credentials to a correctly registered SPN.
Then you could hop-hop-hop all over the place! But, be warned! People can hurt themselves on sharp pointy things when you enable double-hop!
Good KB articles to read:
http://support.microsoft.com/kb/929650
I believe that DirectoryEntry.Exists silently ignores any credentials supplied and uses the creds of the authenticated user. This seems to match the behaviour you've described. For AD work, we never use it for this reason.
I'm sort of stumped at the moment as to why you can't get this working. There is a temporary work around you could try. When instantiating the DirectoryEntry object you could use one of the following constructor overloads:
public DirectoryEntry(
string path,
string username,
string password
)
Documented at: MSDN: DirectoryEntry Constructor (String, String, String)
...or...
public DirectoryEntry(
string path,
string username,
string password,
AuthenticationTypes authenticationType
)
Documented at: MSDN: DirectoryEntry Constructor (String, String, String, AuthenticationTypes)
As it happens I'm building a test AD environment on my virtual server box for a new project to do similar stuff. When I get it up and running I'll have a play around to see if I can reproduce the problem you're encountering. In the meantime let us know what happens if you try these constructor overloads referenced above.
Update (In answer to Michaels comment):
For reasons that evade me just now, we couldn't use DirectoryEntry.Exists() in a particular scenario, there is this snippet of code that gets called now and again in one of our apps:
public static bool MetabasePathExists(string metabasePath)
{
try
{
using(DirectoryEntry site = new DirectoryEntry(metabasePath))
{
if(site.Name != String.Empty)
{
return true;
}
return false;
}
}
catch(COMException ex)
{
if(ex.Message.StartsWith("The system cannot find the path specified"))
{
return false;
}
LogError(ex, String.Format("metabasePath={0}", metabasePath));
throw;
}
catch(Exception ex)
{
LogError(ex, String.Format("metabasePath={0}", metabasePath));
throw;
}
}
You could replace the constructor with one of the ones from above. Admittedly it's a stab in the dark :).

Categories