Powershell to Add serviceAutoStartProvider in IIS

on Friday, April 18, 2014

I’ve used the serviceAutoStart attribute a couple times since its introduction. And mostly only in conjuction with WCF based services. I’ve had pretty good success with Application Initialization (IIS 7.5, IIS 8.0) for normal website preloading.

Recently I wanted to add a new serviceAutoStartProvider and set an application to use it through an automated script. I couldn’t really find a premade tool that would do that on both IIS 7.5 and 8.0 so I tried to put together something.

This worked for me, but that may be specific to the environment I was working.

(Note: When adding a new line to the .config file it doesn’t really get the spacing right. I understand why it’s happening but I don’t really know how to fix the issue. If you know how, please drop in a comment.)

Function Test-AutoStartProviderExists {
Param(
[Parameter(Mandatory = $true)]
[string]$AutoStartProvider,
[string]$AppServerName = [System.Net.Dns]::GetHostName()
)
Process {
[xml]$appHost = New-Object xml;
$appHost.psbase.PreserveWhitespace = $true;

$configDir = "\\$AppServerName\C$\Windows\System32\inetsrv\config";
$configPath = "$configDir\applicationHost.config";
$appHost.Load($configPath);

$provider = $appHost.configuration.'system.applicationHost'.serviceAutoStartProviders.add |? {$_.name -eq $AutoStartProvider};

return $provider -ne $null;
}
}

Function Get-AutoStartProvider {
Param(
[Parameter(Mandatory = $true)]
[string]$SiteName,
#[string]$AppName, # untested
[string]$AppServerName = [System.Net.Dns]::GetHostName()
)
Process {
[xml]$appHost = New-Object xml;
$appHost.psbase.PreserveWhitespace = $true;

$configDir = "\\$AppServerName\C$\Windows\System32\inetsrv\config";
$configPath = "$configDir\applicationHost.config";
$appHost.Load($configPath);

$site = $appHost.configuration.'system.applicationHost'.sites.site |? {$_.name -eq $SiteName};
#$app = $site.application |? {$_.path -eq $("/" + $AppName)}; # untested

return $site.serviceAutoStartProvider;
#return $app.serviceAutoStartProvider; # untested
}
}

Function Set-AutoStartProvider {
Param(
[Parameter(Mandatory = $true)]
[string]$SiteName,
#[string]$AppName, # untested
[Parameter(Mandatory = $true)]
[string]$AutoStartProvider,
[string]$AppServerName = [System.Net.Dns]::GetHostName()
)
Process {
[xml]$appHost = New-Object xml;
$appHost.psbase.PreserveWhitespace = $true;

$configDir = "\\$AppServerName\C$\Windows\System32\inetsrv\config";
$configPath = "$configDir\applicationHost.config";
$appHost.Load($configPath);

$site = $appHost.configuration.'system.applicationHost'.sites.site |? {$_.name -eq $SiteName};
#$app = $site.application |? {$_.path -eq $("/" + $AppName)}; # untested

$site.serviceAutoStartProvider = $AutoStartProvider;
#$app.serviceAutoStartProvider = $AutoStartProvider; # untested

Write-Warning "Updating IIS $AppServerName - Setting $SiteName's serviceAutoStartProvider to '$AutoStartProvider'";
try {
$appHost.Save($configPath);
} catch {
Write-Warning "Unable to save, waiting 5 seconds for file lock to release and try again ..."
Start-Sleep 5
$appHost.Save($configPath);
}
Write-Host "Updated IIS $AppServerName - Set $SiteName's serviceAutoStartProvider to '$AutoStartProvider'";
}
}

