Skip to content

Commit 7a0c42a

Browse files
Migrate win_iis_website and win_iis_webbinding
1 parent 1c833e7 commit 7a0c42a

File tree

28 files changed

+1432
-2392
lines changed

28 files changed

+1432
-2392
lines changed

plugins/modules/website.ps1

Lines changed: 259 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,27 +1,280 @@
11
#!powershell
22

3-
# Copyright: (c) 2024, Ansible Project
3+
# Copyright: (c) 2025, Ansible Project
44
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
55

66
#AnsibleRequires -CSharpUtil Ansible.Basic
77

8+
# Define Bindings Options
9+
$binding_options = @{
10+
type = 'list'
11+
elements = 'dict'
12+
options = @{
13+
ip = @{ type = 'str' }
14+
port = @{ type = 'int' }
15+
hostname = @{ type = 'str' }
16+
protocol = @{ type = 'str' ; default = 'http' ; choices = @('http', 'https') }
17+
ssl_flags = @{ type = 'str' ; default = '0' ; choices = @('0', '1', '2', '3') }
18+
certificate_hash = @{ type = 'str' ; default = ([string]::Empty) }
19+
certificate_store_name = @{ type = 'str' ; default = ([string]::Empty) }
20+
}
21+
}
22+
823
$spec = @{
924
options = @{
1025
name = @{
1126
required = $true
12-
type = 'str'
27+
type = "str"
28+
}
29+
state = @{
30+
type = "str"
31+
default = "started"
32+
choices = @("absent", "restarted", "started", "stopped")
33+
}
34+
site_id = @{
35+
type = "str"
36+
}
37+
application_pool = @{
38+
type = "str"
39+
}
40+
physical_path = @{
41+
type = "str"
42+
}
43+
parameters = @{
44+
type = "str"
45+
}
46+
bindings = @{
47+
default = @{}
48+
type = 'dict'
49+
options = @{
50+
add = $binding_options
51+
set = $binding_options
52+
remove = @{
53+
type = 'list'
54+
elements = 'dict'
55+
options = @{
56+
ip = @{ type = 'str' }
57+
port = @{ type = 'int' }
58+
hostname = @{ type = 'str' }
59+
}
60+
}
61+
}
1362
}
1463
}
1564
supports_check_mode = $true
1665
}
17-
1866
$module = [Ansible.Basic.AnsibleModule]::Create($args, $spec)
1967

