# name and description for the Firewall rules. Used in multiple locations$FireWallRuleDisplayName="Desired State Configuration - Pull Server Port:{0}"$FireWallRuleDescription="Inbound traffic for IIS site on Port:{0} for DSC pull server. Created by DSCWebService resource"

# Validate supplied configuration to setup the PSWS Endpoint# Function checks for the existence of PSWS Schema files, IIS config# Also validate presence of IIS on the target machine#functionInitialize-Endpoint{param($site,$path,$cfgfile,$port,$app,$applicationPoolIdentityType,$svc,$mof,$dispatch,$asax,$dependentBinaries,$language,$dependentMUIFiles,$psFiles,$removeSiteFiles=$false,$certificateThumbPrint)if(!(Test-Path$cfgfile)){throw"ERROR: $cfgfile does not exist"}if(!(Test-Path$svc)){throw"ERROR: $svc does not exist"}if(!(Test-Path$mof)){throw"ERROR: $mof does not exist"}if(!(Test-Path$asax)){throw"ERROR: $asax does not exist"}

if($certificateThumbPrint-ne"AllowUnencryptedTraffic"){Write-Verbose"Verify that the certificate with the provided thumbprint exists in CERT:\LocalMachine\MY\"$certificate=Get-childItemCERT:\LocalMachine\MY\|Where{$_.Thumbprint-eq$certificateThumbPrint}if(!$Certificate){throw"ERROR: Certificate with thumbprint $certificateThumbPrint does not exist in CERT:\LocalMachine\MY\"}}Test-IISInstall$appPool="PSWS"

Write-Verbose"Delete the App Pool if it exists"Remove-AppPool-apppool$appPoolWrite-Verbose"Remove the site if it already exists"Update-Site-siteName$site-siteActionRemove

# check for existing binding, there should be no binding with the same portif((Get-WebBinding|wherebindingInformation-eq"*:$($port):").count-gt0){throw"ERROR: Port $port is already used, please review existing sites and change the port to be used."}if($removeSiteFiles){if(Test-Path$path){Remove-Item-Path$path-Recurse-Force}}Copy-Files-path$path-cfgfile$cfgfile-svc$svc-mof$mof-dispatch$dispatch-asax$asax-dependentBinaries$dependentBinaries-language$language-dependentMUIFiles$dependentMUIFiles-psFiles$psFilesNew-IISWebSite-site$site-path$path-port$port-app$app-apppool$appPool-applicationPoolIdentityType$applicationPoolIdentityType-certificateThumbPrint$certificateThumbPrint}

# Validate if IIS and all required dependencies are installed on the target machine#functionTest-IISInstall{Write-Verbose"Checking IIS requirements"$iisVersion=(Get-ItemPropertyHKLM:\SOFTWARE\Microsoft\InetStp-ErrorActionsilentlycontinue).MajorVersionif($iisVersion-lt7){throw"ERROR: IIS Version detected is $iisVersion , must be running higher than 7.0"}$wsRegKey=(Get-ItemPropertyhklm:\SYSTEM\CurrentControlSet\Services\W3SVC-ErrorActionsilentlycontinue).ImagePathif($wsRegKey-eq$null){throw"ERROR: Cannot retrive W3SVC key. IIS Web Services may not be installed"}if((Get-Servicew3svc).Status-ne"running"){throw"ERROR: service W3SVC is not running"}}

# Verify if a given IIS Site exists#functionTest-IISSiteExists{param($siteName)

if(Get-Website-Name$siteName){return$true}return$false}

# Perform an action (such as stop, start, delete) for a given IIS Site#functionUpdate-Site{param([Parameter(ParameterSetName='SiteName',Mandatory,Position=0)][ValidateNotNullOrEmpty()][String]$siteName,

# Delete the given IIS Application Pool# This is required to cleanup any existing conflicting apppools before setting up the endpoint#functionRemove-AppPool{param($appPool)

# without this tests we may get a breaking error here, despite SilentlyContinueif(Test-Path"IIS:\AppPools\$appPool"){Remove-WebAppPool-Name$appPool-ErrorActionSilentlyContinue}}

# Generate an IIS Site Id while setting up the endpoint# The Site Id will be the max available in IIS config + 1#functionNew-SiteID{return((Get-Website|%{$_.Id}|Measure-Object-Maximum).Maximum+1)}

# Validate the PSWS config files supplied and copy to the IIS endpoint in inetpub#functionCopy-Files{param($path,$cfgfile,$svc,$mof,$dispatch,$asax,$dependentBinaries,$language,$dependentMUIFiles,$psFiles)if(!(Test-Path$cfgfile)){throw"ERROR: $cfgfile does not exist"}if(!(Test-Path$svc)){throw"ERROR: $svc does not exist"}if(!(Test-Path$mof)){throw"ERROR: $mof does not exist"}

if(!(Test-Path$asax)){throw"ERROR: $asax does not exist"}if(!(Test-Path$path)){$null=New-Item-ItemTypecontainer-Path$path}foreach($dependentBinaryin$dependentBinaries){if(!(Test-Path$dependentBinary)){throw"ERROR: $dependentBinary does not exist"}}

