Author Posts

February 9, 2018 at 11:04 am

Hi guys,

I'm trying to figure out why my script won't execute from the beginning, skip first lines and start execution from DSC configuration part?
Generally, I have completely fresh Windows Server 2016 without any additional software installed. I want to provision my server with the code below. And I can't manage it. I'm not sure what I'm missing in the scrip. Can somene hel me?
Thanks!

################################################# 
### Temporary relax execution policy ### 
################################################# 

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force 

################################################# 
### Install necessary modules ### 
################################################# 

#Save-Module -Name xWebAdministration -Path C:\Temp 
Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force 

Install-Module -Name xWebAdministration -Force 
Install-Module -Name xWindowsUpdate -Force 
Install-Module -Name xComputerManagement -Force 

Import-Module -Name xWebAdministration 
Import-Module -Name xWindowsUpdate 
Import-Module -Name xComputerManagement 

################################################# 
### VARIABLES ### 
################################################# 

[string]$NewComputerName = "TEST-SRV" # Max 15 characters 
$softwarePath = "\\SHARE\Temp\DSCInstall" 

################################################# 
### Map network drive with necessary software ### 
################################################# 

$net = new-object -ComObject WScript.Network 
$net.MapNetworkDrive("q:", $softwarePath, $false, $user, $pass) 

################################################# 
### DSC Configuration for Web Server ### 
################################################# 


