Powershell Unit Testing

on Friday, April 25, 2014

Unit testing is always good practice, but with newer languages there aren’t tools available to provide that functionality. So, it’s always awesome when someone uses their time to make the tool. Jon Wagner did an awesome job and put together:

PSMock/PShould/PSate - a collection of PowerShell modules that setup unit testing. And, he makes them really easy to install with a wiki article describing the steps. I think I was setup and (poorly) writing unit tests in about 15 minutes.

image

For installation, I went the PSGet route. I used PSGet because I like package managers, they take a lot of the pain out of updating. And, PSGet could be installed through a package manager itself (PSGet from Chocolatey).

On a side note, the use of Chocolatey is great because the Windows Server team recently announced that they would use Chocolatey as the primary repository for sharing installs through the OneGet PowerShell module.

I wonder if there’s an easy way to run the unit tests in TFS, and use the results for gated checkins?

 

I also poked around at the work of Adam Driscoll, mostly his PowerShell Tools for Visual Studio. It’s pretty interesting because you get the full Visual Studio debugging experience, which reveals a lot of the environment variables you may not be aware of. I certainly wasn’t.

image

It adds in PowerShell projects as a first class citizen and gives you an alphabetically ordered drop down of all the functions in a module. I like the navigational drop down feature soo much that I would love to see it in the PowerShell ISE.

image

image

It’s a really nice VS plugin and I use it when debugging difficult problems where I want to see the state of a lot of variables at the same time.

However, for most development I continue to use the PowerShell ISE. The ability to run scripts instantly and fluidly switch between the command window and script window is something that I missed when using Visual Studio.

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'";
}
}


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