foreach($dependentMUIFilein$dependentMUIFiles){if(!(Test-Path$dependentMUIFile)){throw"ERROR: $dependentMUIFile does not exist"}}Write-Verbose"Create the bin folder for deploying custom dependent binaries required by the endpoint"$binFolderPath=Join-Path$path"bin"$null=New-Item-path$binFolderPath-itemType"directory"-ForceCopy-Item$dependentBinaries$binFolderPath-Force

foreach($psFilein$psFiles){if(!(Test-Path$psFile)){throw"ERROR: $psFile does not exist"}Copy-Item$psFile$path-Force}Copy-Item$cfgfile(Join-Path$path"web.config")-ForceCopy-Item$svc$path-ForceCopy-Item$mof$path-Forceif($dispatch){Copy-Item$dispatch$path-Force}if($asax){Copy-Item$asax$path-Force}}

$appPoolItem=Get-ItemIIS:\AppPools\$appPool$appPoolItem.managedRuntimeVersion="v4.0"$appPoolItem.enable32BitAppOnWin64=$true$appPoolItem.processModel.identityType=$appPoolIdentity$appPoolItem|Set-ItemWrite-Verbose"Add and Set Site Properties"if($certificateThumbPrint-eq"AllowUnencryptedTraffic"){$webSite=New-WebSite-Name$site-Id$siteID-Port$port-IPAddress"*"-PhysicalPath$path-ApplicationPool$appPool}else{$webSite=New-WebSite-Name$site-Id$siteID-Port$port-IPAddress"*"-PhysicalPath$path-ApplicationPool$appPool-Ssl

# Any dependent binaries that need to be deployed to the IIS endpoint, in the bin\mui folder [Optional][ValidateNotNullOrEmpty()][String[]]$dependentMUIFiles,# Any dependent PowerShell Scipts/Modules that need to be deployed to the IIS endpoint application root[ValidateNotNullOrEmpty()][String[]]$psFiles,# True to remove all files for the site at first, false otherwise[Boolean]$removeSiteFiles=$false,

<#
.Synopsis
Removes a DSC WebServices IIS Endpoint
.DESCRIPTION
Removes a PSWS IIS Endpoint
.EXAMPLE
Remove the endpoint with the specified name
Remove-PSWSEndpoint -siteName PSDSCPullServer
#>functionRemove-PSWSEndpoint{[CmdletBinding()]param(# Unique Name of the IIS Site [String]$siteName)# get the site to remove$site=Get-Item-Path"IIS:\sites\$siteName"# and the pool it is using$pool=$site.applicationPool

# get the path so we can delete the files$filePath=$site.PhysicalPath# get the port number for the Firewall rule$bindings=(Get-WebBinding-Name$siteName).bindingInformation$port=[regex]::match($bindings,':(\d+):').Groups[1].Value

# remove the actual site.Remove-Website-Name$siteName# there may be running requests, wait a little# I had an issue where the files were still in use# when I tried to delete themStart-Sleep-Milliseconds200

# remove the files for the siteIf(Test-Path$filePath){Get-ChildItem$filePath-Recurse|Remove-Item-RecurseRemove-Item$filePath}

# find out whether any other site is using this pool$filter="/system.applicationHost/sites/site/application[@applicationPool='"+$pool+"']"$apps=(Get-WebConfigurationProperty-Filter$filter-PSPath"machine/webroot/apphost"-namepath).ItemXPathif($apps.count-eq1){# if we are the only site in the pool, remove the pool as well.Remove-WebAppPool-Name$pool}

# remove all rules with that name$ruleName=($($FireWallRuleDisplayName)-f$port)Get-NetFirewallRule|Where-ObjectDisplayName-eq"$ruleName"|Remove-NetFirewallRule

}

<#
.Synopsis
Set the option into the web.config for an endpoint
.DESCRIPTION
Set the options into the web.config for an endpoint allowing customization.
.EXAMPLE
#>functionSet-AppSettingsInWebconfig{param(# Physical path for the IIS Endpoint on the machine (possibly under inetpub)[parameter(Mandatory)][ValidateNotNullOrEmpty()][String]$path,# Key to add/update[parameter(Mandatory)][ValidateNotNullOrEmpty()][String]$key,

<#
.Synopsis
Set the binding redirect setting in the web.config to redirect 10.0.0.0 version of microsoft.isam.esent.interop to 6.3.0.0.
.DESCRIPTION
This function creates the following section in the web.config:
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="microsoft.isam.esent.interop" publicKeyToken="31bf3856ad364e35" />
<bindingRedirect oldVersion="10.0.0.0" newVersion="6.3.0.0" />
</dependentAssembly>
</assemblyBinding>
</runtime>
#>functionSet-BindingRedirectSettingInWebConfig{param(# Physical path for the IIS Endpoint on the machine (possibly under inetpub)[parameter(Mandatory)][ValidateNotNullOrEmpty()][String]$path,