Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New resource: xWebSiteAlive (fixes #84) #309

Open
wants to merge 4 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
236 changes: 236 additions & 0 deletions DSCResources/MSFT_xWebSiteAlive/MSFT_xWebSiteAlive.psm1
Original file line number Diff line number Diff line change
@@ -0,0 +1,236 @@
# Load the Helper Module
Import-Module -Name "$PSScriptRoot\..\Helper.psm1" -Verbose:$false

# Localized messages
data LocalizedData
{
# culture="en-US"
ConvertFrom-StringData -StringData @'
ErrorWebsiteNotRunning = The website '{0}' is not correctly running.
VerboseGettingWebsiteBindings = Getting bindings of the website '{0}'.
VerboseUrlReturnStatusCode = Url {0} returned status code {1}.
VerboseTestTargetFalseStatusCode = Status code of url {0} does not match the desired state.
VerboseTestTargetFalseExpectedContent = Content of url {0} does not match the desired state.
'@
}

<#
.SYNOPSYS
This will return a hashtable of results. Once the resource state will nerver be changed to 'absent',
this function or will return the resource in the present state or will throw an error.
#>
function Get-TargetResource
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "")]
[CmdletBinding()]
[OutputType([Hashtable])]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$WebSiteName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$RelativeUrl,

[UInt16[]]
$ValidStatusCodes = [int][Net.HttpStatusCode]::OK,

[String]
$ExpectedContent
)

if (Test-WebSiteRunning $WebSiteName $RelativeUrl $ValidStatusCodes $ExpectedContent)
{
return @{
Ensure = 'Present'
WebSiteName = $WebSiteName
RelativeUrl = $RelativeUrl
ValidStatusCodes = $ValidStatusCodes
ExpectedContent = $ExpectedContent
}
}
else
{
$errorMessage = $LocalizedData.ErrorWebsiteNotRunning -f $WebSiteName
New-TerminatingError -ErrorId 'WebsiteNotRunning' `
-ErrorMessage $errorMessage `
-ErrorCategory 'InvalidResult'
}
}

<#
.SYNOPSYS
Once this resource is only for check the state, this function will always throw an error.
#>
function Set-TargetResource
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "")]
[CmdletBinding()]
param
(
[ValidateSet('Present', 'Absent')]
[String]
$Ensure = 'Present',

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$WebSiteName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$RelativeUrl,

[UInt16[]]
$ValidStatusCodes = [int][Net.HttpStatusCode]::OK,

[String]
$ExpectedContent
)

$errorMessage = $LocalizedData.ErrorWebsiteNotRunning -f $WebSiteName
New-TerminatingError -ErrorId 'WebsiteNotRunning' `
-ErrorMessage $errorMessage `
-ErrorCategory 'InvalidResult'
}

<#
.SYNOPSYS
This tests the desired state. It will return $true if the website is alive or $false if it is not.
#>
function Test-TargetResource
{
[Diagnostics.CodeAnalysis.SuppressMessageAttribute("PSDSCUseVerboseMessageInDSCResource", "")]
[CmdletBinding()]
[OutputType([Boolean])]
param
(
[ValidateSet('Present', 'Absent')]
[String]
$Ensure = 'Present',

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$WebSiteName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$RelativeUrl,

[UInt16[]]
$ValidStatusCodes = [int][Net.HttpStatusCode]::OK,

[String]
$ExpectedContent
)

return Test-WebSiteRunning $WebSiteName $RelativeUrl $ValidStatusCodes $ExpectedContent
}

#region Helper Functions

