├── .gitignore
├── LICENSE
├── README.md
├── azure-pipelines.yml
├── scripts
├── disable-network-discovery.cmd
├── disable-screensaver.ps1
├── enable-rdp.cmd
├── enable-winrm.bat
├── enable-winrm.ps1
├── install-vm-tools.cmd
├── microsoft-updates.bat
├── set-temp.ps1
└── win-updates.ps1
├── variables.json
├── w2016.base
├── Server2016_vsphere.json
└── autounattend.xml
├── w2019.base
├── Server2019_vsphere.json
├── autounattend.xml
└── scripts
│ ├── disable-network-discovery.cmd
│ ├── disable-screensaver.ps1
│ ├── enable-rdp.cmd
│ ├── enable-winrm.bat
│ ├── enable-winrm.ps1
│ ├── install-vm-tools.cmd
│ ├── microsoft-updates.bat
│ ├── set-temp.ps1
│ └── win-updates.ps1
└── win10.base
├── Win10_vsphere.json
└── autounattend.xml
/.gitignore:
--------------------------------------------------------------------------------
1 | variables_*
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2020 thomaspreischl
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # vpshere_packer_deployments
2 | this repository contains packer scripts to automatically create, preconfigure and deploy vm templates in vmware vsphere
3 |
4 | The Templates for your OS will also prepared for Ansible (WinRM Connection) and updated from Microsoft Update.
5 |
6 |
7 | ## Reqirements
8 |
9 | Before you can create your vmware vsphere templates with this packer deployment scripts, you have to install packer and the required plugins.
10 |
11 | Folow the steps at https://chocolatey.org/install to install chocolatey.
12 |
13 | If you have installed chocolatey, you can install the reqired packages for packer.
14 |
15 | execute the following commands in your Powershell
16 |
17 | `cinst packer -y`
18 |
19 | `choco install Packer-provisioner-windows-update`
20 |
21 | If the required Packages are installed. You can go on with the next steps
22 |
23 | ## Prepare the scripts to make an automated deployment of your vmware vsphere Templates
24 |
25 | 1. Clone the Repository
26 | 2. Upload the desired ISO Files to a Datastore of your vcenter/ vsphere environment
27 | 3. copy the variables.json file and change the setting for your environment
28 | 3. change the password for your autounattend.xml files
29 |
30 | ` YOUR PASSWORD true `
31 |
32 | and
33 |
34 | ` YOUR PASSWORD true `
35 |
36 | ## Execute the Scripts
37 |
38 | go to the *w***.base* folder
39 |
40 | Execute the scripts as followed:
41 |
42 | `packer build -var-file ..\variables_YOUR_VARFILE.json .\Server2019_vsphere.json`
43 |
--------------------------------------------------------------------------------
/azure-pipelines.yml:
--------------------------------------------------------------------------------
1 | # Starter pipeline
2 | # Start with a minimal pipeline that you can customize to build and deploy your code.
3 | # Add steps that build, run tests, deploy, and more:
4 | # https://aka.ms/yaml
5 |
6 | trigger:
7 | branches:
8 | include:
9 | - master
10 | paths:
11 | include:
12 | - vsphere_packer_templates/*
13 |
14 | schedules:
15 | - cron: "0 1 * * 0"
16 | displayName: Weekly Sunday build
17 | branches:
18 | include:
19 | - master
20 | always: true
21 |
22 | pool:
23 |
24 | name: Default
25 |
26 | steps:
27 |
28 | - task: CopyFiles@2
29 |
30 | displayName: 'Copy Packer Files to Artifacts'
31 |
32 | inputs:
33 |
34 | SourceFolder: vsphere_packer_templates
35 |
36 | TargetFolder: '$(Build.ArtifactStagingDirectory)'
37 | cleanTargetFolder: true
38 |
39 |
40 | - task: PublishPipelineArtifact@1
41 | inputs:
42 | targetPath: '$(Build.ArtifactStagingDirectory)'
43 | artifact: PackerConfig
--------------------------------------------------------------------------------
/scripts/disable-network-discovery.cmd:
--------------------------------------------------------------------------------
1 | reg ADD HKLM\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff /f
2 | netsh advfirewall firewall set rule group="Network Discovery" new enable=No
--------------------------------------------------------------------------------
/scripts/disable-screensaver.ps1:
--------------------------------------------------------------------------------
1 | Write-Host "Disabling Screensaver"
2 | Set-ItemProperty "HKCU:\Control Panel\Desktop" -Name ScreenSaveActive -Value 0 -Type DWord
3 | & powercfg -x -monitor-timeout-ac 0
4 | & powercfg -x -monitor-timeout-dc 0
5 |
--------------------------------------------------------------------------------
/scripts/enable-rdp.cmd:
--------------------------------------------------------------------------------
1 | netsh advfirewall firewall add rule name="Open Port 3389" dir=in action=allow protocol=TCP localport=3389
2 | reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
--------------------------------------------------------------------------------
/scripts/enable-winrm.bat:
--------------------------------------------------------------------------------
1 | rem Enable-NetFirewallRule for WinRM
2 | netsh advfirewall firewall add rule name="Port 5985" dir=in action=allow protocol=TCP localport=5985
3 | sc.exe config winrm start= auto
4 |
--------------------------------------------------------------------------------
/scripts/enable-winrm.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 3.0
2 |
3 | # Configure a Windows host for remote management with Ansible
4 | # -----------------------------------------------------------
5 | #
6 | # This script checks the current WinRM (PS Remoting) configuration and makes
7 | # the necessary changes to allow Ansible to connect, authenticate and
8 | # execute PowerShell commands.
9 | #
10 | # All events are logged to the Windows EventLog, useful for unattended runs.
11 | #
12 | # Use option -Verbose in order to see the verbose output messages.
13 | #
14 | # Use option -CertValidityDays to specify how long this certificate is valid
15 | # starting from today. So you would specify -CertValidityDays 3650 to get
16 | # a 10-year valid certificate.
17 | #
18 | # Use option -ForceNewSSLCert if the system has been SysPreped and a new
19 | # SSL Certificate must be forced on the WinRM Listener when re-running this
20 | # script. This is necessary when a new SID and CN name is created.
21 | #
22 | # Use option -EnableCredSSP to enable CredSSP as an authentication option.
23 | #
24 | # Use option -DisableBasicAuth to disable basic authentication.
25 | #
26 | # Use option -SkipNetworkProfileCheck to skip the network profile check.
27 | # Without specifying this the script will only run if the device's interfaces
28 | # are in DOMAIN or PRIVATE zones. Provide this switch if you want to enable
29 | # WinRM on a device with an interface in PUBLIC zone.
30 | #
31 | # Use option -SubjectName to specify the CN name of the certificate. This
32 | # defaults to the system's hostname and generally should not be specified.
33 |
34 | # Written by Trond Hindenes
35 | # Updated by Chris Church
36 | # Updated by Michael Crilly
37 | # Updated by Anton Ouzounov
38 | # Updated by Nicolas Simond
39 | # Updated by Dag Wieërs
40 | # Updated by Jordan Borean
41 | # Updated by Erwan Quélin
42 | # Updated by David Norman
43 | #
44 | # Version 1.0 - 2014-07-06
45 | # Version 1.1 - 2014-11-11
46 | # Version 1.2 - 2015-05-15
47 | # Version 1.3 - 2016-04-04
48 | # Version 1.4 - 2017-01-05
49 | # Version 1.5 - 2017-02-09
50 | # Version 1.6 - 2017-04-18
51 | # Version 1.7 - 2017-11-23
52 | # Version 1.8 - 2018-02-23
53 | # Version 1.9 - 2018-09-21
54 |
55 | # Support -Verbose option
56 | [CmdletBinding()]
57 |
58 | Param (
59 | [string]$SubjectName = $env:COMPUTERNAME,
60 | [int]$CertValidityDays = 1095,
61 | [switch]$SkipNetworkProfileCheck,
62 | $CreateSelfSignedCert = $true,
63 | [switch]$ForceNewSSLCert,
64 | [switch]$GlobalHttpFirewallAccess,
65 | [switch]$DisableBasicAuth = $false,
66 | [switch]$EnableCredSSP
67 | )
68 |
69 | Function Write-Log
70 | {
71 | $Message = $args[0]
72 | Write-EventLog -LogName Application -Source $EventSource -EntryType Information -EventId 1 -Message $Message
73 | }
74 |
75 | Function Write-VerboseLog
76 | {
77 | $Message = $args[0]
78 | Write-Verbose $Message
79 | Write-Log $Message
80 | }
81 |
82 | Function Write-HostLog
83 | {
84 | $Message = $args[0]
85 | Write-Output $Message
86 | Write-Log $Message
87 | }
88 |
89 | Function New-LegacySelfSignedCert
90 | {
91 | Param (
92 | [string]$SubjectName,
93 | [int]$ValidDays = 1095
94 | )
95 |
96 | $hostnonFQDN = $env:computerName
97 | $hostFQDN = [System.Net.Dns]::GetHostByName(($env:computerName)).Hostname
98 | $SignatureAlgorithm = "SHA256"
99 |
100 | $name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
101 | $name.Encode("CN=$SubjectName", 0)
102 |
103 | $key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
104 | $key.ProviderName = "Microsoft Enhanced RSA and AES Cryptographic Provider"
105 | $key.KeySpec = 1
106 | $key.Length = 4096
107 | $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
108 | $key.MachineContext = 1
109 | $key.Create()
110 |
111 | $serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
112 | $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
113 | $ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
114 | $ekuoids.Add($serverauthoid)
115 | $ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
116 | $ekuext.InitializeEncode($ekuoids)
117 |
118 | $cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
119 | $cert.InitializeFromPrivateKey(2, $key, "")
120 | $cert.Subject = $name
121 | $cert.Issuer = $cert.Subject
122 | $cert.NotBefore = (Get-Date).AddDays(-1)
123 | $cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
124 |
125 | $SigOID = New-Object -ComObject X509Enrollment.CObjectId
126 | $SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value)
127 |
128 | [string[]] $AlternativeName += $hostnonFQDN
129 | $AlternativeName += $hostFQDN
130 | $IAlternativeNames = New-Object -ComObject X509Enrollment.CAlternativeNames
131 |
132 | foreach ($AN in $AlternativeName)
133 | {
134 | $AltName = New-Object -ComObject X509Enrollment.CAlternativeName
135 | $AltName.InitializeFromString(0x3,$AN)
136 | $IAlternativeNames.Add($AltName)
137 | }
138 |
139 | $SubjectAlternativeName = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
140 | $SubjectAlternativeName.InitializeEncode($IAlternativeNames)
141 |
142 | [String[]]$KeyUsage = ("DigitalSignature", "KeyEncipherment")
143 | $KeyUsageObj = New-Object -ComObject X509Enrollment.CX509ExtensionKeyUsage
144 | $KeyUsageObj.InitializeEncode([int][Security.Cryptography.X509Certificates.X509KeyUsageFlags]($KeyUsage))
145 | $KeyUsageObj.Critical = $true
146 |
147 | $cert.X509Extensions.Add($KeyUsageObj)
148 | $cert.X509Extensions.Add($ekuext)
149 | $cert.SignatureInformation.HashAlgorithm = $SigOID
150 | $CERT.X509Extensions.Add($SubjectAlternativeName)
151 | $cert.Encode()
152 |
153 | $enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
154 | $enrollment.InitializeFromRequest($cert)
155 | $certdata = $enrollment.CreateRequest(0)
156 | $enrollment.InstallResponse(2, $certdata, 0, "")
157 |
158 | # extract/return the thumbprint from the generated cert
159 | $parsed_cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
160 | $parsed_cert.Import([System.Text.Encoding]::UTF8.GetBytes($certdata))
161 |
162 | return $parsed_cert.Thumbprint
163 | }
164 |
165 | Function Enable-GlobalHttpFirewallAccess
166 | {
167 | Write-Verbose "Forcing global HTTP firewall access"
168 | # this is a fairly naive implementation; could be more sophisticated about rule matching/collapsing
169 | $fw = New-Object -ComObject HNetCfg.FWPolicy2
170 |
171 | # try to find/enable the default rule first
172 | $add_rule = $false
173 | $matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" }
174 | $rule = $null
175 | If ($matching_rules) {
176 | If ($matching_rules -isnot [Array]) {
177 | Write-Verbose "Editing existing single HTTP firewall rule"
178 | $rule = $matching_rules
179 | }
180 | Else {
181 | # try to find one with the All or Public profile first
182 | Write-Verbose "Found multiple existing HTTP firewall rules..."
183 | $rule = $matching_rules | ForEach-Object { $_.Profiles -band 4 }[0]
184 |
185 | If (-not $rule -or $rule -is [Array]) {
186 | Write-Verbose "Editing an arbitrary single HTTP firewall rule (multiple existed)"
187 | # oh well, just pick the first one
188 | $rule = $matching_rules[0]
189 | }
190 | }
191 | }
192 |
193 | If (-not $rule) {
194 | Write-Verbose "Creating a new HTTP firewall rule"
195 | $rule = New-Object -ComObject HNetCfg.FWRule
196 | $rule.Name = "Windows Remote Management (HTTP-In)"
197 | $rule.Description = "Inbound rule for Windows Remote Management via WS-Management. [TCP 5985]"
198 | $add_rule = $true
199 | }
200 |
201 | $rule.Profiles = 0x7FFFFFFF
202 | $rule.Protocol = 6
203 | $rule.LocalPorts = 5985
204 | $rule.RemotePorts = "*"
205 | $rule.LocalAddresses = "*"
206 | $rule.RemoteAddresses = "*"
207 | $rule.Enabled = $true
208 | $rule.Direction = 1
209 | $rule.Action = 1
210 | $rule.Grouping = "Windows Remote Management"
211 |
212 | If ($add_rule) {
213 | $fw.Rules.Add($rule)
214 | }
215 |
216 | Write-Verbose "HTTP firewall rule $($rule.Name) updated"
217 | }
218 |
219 | # Setup error handling.
220 | Trap
221 | {
222 | $_
223 | Exit 1
224 | }
225 | $ErrorActionPreference = "Stop"
226 |
227 | # Get the ID and security principal of the current user account
228 | $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
229 | $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
230 |
231 | # Get the security principal for the Administrator role
232 | $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
233 |
234 | # Check to see if we are currently running "as Administrator"
235 | if (-Not $myWindowsPrincipal.IsInRole($adminRole))
236 | {
237 | Write-Output "ERROR: You need elevated Administrator privileges in order to run this script."
238 | Write-Output " Start Windows PowerShell by using the Run as Administrator option."
239 | Exit 2
240 | }
241 |
242 | $EventSource = $MyInvocation.MyCommand.Name
243 | If (-Not $EventSource)
244 | {
245 | $EventSource = "Powershell CLI"
246 | }
247 |
248 | If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False)
249 | {
250 | New-EventLog -LogName Application -Source $EventSource
251 | }
252 |
253 | # Detect PowerShell version.
254 | If ($PSVersionTable.PSVersion.Major -lt 3)
255 | {
256 | Write-Log "PowerShell version 3 or higher is required."
257 | Throw "PowerShell version 3 or higher is required."
258 | }
259 |
260 | # Find and start the WinRM service.
261 | Write-Verbose "Verifying WinRM service."
262 | If (!(Get-Service "WinRM"))
263 | {
264 | Write-Log "Unable to find the WinRM service."
265 | Throw "Unable to find the WinRM service."
266 | }
267 | ElseIf ((Get-Service "WinRM").Status -ne "Running")
268 | {
269 | Write-Verbose "Setting WinRM service to start automatically on boot."
270 | Set-Service -Name "WinRM" -StartupType Automatic
271 | Write-Log "Set WinRM service to start automatically on boot."
272 | Write-Verbose "Starting WinRM service."
273 | Start-Service -Name "WinRM" -ErrorAction Stop
274 | Write-Log "Started WinRM service."
275 |
276 | }
277 |
278 | # WinRM should be running; check that we have a PS session config.
279 | If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
280 | {
281 | If ($SkipNetworkProfileCheck) {
282 | Write-Verbose "Enabling PS Remoting without checking Network profile."
283 | Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
284 | Write-Log "Enabled PS Remoting without checking Network profile."
285 | }
286 | Else {
287 | Write-Verbose "Enabling PS Remoting."
288 | Enable-PSRemoting -Force -ErrorAction Stop
289 | Write-Log "Enabled PS Remoting."
290 | }
291 | }
292 | Else
293 | {
294 | Write-Verbose "PS Remoting is already enabled."
295 | }
296 |
297 | # Ensure LocalAccountTokenFilterPolicy is set to 1
298 | # https://github.com/ansible/ansible/issues/42978
299 | $token_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
300 | $token_prop_name = "LocalAccountTokenFilterPolicy"
301 | $token_key = Get-Item -Path $token_path
302 | $token_value = $token_key.GetValue($token_prop_name, $null)
303 | if ($token_value -ne 1) {
304 | Write-Verbose "Setting LocalAccountTOkenFilterPolicy to 1"
305 | if ($null -ne $token_value) {
306 | Remove-ItemProperty -Path $token_path -Name $token_prop_name
307 | }
308 | New-ItemProperty -Path $token_path -Name $token_prop_name -Value 1 -PropertyType DWORD > $null
309 | }
310 |
311 | # Make sure there is a SSL listener.
312 | $listeners = Get-ChildItem WSMan:\localhost\Listener
313 | If (!($listeners | Where-Object {$_.Keys -like "TRANSPORT=HTTPS"}))
314 | {
315 | # We cannot use New-SelfSignedCertificate on 2012R2 and earlier
316 | $thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
317 | Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint"
318 |
319 | # Create the hashtables of settings to be used.
320 | $valueset = @{
321 | Hostname = $SubjectName
322 | CertificateThumbprint = $thumbprint
323 | }
324 |
325 | $selectorset = @{
326 | Transport = "HTTPS"
327 | Address = "*"
328 | }
329 |
330 | Write-Verbose "Enabling SSL listener."
331 | New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
332 | Write-Log "Enabled SSL listener."
333 | }
334 | Else
335 | {
336 | Write-Verbose "SSL listener is already active."
337 |
338 | # Force a new SSL cert on Listener if the $ForceNewSSLCert
339 | If ($ForceNewSSLCert)
340 | {
341 |
342 | # We cannot use New-SelfSignedCertificate on 2012R2 and earlier
343 | $thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
344 | Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint"
345 |
346 | $valueset = @{
347 | CertificateThumbprint = $thumbprint
348 | Hostname = $SubjectName
349 | }
350 |
351 | # Delete the listener for SSL
352 | $selectorset = @{
353 | Address = "*"
354 | Transport = "HTTPS"
355 | }
356 | Remove-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset
357 |
358 | # Add new Listener with new SSL cert
359 | New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
360 | }
361 | }
362 |
363 | # Check for basic authentication.
364 | $basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "Basic"}
365 |
366 | If ($DisableBasicAuth)
367 | {
368 | If (($basicAuthSetting.Value) -eq $true)
369 | {
370 | Write-Verbose "Disabling basic auth support."
371 | Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $false
372 | Write-Log "Disabled basic auth support."
373 | }
374 | Else
375 | {
376 | Write-Verbose "Basic auth is already disabled."
377 | }
378 | }
379 | Else
380 | {
381 | If (($basicAuthSetting.Value) -eq $false)
382 | {
383 | Write-Verbose "Enabling basic auth support."
384 | Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
385 | Write-Log "Enabled basic auth support."
386 | }
387 | Else
388 | {
389 | Write-Verbose "Basic auth is already enabled."
390 | }
391 | }
392 |
393 | # If EnableCredSSP if set to true
394 | If ($EnableCredSSP)
395 | {
396 | # Check for CredSSP authentication
397 | $credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "CredSSP"}
398 | If (($credsspAuthSetting.Value) -eq $false)
399 | {
400 | Write-Verbose "Enabling CredSSP auth support."
401 | Enable-WSManCredSSP -role server -Force
402 | Write-Log "Enabled CredSSP auth support."
403 | }
404 | }
405 |
406 | If ($GlobalHttpFirewallAccess) {
407 | Enable-GlobalHttpFirewallAccess
408 | }
409 |
410 | # Configure firewall to allow WinRM HTTPS connections.
411 | $fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
412 | $fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
413 | If ($fwtest1.count -lt 5)
414 | {
415 | Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
416 | netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
417 | Write-Log "Added firewall rule to allow WinRM HTTPS."
418 | }
419 | ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
420 | {
421 | Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
422 | netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
423 | Write-Log "Updated firewall rule to allow WinRM HTTPS for any profile."
424 | }
425 | Else
426 | {
427 | Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
428 | }
429 |
430 | # Test a remoting connection to localhost, which should work.
431 | $httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
432 | $httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
433 |
434 | $httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
435 |
436 | If ($httpResult -and $httpsResult)
437 | {
438 | Write-Verbose "HTTP: Enabled | HTTPS: Enabled"
439 | }
440 | ElseIf ($httpsResult -and !$httpResult)
441 | {
442 | Write-Verbose "HTTP: Disabled | HTTPS: Enabled"
443 | }
444 | ElseIf ($httpResult -and !$httpsResult)
445 | {
446 | Write-Verbose "HTTP: Enabled | HTTPS: Disabled"
447 | }
448 | Else
449 | {
450 | Write-Log "Unable to establish an HTTP or HTTPS remoting session."
451 | Throw "Unable to establish an HTTP or HTTPS remoting session."
452 | }
453 | Write-VerboseLog "PS Remoting has been successfully configured for Ansible."
--------------------------------------------------------------------------------
/scripts/install-vm-tools.cmd:
--------------------------------------------------------------------------------
1 | @rem Silent mode, basic UI, no reboot
2 | e:\setup64 /s /v "/qb REBOOT=R"
--------------------------------------------------------------------------------
/scripts/microsoft-updates.bat:
--------------------------------------------------------------------------------
1 | net stop wuauserv
2 |
3 | reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v EnableFeaturedSoftware /t REG_DWORD /d 1 /f
4 |
5 | reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v IncludeRecommendedUpdates /t REG_DWORD /d 1 /f
6 |
7 | echo Set ServiceManager = CreateObject("Microsoft.Update.ServiceManager") > A:\temp.vbs
8 | echo Set NewUpdateService = ServiceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") >> A:\temp.vbs
9 |
10 | cscript A:\temp.vbs
11 |
12 | net start wuauserv
13 |
--------------------------------------------------------------------------------
/scripts/set-temp.ps1:
--------------------------------------------------------------------------------
1 | # Set Temp Variable using PowerShell
2 |
3 | $TempFolder = "C:\TEMP"
4 | New-Item -ItemType Directory -Force -Path $TempFolder
5 | [Environment]::SetEnvironmentVariable("TEMP", $TempFolder, [EnvironmentVariableTarget]::Machine)
6 | [Environment]::SetEnvironmentVariable("TMP", $TempFolder, [EnvironmentVariableTarget]::Machine)
7 | [Environment]::SetEnvironmentVariable("TEMP", $TempFolder, [EnvironmentVariableTarget]::User)
8 | [Environment]::SetEnvironmentVariable("TMP", $TempFolder, [EnvironmentVariableTarget]::User)
--------------------------------------------------------------------------------
/scripts/win-updates.ps1:
--------------------------------------------------------------------------------
1 | param($global:RestartRequired=0,
2 | $global:MoreUpdates=0,
3 | $global:MaxCycles=5,
4 | $MaxUpdatesPerCycle=500,
5 | $BeginWithRestart=0)
6 |
7 | $Logfile = "C:\Windows\Temp\win-updates.log"
8 |
9 | function LogWrite {
10 | Param ([string]$logstring)
11 | $now = Get-Date -format s
12 | Add-Content $Logfile -value "$now $logstring"
13 | Write-Output $logstring
14 | }
15 |
16 | function Check-ContinueRestartOrEnd() {
17 | $RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
18 | $RegistryEntry = "InstallWindowsUpdates"
19 | switch ($global:RestartRequired) {
20 | 0 {
21 | $prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
22 | if ($prop) {
23 | LogWrite "Restart Registry Entry Exists - Removing It"
24 | Remove-ItemProperty -Path $RegistryKey -Name $RegistryEntry -ErrorAction SilentlyContinue
25 | }
26 |
27 | LogWrite "No Restart Required"
28 | Check-WindowsUpdates
29 |
30 | if (($global:MoreUpdates -eq 1) -and ($script:Cycles -le $global:MaxCycles)) {
31 | Install-WindowsUpdates
32 | } elseif ($script:Cycles -gt $global:MaxCycles) {
33 | LogWrite "Exceeded Cycle Count - Stopping"
34 | & "a:\enable-winrm.ps1"
35 | } else {
36 | LogWrite "Done Installing Windows Updates"
37 | & "a:\enable-winrm.ps1"
38 | }
39 | }
40 | 1 {
41 | $prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
42 | if (-not $prop) {
43 | LogWrite "Restart Registry Entry Does Not Exist - Creating It"
44 | Set-ItemProperty -Path $RegistryKey -Name $RegistryEntry -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File $($script:ScriptPath) -MaxUpdatesPerCycle $($MaxUpdatesPerCycle)"
45 | } else {
46 | LogWrite "Restart Registry Entry Exists Already"
47 | }
48 |
49 | LogWrite "Restart Required - Restarting..."
50 | Restart-Computer
51 | }
52 | default {
53 | LogWrite "Unsure If A Restart Is Required"
54 | break
55 | }
56 | }
57 | }
58 |
59 | function Install-WindowsUpdates() {
60 | $script:Cycles++
61 | LogWrite "Evaluating Available Updates with limit of $($MaxUpdatesPerCycle):"
62 | $UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
63 | $script:i = 0;
64 | $CurrentUpdates = $SearchResult.Updates
65 | while($script:i -lt $CurrentUpdates.Count -and $script:CycleUpdateCount -lt $MaxUpdatesPerCycle) {
66 | $Update = $CurrentUpdates.Item($script:i)
67 | if ($null -ne $Update) {
68 | [bool]$addThisUpdate = $false
69 | if ($Update.InstallationBehavior.CanRequestUserInput) {
70 | LogWrite "> Skipping: $($Update.Title) because it requires user input"
71 | } else {
72 | if (!($Update.EulaAccepted)) {
73 | LogWrite "> Note: $($Update.Title) has a license agreement that must be accepted. Accepting the license."
74 | $Update.AcceptEula()
75 | [bool]$addThisUpdate = $true
76 | $script:CycleUpdateCount++
77 | } else {
78 | [bool]$addThisUpdate = $true
79 | $script:CycleUpdateCount++
80 | }
81 | }
82 |
83 | if ([bool]$addThisUpdate) {
84 | LogWrite "Adding: $($Update.Title)"
85 | $UpdatesToDownload.Add($Update) |Out-Null
86 | }
87 | }
88 | $script:i++
89 | }
90 |
91 | if ($UpdatesToDownload.Count -eq 0) {
92 | LogWrite "No Updates To Download..."
93 | } else {
94 | LogWrite 'Downloading Updates...'
95 | $ok = 0;
96 | while (! $ok) {
97 | try {
98 | $Downloader = $UpdateSession.CreateUpdateDownloader()
99 | $Downloader.Updates = $UpdatesToDownload
100 | $Downloader.Download()
101 | $ok = 1;
102 | } catch {
103 | LogWrite $_.Exception | Format-List -force
104 | LogWrite "Error downloading updates. Retrying in 30s."
105 | $script:attempts = $script:attempts + 1
106 | Start-Sleep -s 30
107 | }
108 | }
109 | }
110 |
111 | $UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
112 | [bool]$rebootMayBeRequired = $false
113 | LogWrite 'The following updates are downloaded and ready to be installed:'
114 | foreach ($Update in $SearchResult.Updates) {
115 | if (($Update.IsDownloaded)) {
116 | LogWrite "> $($Update.Title)"
117 | $UpdatesToInstall.Add($Update) |Out-Null
118 |
119 | if ($Update.InstallationBehavior.RebootBehavior -gt 0){
120 | [bool]$rebootMayBeRequired = $true
121 | }
122 | }
123 | }
124 |
125 | if ($UpdatesToInstall.Count -eq 0) {
126 | LogWrite 'No updates available to install...'
127 | $global:MoreUpdates=0
128 | $global:RestartRequired=0
129 | & "a:\enable-winrm.ps1"
130 | break
131 | }
132 |
133 | if ($rebootMayBeRequired) {
134 | LogWrite 'These updates may require a reboot'
135 | $global:RestartRequired=1
136 | }
137 |
138 | LogWrite 'Installing updates...'
139 |
140 | $Installer = $script:UpdateSession.CreateUpdateInstaller()
141 | $Installer.Updates = $UpdatesToInstall
142 | $InstallationResult = $Installer.Install()
143 |
144 | LogWrite "Installation Result: $($InstallationResult.ResultCode)"
145 | LogWrite "Reboot Required: $($InstallationResult.RebootRequired)"
146 | LogWrite 'Listing of updates installed and individual installation results:'
147 | if ($InstallationResult.RebootRequired) {
148 | $global:RestartRequired=1
149 | } else {
150 | $global:RestartRequired=0
151 | }
152 |
153 | for($i=0; $i -lt $UpdatesToInstall.Count; $i++) {
154 | New-Object -TypeName PSObject -Property @{
155 | Title = $UpdatesToInstall.Item($i).Title
156 | Result = $InstallationResult.GetUpdateResult($i).ResultCode
157 | }
158 | LogWrite "Item: $($UpdatesToInstall.Item($i).Title)"
159 | LogWrite "Result: $($InstallationResult.GetUpdateResult($i).ResultCode)"
160 | }
161 |
162 | Check-ContinueRestartOrEnd
163 | }
164 |
165 | function Check-WindowsUpdates() {
166 | LogWrite "Checking For Windows Updates"
167 | $Username = $env:USERDOMAIN + "\" + $env:USERNAME
168 | LogWrite "Script: $script:ScriptPath `nScript User: $Username `nStarted: $(Get-Date)"
169 |
170 | $script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
171 | $script:successful = $FALSE
172 | $script:attempts = 0
173 | $script:maxAttempts = 12
174 | while(-not $script:successful -and $script:attempts -lt $script:maxAttempts) {
175 | try {
176 | $script:SearchResult = $script:UpdateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
177 | $script:successful = $TRUE
178 | } catch {
179 | LogWrite $_.Exception | Format-List -force
180 | LogWrite "Search call to UpdateSearcher was unsuccessful. Retrying in 10s."
181 | $script:attempts = $script:attempts + 1
182 | Start-Sleep -s 10
183 | }
184 | }
185 |
186 | if ($SearchResult.Updates.Count -ne 0) {
187 | $Message = "There are " + $SearchResult.Updates.Count + " more updates."
188 | LogWrite $Message
189 | try {
190 | for($i=0; $i -lt $script:SearchResult.Updates.Count; $i++) {
191 | LogWrite $script:SearchResult.Updates.Item($i).Title
192 | LogWrite $script:SearchResult.Updates.Item($i).Description
193 | LogWrite $script:SearchResult.Updates.Item($i).RebootRequired
194 | LogWrite $script:SearchResult.Updates.Item($i).EulaAccepted
195 | }
196 | $global:MoreUpdates=1
197 | } catch {
198 | LogWrite $_.Exception | Format-List -force
199 | LogWrite "Showing SearchResult was unsuccessful. Rebooting."
200 | $global:RestartRequired=1
201 | $global:MoreUpdates=0
202 | Check-ContinueRestartOrEnd
203 | LogWrite "Show never happen to see this text!"
204 | Restart-Computer
205 | }
206 | } else {
207 | LogWrite 'There are no applicable updates'
208 | $global:RestartRequired=0
209 | $global:MoreUpdates=0
210 | }
211 | }
212 |
213 | $script:ScriptName = $MyInvocation.MyCommand.ToString()
214 | $script:ScriptPath = $MyInvocation.MyCommand.Path
215 | $script:UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
216 | $script:UpdateSession.ClientApplicationID = 'Packer Windows Update Installer'
217 | $script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
218 | $script:SearchResult = New-Object -ComObject 'Microsoft.Update.UpdateColl'
219 | $script:Cycles = 0
220 | $script:CycleUpdateCount = 0
221 |
222 | if ($BeginWithRestart) {
223 | $global:RestartRequired = 1
224 | Check-ContinueRestartOrEnd
225 | }
226 |
227 | Check-WindowsUpdates
228 | if ($global:MoreUpdates -eq 1) {
229 | Install-WindowsUpdates
230 | } else {
231 | Check-ContinueRestartOrEnd
232 | }
233 |
--------------------------------------------------------------------------------
/variables.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 |
4 | "vsphere-server": "192.168.2.3",
5 | "vsphere-user": "administrator@vsphere.local",
6 | "vsphere-password": "YOUR_Password",
7 |
8 | "vsphere-datacenter": "YOUR_Dataceneter",
9 | "vsphere-cluster": "YOUR_Cluster",
10 | "vsphere-network": "YOUR_Network",
11 | "vsphere-datastore": "Your_Datastore",
12 | "vsphere-folder": "Your_vmfolder",
13 |
14 | "vm-name": "Win2019-Template-Base",
15 | "vm-cpu-num": "2",
16 | "vm-mem-size": "4096",
17 | "vm-disk-size": "40960",
18 | "winadmin-password": "Your WindowsPassword",
19 | "os_iso_path": "[VNX5300_Auto-Tier_LUN1] ISO/Windows Server 2019/SW_DVD9_Win_Server_STD_CORE_2019_64Bit_German_DC_STD_MLF_X21-96583.ISO",
20 | "winrm_username": "Administrator"
21 |
22 |
23 |
24 | }
--------------------------------------------------------------------------------
/w2016.base/Server2016_vsphere.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 |
4 | "sensitive-variables": ["vsphere_password", "winadmin_password"],
5 |
6 | "builders": [
7 | {
8 | "type": "vsphere-iso",
9 |
10 | "vcenter_server": "{{user `vsphere-server`}}",
11 | "username": "{{user `vsphere-user`}}",
12 | "password": "{{user `vsphere-password`}}",
13 | "insecure_connection": "true",
14 |
15 | "datacenter": "{{user `vsphere-datacenter`}}",
16 | "cluster": "{{user `vsphere-cluster`}}",
17 | "network": "{{user `vsphere-network`}}",
18 | "datastore": "{{user `vsphere-datastore`}}",
19 | "folder": "{{user `vsphere-folder`}}",
20 |
21 | "communicator": "winrm",
22 | "winrm_use_ssl":"true",
23 | "winrm_insecure": "true",
24 | "winrm_username": "{{user `winrm_username`}}",
25 | "winrm_password": "{{user `winadmin-password`}}",
26 |
27 | "convert_to_template": "true",
28 |
29 | "vm_name": "{{user `vm-name`}}",
30 | "guest_os_type": "windows9Server64Guest",
31 |
32 | "CPUs": "{{user `vm-cpu-num`}}",
33 | "RAM": "{{user `vm-mem-size`}}",
34 | "RAM_reserve_all": true,
35 | "firmware": "bios",
36 |
37 | "disk_controller_type": "lsilogic-sas",
38 | "disk_size": "{{user `vm-disk-size`}}",
39 | "disk_thin_provisioned": true,
40 |
41 | "network_card": "vmxnet3",
42 |
43 | "iso_paths": [
44 | "{{user `os_iso_path`}}",
45 | "[] /vmimages/tools-isoimages/windows.iso"
46 | ],
47 |
48 | "floppy_files": [
49 | "autounattend.xml",
50 | "../scripts/disable-network-discovery.cmd",
51 | "../scripts/enable-rdp.cmd",
52 | "../scripts/enable-winrm.ps1",
53 | "../scripts/install-vm-tools.cmd",
54 | "../scripts/set-temp.ps1",
55 | "../scripts/microsoft-updates.bat",
56 | "../scripts/win-updates.ps1",
57 | "../scripts/disable-screensaver.ps1"
58 | ]
59 | }
60 |
61 | ],
62 | "provisioners": [
63 | {
64 | "type": "windows-restart",
65 | "restart_timeout": "30m"
66 | },
67 |
68 | {
69 | "type": "windows-update",
70 | "search_criteria": "IsInstalled=0",
71 | "filters": [
72 | "exclude:$_.Title -like '*Preview*'",
73 | "exclude:$_.Title -like '*Cumulative*'",
74 | "exclude:$_.Title -like '*Kumulatives*'",
75 | "exclude:$_.Title -like '*VMware*'",
76 | "exclude:$_.Title -like '*Defender*'",
77 | "include:$true"
78 | ],
79 | "pause_before": "30s"
80 | },
81 | {
82 | "type": "windows-restart"
83 | }
84 |
85 |
86 | ]
87 |
88 |
89 | }
--------------------------------------------------------------------------------
/w2016.base/autounattend.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | de-DE
7 |
8 | de-DE
9 | de-DE
10 | de-DE
11 | de-DE
12 |
13 |
14 |
15 |
16 |
17 |
18 | 1
19 | 500
20 | Primary
21 |
22 |
23 | 2
24 | true
25 | Primary
26 |
27 |
28 |
29 |
30 | 1
31 | 1
32 | NTFS
33 |
34 | true
35 |
36 |
37 | 2
38 | 2
39 | NTFS
40 |
41 |
42 |
43 | 0
44 | true
45 |
46 |
47 |
48 |
49 |
50 |
51 | /IMAGE/NAME
52 | Windows Server 2016 SERVERSTANDARD
53 |
54 |
55 |
56 | 0
57 | 2
58 |
59 | OnError
60 | false
61 |
62 |
63 |
64 | true
65 |
66 |
67 |
68 |
69 |
70 | W. Europe Standard Time
71 |
72 |
73 |
74 |
75 | 1
76 | Disable Network Discovery
77 | cmd.exe /c a:\disable-network-discovery.cmd
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | Lab2020
87 | true
88 |
89 | 2
90 | Administrator
91 | true
92 |
93 |
94 |
95 | 1
96 | Set Execution Policy 64 Bit
97 | cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
98 | true
99 |
100 |
101 | 2
102 | Set Execution Policy 32 Bit
103 | C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
104 | true
105 |
106 |
107 | 3
108 | Disable WinRM
109 | C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\disable-winrm.ps1
110 | true
111 |
112 |
113 | %SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v HideFileExt /t REG_DWORD /d 0 /f
114 | 4
115 | Show file extensions in Explorer
116 |
117 |
118 | %SystemRoot%\System32\reg.exe ADD HKCU\Console /v QuickEdit /t REG_DWORD /d 1 /f
119 | 5
120 | Enable QuickEdit mode
121 |
122 |
123 | %SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v Start_ShowRun /t REG_DWORD /d 1 /f
124 | 6
125 | Show Run command in Start Menu
126 |
127 |
128 | %SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v StartMenuAdminTools /t REG_DWORD /d 1 /f
129 | 7
130 | Show Administrative Tools in Start Menu
131 |
132 |
133 | %SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateFileSizePercent /t REG_DWORD /d 0 /f
134 | 8
135 | Zero Hibernation File
136 |
137 |
138 | %SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateEnabled /t REG_DWORD /d 0 /f
139 | 9
140 | Disable Hibernation Mode
141 |
142 |
143 | cmd.exe /c wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE
144 | 10
145 | Disable password expiration for Administrator user
146 |
147 |
148 | cmd.exe /c a:\install-vm-tools.cmd
149 | 14
150 | Install VMware Tools
151 |
152 |
153 | cmd.exe /c a:\enable-rdp.cmd
154 | 12
155 | Enable RDP
156 |
157 |
158 | cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\set-temp.ps1
159 | 13
160 | Set Temp Folders
161 |
162 |
163 |
164 |
165 | cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\enable-winrm.ps1
166 | Enable WinRM
167 | 16
168 |
169 |
170 |
171 |
172 | true
173 | true
174 | true
175 | true
176 | true
177 | Home
178 | 1
179 |
180 |
181 |
182 |
183 | Lab2020
184 | true
185 |
186 |
187 |
188 |
189 |
190 |
--------------------------------------------------------------------------------
/w2019.base/Server2019_vsphere.json:
--------------------------------------------------------------------------------
1 | {
2 |
3 |
4 | "sensitive-variables": ["vsphere_password", "winadmin_password"],
5 |
6 | "builders": [
7 | {
8 | "type": "vsphere-iso",
9 |
10 | "vcenter_server": "{{user `vsphere-server`}}",
11 | "username": "{{user `vsphere-user`}}",
12 | "password": "{{user `vsphere-password`}}",
13 | "insecure_connection": "true",
14 |
15 | "datacenter": "{{user `vsphere-datacenter`}}",
16 | "cluster": "{{user `vsphere-cluster`}}",
17 | "network": "{{user `vsphere-network`}}",
18 | "datastore": "{{user `vsphere-datastore`}}",
19 | "folder": "{{user `vsphere-folder`}}",
20 |
21 | "communicator": "winrm",
22 | "winrm_use_ssl":"true",
23 | "winrm_insecure": "true",
24 | "winrm_username": "{{user `winrm_username`}}",
25 | "winrm_password": "{{user `winadmin-password`}}",
26 |
27 | "convert_to_template": "true",
28 |
29 | "vm_name": "{{user `vm-name`}}",
30 | "guest_os_type": "windows9Server64Guest",
31 |
32 | "CPUs": "{{user `vm-cpu-num`}}",
33 | "RAM": "{{user `vm-mem-size`}}",
34 | "RAM_reserve_all": true,
35 | "firmware": "bios",
36 |
37 | "disk_controller_type": "lsilogic-sas",
38 | "disk_size": "{{user `vm-disk-size`}}",
39 | "disk_thin_provisioned": true,
40 |
41 | "network_card": "vmxnet3",
42 |
43 | "iso_paths": [
44 | "{{user `os_iso_path`}}",
45 | "[] /vmimages/tools-isoimages/windows.iso"
46 | ],
47 |
48 | "floppy_files": [
49 | "{{template_dir}}/autounattend.xml",
50 | "{{template_dir}}/scripts/disable-network-discovery.cmd",
51 | "{{template_dir}}/scripts/enable-rdp.cmd",
52 | "{{template_dir}}/scripts/enable-winrm.ps1",
53 | "{{template_dir}}/scripts/install-vm-tools.cmd",
54 | "{{template_dir}}/scripts/set-temp.ps1",
55 | "{{template_dir}}/scripts/microsoft-updates.bat",
56 | "{{template_dir}}/scripts/win-updates.ps1",
57 | "{{template_dir}}/scripts/disable-screensaver.ps1"
58 | ]
59 | }
60 | ],
61 | "provisioners": [
62 | {
63 | "type": "windows-restart",
64 | "restart_timeout": "30m"
65 | },
66 |
67 | {
68 | "type": "windows-update",
69 | "search_criteria": "IsInstalled=0",
70 | "filters": [
71 | "exclude:$_.Title -like '*Preview*'",
72 | "exclude:$_.Title -like '*Cumulative*'",
73 | "exclude:$_.Title -like '*Kumulatives*'",
74 | "exclude:$_.Title -like '*VMware*'",
75 | "exclude:$_.Title -like '*Defender*'",
76 | "include:$true"
77 | ],
78 | "pause_before": "30s"
79 | },
80 | {
81 | "type": "windows-restart"
82 | }
83 |
84 |
85 | ]
86 |
87 |
88 |
89 | }
90 |
--------------------------------------------------------------------------------
/w2019.base/autounattend.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | de-DE
7 |
8 | de-DE
9 | de-DE
10 | de-DE
11 | de-DE
12 |
13 |
14 |
15 |
16 |
17 |
18 | 1
19 | 500
20 | Primary
21 |
22 |
23 | 2
24 | true
25 | Primary
26 |
27 |
28 |
29 |
30 | 1
31 | 1
32 | NTFS
33 |
34 | true
35 |
36 |
37 | 2
38 | 2
39 | NTFS
40 |
41 |
42 |
43 | 0
44 | true
45 |
46 |
47 |
48 |
49 |
50 |
51 | /IMAGE/NAME
52 | Windows Server 2019 SERVERSTANDARD
53 |
54 |
55 |
56 | 0
57 | 2
58 |
59 | OnError
60 | false
61 |
62 |
63 |
64 | true
65 |
66 |
67 |
68 |
69 |
70 | Romance Standard Time
71 |
72 |
73 |
74 |
75 | 1
76 | Disable Network Discovery
77 | cmd.exe /c a:\disable-network-discovery.cmd
78 |
79 |
80 |
81 |
82 |
83 |
84 |
85 |
86 | Lab2020
87 | true
88 |
89 | 2
90 | Administrator
91 | true
92 |
93 |
94 |
95 | 1
96 | Set Execution Policy 64 Bit
97 | cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
98 | true
99 |
100 |
101 | 2
102 | Set Execution Policy 32 Bit
103 | C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
104 | true
105 |
106 |
107 | 3
108 | Disable WinRM
109 | C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\disable-winrm.ps1
110 | true
111 |
112 |
113 | %SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v HideFileExt /t REG_DWORD /d 0 /f
114 | 4
115 | Show file extensions in Explorer
116 |
117 |
118 | %SystemRoot%\System32\reg.exe ADD HKCU\Console /v QuickEdit /t REG_DWORD /d 1 /f
119 | 5
120 | Enable QuickEdit mode
121 |
122 |
123 | %SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v Start_ShowRun /t REG_DWORD /d 1 /f
124 | 6
125 | Show Run command in Start Menu
126 |
127 |
128 | %SystemRoot%\System32\reg.exe ADD HKCU\SOFTWARE\Microsoft\Windows\CurrentVersion\Explorer\Advanced\ /v StartMenuAdminTools /t REG_DWORD /d 1 /f
129 | 7
130 | Show Administrative Tools in Start Menu
131 |
132 |
133 | %SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateFileSizePercent /t REG_DWORD /d 0 /f
134 | 8
135 | Zero Hibernation File
136 |
137 |
138 | %SystemRoot%\System32\reg.exe ADD HKLM\SYSTEM\CurrentControlSet\Control\Power\ /v HibernateEnabled /t REG_DWORD /d 0 /f
139 | 9
140 | Disable Hibernation Mode
141 |
142 |
143 | cmd.exe /c wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE
144 | 10
145 | Disable password expiration for Administrator user
146 |
147 |
148 | cmd.exe /c a:\install-vm-tools.cmd
149 | 12
150 | Install VMware Tools
151 |
152 |
153 | cmd.exe /c a:\enable-rdp.cmd
154 | 13
155 | Enable RDP
156 |
157 |
158 | cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\set-temp.ps1
159 | 14
160 | Set Temp Folders
161 |
162 |
163 |
164 |
165 | cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File a:\enable-winrm.ps1
166 | Enable WinRM
167 | 11
168 |
169 |
170 |
171 |
172 |
173 | true
174 | true
175 | true
176 | true
177 | true
178 | Home
179 | 1
180 |
181 |
182 |
183 |
184 | Lab2020
185 | true
186 |
187 |
188 |
189 |
190 |
191 |
--------------------------------------------------------------------------------
/w2019.base/scripts/disable-network-discovery.cmd:
--------------------------------------------------------------------------------
1 | reg ADD HKLM\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff /f
2 | netsh advfirewall firewall set rule group="Network Discovery" new enable=No
--------------------------------------------------------------------------------
/w2019.base/scripts/disable-screensaver.ps1:
--------------------------------------------------------------------------------
1 | Write-Host "Disabling Screensaver"
2 | Set-ItemProperty "HKCU:\Control Panel\Desktop" -Name ScreenSaveActive -Value 0 -Type DWord
3 | & powercfg -x -monitor-timeout-ac 0
4 | & powercfg -x -monitor-timeout-dc 0
5 |
--------------------------------------------------------------------------------
/w2019.base/scripts/enable-rdp.cmd:
--------------------------------------------------------------------------------
1 | netsh advfirewall firewall add rule name="Open Port 3389" dir=in action=allow protocol=TCP localport=3389
2 | reg add "HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Control\Terminal Server" /v fDenyTSConnections /t REG_DWORD /d 0 /f
--------------------------------------------------------------------------------
/w2019.base/scripts/enable-winrm.bat:
--------------------------------------------------------------------------------
1 | rem Enable-NetFirewallRule for WinRM
2 | netsh advfirewall firewall add rule name="Port 5985" dir=in action=allow protocol=TCP localport=5985
3 | sc.exe config winrm start= auto
4 |
--------------------------------------------------------------------------------
/w2019.base/scripts/enable-winrm.ps1:
--------------------------------------------------------------------------------
1 | #Requires -Version 3.0
2 |
3 | # Configure a Windows host for remote management with Ansible
4 | # -----------------------------------------------------------
5 | #
6 | # This script checks the current WinRM (PS Remoting) configuration and makes
7 | # the necessary changes to allow Ansible to connect, authenticate and
8 | # execute PowerShell commands.
9 | #
10 | # All events are logged to the Windows EventLog, useful for unattended runs.
11 | #
12 | # Use option -Verbose in order to see the verbose output messages.
13 | #
14 | # Use option -CertValidityDays to specify how long this certificate is valid
15 | # starting from today. So you would specify -CertValidityDays 3650 to get
16 | # a 10-year valid certificate.
17 | #
18 | # Use option -ForceNewSSLCert if the system has been SysPreped and a new
19 | # SSL Certificate must be forced on the WinRM Listener when re-running this
20 | # script. This is necessary when a new SID and CN name is created.
21 | #
22 | # Use option -EnableCredSSP to enable CredSSP as an authentication option.
23 | #
24 | # Use option -DisableBasicAuth to disable basic authentication.
25 | #
26 | # Use option -SkipNetworkProfileCheck to skip the network profile check.
27 | # Without specifying this the script will only run if the device's interfaces
28 | # are in DOMAIN or PRIVATE zones. Provide this switch if you want to enable
29 | # WinRM on a device with an interface in PUBLIC zone.
30 | #
31 | # Use option -SubjectName to specify the CN name of the certificate. This
32 | # defaults to the system's hostname and generally should not be specified.
33 |
34 | # Written by Trond Hindenes
35 | # Updated by Chris Church
36 | # Updated by Michael Crilly
37 | # Updated by Anton Ouzounov
38 | # Updated by Nicolas Simond
39 | # Updated by Dag Wieërs
40 | # Updated by Jordan Borean
41 | # Updated by Erwan Quélin
42 | # Updated by David Norman
43 | #
44 | # Version 1.0 - 2014-07-06
45 | # Version 1.1 - 2014-11-11
46 | # Version 1.2 - 2015-05-15
47 | # Version 1.3 - 2016-04-04
48 | # Version 1.4 - 2017-01-05
49 | # Version 1.5 - 2017-02-09
50 | # Version 1.6 - 2017-04-18
51 | # Version 1.7 - 2017-11-23
52 | # Version 1.8 - 2018-02-23
53 | # Version 1.9 - 2018-09-21
54 |
55 | # Support -Verbose option
56 | [CmdletBinding()]
57 |
58 | Param (
59 | [string]$SubjectName = $env:COMPUTERNAME,
60 | [int]$CertValidityDays = 1095,
61 | [switch]$SkipNetworkProfileCheck,
62 | $CreateSelfSignedCert = $true,
63 | [switch]$ForceNewSSLCert,
64 | [switch]$GlobalHttpFirewallAccess,
65 | [switch]$DisableBasicAuth = $false,
66 | [switch]$EnableCredSSP
67 | )
68 |
69 | Function Write-Log
70 | {
71 | $Message = $args[0]
72 | Write-EventLog -LogName Application -Source $EventSource -EntryType Information -EventId 1 -Message $Message
73 | }
74 |
75 | Function Write-VerboseLog
76 | {
77 | $Message = $args[0]
78 | Write-Verbose $Message
79 | Write-Log $Message
80 | }
81 |
82 | Function Write-HostLog
83 | {
84 | $Message = $args[0]
85 | Write-Output $Message
86 | Write-Log $Message
87 | }
88 |
89 | Function New-LegacySelfSignedCert
90 | {
91 | Param (
92 | [string]$SubjectName,
93 | [int]$ValidDays = 1095
94 | )
95 |
96 | $hostnonFQDN = $env:computerName
97 | $hostFQDN = [System.Net.Dns]::GetHostByName(($env:computerName)).Hostname
98 | $SignatureAlgorithm = "SHA256"
99 |
100 | $name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1"
101 | $name.Encode("CN=$SubjectName", 0)
102 |
103 | $key = New-Object -COM "X509Enrollment.CX509PrivateKey.1"
104 | $key.ProviderName = "Microsoft Enhanced RSA and AES Cryptographic Provider"
105 | $key.KeySpec = 1
106 | $key.Length = 4096
107 | $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)"
108 | $key.MachineContext = 1
109 | $key.Create()
110 |
111 | $serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1"
112 | $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1")
113 | $ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1"
114 | $ekuoids.Add($serverauthoid)
115 | $ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1"
116 | $ekuext.InitializeEncode($ekuoids)
117 |
118 | $cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1"
119 | $cert.InitializeFromPrivateKey(2, $key, "")
120 | $cert.Subject = $name
121 | $cert.Issuer = $cert.Subject
122 | $cert.NotBefore = (Get-Date).AddDays(-1)
123 | $cert.NotAfter = $cert.NotBefore.AddDays($ValidDays)
124 |
125 | $SigOID = New-Object -ComObject X509Enrollment.CObjectId
126 | $SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value)
127 |
128 | [string[]] $AlternativeName += $hostnonFQDN
129 | $AlternativeName += $hostFQDN
130 | $IAlternativeNames = New-Object -ComObject X509Enrollment.CAlternativeNames
131 |
132 | foreach ($AN in $AlternativeName)
133 | {
134 | $AltName = New-Object -ComObject X509Enrollment.CAlternativeName
135 | $AltName.InitializeFromString(0x3,$AN)
136 | $IAlternativeNames.Add($AltName)
137 | }
138 |
139 | $SubjectAlternativeName = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames
140 | $SubjectAlternativeName.InitializeEncode($IAlternativeNames)
141 |
142 | [String[]]$KeyUsage = ("DigitalSignature", "KeyEncipherment")
143 | $KeyUsageObj = New-Object -ComObject X509Enrollment.CX509ExtensionKeyUsage
144 | $KeyUsageObj.InitializeEncode([int][Security.Cryptography.X509Certificates.X509KeyUsageFlags]($KeyUsage))
145 | $KeyUsageObj.Critical = $true
146 |
147 | $cert.X509Extensions.Add($KeyUsageObj)
148 | $cert.X509Extensions.Add($ekuext)
149 | $cert.SignatureInformation.HashAlgorithm = $SigOID
150 | $CERT.X509Extensions.Add($SubjectAlternativeName)
151 | $cert.Encode()
152 |
153 | $enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1"
154 | $enrollment.InitializeFromRequest($cert)
155 | $certdata = $enrollment.CreateRequest(0)
156 | $enrollment.InstallResponse(2, $certdata, 0, "")
157 |
158 | # extract/return the thumbprint from the generated cert
159 | $parsed_cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2
160 | $parsed_cert.Import([System.Text.Encoding]::UTF8.GetBytes($certdata))
161 |
162 | return $parsed_cert.Thumbprint
163 | }
164 |
165 | Function Enable-GlobalHttpFirewallAccess
166 | {
167 | Write-Verbose "Forcing global HTTP firewall access"
168 | # this is a fairly naive implementation; could be more sophisticated about rule matching/collapsing
169 | $fw = New-Object -ComObject HNetCfg.FWPolicy2
170 |
171 | # try to find/enable the default rule first
172 | $add_rule = $false
173 | $matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" }
174 | $rule = $null
175 | If ($matching_rules) {
176 | If ($matching_rules -isnot [Array]) {
177 | Write-Verbose "Editing existing single HTTP firewall rule"
178 | $rule = $matching_rules
179 | }
180 | Else {
181 | # try to find one with the All or Public profile first
182 | Write-Verbose "Found multiple existing HTTP firewall rules..."
183 | $rule = $matching_rules | ForEach-Object { $_.Profiles -band 4 }[0]
184 |
185 | If (-not $rule -or $rule -is [Array]) {
186 | Write-Verbose "Editing an arbitrary single HTTP firewall rule (multiple existed)"
187 | # oh well, just pick the first one
188 | $rule = $matching_rules[0]
189 | }
190 | }
191 | }
192 |
193 | If (-not $rule) {
194 | Write-Verbose "Creating a new HTTP firewall rule"
195 | $rule = New-Object -ComObject HNetCfg.FWRule
196 | $rule.Name = "Windows Remote Management (HTTP-In)"
197 | $rule.Description = "Inbound rule for Windows Remote Management via WS-Management. [TCP 5985]"
198 | $add_rule = $true
199 | }
200 |
201 | $rule.Profiles = 0x7FFFFFFF
202 | $rule.Protocol = 6
203 | $rule.LocalPorts = 5985
204 | $rule.RemotePorts = "*"
205 | $rule.LocalAddresses = "*"
206 | $rule.RemoteAddresses = "*"
207 | $rule.Enabled = $true
208 | $rule.Direction = 1
209 | $rule.Action = 1
210 | $rule.Grouping = "Windows Remote Management"
211 |
212 | If ($add_rule) {
213 | $fw.Rules.Add($rule)
214 | }
215 |
216 | Write-Verbose "HTTP firewall rule $($rule.Name) updated"
217 | }
218 |
219 | # Setup error handling.
220 | Trap
221 | {
222 | $_
223 | Exit 1
224 | }
225 | $ErrorActionPreference = "Stop"
226 |
227 | # Get the ID and security principal of the current user account
228 | $myWindowsID=[System.Security.Principal.WindowsIdentity]::GetCurrent()
229 | $myWindowsPrincipal=new-object System.Security.Principal.WindowsPrincipal($myWindowsID)
230 |
231 | # Get the security principal for the Administrator role
232 | $adminRole=[System.Security.Principal.WindowsBuiltInRole]::Administrator
233 |
234 | # Check to see if we are currently running "as Administrator"
235 | if (-Not $myWindowsPrincipal.IsInRole($adminRole))
236 | {
237 | Write-Output "ERROR: You need elevated Administrator privileges in order to run this script."
238 | Write-Output " Start Windows PowerShell by using the Run as Administrator option."
239 | Exit 2
240 | }
241 |
242 | $EventSource = $MyInvocation.MyCommand.Name
243 | If (-Not $EventSource)
244 | {
245 | $EventSource = "Powershell CLI"
246 | }
247 |
248 | If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False)
249 | {
250 | New-EventLog -LogName Application -Source $EventSource
251 | }
252 |
253 | # Detect PowerShell version.
254 | If ($PSVersionTable.PSVersion.Major -lt 3)
255 | {
256 | Write-Log "PowerShell version 3 or higher is required."
257 | Throw "PowerShell version 3 or higher is required."
258 | }
259 |
260 | # Find and start the WinRM service.
261 | Write-Verbose "Verifying WinRM service."
262 | If (!(Get-Service "WinRM"))
263 | {
264 | Write-Log "Unable to find the WinRM service."
265 | Throw "Unable to find the WinRM service."
266 | }
267 | ElseIf ((Get-Service "WinRM").Status -ne "Running")
268 | {
269 | Write-Verbose "Setting WinRM service to start automatically on boot."
270 | Set-Service -Name "WinRM" -StartupType Automatic
271 | Write-Log "Set WinRM service to start automatically on boot."
272 | Write-Verbose "Starting WinRM service."
273 | Start-Service -Name "WinRM" -ErrorAction Stop
274 | Write-Log "Started WinRM service."
275 |
276 | }
277 |
278 | # WinRM should be running; check that we have a PS session config.
279 | If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener)))
280 | {
281 | If ($SkipNetworkProfileCheck) {
282 | Write-Verbose "Enabling PS Remoting without checking Network profile."
283 | Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop
284 | Write-Log "Enabled PS Remoting without checking Network profile."
285 | }
286 | Else {
287 | Write-Verbose "Enabling PS Remoting."
288 | Enable-PSRemoting -Force -ErrorAction Stop
289 | Write-Log "Enabled PS Remoting."
290 | }
291 | }
292 | Else
293 | {
294 | Write-Verbose "PS Remoting is already enabled."
295 | }
296 |
297 | # Ensure LocalAccountTokenFilterPolicy is set to 1
298 | # https://github.com/ansible/ansible/issues/42978
299 | $token_path = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System"
300 | $token_prop_name = "LocalAccountTokenFilterPolicy"
301 | $token_key = Get-Item -Path $token_path
302 | $token_value = $token_key.GetValue($token_prop_name, $null)
303 | if ($token_value -ne 1) {
304 | Write-Verbose "Setting LocalAccountTOkenFilterPolicy to 1"
305 | if ($null -ne $token_value) {
306 | Remove-ItemProperty -Path $token_path -Name $token_prop_name
307 | }
308 | New-ItemProperty -Path $token_path -Name $token_prop_name -Value 1 -PropertyType DWORD > $null
309 | }
310 |
311 | # Make sure there is a SSL listener.
312 | $listeners = Get-ChildItem WSMan:\localhost\Listener
313 | If (!($listeners | Where-Object {$_.Keys -like "TRANSPORT=HTTPS"}))
314 | {
315 | # We cannot use New-SelfSignedCertificate on 2012R2 and earlier
316 | $thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
317 | Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint"
318 |
319 | # Create the hashtables of settings to be used.
320 | $valueset = @{
321 | Hostname = $SubjectName
322 | CertificateThumbprint = $thumbprint
323 | }
324 |
325 | $selectorset = @{
326 | Transport = "HTTPS"
327 | Address = "*"
328 | }
329 |
330 | Write-Verbose "Enabling SSL listener."
331 | New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
332 | Write-Log "Enabled SSL listener."
333 | }
334 | Else
335 | {
336 | Write-Verbose "SSL listener is already active."
337 |
338 | # Force a new SSL cert on Listener if the $ForceNewSSLCert
339 | If ($ForceNewSSLCert)
340 | {
341 |
342 | # We cannot use New-SelfSignedCertificate on 2012R2 and earlier
343 | $thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays
344 | Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint"
345 |
346 | $valueset = @{
347 | CertificateThumbprint = $thumbprint
348 | Hostname = $SubjectName
349 | }
350 |
351 | # Delete the listener for SSL
352 | $selectorset = @{
353 | Address = "*"
354 | Transport = "HTTPS"
355 | }
356 | Remove-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset
357 |
358 | # Add new Listener with new SSL cert
359 | New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset
360 | }
361 | }
362 |
363 | # Check for basic authentication.
364 | $basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "Basic"}
365 |
366 | If ($DisableBasicAuth)
367 | {
368 | If (($basicAuthSetting.Value) -eq $true)
369 | {
370 | Write-Verbose "Disabling basic auth support."
371 | Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $false
372 | Write-Log "Disabled basic auth support."
373 | }
374 | Else
375 | {
376 | Write-Verbose "Basic auth is already disabled."
377 | }
378 | }
379 | Else
380 | {
381 | If (($basicAuthSetting.Value) -eq $false)
382 | {
383 | Write-Verbose "Enabling basic auth support."
384 | Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true
385 | Write-Log "Enabled basic auth support."
386 | }
387 | Else
388 | {
389 | Write-Verbose "Basic auth is already enabled."
390 | }
391 | }
392 |
393 | # If EnableCredSSP if set to true
394 | If ($EnableCredSSP)
395 | {
396 | # Check for CredSSP authentication
397 | $credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object {$_.Name -eq "CredSSP"}
398 | If (($credsspAuthSetting.Value) -eq $false)
399 | {
400 | Write-Verbose "Enabling CredSSP auth support."
401 | Enable-WSManCredSSP -role server -Force
402 | Write-Log "Enabled CredSSP auth support."
403 | }
404 | }
405 |
406 | If ($GlobalHttpFirewallAccess) {
407 | Enable-GlobalHttpFirewallAccess
408 | }
409 |
410 | # Configure firewall to allow WinRM HTTPS connections.
411 | $fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS"
412 | $fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any
413 | If ($fwtest1.count -lt 5)
414 | {
415 | Write-Verbose "Adding firewall rule to allow WinRM HTTPS."
416 | netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow
417 | Write-Log "Added firewall rule to allow WinRM HTTPS."
418 | }
419 | ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5))
420 | {
421 | Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile."
422 | netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any
423 | Write-Log "Updated firewall rule to allow WinRM HTTPS for any profile."
424 | }
425 | Else
426 | {
427 | Write-Verbose "Firewall rule already exists to allow WinRM HTTPS."
428 | }
429 |
430 | # Test a remoting connection to localhost, which should work.
431 | $httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock {$env:COMPUTERNAME} -ErrorVariable httpError -ErrorAction SilentlyContinue
432 | $httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck
433 |
434 | $httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue
435 |
436 | If ($httpResult -and $httpsResult)
437 | {
438 | Write-Verbose "HTTP: Enabled | HTTPS: Enabled"
439 | }
440 | ElseIf ($httpsResult -and !$httpResult)
441 | {
442 | Write-Verbose "HTTP: Disabled | HTTPS: Enabled"
443 | }
444 | ElseIf ($httpResult -and !$httpsResult)
445 | {
446 | Write-Verbose "HTTP: Enabled | HTTPS: Disabled"
447 | }
448 | Else
449 | {
450 | Write-Log "Unable to establish an HTTP or HTTPS remoting session."
451 | Throw "Unable to establish an HTTP or HTTPS remoting session."
452 | }
453 | Write-VerboseLog "PS Remoting has been successfully configured for Ansible."
--------------------------------------------------------------------------------
/w2019.base/scripts/install-vm-tools.cmd:
--------------------------------------------------------------------------------
1 | @rem Silent mode, basic UI, no reboot
2 | e:\setup64 /s /v "/qb REBOOT=R"
--------------------------------------------------------------------------------
/w2019.base/scripts/microsoft-updates.bat:
--------------------------------------------------------------------------------
1 | net stop wuauserv
2 |
3 | reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v EnableFeaturedSoftware /t REG_DWORD /d 1 /f
4 |
5 | reg add "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update" /v IncludeRecommendedUpdates /t REG_DWORD /d 1 /f
6 |
7 | echo Set ServiceManager = CreateObject("Microsoft.Update.ServiceManager") > A:\temp.vbs
8 | echo Set NewUpdateService = ServiceManager.AddService2("7971f918-a847-4430-9279-4a52d1efe18d",7,"") >> A:\temp.vbs
9 |
10 | cscript A:\temp.vbs
11 |
12 | net start wuauserv
13 |
--------------------------------------------------------------------------------
/w2019.base/scripts/set-temp.ps1:
--------------------------------------------------------------------------------
1 | # Set Temp Variable using PowerShell
2 |
3 | $TempFolder = "C:\TEMP"
4 | New-Item -ItemType Directory -Force -Path $TempFolder
5 | [Environment]::SetEnvironmentVariable("TEMP", $TempFolder, [EnvironmentVariableTarget]::Machine)
6 | [Environment]::SetEnvironmentVariable("TMP", $TempFolder, [EnvironmentVariableTarget]::Machine)
7 | [Environment]::SetEnvironmentVariable("TEMP", $TempFolder, [EnvironmentVariableTarget]::User)
8 | [Environment]::SetEnvironmentVariable("TMP", $TempFolder, [EnvironmentVariableTarget]::User)
--------------------------------------------------------------------------------
/w2019.base/scripts/win-updates.ps1:
--------------------------------------------------------------------------------
1 | param($global:RestartRequired=0,
2 | $global:MoreUpdates=0,
3 | $global:MaxCycles=5,
4 | $MaxUpdatesPerCycle=500,
5 | $BeginWithRestart=0)
6 |
7 | $Logfile = "C:\Windows\Temp\win-updates.log"
8 |
9 | function LogWrite {
10 | Param ([string]$logstring)
11 | $now = Get-Date -format s
12 | Add-Content $Logfile -value "$now $logstring"
13 | Write-Output $logstring
14 | }
15 |
16 | function Check-ContinueRestartOrEnd() {
17 | $RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Run"
18 | $RegistryEntry = "InstallWindowsUpdates"
19 | switch ($global:RestartRequired) {
20 | 0 {
21 | $prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
22 | if ($prop) {
23 | LogWrite "Restart Registry Entry Exists - Removing It"
24 | Remove-ItemProperty -Path $RegistryKey -Name $RegistryEntry -ErrorAction SilentlyContinue
25 | }
26 |
27 | LogWrite "No Restart Required"
28 | Check-WindowsUpdates
29 |
30 | if (($global:MoreUpdates -eq 1) -and ($script:Cycles -le $global:MaxCycles)) {
31 | Install-WindowsUpdates
32 | } elseif ($script:Cycles -gt $global:MaxCycles) {
33 | LogWrite "Exceeded Cycle Count - Stopping"
34 | & "a:\enable-winrm.ps1"
35 | } else {
36 | LogWrite "Done Installing Windows Updates"
37 | & "a:\enable-winrm.ps1"
38 | }
39 | }
40 | 1 {
41 | $prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
42 | if (-not $prop) {
43 | LogWrite "Restart Registry Entry Does Not Exist - Creating It"
44 | Set-ItemProperty -Path $RegistryKey -Name $RegistryEntry -Value "C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File $($script:ScriptPath) -MaxUpdatesPerCycle $($MaxUpdatesPerCycle)"
45 | } else {
46 | LogWrite "Restart Registry Entry Exists Already"
47 | }
48 |
49 | LogWrite "Restart Required - Restarting..."
50 | Restart-Computer
51 | }
52 | default {
53 | LogWrite "Unsure If A Restart Is Required"
54 | break
55 | }
56 | }
57 | }
58 |
59 | function Install-WindowsUpdates() {
60 | $script:Cycles++
61 | LogWrite "Evaluating Available Updates with limit of $($MaxUpdatesPerCycle):"
62 | $UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
63 | $script:i = 0;
64 | $CurrentUpdates = $SearchResult.Updates
65 | while($script:i -lt $CurrentUpdates.Count -and $script:CycleUpdateCount -lt $MaxUpdatesPerCycle) {
66 | $Update = $CurrentUpdates.Item($script:i)
67 | if ($null -ne $Update) {
68 | [bool]$addThisUpdate = $false
69 | if ($Update.InstallationBehavior.CanRequestUserInput) {
70 | LogWrite "> Skipping: $($Update.Title) because it requires user input"
71 | } else {
72 | if (!($Update.EulaAccepted)) {
73 | LogWrite "> Note: $($Update.Title) has a license agreement that must be accepted. Accepting the license."
74 | $Update.AcceptEula()
75 | [bool]$addThisUpdate = $true
76 | $script:CycleUpdateCount++
77 | } else {
78 | [bool]$addThisUpdate = $true
79 | $script:CycleUpdateCount++
80 | }
81 | }
82 |
83 | if ([bool]$addThisUpdate) {
84 | LogWrite "Adding: $($Update.Title)"
85 | $UpdatesToDownload.Add($Update) |Out-Null
86 | }
87 | }
88 | $script:i++
89 | }
90 |
91 | if ($UpdatesToDownload.Count -eq 0) {
92 | LogWrite "No Updates To Download..."
93 | } else {
94 | LogWrite 'Downloading Updates...'
95 | $ok = 0;
96 | while (! $ok) {
97 | try {
98 | $Downloader = $UpdateSession.CreateUpdateDownloader()
99 | $Downloader.Updates = $UpdatesToDownload
100 | $Downloader.Download()
101 | $ok = 1;
102 | } catch {
103 | LogWrite $_.Exception | Format-List -force
104 | LogWrite "Error downloading updates. Retrying in 30s."
105 | $script:attempts = $script:attempts + 1
106 | Start-Sleep -s 30
107 | }
108 | }
109 | }
110 |
111 | $UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
112 | [bool]$rebootMayBeRequired = $false
113 | LogWrite 'The following updates are downloaded and ready to be installed:'
114 | foreach ($Update in $SearchResult.Updates) {
115 | if (($Update.IsDownloaded)) {
116 | LogWrite "> $($Update.Title)"
117 | $UpdatesToInstall.Add($Update) |Out-Null
118 |
119 | if ($Update.InstallationBehavior.RebootBehavior -gt 0){
120 | [bool]$rebootMayBeRequired = $true
121 | }
122 | }
123 | }
124 |
125 | if ($UpdatesToInstall.Count -eq 0) {
126 | LogWrite 'No updates available to install...'
127 | $global:MoreUpdates=0
128 | $global:RestartRequired=0
129 | & "a:\enable-winrm.ps1"
130 | break
131 | }
132 |
133 | if ($rebootMayBeRequired) {
134 | LogWrite 'These updates may require a reboot'
135 | $global:RestartRequired=1
136 | }
137 |
138 | LogWrite 'Installing updates...'
139 |
140 | $Installer = $script:UpdateSession.CreateUpdateInstaller()
141 | $Installer.Updates = $UpdatesToInstall
142 | $InstallationResult = $Installer.Install()
143 |
144 | LogWrite "Installation Result: $($InstallationResult.ResultCode)"
145 | LogWrite "Reboot Required: $($InstallationResult.RebootRequired)"
146 | LogWrite 'Listing of updates installed and individual installation results:'
147 | if ($InstallationResult.RebootRequired) {
148 | $global:RestartRequired=1
149 | } else {
150 | $global:RestartRequired=0
151 | }
152 |
153 | for($i=0; $i -lt $UpdatesToInstall.Count; $i++) {
154 | New-Object -TypeName PSObject -Property @{
155 | Title = $UpdatesToInstall.Item($i).Title
156 | Result = $InstallationResult.GetUpdateResult($i).ResultCode
157 | }
158 | LogWrite "Item: $($UpdatesToInstall.Item($i).Title)"
159 | LogWrite "Result: $($InstallationResult.GetUpdateResult($i).ResultCode)"
160 | }
161 |
162 | Check-ContinueRestartOrEnd
163 | }
164 |
165 | function Check-WindowsUpdates() {
166 | LogWrite "Checking For Windows Updates"
167 | $Username = $env:USERDOMAIN + "\" + $env:USERNAME
168 | LogWrite "Script: $script:ScriptPath `nScript User: $Username `nStarted: $(Get-Date)"
169 |
170 | $script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
171 | $script:successful = $FALSE
172 | $script:attempts = 0
173 | $script:maxAttempts = 12
174 | while(-not $script:successful -and $script:attempts -lt $script:maxAttempts) {
175 | try {
176 | $script:SearchResult = $script:UpdateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
177 | $script:successful = $TRUE
178 | } catch {
179 | LogWrite $_.Exception | Format-List -force
180 | LogWrite "Search call to UpdateSearcher was unsuccessful. Retrying in 10s."
181 | $script:attempts = $script:attempts + 1
182 | Start-Sleep -s 10
183 | }
184 | }
185 |
186 | if ($SearchResult.Updates.Count -ne 0) {
187 | $Message = "There are " + $SearchResult.Updates.Count + " more updates."
188 | LogWrite $Message
189 | try {
190 | for($i=0; $i -lt $script:SearchResult.Updates.Count; $i++) {
191 | LogWrite $script:SearchResult.Updates.Item($i).Title
192 | LogWrite $script:SearchResult.Updates.Item($i).Description
193 | LogWrite $script:SearchResult.Updates.Item($i).RebootRequired
194 | LogWrite $script:SearchResult.Updates.Item($i).EulaAccepted
195 | }
196 | $global:MoreUpdates=1
197 | } catch {
198 | LogWrite $_.Exception | Format-List -force
199 | LogWrite "Showing SearchResult was unsuccessful. Rebooting."
200 | $global:RestartRequired=1
201 | $global:MoreUpdates=0
202 | Check-ContinueRestartOrEnd
203 | LogWrite "Show never happen to see this text!"
204 | Restart-Computer
205 | }
206 | } else {
207 | LogWrite 'There are no applicable updates'
208 | $global:RestartRequired=0
209 | $global:MoreUpdates=0
210 | }
211 | }
212 |
213 | $script:ScriptName = $MyInvocation.MyCommand.ToString()
214 | $script:ScriptPath = $MyInvocation.MyCommand.Path
215 | $script:UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
216 | $script:UpdateSession.ClientApplicationID = 'Packer Windows Update Installer'
217 | $script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
218 | $script:SearchResult = New-Object -ComObject 'Microsoft.Update.UpdateColl'
219 | $script:Cycles = 0
220 | $script:CycleUpdateCount = 0
221 |
222 | if ($BeginWithRestart) {
223 | $global:RestartRequired = 1
224 | Check-ContinueRestartOrEnd
225 | }
226 |
227 | Check-WindowsUpdates
228 | if ($global:MoreUpdates -eq 1) {
229 | Install-WindowsUpdates
230 | } else {
231 | Check-ContinueRestartOrEnd
232 | }
233 |
--------------------------------------------------------------------------------
/win10.base/Win10_vsphere.json:
--------------------------------------------------------------------------------
1 | {
2 | "builders": [
3 | {
4 | "CPUs": "{{user `vm-cpu-num`}}",
5 | "RAM": "{{user `vm-mem-size`}}",
6 | "RAM_reserve_all": true,
7 | "communicator": "winrm",
8 | "convert_to_template": "true",
9 | "datacenter": "{{user `vsphere-datacenter`}}",
10 | "datastore": "{{user `vsphere-datastore`}}",
11 | "disk_controller_type": "lsilogic-sas",
12 | "firmware": "bios",
13 | "floppy_files": [
14 | "autounattend.xml",
15 | "../scripts/disable-network-discovery.cmd",
16 | "../scripts/enable-rdp.cmd",
17 | "../scripts/enable-winrm.ps1",
18 | "../scripts/install-vm-tools.cmd",
19 | "../scripts/set-temp.ps1",
20 | "../scripts/microsoft-updates.bat",
21 | "../scripts/win-updates.ps1",
22 | "../scripts/disable-screensaver.ps1"
23 | ],
24 | "folder": "{{user `vsphere-folder`}}",
25 | "guest_os_type": "windows9_64Guest",
26 | "host": "{{user `vsphere-host`}}",
27 | "insecure_connection": "true",
28 | "iso_paths": [
29 | "{{user `os_iso_path`}}",
30 | "[] /vmimages/tools-isoimages/windows.iso"
31 | ],
32 | "network_adapters": [
33 | {
34 | "network": "{{user `vsphere-network`}}",
35 | "network_card": "vmxnet3"
36 | }
37 | ],
38 | "password": "{{user `vsphere-password`}}",
39 | "storage": [
40 | {
41 | "disk_size": "{{user `vm-disk-size`}}",
42 | "disk_thin_provisioned": true
43 | }
44 | ],
45 | "type": "vsphere-iso",
46 | "username": "{{user `vsphere-user`}}",
47 | "vcenter_server": "{{user `vsphere-server`}}",
48 | "vm_name": "{{user `vm-name`}}",
49 | "winrm_insecure": "true",
50 | "winrm_password": "{{user `winadmin-password`}}",
51 | "winrm_use_ssl": "true",
52 | "winrm_username": "{{user `winrm_username`}}"
53 | }
54 | ],
55 | "provisioners": [
56 | {
57 | "type": "windows-restart"
58 | }
59 | ],
60 | "sensitive-variables": [
61 | "vsphere_password",
62 | "winadmin_password"
63 | ]
64 | }
65 |
--------------------------------------------------------------------------------
/win10.base/autounattend.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 | 1
11 | Primary
12 | true
13 |
14 |
15 |
16 |
17 | false
18 | NTFS
19 | C
20 | 1
21 | 1
22 |
23 |
24 |
25 | 0
26 | true
27 |
28 | OnError
29 |
30 |
31 | true
32 | Administrator Administrator
33 | Administrator Inc.
34 |
35 |
47 |
48 |
49 |
52 |
53 |
54 |
55 |
56 | 0
57 | 1
58 |
59 | OnError
60 | false
61 |
62 |
63 | /IMAGE/NAME
64 | Windows 10 Enterprise
65 |
66 |
67 |
68 |
69 |
70 |
71 |
72 | de-DE
73 |
74 | de-DE
75 | de-DE
76 | de-DE
77 |
78 | de-DE
79 |
80 |
81 |
82 |
83 | false
84 |
85 |
86 |
87 |
88 |
89 |
90 | true
91 | true
92 | true
93 | true
94 | true
95 | true
96 | Home
97 | 1
98 |
99 |
100 |
101 | Lab2020
102 | true
103 |
104 |
105 |
106 |
107 | Lab2020
108 | true
109 |
110 | 2
111 | Administrator
112 | true
113 |
114 |
115 |
116 | 1
117 | Set Execution Policy 64 Bit
118 | cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
119 | true
120 |
121 |
122 | 2
123 | Set Execution Policy 32 Bit
124 | C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"
125 | true
126 |
127 |
128 | cmd.exe /c wmic useraccount where "name='Administrator'" set PasswordExpires=FALSE
129 | 18
130 | Disable password expiration for Administrator user
131 |
132 |
133 | cmd.exe /c a:\install-vm-tools.cmd
134 | 20
135 | Install VMware Tools
136 |
137 |
138 | cmd.exe /c a:\enable-rdp.cmd
139 | 21
140 | Enable RDP
141 |
142 |
143 | cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\set-temp.ps1
144 | 22
145 | Set Temp Folders
146 |
147 |
148 |
149 | cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -ExecutionPolicy Bypass -File a:\enable-winrm.ps1
150 | Enable WinRM
151 | 23
152 |
153 |
154 |
155 | false
156 |
157 |
158 |
172 |
173 |
--------------------------------------------------------------------------------