2068
$name = $module.Params.name
69+
$state = $module.Params.state
70+
$site_id = $module.Params.site_id
71+
$application_pool = $module.Params.application_pool
72+
$physical_path = $module.Params.physical_path
73+
$bindings = $module.Params.bindings
74+
75+
# Custom site Parameters from string where properties are separated by a pipe and property name/values by colon.
76+
# Ex. "foo:1|bar:2"
77+
$parameters = $module.Params.parameters
78+
if ($null -ne $parameters) {
79+
$parameters = @($parameters -split '\|' | ForEach-Object {
80+
return , ($_ -split "\:", 2)
81+
})
82+
}
83+
84+
$check_mode = $module.CheckMode
85+
$module.Result.changed = $false
86+
87+
if ($check_mode) {
88+
Write-Output "in check mode"
89+
}
90+
91+
# Ensure WebAdministration module is loaded
92+
if ($null -eq (Get-Module "WebAdministration" -ErrorAction SilentlyContinue)) {
93+
Import-Module WebAdministration
94+
}
95+
96+
# Site info
97+
$site = Get-Website | Where-Object { $_.Name -eq $name }
98+
99+
Try {
100+
# Add site
101+
If (($state -ne 'absent') -and (-not $site)) {
102+
If (-not $physical_path) {
103+
$module.FailJson("missing required arguments: physical_path $($_.Exception.Message)")
104+
}
105+
ElseIf (-not (Test-Path -LiteralPath $physical_path)) {
106+
$module.FailJson("specified folder must already exist: physical_path $($_.Exception.Message)")
107+
}
21108

22-
$module.Diff.before = $null
23-
$module.Diff.after = @{
24-
name = $name
109+
$site_parameters = @{
110+
Name = $name
111+
PhysicalPath = $physical_path
112+
}
113+
114+
If ($application_pool) {
115+
$site_parameters.ApplicationPool = $application_pool
116+
}
117+
118+
If ($site_id) {
119+
$site_parameters.ID = $site_id
120+
}
121+
# Fix for error "New-Item : Index was outside the bounds of the array."
122+
# This is a bug in the New-WebSite commandlet. Apparently there must be at least one site configured in IIS otherwise New-WebSite crashes.
123+
# For more details, see http://stackoverflow.com/questions/3573889/ps-c-new-website-blah-throws-index-was-outside-the-bounds-of-the-array
124+
$sites_list = Get-ChildItem -LiteralPath IIS:\sites
125+
if ($null -eq $sites_list) {
126+
if ($site_id) {
127+
$site_parameters.ID = $site_id
128+
}
129+
else {
130+
$site_parameters.ID = 1
131+
}
132+
}
133+
if ( -not $check_mode) {
134+
$site = New-Website @site_parameters -Force
135+
}
136+
# Verify that initial site has no binding
137+
Get-WebBinding -Name $site.Name | Remove-WebBinding -WhatIf:$check_mode
138+
$module.Result.changed = $true
139+
}
140+
# Remove site
141+
If ($state -eq 'absent' -and $site) {
142+
$site = Remove-Website -Name $name -WhatIf:$check_mode
143+
$module.Result.changed = $true
144+
}
145+
$site = Get-Website | Where-Object { $_.Name -eq $name }
146+
If ($site) {
147+
# Change Physical Path if needed
148+
if ($physical_path) {
149+
If (-not (Test-Path -LiteralPath $physical_path)) {
150+
$module.FailJson("specified folder must already exist: physical_path $($_.Exception.Message)")
151+
}
152+
153+
$folder = Get-Item -LiteralPath $physical_path
154+
If ($folder.FullName -ne $site.PhysicalPath) {
155+
Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name physicalPath -value $folder.FullName -WhatIf:$check_mode
156+
$module.Result.changed = $true
157+
}
158+
}
159+
# Change Application Pool if needed
160+
if ($application_pool) {
161+
If ($application_pool -ne $site.applicationPool) {
162+
Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" -name applicationPool -value $application_pool -WhatIf:$check_mode
163+
$module.Result.changed = $true
164+
}
165+
}
166+
# Add Remove or Set bindings if needed
167+
if ($bindings) {
168+
$site_bindings = (Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)").Bindings.Collection
169+
$user_bindings = if ($Module.Params.bindings.add) { $Module.Params.bindings.add }
170+
elseif ($Module.Params.bindings.remove) { $Module.Params.bindings.remove }
171+
elseif ($Module.Params.bindings.set) { $Module.Params.bindings.set }
172+
# Validate User Bindings Information
173+
$user_bindings | ForEach-Object {
174+
# Make sure ssl flags only specified with https protocol
175+
If ($_.protocol -ne 'https' -and $_.ssl_flags -gt 0) {
176+
$module.FailJson("SSLFlags can only be set for https protocol")
177+
}
178+
# Validate certificate details if provided
179+
If ($_.certificate_hash -and $_.operation -ne 'remove') {
180+
If ($_.protocol -ne 'https') {
181+
$module.FailJson("You can only provide a certificate thumbprint when protocol is set to https")
182+
}
183+
# Apply default for cert store name
184+
If (-Not $_.certificate_store_name) {
185+
$_.certificate_store_name = 'my'
186+
}
187+
# Validate cert path
188+
$cert_path = "cert:\LocalMachine\$($_.certificate_store_name)\$($_.certificate_hash)"
189+
If (-Not (Test-Path -LiteralPath $cert_path) ) {
190+
$module.FailJson("Unable to locate certificate at $cert_path")
191+
}
192+
}
193+
# Make sure binding info is valid for central cert store if sslflags -gt 1
194+
If ($_.ssl_flags -gt 1 -and ($_.certificate_hash -ne [string]::Empty -or $_.certificate_store_name -ne [string]::Empty)) {
195+
$module.FailJson("You set sslFlags to $($_.ssl_flags). This indicates you wish to use the Central Certificate Store feature.
196+
This cannot be used in combination with certficiate_hash and certificate_store_name. When using the Central Certificate Store feature,
197+
the certificate is automatically retrieved from the store rather than manually assigned to the binding.")
198+
}
199+
}
200+
if ($null -ne $bindings.add) {
201+
$add_binding = $user_bindings | Where-Object { -not ($site_bindings.bindingInformation -contains "$($_.ip):$($_.port):$($_.hostname)") }
202+
if ($add_binding) {
203+
$add_binding | ForEach-Object {
204+
if (-not $check_mode) {
205+
New-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname -Protocol $_.protocol -SslFlags $_.ssl_flags
206+
If ($_.certificate_hash) {
207+
$new_binding = Get-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname
208+
$new_binding.AddSslCertificate($_.certificate_hash, $_.certificate_store_name)
209+
}
210+
}
211+
$module.Result.changed = $true
212+
}
213+
}
214+
}
215+
if ($null -ne $bindings.remove) {
216+
$remove_binding = $user_bindings | Where-Object { ($site_bindings.bindingInformation -contains "$($_.ip):$($_.port):$($_.hostname)") }
217+
if ($remove_binding) {
218+
$remove_binding | ForEach-Object {
219+
Get-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname | Remove-WebBinding -WhatIf:$check_mode
220+
$module.Result.changed = $true
221+
}
222+
}
223+
}
224+
if ($null -ne $bindings.set) {
225+
$set_binding = $user_bindings | ForEach-Object { "$($_.ip):$($_.port):$($_.hostname)" }
226+
$diff = Compare-Object -ReferenceObject @($set_binding | Select-Object) -DifferenceObject @($site_bindings.bindingInformation | Select-Object)
227+
if ($diff.Count -ne 0) {
228+
# Remove All Bindings
229+
Get-WebBinding -Name $site.Name | Remove-WebBinding -WhatIf:$check_mode
230+
# Set Bindings
231+
$user_bindings | ForEach-Object {
232+
if (-not $check_mode) {
233+
New-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname -Protocol $_.protocol -SslFlags $_.ssl_flags
234+
If ($_.certificate_hash) {
235+
$new_binding = Get-WebBinding -Name $site.Name -IPAddress $_.ip -Port $_.port -HostHeader $_.hostname
236+
$new_binding.AddSslCertificate($_.certificate_hash, $_.certificate_store_name)
237+
}
238+
}
239+
}
240+
$module.Result.changed = $true
241+
}
242+
}
243+
}
244+
# Set properties
245+
if ($parameters) {
246+
$parameters | ForEach-Object {
247+
$property_value = Get-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0]
248+
249+
switch ($property_value.GetType().Name) {
250+
"ConfigurationAttribute" { $parameter_value = $property_value.value }
251+
"String" { $parameter_value = $property_value }
252+
}
253+
254+
if ((-not $parameter_value) -or ($parameter_value) -ne $_[1]) {
255+
Set-ItemProperty -LiteralPath "IIS:\Sites\$($site.Name)" $_[0] $_[1] -WhatIf:$check_mode
256+
$module.Result.changed = $true
257+
}
258+
}
259+
}
260+
261+
# Set run state
262+
if ((($state -eq 'stopped') -or ($state -eq 'restarted')) -and ($site.State -eq 'Started')) {
263+
if (-not $check_mode) {
264+
Stop-Website -Name $name -ErrorAction Stop
265+
}
266+
$module.Result.changed = $true
267+
}
268+
if ((($state -eq 'started') -and ($site.State -eq 'Stopped')) -or ($state -eq 'restarted')) {
269+
if (-not $check_mode) {
270+
Start-Website -Name $name -ErrorAction Stop
271+
}
272+
$module.Result.changed = $true
273+
}
274+
}
275+
}
276+
Catch {
277+
$module.FailJson("$($module.Result) - $($_.Exception.Message)")
25278
}
26279

27280
$module.ExitJson()

0 commit comments

Comments
 (0)