Function New-AutoStartProvider {
Param(
[Parameter(Mandatory = $true)]
[string]$AutoStartProvider,
[Parameter(Mandatory=$true)]
[string]$Type,
[string]$AppServerName = [System.Net.Dns]::GetHostName()
)
Process {
if(Test-AutoStartProviderExists -AutoStartProvider $AutoStartProvider -AppServerName $AppServerName) {
throw "IIS $AppServerName - Unable to add autoStartProvider $AutoStartProvider. It already exists."
}

[xml]$appHost = New-Object xml;
$appHost.psbase.PreserveWhitespace = $true;

$configDir = "\\$AppServerName\C$\Windows\System32\inetsrv\config";
$configPath = "$configDir\applicationHost.config";
$appHost.Load($configPath);

$autoStartProviders = $appHost.configuration.'system.applicationHost'.serviceAutoStartProviders;

$provider = $appHost.CreateElement("add")
$provider.SetAttribute("name", $AutoStartProvider);
$provider.SetAttribute("type", $Type);
$autoStartProviders.AppendChild($provider);

Write-Warning "Updating IIS $AppServerName - Adding serviceAutoStartProvider '$AutoStartProvider'";
try {
$appHost.Save($configPath);
} catch {
Write-Warning "Unable to save, waiting 5 seconds for file lock to release and try again ..."
Start-Sleep 5
$appHost.Save($configPath);
}
Write-Host "Updated IIS $AppServerName - Added serviceAutoStartProvider '$AutoStartProvider'";
}
}

TFS 2013 has some hacks

on Friday, November 1, 2013

I’m attempting to install TFS 2013 and as part of the process I’m trying to install Sharepoint 2013 that comes with the installer.

The installer asked me to create a domain account for TFS’s SharePoint to run under (Server farm account). And, after looking at, http://technet.microsoft.com/en-us/library/cc263445.aspx, I decided that it would be a good idea to add the account to my SQL Server instance. So, I created one and gave the username/password to the TFS installer.

The TFS installer comes with a “version” of Sharepoint that it will install on the server to host TFS sites. I gave the installer the username/password of the domain account, and gave it the SQL server name. The Sharepoint installer used that information to promote the Login to have these roles on SQL Server

  • dbcreator
  • securityadmin

It also created these databases, with these rights to each database

  • WSS_AdminContent
    • db_owner
    • SharePoint_Shell_Access
    • SFDataAccess
    • WSS_Content_Application_Pools
  • WSS_Config
    • db_accessadmin
    • SharePoint_Shell_Access
    • WSS_Content_Application_Pools
  • WSS_Content
    • SPDataAccess

With the usage of underscores some places and no underscores other places you can see that Sharepoint was developed under a single vision.

But, the amazing part is that this account wasn’t setup with any special permissions; it was added to the database as a Login with no permissions to anything. After the SharePoint installer ran, it had a ton of permissions.

I like that it makes the installation easier, but I feel like I was left out of the loop. Did I miss an installation screen that explained all this? My apologizes if I did.

Web Farm Rewrite rules in web.config files

on Saturday, October 19, 2013

