How to call Site with F# function? - iis

I am new to F# and want to create IIS site with FAKE.
Now I see the code as the following.
[https://github.com/fsharp/FAKE/blob/develop/src/app/Fake.IIS/IISHelper.fs]
let Site (name : string) protocol binding (physicalPath : string) appPool (mgr : ServerManager) =
let mutable site = mgr.Sites.[name]
match (site) with
| null -> site <- mgr.Sites.Add(name, protocol, binding, physicalPath)
| _ ->
SetPhysicalPath "/" physicalPath name (Some mgr)
AddBindingToSite binding protocol name (Some mgr)
site.ApplicationDefaults.ApplicationPoolName <- appPool
site
How do I call this Site function to create site ?

Realise this is a little late but the following will create a web site in IIS for you
open Fake
open Fake.IISHelper
(IIS
(Site options.WebSiteName "http" (":9090:") #"C:\inetpub\wwwroot" "myAppPool")
(ApplicationPool "myAppPool" true "v4.0")
(Some(Application "/" )))
This method will create a website bound to Http on port 9090 located in C:\inetpub\wwwroot additionally
it will create an application pool myAppPool and application and associated it with the site.

Related

Calling Bindings.Remove does not remove SSL cert from HTTP.sys

The shortest version of my question is that calling ServerManager.Binding.Remove seems to remove a binding from IIS, but still leave it in HTTP.sys or wherever SSL bindings are set and breaks layers of my code further down.
I'm running an Azure Cloud Service that needs to use SNI to support multiple hostnames using SSL. Effectively what I'm doing is in OnStart removing the default binding using ServerManager.Binding.Remove(binding) and adding my own bindings using ServerManager.Binding.Add(binding). So for example:
ServerManager serverManager = new ServerManager();
Site site = serverManager.Sites[0];
// Add my site bindings.
foreach (string host in listOfHostsToBind)
{
X509Certificate2 cert = LookupCertificate(host.sslThumbprint);
var binding = site.Bindings.Add(":443:" + host, cert.GetCertHash(), "My");
binding.SetAttributeValue("sslFlags", 1); //Set SNI flag
}
// Remove the default binding
var bindingsToRemove = new List<Binding>();
foreach (Binding binding in site.Bindings)
{
if (binding.Protocol == "https" && Convert.ToInt64(binding.Attributes["sslFlags"].Value) != 1)
{
bindingsToRemove.Add(binding);
}
}
foreach (Binding binding in bindingsToRemove)
{
site.Bindings.Remove(binding);
serverManager.CommitChanges();
}
serverManager.CommitChanges();
What ends up happening is that the default IP:Port binding is removed from the list of IIS bindings, but it still shows up in the list of SSL bindings when I call netsh http show sslcert.
So, for example, here's the output from calling Get-WebBinding in Powershell. Notice that the default IP:Port binding is not there:
protocol bindingInformation sslFlags
-------- ------------------ --------
http 10.20.30.40:80: 0
https :443:myfirstaddedhost.com 1
https :443:mysecondaddedhost.com 1
Looks good, but it still doesn't work, because if I run netsh http show sslcert I get the following:
IP:port : 10.20.30.40:443
Certificate Hash : xxx
Application ID : {00000000-0000-0000-0000-000000000000}
Certificate Store Name : MY
...
Hostname:port : myfirstaddedhost.com:443
Certificate Hash : xxx
Application ID : {4dc3e181-e14b-4a21-b022-59fc669b0914}
Certificate Store Name : My
...
Hostname:port : mysecondaddedhost.com:443
Certificate Hash : xxx
Application ID : {4dc3e181-e14b-4a21-b022-59fc669b0914}
Certificate Store Name : My
...
Why would the SSL Cert binding still be there if I successfully removed the binding from IIS using ServerManager?
Turns out that configuring the role for Remote Desktop from the Azure Portal was adding the binding. More specifically, updating the Certificate configuration for the role (which happens as part of RDP config) is causing it. This meant that it worked until I went in via RDP to check whether it was working at which point it would start to fail. Of course, genius that I am I was trying to be methodical and do things in the same order every time, which meant I was configuring remote desktop before actually attempting a request, so from my perspective it looked like it was failing from the beginning. It was only when I tried things in the opposite (running requests before configuring RDP) that it started to work.
You can use netsh http delete sslcert to delete the binding and it does not affect your ability to log in via RDP to that instance.
When you configure RDP it calls the RoleEnvironment.Changing and RoleEnvironment.Changed events, but unfortunately when those events are called the binding has not been created yet, so there's not an obvious place where you could use netsh http delete sslcert to delete the binding in code.
I don't know that this is an "answer" exactly. It means I still have an issue where configuring an Azure Instance for RDP or changing the cert configuration breaks my SNI bindings. For my organization this is OK because there are only a couple people with enough permissions to configure RDP and they can be trained to explicitly delete the new binding if they need to use RDP. I'll follow up here if I figure out a way to prevent this altogether.

Is it possible to query for VIP (with endpoint ports) both in emulated compute environment and in cloud "cleanly"?

I have two Web Roles, another of which provides a data API an another one hosts a frontend www site and then some compute roles that produce data.
What I would like to achieve is in the www Web Role to query the VIP of the data API Web Role by running a query function that abstracts the details if I'm running locally or in Azure. It looks like querying the PublicIPEndpoint would work in Azure, but not locally. The need would be such that I could further give out, say, some URL constants for JavaScript.
Is there a better way than to hardcode some string or, say, read the .csdef file with a relative path and take it from there?
In code crudely something like
let IsInAzureFabric =
try
RoleEnvironment.IsAvailable
with _ ->
false
let IsInAzureCloud =
try
IsInAzureFabric && not RoleEnvironment.IsEmulated
with _ ->
false
let GetVirtualIP(roleName, endPoint) =
try
if IsInAzureCloud then
//Collect the protocol (http/https) from the endpoint information and pick only one endpoint as it's the one shown on the loadbalancer...
RoleEnvironment.Roles.[roleName].Instances
|> Seq.map(fun roleInstance -> "http://" + roleInstance.InstanceEndpoints.[endPoint].PublicIPEndpoint.ToString())
elif IsInAzureFabric then
//In local development fabric...
Seq.ofList ["http://localhost:8080"]
else
//This is locally outside of Azure Fabric (or in virtual machine?).
Seq.ofList ["http://localhost:1943"]
with _ ->
Seq.empty

IIS reverses web site settings when stopping

I have an issue with configuring IIS. I programmatically create a web site and an application (virtual dir) under the web site. Among other settings, I add a wildcard application map in the applications settings. When IIS is restarted, it removes the wilcard application map (and some other settings, but I just mention the wilcard map for simplicity). I can re-add the map, using IIS manager, but when I restart IIS, the map is removed. BUT - if I add the wildcard map and then, without restarting IIS, use a browser first to hit a page in that application, then any subsequent IIS restarts do not cause the map to disappear. Any idea what's going on?
here's my code:
// root virtual dir object
string strRootVirtDirPath = "IIS://localhost/w3svc/" + strWebSiteID + "/root";
DirectoryEntry deRootVirtDir = new DirectoryEntry(strRootVirtDirPath);
// add new virtual dir
DirectoryEntry deNewVirtDir = deRootVirtDir.Children.Add(strAppName, "IIsWebVirtualDir");
deNewVirtDir.Properties["Path"].Value = strPhysicalDir;
deNewVirtDir.Properties["AppFriendlyName"].Value = strAppName;
deNewVirtDir.Properties["AppRoot"].Value = "/LM/W3SVC/" + strWebSiteID + "/Root/" + strAppName;
deNewVirtDir.Properties["AppPoolId"].Value = strAppPoolName;
// create the application
deNewVirtDir.Invoke("AppCreate", 1);
// commit changes
deNewVirtDir.CommitChanges();
deRootVirtDir.CommitChanges();
deNewVirtDir.Close();
deRootVirtDir.Close();
Figured out the problem. It's described in Microsoft's KB article 286196: http://support.microsoft.com/kb/286196
All my affected machines were Windows Server 2K3 R2 just like described in the article.

Sharepoint 2010 unextend web application

I am trying to unextend a web application.
First i tried this code:
getWebApp.IisSettings.Remove(SPUrlZone.Internet);
It is working fine but not deleting the IIS website or physical folder of this extended web app. So i started to delete IIS website manually by using the following code:
int instID = getWebApp.IisSettings[SPUrlZone.Internet].PreferredInstanceId;
SPIisWebSite iisWebSite = new SPIisWebSite(instID);
iisWebSite.Unprovision();
or:
ServerManager iisManager = new ServerManager();
Site s1 = iisManager.Sites["MySiteName - 1234"]; // you can pass the site name or the site ID
iisManager.Sites.Remove(s1);
iisManager.CommitChanges();
IIS website is not getting deleted.
Any help?
You can do this without code. In SharePoint 2010, all you need to do is go to Central Administration, Manage Web Application, select your application, select the drop down below the 'Delete' button and select 'Remove SharePoint from IIS web site'. Select your extended site, then also be sure to select 'Yes' to delete the site from IIS.
SPWebApplication getWebApp = GetWebAppById(GlobalVar._webAppId);
getWebApp.IisSettings.Remove(SPUrlZone.Internet);
getWebApp.Update();
Directory.Delete(GlobalVar._exWebAppPhyPath, true);
ServerManager iisManager = new ServerManager();
Site getSite = iisManager.Sites[GlobalVar._webAppExtendedName];
iisManager.Sites.Remove(getSite);
iisManager.CommitChanges();
getWebApp.Update();
getWebApp.Provision();

Install ClientAccessPolicy.xml to Default Web Site using Wix

I'm using Wix to install my web application, and it includes a Silverlight app. Because of cross-domain restrictions, I need to install a ClientAccessPolicy file to ensure that the Silverlight app can talk to the included web services.
Unfortunately, ClientAccessPolicy.xml has to be available from the root of the site, so I can't just place it with my web services or web site. e.g.
Works: http://someserver/ClientAccessPolicy.xml
Doesn't work: http://someserver/MyApp/ClientAccessPolicy.xml
How can I find the directory for the IIS "Default Web Site" to copy the file there as part of the install?
Unfortunately, you have to author a custom action for this. It seems to be just a simple immediate action, which is to find the correct directory path and put it to a property.
UPDATE: The sample C# code for this might look like this:
DirectoryEntry website = new DirectoryEntry(string.Format("IIS://localhost/w3svc/{0}/Root", siteID));
if (website != null)
{
string sitePath = website.InvokeGet("Path") as string;
if (sitePath != null)
{
session["SITE_PATH"] = sitePath;
return ActionResult.Success;
}
}
return ActionResult.Failure;
It assumes that you know the siteID in some way. If it's not always default web site, it is better to let the user choose, for instance. But that's another story.
Note also that this code requires special privileges to access DirectoryEntry - the regular user is not enough.
Hope this helps.

Resources