Configuration IIS 
{ 
Import-DscResource –ModuleName PSDesiredStateConfiguration 
Import-DscResource –ModuleName xWindowsUpdate 
Import-DscResource –ModuleName xWebAdministration 

Node "localhost" 
{ 
### CREATE REQUIRED DIRECTORIES ### 
File InstallLogDirectory 
{ 
Ensure = "Present" 
Type = "Directory" 
DestinationPath = "C:\DSCDeployment" 
} 

File LogDirectory 
{ 
Ensure = "Present" 
Type = "Directory" 
DestinationPath = "C:\Logfiles" 
} 

### WEBSERVER ROLE ### 
WindowsFeature Web-Server 
{ 
Name = "Web-Server" 
Ensure = "Present" 
} 

foreach($feature in $disableFeatures) 
{ 
WindowsFeature $feature 
{ 
Name= $feature 
Ensure = "Absent" 
DependsOn = "[WindowsFeature]Web-Server" 
} 
} 

foreach($feature in $enableFeatures) 
{ 
WindowsFeature $feature 
{ 
Name = $feature 
Ensure = "Present" 
DependsOn = "[WindowsFeature]Web-Server" 
} 
} 

### CONFIGURE IIS ### 
xIISLogging EnableAllLoggingFields 
{ 
LogPath = "C:\inetpub\logs\LogFiles" 
LogFormat = "W3C" 
LogFlags = "Date","Time","ClientIP","UserName","SiteName","ComputerName","ServerIP","Method","UriStem","UriQuery","HttpStatus","Win32Status","BytesSent","BytesRecv","TimeTaken","ServerPort","UserAgent","Cookie","Referer","ProtocolVersion","Host","HttpSubStatus" 
LogPeriod = "Daily" 
LoglocalTimeRollover = $true 
DependsOn = "[WindowsFeature]Web-Server" 
} 

xIisFeatureDelegation IPSecurity-FeatureDelegation 
{ 
SectionName = "security/ipSecurity" 
OverrideMode = "Allow" 
DependsOn = "[WindowsFeature]Web-Server" 
} 

Script IPSecurity-SetDefaults 
{ 
SetScript = 
{ 
Set-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/security/ipSecurity" -Name "." -Value @{enableProxyMode=$true; allowUnlisted=$false} 
} 
TestScript = { return $false } 
GetScript = { } 
} 

Script IPSecurity-RemoveAllowedNetworks 
{ 
SetScript = 
{ 
Clear-WebConfiguration -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/security/ipSecurity/*" 
} 
TestScript = { return $false } 
GetScript = { } 
} 

foreach($network in $IPSecurityAllowedNetworks) 
{ 
Script "IPSecirity-AllowNetwork[$network]" 
{ 
SetScript = 
{ 
$value = @{ allowed = "true"; ipAddress = "$Using:network" } 
Add-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/security/ipSecurity" -Name "." -Value $value 
} 
TestScript = { return $false } 
GetScript = { } 
} 
} 

Script RemoveIISHeader-X-Powered-By 
{ 
DependsOn = "[WindowsFeature]Web-Server" 

SetScript = 
{ 
Remove-WebConfigurationProperty -PSPath "MACHINE/WEBROOT/APPHOST" -Filter "system.webServer/httpProtocol/customHeaders" -Name "." -AtElement @{name='X-Powered-By'} 
} 
TestScript = 
{ 
return (Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "/system.webServer/httpProtocol/customHeaders/add[@name='X-Powered-By']" -Name ".").Count -eq 0 
} 
GetScript = 
{ 
#Do Nothing 
} 
} 


Package UrlRewrite 
{ 
# Install URL Rewrite module for IIS 
DependsOn = "[WindowsFeature]Web-Server" 
Ensure = "Present" 
Name = "IIS URL Rewrite Module 2" 
Path = "$softwarePath\rewrite_amd64.msi" 
Arguments = "/quiet" 
ProductId = "08F0318A-D113-4CF0-993E-50F191D397AD" 
} 

Script RewriteRules-X-Forwarded-For 
{ 
DependsOn = "[Package]UrlRewrite" 
SetScript = 
{ 
$rulesPath = "/system.webServer/rewrite/globalRules/rule[@name='X-Forwarded-For Rewrite']" 

Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -filter "system.webServer/rewrite/globalRules" -name "." -value @{name='X-Forwarded-For Rewrite';patternSyntax='Wildcard';stopProcessing='False'} 
Set-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -filter "$rulesPath/match" -Name "url" -Value '*' 

Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -filter "$rulesPath/serverVariables" -Name "." -Value @{name='REMOTE_ADDR';value='{HTTP_X_FORWARDED_FOR}'} 
Add-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -filter "$rulesPath/serverVariables" -Name "." -Value @{name='REMOTE_HOST';value='{HTTP_X_FORWARDED_FOR}'} 

Set-WebConfigurationProperty -pspath 'MACHINE/WEBROOT/APPHOST' -filter "$rulesPath/action" -name "type" -value "None" 
} 
TestScript = 
{ 
return (Get-WebConfigurationProperty -PSPath 'MACHINE/WEBROOT/APPHOST' -Filter "/system.webServer/rewrite/globalRules/rule[@name='X-Forwarded-For Rewrite']" -Name ".").Count -eq 1 
} 
GetScript = 
{ 
#Do Nothing 
} 
} 

Script ReWriteRules-AllowedServerVariables 
{ 
#Adds rewrite allowedServerVariables to applicationHost.config 
DependsOn = "[Package]UrlRewrite" 
SetScript = { 
$current = Get-WebConfiguration /system.webServer/rewrite/allowedServerVariables | select -ExpandProperty collection | ?{$_.ElementTagName -eq "add"} | select -ExpandProperty name 
$expected = @("HTTPS", "HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_PROTO", "REMOTE_ADDR") 
$missing = $expected | where {$current -notcontains $_} 
try 
{ 
Start-WebCommitDelay 
$missing | %{ Add-WebConfiguration /system.webServer/rewrite/allowedServerVariables -atIndex 0 -value @{name="$_"} -Verbose } 
Stop-WebCommitDelay -Commit $true 
} 
catch [System.Exception] 
{ 
$_ | Out-String 
} 
} 
TestScript = { 
$current = Get-WebConfiguration /system.webServer/rewrite/allowedServerVariables | select -ExpandProperty collection | select -ExpandProperty name 
$expected = @("HTTPS", "HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_PROTO", "REMOTE_ADDR") 
$result = -not @($expected| where {$current -notcontains $_}| select -first 1).Count 
return $result 
} 
GetScript = { 
$allowedServerVariables = Get-WebConfiguration /system.webServer/rewrite/allowedServerVariables | select -ExpandProperty collection 
return $allowedServerVariables 
} 
} 

### ENABLE RDP ### 
Registry EnableRDP-Step1 
{ 
Ensure = "Present" 
Key = "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server" 
ValueName = "fDenyTSConnections" 
ValueData = "0" 
ValueType = "Dword" 
Force = $true 
} 

Registry EnableRDP-Step2 
{ 
Ensure = "Present" 
Key = "HKEY_LOCAL_MACHINE\System\CurrentControlSet\Control\Terminal Server\WinStations\RDP-Tcp" 
ValueName = "UserAuthentication" 
ValueData = "1" 
ValueType = "Dword" 
Force = $true 
} 

Script EnableRDP 
{ 
SetScript = { 
Enable-NetFirewallRule -DisplayGroup "Remote Desktop" 
eventcreate /t INFORMATION /ID 2 /L APPLICATION /SO "DSC-Client" /D "Enabled Remote Desktop access" 
} 
TestScript = { 
if ((Get-NetFirewallRule -Name "RemoteDesktop-UserMode-In-TCP").Enabled -ne "True") { 
$false 
} else { 
$true 
} 
} 
GetScript = { 
# Do Nothing 
} 
} 
} 
} 

# Compile the configuration into MOF file, so DSC configuration can be applied to a node 
IIS -OutputPath C:\DSCDeployment 
LocalConfiguration -OutputPath C:\DSCDeployment 
Set-DscLocalConfigurationManager -Path C:\DSCDeployment\ -Verbose 

Start-DscConfiguration -Wait -Path C:\DSCDeployment\ -Force -Verbose 
################################################# 

February 9, 2018 at 2:45 pm

Hiya,

In short, before it even executes the top of the script, PowerShell will parse the Configuration, and will try to resolve the Import-DSCResource keywords (and fail because they're not available).
So your script above is likely to fail, before doing anything, telling you some DSC resources or modules are missing.

One trick to work around this is to put the configuration into a second file, and dot source it after your bootstrap (the part where you install modules).
By doing so, PowerShell will first parse the file, execute it, and will only parse the Configuration when it reached the dot sourcing of the configuration file.

The first file would look like:

Set-ExecutionPolicy -ExecutionPolicy Bypass -Scope Process -Force 

################################################# 
### Install necessary modules ### 
################################################# 

#Save-Module -Name xWebAdministration -Path C:\Temp 
Install-PackageProvider -Name NuGet -RequiredVersion 2.8.5.201 -Force 

Install-Module -Name xWebAdministration -Force 
Install-Module -Name xWindowsUpdate -Force 
Install-Module -Name xComputerManagement -Force 

Import-Module -Name xWebAdministration 
Import-Module -Name xWindowsUpdate 
Import-Module -Name xComputerManagement 

################################################# 
### VARIABLES ### 
################################################# 

[string]$NewComputerName = "TEST-SRV" # Max 15 characters 
$softwarePath = "\\SHARE\Temp\DSCInstall" 

################################################# 
### Map network drive with necessary software ### 
################################################# 

$net = new-object -ComObject WScript.Network 
$net.MapNetworkDrive("q:", $softwarePath, $false, $user, $pass) 

. ./Configuration_IIS.ps1

...and the Configuration_IIS.ps1 would have the rest of the file.

February 9, 2018 at 6:31 pm

Thank you for a detailed explanation. So, there is no way to do this in one script at all?