It looks like when Web Farm Framework was folded into the ARR module (http://www.iis.net/downloads/microsoft/application-request-routing) there was a nice feature update that allowed for the Web Farm Rewrite rules (eg. “rewrite” to “http://XXXWebFarm/{R:0}”) to be set within the web.config files of individual websites on your proxy server. At least, I think it was implemented during that transition; it may have been earlier.

This is a pretty nice feature that can really alter the way URL Rewrite rules are managed on the proxy server. If the rewrite rules are only available within the applicationHost.config file, then all rules need to be centrally managed through that one file. This could lead to 1000’s of lines of xml rules for probably less than 100 sites.

Having the ability to move site specific rules into web.config files for those sites doesn’t change that each “type” of rule needs to have a defined policy on how it will be implemented and managed. But, it will make discovery and management of the rules simplified and easy to understand. This is a pretty nice improvement.

The improvement also allows for global rules to continue to be defined within the global applicationHost.config (ie. setting variables), which can be reused in the individual site web.config rules. So, the best of both worlds.

A big thanks to my coworker Keith Jakobs for discovering this!

Getting an SSL Certificate into the Certificate Store

I’ve probably got all the steps jumbled up and backwards. But, hopefully this can one day become scripted in the right order with the right settings/permissions.

certreq: http://technet.microsoft.com/library/cc725793.aspx

  1. Use a template.inf file with certreq.exe -new to create the certificate request. This could probably be scripted similar to http://www.networkworld.com/community/node/18638.
  2. Use certreq –submit to process the request on the Issuing CA. Through the command line/powershell this automatically pops up some GUI windows to select configuration options and save the resultant .cer file.
    1. The .cer file seems a bit frustrating; why can’t I find a way to directly create a .pfx.
      1. I should probably set UserProtected = TRUE and maybe PrivateKeyArchive = TRUE in the .inf. It will probably prompt for a password at the time of certreq –new.
    2. Remember to use CertificateTemplate = WebServer
    3. Follow the instructions of Vadims Podans from http://social.technet.microsoft.com/Forums/windowsserver/en-US/d0f0fe74-d14a-4718-b00c-47545b56911d/submit-new-request-nothing-happens?forum=winserversecurity
      1. certutil -setreg policy\EditFlags +EDITF_ATTRIBUTESUBJECTALTNAME2
  3. Use IIS’s Server Certificates Feature to “Complete Certificate Request …” into your Personal store
  4. Export the certificate to a .pfx file (maybe this won’t be necessary if the password is assigned at certreq –new) and add it to the Centralized Certificate Store
    1. Remember to setup the Centralized Certificate Store Feature at the root level
  5. On the site, in the https binding, check Use Centralized Certificate Store
    1. If the names match up, it will automatically be used
  6. Back in IIS’s Server Certificates Feature, Remove the certificate. It’s now being used from the Centralized Certificate Store.

Web Farm Framework and Win 2012/IIS 8

on Friday, October 18, 2013

So, it looks like the Web Farm Framework may have been folded into IIS after IIS 7. But, it wasn’t made very clear to the community. The closest thing I could find to explain why Web Farm Framework was no longer available was in the IIS.net forums. Which is kind of disappointing, because you’d think there would be an evangelist on the product talking about the change.

Anyways, the thread post that talks about IIS 8 not using WFF.

http://forums.iis.net/t/1191340.aspx?WFF+and+IIS+8

And, the associated technet article that explains it:

http://technet.microsoft.com/en-us/library/jj129385.aspx

What I have gained from the experience is that technet’s articles are the authoritative source on the latest way you should go about implementing anything within IIS. And, you should not expect an evangelist to spread the word through a blog. The change will happen in the background, and you will need to check technet to be aware.

VS All Caps and IIS AppPools

This is mostly just a reminder post.

Removing the All Caps from VS 2012/2013:

http://stackoverflow.com/questions/17413001/disable-all-caps-menu-items-in-visual-studio-2013

Really nice PowerShell:

Set-ItemProperty -Path HKCU:\Software\Microsoft\VisualStudio\12.0\General -Name SuppressUppercaseConversion -Type DWord -Value 1


We use domain accounts for all application pools at work, so I never remember how to set an “application pool” identity to have permissions on a directory correctly using the machine accounts.



http://stackoverflow.com/questions/7334216/iis7-permissions-overview-applicationpoolidentity

SSD Load Time Performance

The OS load time in an SSD is just amazing. And, I thought I’d track a few figures to just show the difference.

Test System Configurations

  HDD Test Box SSD Test Box
CPU Core i7-3770K Core i7-4770K
RAM G.Skill 16 GB DDR3 1600 G.Skill 32 GB DDR3 1600
SSD (OS) Mushkin 480GB SATA III Samsung 750GB SATA III
HDD Seagate 2TB 5900 RPM  

One thing to note beforehand is that the HDD used in the test was 5900 RPM, which I don’t think most people use.

Test Description

Using Oracle VirtualBox 4.3.0, I setup a couple of virtual machines of Windows Server 2012 R2 with different roles installed. And, the speed test was just the amount of time it took to Power On the virtual machine, until the “grey login screen” appeared.

On the HDD Test Box, the .vhd image was on the HDD drive. On the SSD Test Box, the .vhd image was on the SSD drive.

All virtual machines were configured with 1 CPU and 1 GB RAM, except for SQL which had 2 CPU and 2 GB RAM. I ran some tests on different CPU and RAM pairings and found that 1 CPU/1 GB was pretty close to optimal for load times; and it was plenty of power for a home network configuration with one user. I also noticed that as I added more RAM into the configuration, the load times became longer because extra time was being spent allocating the RAM.

Results

  HDD Test Box (secs) SSD Test Box (secs)
DC/AD/DNS 87 49
SQL 50 10
Azure Pack AdminAPI 60 11
Azure Pack AdminAuth 58 9
IIS 65 13

It’s a pretty nice speed improvement.


Creative Commons License
This site uses Alex Gorbatchev's SyntaxHighlighter, and hosted by herdingcode.com's Jon Galloway.