However, such activity is repetitious, tedious and attracts the odd error or two in interpretation or the absence of some step. Additionally, IP gained from such activities is not often captured formally and hence may be lost over time.
So I wrote a 'menu' based powershell script to automate a number of the more common scenarios.To do this, I made particular use of the web administration powershell module (see http://technet.microsoft.com/en-us/library/ee790599.aspx for details). This post just describes a few simple tasks that might be of use.
One of the initial issues I had was the platform differences in using the web administration module. On IIS 7.5, web administration (WM) is a module, otherwise a snap in. As the script needed to work on Windows 7 as well as Windows 2008 (not R2), an adaptive way to load WM is required.
Stack overflow to the rescue! See this excellent answer from a stack overflow user, which I morphed into the following function:
# Ensure that the correct mechanism is used to load the web administration module
function ImportWebAdministration() {
$iisVersion = Get-ItemProperty "HKLM:\software\microsoft\InetStp";
if ($iisVersion.MajorVersion -eq 7)
{
if ($iisVersion.MinorVersion -ge 5)
{
Import-Module WebAdministration;
}
else
{
if (-not (Get-PSSnapIn | Where {$_.Name -eq "WebAdministration";})) {
Add-PSSnapIn WebAdministration;
}
}
}
}
So this is a snippet from one of the scripts, showing an excerpted 'status' set of behaviours, that expects the name of a web site name to be supplied to it, and that a sub site with a specific relative URL exists.
Just a few very minor points of interest, focusing on IIS cmdlet use:
Line 2: Search a web config file (obtained using get-webconfigfile) for some pattern
Line 16: Get a web site object that matches some parameter name we have passed in
Line 28: Output some details of the application pool associated with the main web site
Lines 33-35: Use a regex from the Expresso library to strip out just a URL
Lines 42-46: Since we believe that a URL should be reachable as part of the overall health of the site, use some low level .NET objects to verify this using a GET call
1: function GetWebConfigEntry([string] $url, [string] $searchString) {
2: $m = select-string (get-webconfigfile IIS:\Sites\$url) -pattern $searchString |
3: select-object Line
4: $m.Line.ToString().Trim()
5: }
6: function CompareDSCURLs([string] $lhs, [string] $rhs) {
7: $same = $lhs -eq $rhs
8: if (-not $same) {
9: Write-Error "DSC mismatch"
10: }
11: $same
12: }
13: function WebServerRoleStatus() {
14: write-Host "`nWeb Server Role Status`n"
15: write-Host `n"Check DSC configuration"
16: $ws=get-website | where-object { $_.Name -match $webSiteName }
17: if ($ws -eq $null) {
18: Throw "There is no web site like/called $webSiteName"
19: }
20: $wsname=$ws.name
21: $sitedsc = MatchURL (GetWebConfigEntry $wsname "dsc.svc")
22: $subsitedsc = MatchURL (GetWebConfigEntry "$wsname/subsite" "dsc.svc")
23: $same = CompareDSCURLs $sitedsc $subsitedsc
24: if ($same) {
25: ValidateGETOnURL $sitedsc
26: }
27: write-Host "`nApplication pool for $wsname"
28: Get-ChildItem -Path IIS:\AppPools |
29: Where-object { $_.Name -eq $ws.applicationPool } |
30: select-object -property Name,state,managedPipelineMode
31: }
32: function MatchURL([string] $url, [bool] $outputMatch = $true) {
33: $url -match
34: '(?<Protocol>\w+):\/\/(?<Domain>[\w@][\w.:@]+)\/?[\w\.?=%&=\-@/$,]*' |
35: out-null
36: if ($outputMatch) {
37: Write-Host $matches[0]
38: }
39: $matches[0]
40: }
41: function ValidateGETOnURL([string] $url) {
42: write-Host "Check URL $url is reachable"
43: [net.httpWebRequest] $req = [net.webRequest]::create($url)
44: $req.method = "GET"
45: $req.TimeOut = 10000
46: [net.httpWebResponse] $res = $req.getResponse()
47: $result = $res.StatusCode
48: write-host "HTTP Response is " $result "`n"
49: }
Of course, the use of a pattern match across a web.config file is clumsier than it should be, but the script is not meant to represent 'gold plated' powershell development - it's deliberately utilitarian. We could of course use XPath over an XmlDocument to do a more targeted action, as below:
1: $xml = [xml] (get-content (get-webconfigfile IIS:\Sites\Site))
2: $xml.SelectNodes("/Configuration/applicationsettings/Org.Internet.Infrastructure.Site.WebServices.
3: Properties.Settings/setting[@name='Org_Internet_Infrastructure_
4: Site_WebServices_DSC']/value")
This assumes that the node we are interested in has the XPath as indicated. Powershell script writing is almost cathartic - but I still prefer the Korn shell!
No comments:
Post a Comment