function Test-WebSiteRunning
{
[OutputType([Boolean])]
param
(
[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$WebSiteName,

[Parameter(Mandatory = $true)]
[ValidateNotNullOrEmpty()]
[String]
$RelativeUrl,

[UInt16[]]
$ValidStatusCodes,

[String]
$ExpectedContent
)

function Get-UrlStatus
{
[OutputType([Hashtable])]
param ([string] $Url)

try
{
$webResponse = Invoke-WebRequest -Uri $Url -UseBasicParsing -DisableKeepAlive

return @{
StatusCode = $webResponse.StatusCode
Content = $webResponse.Content -replace "`r`n", "`n"
}
}
catch [Net.WebException]
{
return @{
StatusCode = [int]$_.Exception.Response.StatusCode
Content = ''
}
}
}

Write-Verbose -Message ($LocalizedData.VerboseGettingWebsiteBindings -f $WebSiteName)

$bindings = Get-WebBinding -Name $WebSiteName

foreach ($binding in $bindings)
{
if ($binding.Protocol -in @('http', 'https'))
{
# Extract IPv6 address
if ($binding.bindingInformation -match '^\[(.*?)\]\:(.*?)\:(.*?)$')
{
$ipAddress = $Matches[1]
$port = $Matches[2]
$hostName = $Matches[3]
}
else
{
$ipAddress, $port, $hostName = $binding.bindingInformation -split '\:'
}

if (-not $hostName)
{
$hostName = 'localhost'
}

$url = "$($binding.protocol)://$($hostName):$port$RelativeUrl"

$urlStatus = Get-UrlStatus $url

Write-Verbose -Message ($LocalizedData.VerboseUrlReturnStatusCode -f $url, $urlStatus.StatusCode)

if ($ValidStatusCodes -notcontains $urlStatus.StatusCode)
{
Write-Verbose -Message ($LocalizedData.VerboseTestTargetFalseStatusCode -f $url)

return $false
}

if ($ExpectedContent -and $urlStatus.Content -ne $ExpectedContent)
{
Write-Verbose -Message ($LocalizedData.VerboseTestTargetFalseExpectedContent -f $url)

return $false
}
}
}

return $true
}

#endregion

Export-ModuleMember -Function *-TargetResource
9 changes: 9 additions & 0 deletions DSCResources/MSFT_xWebSiteAlive/MSFT_xWebSiteAlive.schema.mof
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
[ClassVersion("1.0.0"), FriendlyName("xWebSiteAlive")]
class MSFT_xWebSiteAlive : OMI_BaseResource
{
[Write, ValueMap{"Present", "Absent"}, Values{"Present", "Absent"}] String Ensure;
[Key] String WebSiteName;
[Key] String RelativeUrl;
[Write] UInt16 ValidStatusCodes[];
[Write] String ExpectedContent;
};
17 changes: 17 additions & 0 deletions Examples/Sample_xWebSiteAlive_200ok.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
Configuration Sample_xWebSiteAlive_200ok
{
Import-DscResource -Module xWebAdministration

xWebsite DefaultWebSite
{
Ensure = 'Present'
Name = 'Default Web Site'
State = 'Started'
}

xWebSiteAlive WebSiteAlive
{
WebSiteName = 'Default Web Site'
RelativeUrl = '/'
}
}
52 changes: 52 additions & 0 deletions Examples/Sample_xWebSiteAlive_ExpectedContent.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
Configuration Sample_xWebSiteAlive_ExpectedContent
{
Import-DscResource -Module xWebAdministration

xWebsite DefaultWebSite
{
Ensure = 'Present'
Name = 'Default Web Site'
State = 'Started'
}

xWebSiteAlive WebSiteAlive
{
WebSiteName = 'Default Web Site'
RelativeUrl = '/iisstart.htm'
ValidStatusCodes = @(200)
ExpectedContent = @'
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
<title>IIS Windows Server</title>
<style type="text/css">
<!--
body {
color:#000000;
background-color:#0072C6;
margin:0;
}

#container {
margin-left:auto;
margin-right:auto;
text-align:center;
}

a img {
border:none;
}

-->
</style>
</head>
<body>
<div id="container">
<a href="http://go.microsoft.com/fwlink/?linkid=66138&amp;clcid=0x409"><img src="iisstart.png" alt="IIS" width="960" height="600" /></a>
</div>
</body>
</html>
'@
}
}
11 changes: 10 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Build status](https://ci.appveyor.com/api/projects/status/gnsxkjxht31ctan1/branch/master?svg=true)](https://ci.appveyor.com/project/PowerShell/xwebadministration/branch/master)

The **xWebAdministration** module contains the **xIISModule**, **xIISLogging**, **xWebAppPool**, **xWebsite**, **xWebApplication**, **xWebVirtualDirectory**, **xSSLSettings** and **xWebConfigKeyValue** DSC resources for creating and configuring various IIS artifacts.
The **xWebAdministration** module contains the **xIISModule**, **xIISLogging**, **xWebAppPool**, **xWebsite**, **xWebApplication**, **xWebVirtualDirectory**, **xSSLSettings**, **xWebConfigKeyValue** and **xWebSiteAlive** DSC resources for creating and configuring various IIS artifacts.

This project has adopted the [Microsoft Open Source Code of Conduct](https://opensource.microsoft.com/codeofconduct/).
For more information see the [Code of Conduct FAQ](https://opensource.microsoft.com/codeofconduct/faq/) or contact [opencode@microsoft.com](mailto:opencode@microsoft.com) with any additional questions or comments.
Expand Down Expand Up @@ -235,10 +235,19 @@ Please check out common DSC Resources [contributing guidelines](https://github.c
* **DefaultApplicationPool**: Name of the default application pool used by websites.
* **AllowSubDirConfig**: Should IIS look for config files in subdirectories, either **true** or **false**

### xWebSiteAlive

* **WebSiteName**: Name of the website that must be running, such as **Default Web Site**.
* **RelativeUrl**: A relative url to joint to each website binding.
* **ValidStatusCodes**: A list of HTTP status codes to be considered successful results. Defaults to **200 OK**.
* **ExpectedContent**: The content considered to be successful result.

## Versions

### Unreleased

* Added **xWebSiteAlive**.

### 1.17.0.0

* Added removal of self signed certificate to the integration tests of **xWebsite**, fixes #276.
Expand Down
Loading