This commit is contained in:
2020-08-17 12:06:41 -04:00
parent 9fa09f26bd
commit 6eb48873e6
455 changed files with 45184 additions and 14 deletions

View File

@@ -0,0 +1,29 @@
---
language: python
python: "2.7"
# Use the new container infrastructure
sudo: false
# Install ansible
addons:
apt:
packages:
- python-pip
install:
# Install ansible
- pip install ansible
# Check ansible version
- ansible --version
# Create ansible.cfg with correct roles_path
- printf '[defaults]\nroles_path=../' >ansible.cfg
script:
# Basic role syntax check
- ansible-playbook tests/test.yml -i tests/inventory --syntax-check
notifications:
webhooks: https://galaxy.ansible.com/api/v1/notifications/

View File

@@ -0,0 +1,21 @@
MIT License
Copyright (c) 2019 Orcun Atakan
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -0,0 +1,46 @@
# windows_template_build
This repo contains an Ansible role that build a Windows template on any cloud platform(ovirt/rhev, VMware, EC2, Azure etc.)
You can run this role as part of VMware template build role or packer role as part of CI/CD pipeline for building Windows templates.
> **_Note:_** This role is provided as an example only. Do not use this in production. You can fork/clone and add/remove steps for your environment based on your organization's security and operational requirements.
Requirements
------------
Any pre-requisites that may not be covered by Ansible itself or the role should be mentioned here. For instance, if the role uses the EC2 module, it may be a good idea to mention in this section that the boto package is required.
Role Variables
--------------
A description of the settable variables for this role should go here, including any variables that are in defaults/main.yml, vars/main.yml, and any variables that can/should be set via parameters to the role. Any variables that are read from other roles and/or the global scope (ie. hostvars, group vars, etc.) should be mentioned here as well.
Dependencies
------------
A list of roles that this role utilizes:
- oatakan.windows_ec2_ena_driver
- oatakan.windows_ovirt_guest_agent
- oatakan.windows_virtio
- oatakan.windows_vmware_tools
- oatakan.windows_virtualbox_guest_additions
Example Playbook
----------------
Including an example of how to use your role (for instance, with variables passed in as parameters) is always nice for users too:
- hosts: servers
roles:
- oatakan.windows_template_build
License
-------
MIT
Author Information
------------------
Orcun Atakan

View File

@@ -0,0 +1,83 @@
---
install_updates: yes
remove_apps: no
clean_up_components: yes
upgrade_powershell: no
powershell_target_version: 4.0
temp_directory: "{{ ansible_env.TEMP }}"
update_retry_limit: 10
powershell_script_url: https://raw.githubusercontent.com/jborean93/ansible-windows/master/scripts/Upgrade-PowerShell.ps1
powershell_upgrade_script_file: 'C:\Upgrade-PowerShell.ps1'
enable_tlsv12_hotfix_download_location: "{{ ansible_env.TEMP }}"
enable_tlsv12_hotfix:
kb: KB3080079
file: Windows6.1-KB3080079-x64.msu
url: https://download.microsoft.com/download/F/4/1/F4154AD2-2119-48B4-BF99-CC15F68E110D/Windows6.1-KB3080079-x64.msu
#sdelete_download_url: http://web.archive.org/web/20140902022253/http://download.sysinternals.com/files/SDelete.zip
bleachbit_download_url: https://download.bleachbit.org/BleachBit-2.2-portable.zip
sdelete_download_url: https://download.sysinternals.com/files/SDelete.zip
#ultradefrag_download_url: http://downloads.sourceforge.net/project/ultradefrag/stable-release/6.1.0/ultradefrag-portable-6.1.0.bin.amd64.zip
ultradefrag_download_url: https://astuteinternet.dl.sourceforge.net/project/ultradefrag/stable-release/7.1.3/ultradefrag-portable-7.1.3.bin.amd64.zip
enable_auto_logon: yes
target_ovirt: no
target_qemu: no
target_ec2: no
target_vagrant: no
bleachbit_clean: yes
bleachbit_free_disk_space: yes
ec2_ena_driver_role: oatakan.windows_ec2_ena_driver
ovirt_guest_agent_role: oatakan.windows_ovirt_guest_agent
virtio_role: oatakan.windows_virtio
vmware_tools_role: oatakan.windows_vmware_tools
virtualbox_guest_additions_role: oatakan.windows_virtualbox_guest_additions
policy:
allow_unauthenticated_guest_access: no
local_administrator_password: Chang3MyP@ssw0rd21
local_account_username: ansible
local_account_password: Chang3MyP@ssw0rd21
shutdown_instance: yes
winsxs_cleanmgr_file:
2008r2: '{{ ansible_env.windir }}\winsxs\amd64_microsoft-windows-cleanmgr_31bf3856ad364e35_6.1.7600.16385_none_c9392808773cd7da\cleanmgr.exe'
2012: '{{ ansible_env.windir }}\WinSxS\amd64_microsoft-windows-cleanmgr_31bf3856ad364e35_6.2.9200.16384_none_c60dddc5e750072a\cleanmgr.exe'
winsxs_cleanmgr_mui_file:
2008r2: '{{ ansible_env.windir }}\winsxs\amd64_microsoft-windows-cleanmgr.resources_31bf3856ad364e35_6.1.7600.16385_en-us_b9cb6194b257cc63\cleanmgr.exe.mui'
2012: '{{ ansible_env.windir }}\WinSxS\amd64_microsoft-windows-cleanmgr.resources_31bf3856ad364e35_6.2.9200.16384_en-us_b6a01752226afbb3\cleanmgr.exe.mui'
cleanup_registry_keys:
- Active Setup Temp Folders
- BranchCache
- Downloaded Program Files
- Internet Cache Files
- Memory Dump Files
- Old ChkDsk Files
- Previous Installations
- Recycle Bin
- Service Pack Cleanup
- Setup Log Files
- System error memory dump files
- System error minidump files
- Temporary Files
- Temporary Setup Files
- Thumbnail Cache
- Update Cleanup
- Upgrade Discarded Files
- User file versions
- Windows Defender
- Windows Error Reporting Archive Files
- Windows Error Reporting Queue Files
- Windows Error Reporting System Archive Files
- Windows Error Reporting System Queue Files
- Windows ESD installation files
- Windows Upgrade Log Files

View File

@@ -0,0 +1,49 @@
function Get-LogDir
{
try
{
$ts = New-Object -ComObject Microsoft.SMS.TSEnvironment -ErrorAction Stop
if ($ts.Value("LogPath") -ne "")
{
$logDir = $ts.Value("LogPath")
}
else
{
$logDir = $ts.Value("_SMSTSLogPath")
}
}
catch
{
$logDir = $env:TEMP
}
return $logDir
}
$logDir = Get-LogDir
Start-Transcript "$logDir\RemoveUserApps.log"
# Get the list of provisioned packages
$provisioned = Get-AppxProvisionedPackage -online
# Check each installed app
$count = 0
for ($i=1; $i -ile 2; $i++) {
# Check each app (two loops just in case there are dependencies that can't be removed until the
# main app is removed)
Get-AppxPackage | ? {$_.SignatureKind -ne 'System'} | ForEach-Object {
$current = $_
$found = $provisioned | ? {$_.DisplayName -eq $current.Name -and $_.Version -eq $current.Version}
if ($found.Count -eq 0)
{
Write-Host "$($current.Name) version $($current.Version) is not provisioned, removing."
Remove-AppxPackage -Package $current.PackageFullName
$count++
}
}
}
Write-Host "Number of apps removed: $count"
Stop-Transcript

View File

@@ -0,0 +1,229 @@
param($global:RestartRequired=0,
$global:MoreUpdates=0,
$global:MaxCycles=5,
$MaxUpdatesPerCycle=500)
$Logfile = "C:\Windows\Temp\win-updates.log"
function LogWrite {
Param ([string]$logstring)
$now = Get-Date -format s
Add-Content $Logfile -value "$now $logstring"
Write-Host $logstring
}
function Check-ContinueRestartOrEnd() {
$RegistryKey = "HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update"
$RegistryEntry = "CustomRebootRequired"
switch ($global:RestartRequired) {
0 {
$prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
if ($prop) {
LogWrite "Restart Registry Entry Exists - Removing It"
Remove-ItemProperty -Path $RegistryKey -Name $RegistryEntry -ErrorAction SilentlyContinue
}
LogWrite "No Restart Required"
Check-WindowsUpdates
if (($global:MoreUpdates -eq 1) -and ($script:Cycles -le $global:MaxCycles)) {
Install-WindowsUpdates
} elseif ($script:Cycles -gt $global:MaxCycles) {
LogWrite "Exceeded Cycle Count - Stopping"
} else {
LogWrite "Done Installing Windows Updates"
}
}
1 {
$prop = (Get-ItemProperty $RegistryKey).$RegistryEntry
if (-not $prop) {
LogWrite "Restart Registry Entry Does Not Exist - Creating It"
Set-ItemProperty -Path $RegistryKey -Name $RegistryEntry -Value "1"
} else {
LogWrite "Restart Registry Entry Exists Already"
}
#LogWrite "Restart Required - Restarting..."
#Restart-Computer
}
default {
LogWrite "Unsure If A Restart Is Required"
break
}
}
}
function Install-WindowsUpdates() {
$script:Cycles++
LogWrite "Evaluating Available Updates with limit of $($MaxUpdatesPerCycle):"
$UpdatesToDownload = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$script:i = 0;
$CurrentUpdates = $SearchResult.Updates
while($script:i -lt $CurrentUpdates.Count -and $script:CycleUpdateCount -lt $MaxUpdatesPerCycle) {
$Update = $CurrentUpdates.Item($script:i)
if (($Update -ne $null) -and (!$Update.IsDownloaded)) {
[bool]$addThisUpdate = $false
if ($Update.InstallationBehavior.CanRequestUserInput) {
LogWrite "> Skipping: $($Update.Title) because it requires user input"
} else {
if (!($Update.EulaAccepted)) {
LogWrite "> Note: $($Update.Title) has a license agreement that must be accepted. Accepting the license."
$Update.AcceptEula()
[bool]$addThisUpdate = $true
$script:CycleUpdateCount++
} else {
[bool]$addThisUpdate = $true
$script:CycleUpdateCount++
}
}
if ([bool]$addThisUpdate) {
LogWrite "Adding: $($Update.Title)"
$UpdatesToDownload.Add($Update) |Out-Null
}
}
$script:i++
}
if ($UpdatesToDownload.Count -eq 0) {
LogWrite "No Updates To Download..."
} else {
LogWrite 'Downloading Updates...'
$ok = 0;
while (! $ok) {
try {
$Downloader = $UpdateSession.CreateUpdateDownloader()
$Downloader.Updates = $UpdatesToDownload
$Downloader.Download()
$ok = 1;
} catch {
LogWrite $_.Exception | Format-List -force
LogWrite "Error downloading updates. Retrying in 30s."
$script:attempts = $script:attempts + 1
Start-Sleep -s 30
}
}
}
$UpdatesToInstall = New-Object -ComObject 'Microsoft.Update.UpdateColl'
[bool]$rebootMayBeRequired = $false
LogWrite 'The following updates are downloaded and ready to be installed:'
foreach ($Update in $SearchResult.Updates) {
if (($Update.IsDownloaded)) {
LogWrite "> $($Update.Title)"
$UpdatesToInstall.Add($Update) |Out-Null
if ($Update.InstallationBehavior.RebootBehavior -gt 0){
[bool]$rebootMayBeRequired = $true
}
}
}
if ($UpdatesToInstall.Count -eq 0) {
LogWrite 'No updates available to install...'
$global:MoreUpdates=0
$global:RestartRequired=0
break
}
if ($rebootMayBeRequired) {
LogWrite 'These updates may require a reboot'
$global:RestartRequired=1
}
LogWrite 'Installing updates...'
$Installer = $script:UpdateSession.CreateUpdateInstaller()
$Installer.Updates = $UpdatesToInstall
$InstallationResult = $Installer.Install()
LogWrite "Installation Result: $($InstallationResult.ResultCode)"
LogWrite "Reboot Required: $($InstallationResult.RebootRequired)"
LogWrite 'Listing of updates installed and individual installation results:'
if ($InstallationResult.RebootRequired) {
$global:RestartRequired=1
} else {
$global:RestartRequired=0
}
for($i=0; $i -lt $UpdatesToInstall.Count; $i++) {
New-Object -TypeName PSObject -Property @{
Title = $UpdatesToInstall.Item($i).Title
Result = $InstallationResult.GetUpdateResult($i).ResultCode
}
LogWrite "Item: " $UpdatesToInstall.Item($i).Title
LogWrite "Result: " $InstallationResult.GetUpdateResult($i).ResultCode;
}
Check-ContinueRestartOrEnd
}
function Check-WindowsUpdates() {
LogWrite "Checking For Windows Updates"
$Username = $env:USERDOMAIN + "\" + $env:USERNAME
New-EventLog -Source $ScriptName -LogName 'Windows Powershell' -ErrorAction SilentlyContinue
$Message = "Script: " + $ScriptPath + "`nScript User: " + $Username + "`nStarted: " + (Get-Date).toString()
Write-EventLog -LogName 'Windows Powershell' -Source $ScriptName -EventID "104" -EntryType "Information" -Message $Message
LogWrite $Message
$script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
$script:successful = $FALSE
$script:attempts = 0
$script:maxAttempts = 12
while(-not $script:successful -and $script:attempts -lt $script:maxAttempts) {
try {
$script:SearchResult = $script:UpdateSearcher.Search("IsInstalled=0 and Type='Software' and IsHidden=0")
$script:successful = $TRUE
} catch {
LogWrite $_.Exception | Format-List -force
LogWrite "Search call to UpdateSearcher was unsuccessful. Retrying in 10s."
$script:attempts = $script:attempts + 1
Start-Sleep -s 10
}
}
if ($SearchResult.Updates.Count -ne 0) {
$Message = "There are " + $SearchResult.Updates.Count + " more updates."
LogWrite $Message
try {
for($i=0; $i -lt $script:SearchResult.Updates.Count; $i++) {
LogWrite $script:SearchResult.Updates.Item($i).Title
LogWrite $script:SearchResult.Updates.Item($i).Description
LogWrite $script:SearchResult.Updates.Item($i).RebootRequired
LogWrite $script:SearchResult.Updates.Item($i).EulaAccepted
}
$global:MoreUpdates=1
} catch {
LogWrite $_.Exception | Format-List -force
LogWrite "Showing SearchResult was unsuccessful. Rebooting."
$global:RestartRequired=1
$global:MoreUpdates=0
Check-ContinueRestartOrEnd
LogWrite "Show never happen to see this text!"
Restart-Computer
}
} else {
LogWrite 'There are no applicable updates'
$global:RestartRequired=0
$global:MoreUpdates=0
}
}
$script:ScriptName = $MyInvocation.MyCommand.ToString()
$script:ScriptPath = $MyInvocation.MyCommand.Path
$script:UpdateSession = New-Object -ComObject 'Microsoft.Update.Session'
$script:UpdateSession.ClientApplicationID = 'Packer Windows Update Installer'
$script:UpdateSearcher = $script:UpdateSession.CreateUpdateSearcher()
$script:SearchResult = New-Object -ComObject 'Microsoft.Update.UpdateColl'
$script:Cycles = 0
$script:CycleUpdateCount = 0
Check-WindowsUpdates
if ($global:MoreUpdates -eq 1) {
Install-WindowsUpdates
} else {
Check-ContinueRestartOrEnd
}

View File

@@ -0,0 +1,2 @@
install_date: Wed Jun 24 18:44:34 2020
version: master

View File

@@ -0,0 +1,39 @@
---
galaxy_info:
author: Orcun Atakan
description: Ansible galaxy role for building a Windows template on any cloud platform(ovirt/rhev, VMware, EC2, Azure etc.)
role_name: windows_template_build
company: Red Hat
license: MIT
min_ansible_version: 2.5
platforms:
- name: Windows
versions:
- all
cloud_platforms:
- amazon
- google
- azure
- azure
- vmware
- ovirt
galaxy_tags:
- windows
- ec2
- vmware
- azure
- microsoft
- rhev
- rhv
- ovirt
- aws
- cloud
- multicloud
- template
dependencies: []

View File

@@ -0,0 +1,14 @@
---
- name: clean up components and update files
win_shell: Dism.exe /online /Cleanup-Image /StartComponentCleanup /ResetBase
when: "'Windows Server 2008' not in ansible_distribution"
ignore_errors: yes
- include_tasks: clean-up-with-cleanmgr.yml
when: "'Windows Server 2008' in ansible_distribution"
- name: clean up components and update files
win_shell: Dism.exe /online /Cleanup-Image /SpSuperseded
when: "'Windows Server 2008' in ansible_distribution"
ignore_errors: yes

View File

@@ -0,0 +1,64 @@
---
- block:
- name: check for cleanmgr executable
win_stat:
path: '{{ ansible_env.windir }}\System32\cleanmgr.exe'
register: check_cleanmgr_file
- include_tasks: copy_cleanmgr.yml
vars:
os_short_name: 2008r2
when:
- not check_cleanmgr_file.stat.exists
- ('Windows Server 2008 R2' in ansible_distribution)
- include_tasks: copy_cleanmgr.yml
vars:
os_short_name: 2012
when:
- not check_cleanmgr_file.stat.exists
- ('Windows Server 2012' in ansible_distribution)
- (not 'Windows Server 2012 R2' in ansible_distribution)
- name: get free space
win_shell: Get-PSDrive C | Select-Object Free | ConvertTo-Json
register: free_space_before_cleanup
- name: ensure cleanup registry paths exist
win_regedit:
path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\{{ item }}
loop: "{{ cleanup_registry_keys }}"
- name: set cleanup registry keys
win_regedit:
path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Explorer\VolumeCaches\{{ item }}
name: StateFlags0012
data: 2
type: dword
loop: "{{ cleanup_registry_keys }}"
- name: run cleanmgr
win_shell: cleanmgr /sagerun:12
- name: wait for cleanmgr to finish
win_shell: (get-wmiobject win32_process | where-object {$_.processname -eq 'cleanmgr.exe'} | measure).count
register: check_cleanmgr_process
until: check_cleanmgr_process.stdout is defined and check_cleanmgr_process.stdout|int == 0
delay: 5
retries: 300
- name: get free space
win_shell: Get-PSDrive C | Select-Object Free | ConvertTo-Json
register: free_space_after_cleanup
- debug:
msg:
- "Free space before cleanup: {{ ((free_space_before_cleanup.stdout | from_json)['Free']|int / (1024*1024*1024)) | round(2, 'floor') }} GB"
- "Free space after cleanup: {{ ((free_space_after_cleanup.stdout | from_json)['Free']|int / (1024*1024*1024)) | round(2, 'floor') }} GB"
rescue:
- name: ignore any errors
debug:
msg: "ignoring any error with clean up with cleanmgr"

View File

@@ -0,0 +1,41 @@
---
- name: remove page file
win_regedit:
path: HKLM:\System\CurrentControlSet\Control\Session Manager\Memory Management
name: PagingFiles
data: ""
state: present
register: cleanup_pagefile_removal
- name: reboot server after clearing page file
win_reboot:
when: cleanup_pagefile_removal is changed
- name: cleanup the temp folders
win_file:
path: '{{ item }}'
state: absent
ignore_errors: yes
loop:
- C:\Temp
- C:\Windows\Panther
- C:\Windows\Temp
- name: cleanup the C:\Recovery folder
win_shell: Remove-Item -Path C:\Recovery -Force -Recurse
ignore_errors: yes
- name: check to see if WinSXS ManifestCache folder exist
win_stat:
path: '{{ ansible_env.windir }}\winsxs\ManifestCache'
register: winsxs_dir
- name: clear out the WinSXS ManifestCache folder
win_shell: |
&cmd.exe /c Takeown /f %windir%\winsxs\ManifestCache\*
&cmd.exe /c Icacls %windir%\winsxs\ManifestCache\* /GRANT administrators:F
&cmd.exe /c Del /q %windir%\winsxs\ManifestCache\*
when:
- winsxs_dir.stat is defined
- winsxs_dir.stat.exists

View File

@@ -0,0 +1,9 @@
---
- name: install cloudbase init package
win_package:
path: https://cloudbase.it/downloads/CloudbaseInitSetup_x64.msi
product_id: '{ED85F19F-057A-4EE6-BC8D-F576DEACE78D}'
arguments:
- /qn
state: present

View File

@@ -0,0 +1,36 @@
---
- name: see if Optimize-Volume cmdlet is available
win_command: powershell.exe "Get-Command -Name Optimize-Volume"
register: cleanup_defrag_cmdlet
failed_when: False
- name: defrag C with PS cmdlet
win_command: powershell.exe "Optimize-Volume -DriveLetter C"
when: cleanup_defrag_cmdlet.rc == 0
- name: defrag C with legacy exe
win_command: 'Defrag.exe C:'
when: cleanup_defrag_cmdlet.rc != 0
- name: 0 out empty space for later compression
win_shell: |
$path = "C:\zero"
$volume = Get-WmiObject -Class Win32_LogicalDisk -Filter "DeviceID='C:'"
$block_size = 64kb
$leftover_size = $volume.Size * 0.05
$file_size = $volume.FreeSpace - $leftover_size
$data_array = New-Object -TypeName byte[]($block_size)
$stream = [System.IO.File]::OpenWrite($path)
try {
$current_file_size = 0
while ($current_file_size -lt $file_size) {
$stream.Write($data_array, 0, $data_array.Length)
$current_file_size += $data_array.Length
}
} finally {
if ($stream) {
$stream.Close()
}
}
Remove-Item -Path $path -Force | Out-Null

View File

@@ -0,0 +1,164 @@
---
- name: ensure temp directory exists
win_file:
path: '{{ temp_directory }}'
state: directory
- name: download bleachbit
win_get_url:
url: '{{ bleachbit_download_url }}'
dest: '{{ temp_directory }}\BleachBit-portable.zip'
register: download_bleachbit
until: download_bleachbit is success
delay: 3
retries: 5
when: bleachbit_download_url is defined
- name: unzip bleachbit
win_unzip:
src: '{{ temp_directory }}\BleachBit-portable.zip'
dest: '{{ ansible_user_dir }}'
when: download_bleachbit is success
# This is needed on 2008 for bleachbit to work
- name: install the visual C libraries
win_package:
path: https://download.microsoft.com/download/5/D/8/5D8C65CB-C849-4025-8E95-C3966CAFD8AE/vcredist_x86.exe
product_id: '{9BE518E6-ECC6-35A9-88E4-87755C07200F}'
arguments: '/qb!'
when: "'Windows Server 2008' in ansible_distribution"
- name: stop windows update service
win_service:
name: wuauserv
state: stopped
ignore_errors: yes
- name: delete update directory
win_file:
path: C:\Windows\SoftwareDistribution\Download
state: absent
ignore_errors: yes
- name: remove windows update settings
win_regedit:
path: HKLM:\Software\Microsoft\Windows\CurrentVersion\WindowsUpdate
name: "{{ item }}"
state: absent
loop:
- SusClientId
- PingID
- AccountDomainSid
- name: start windows update service
win_service:
name: wuauserv
state: started
ignore_errors: yes
- name: create update directory
win_file:
path: C:\Windows\SoftwareDistribution\Download
state: directory
ignore_errors: yes
- name: reset windows update
win_shell: wuauclt /resetauthorization /detectnow
ignore_errors: yes
- name: clean with bleachbit
win_shell: >
'{{ ansible_user_dir }}\BleachBit-Portable\bleachbit_console.exe --clean deepscan.backup
deepscan.ds_store deepscan.thumbs_db deepscan.tmp internet_explorer.cookies internet_explorer.forms
internet_explorer.history internet_explorer.temporary_files system.clipboard system.custom system.logs
system.memory_dump system.muicache system.prefetch system.recycle_bin system.tmp system.updates
windows_defender.history windows_explorer.mru windows_explorer.recent_documents windows_explorer.run
windows_explorer.search_history windows_explorer.thumbnails > NUL'
args:
executable: cmd
when:
- bleachbit_clean|bool
- download_bleachbit is success
ignore_errors: yes
- name: create temp directory
win_file:
path: '{{ temp_directory }}\win_build'
state: directory
- name: download ultradefrag
win_get_url:
url: '{{ ultradefrag_download_url }}'
dest: '{{ temp_directory }}\win_build\ultradefrag.zip'
register: download_ultradefrag
until: download_ultradefrag is success
delay: 3
retries: 5
- name: unzip ultradefrag
win_unzip:
src: '{{ temp_directory }}\win_build\ultradefrag.zip'
dest: '{{ temp_directory }}\win_build'
- name: set udefrag extract directory
set_fact:
udefrag_dir: '{{ temp_directory }}\win_build\ultradefrag-portable-7.1.3.amd64'
- name: defrag with ultradefrag
win_shell: '{{ udefrag_dir }}\udefrag.exe --optimize --repeat C:'
args:
executable: cmd
- name: download sdelete
win_get_url:
url: '{{ sdelete_download_url }}'
dest: '{{ temp_directory }}\win_build\SDelete.zip'
register: download_sdelete
until: download_sdelete is success
delay: 3
retries: 5
when: sdelete_download_url is defined
- name: copy sdelete
win_copy:
src: SDelete.zip
dest: '{{ temp_directory }}\win_build\SDelete.zip'
when: sdelete_download_url is undefined
- name: unzip sdelete
win_unzip:
src: '{{ temp_directory }}\win_build\SDelete.zip'
dest: '{{ temp_directory }}\win_build'
- name: accept sdelete eula
win_regedit:
path: HKCU:\Software\Sysinternals\SDelete
name: EulaAccepted
data: 1
type: dword
- name: compact with sdelete
win_shell: '{{ temp_directory }}\win_build\sdelete.exe -q -z C:'
args:
executable: cmd
- name: remove temp files
win_file:
path: '{{ temp_directory }}\win_build'
state: absent
- name: free disk space with bleachbit
win_shell: '{{ ansible_user_dir }}\BleachBit-Portable\bleachbit_console.exe --clean system.free_disk_space'
args:
executable: cmd
when:
- bleachbit_free_disk_space|bool
- download_bleachbit is success
ignore_errors: yes
- name: remove bleachbit files
win_file:
path: '{{ ansible_user_dir }}\BleachBit-Portable'
state: absent
when: download_bleachbit is success

View File

@@ -0,0 +1,29 @@
---
- name: check winsxs cleanmgr file
win_stat:
path: "{{ winsxs_cleanmgr_file[os_short_name] }}"
register: check_winsxs_cleanmgr_file
- name: check winsxs cleanmgr mui file
win_stat:
path: "{{ winsxs_cleanmgr_mui_file[os_short_name] }}"
register: check_winsxs_cleanmgr_mui_file
- name: copy cleanmgr file from winsxs folder
win_copy:
src: "{{ winsxs_cleanmgr_file[os_short_name] }}"
dest: '{{ ansible_env.windir }}\System32\cleanmgr.exe'
remote_src: yes
when:
- check_winsxs_cleanmgr_file.stat.exists
- check_winsxs_cleanmgr_mui_file.stat.exists
- name: copy cleanmgr mui file from winsxs folder
win_copy:
src: "{{ winsxs_cleanmgr_mui_file[os_short_name] }}"
dest: '{{ ansible_env.windir }}\System32\en-US\cleanmgr.exe.mui'
remote_src: yes
when:
- check_winsxs_cleanmgr_file.stat.exists
- check_winsxs_cleanmgr_mui_file.stat.exists

View File

@@ -0,0 +1,8 @@
---
- name: disable auto login
win_regedit:
path: HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
name: "{{ item.name }}"
state: absent
loop: "{{ autologin_registry }}"

View File

@@ -0,0 +1,18 @@
---
- name: enable RDP port
win_firewall_rule:
name: Remote Desktop
localport: 3389
action: allow
direction: in
protocol: tcp
state: present
enabled: yes
- name: enable RDP
win_regedit:
path: HKLM:\System\CurrentControlSet\Control\Terminal Server
name: fDenyTSConnections
data: 0
type: dword

View File

@@ -0,0 +1,69 @@
---
- name: ensure Windows ADK with DISM is installed
win_chocolatey:
name: windows-adk-deploy
state: present
version: 10.0.17134.0
register: install_windows_adk_deploy
- name: ensure PATH contains Windows ADK
win_path:
scope: machine
state: present
elements: "C:\\Program Files (x86)\\Windows Kits\\10\\Assessment and Deployment Kit\\Deployment Tools\\amd64\\DISM"
- name: download hotfix
win_get_url:
url: '{{ enable_tlsv12_hotfix.url }}'
dest: '{{ enable_tlsv12_hotfix_download_location }}\{{ enable_tlsv12_hotfix.file }}'
- name: install hotfix
win_hotfix:
source: '{{ enable_tlsv12_hotfix_download_location }}\{{ enable_tlsv12_hotfix.file }}'
state: present
register: hotfix_install
- name: debug hotfix installation result
debug:
var: hotfix_install
- name: ensure hotfix file is removed
win_file:
path: '{{ enable_tlsv12_hotfix_download_location }}\{{ enable_tlsv12_hotfix.file }}'
state: absent
- name: reboot if needed
win_reboot:
when: hotfix_install.reboot_required
- name: enable TLSv1.2 support
win_regedit:
path: HKLM:\SYSTEM\CurrentControlSet\Control\SecurityProviders\SCHANNEL\Protocols\TLS 1.2\{{ item.type }}
name: '{{ item.property }}'
data: '{{ item.value }}'
type: dword
state: present
register: enable_tls12
loop:
- type: Server
property: Enabled
value: 1
- type: Server
property: DisabledByDefault
value: 0
- type: Client
property: Enabled
value: 1
- type: Client
property: DisabledByDefault
value: 0
- name: ensure Windows ADK with DISM is removed
win_chocolatey:
name: windows-adk-deploy
state: absent
- name: reboot if TLS config was applied
win_reboot:
when: enable_tls12 is changed

View File

@@ -0,0 +1,69 @@
---
- include_tasks: powershell-upgrade.yml
when: upgrade_powershell | bool
- name: run setup module
setup:
- include_tasks: enable-tlsv12.yml
when: upgrade_powershell | bool
- include_tasks: disable-auto-logon.yml
- include_tasks: updates.yml
when: install_updates | bool
- include_role:
name: "{{ ovirt_guest_agent_role }}"
when: target_ovirt | bool and not target_qemu | bool
- include_role:
name: "{{ virtio_role }}"
when: target_qemu | bool or ('KubeVirt' in ansible_system_vendor | default(''))
- include_role:
name: "{{ virtualbox_guest_additions_role }}"
when: "'VirtualBox' in ansible_product_name"
- include_role:
name: "{{ vmware_tools_role }}"
when: "'VMware' in ansible_product_name"
- include_tasks: startup.yml
- include_tasks: policy.yml
- include_tasks: power.yml
when: "'Windows 10' in ansible_distribution"
- include_tasks: enable-rdp.yml
- include_tasks: cloudbase-init.yml
when:
- "'VMware' not in ansible_product_name"
- "'VirtualBox' not in ansible_product_name"
- ('KubeVirt' not in ansible_system_vendor | default(False))
- not target_ovirt | bool
- not target_vagrant | bool
- include_tasks: remove-apps-alt-2.yml
when:
- remove_apps | bool
- "'Windows 10' in ansible_distribution"
- include_role:
name: "{{ ec2_ena_driver_role }}"
when: target_ec2 | bool
- include_tasks: clean-up-components.yml
when: clean_up_components | bool
- include_tasks: clean-up.yml
- include_tasks: sysprep.yml
- include_tasks: compact.yml
- include_tasks: shutdown.yml
when: shutdown_instance | bool

View File

@@ -0,0 +1,20 @@
---
# do not enable this by default
- name: allow unauthenticated guest access
win_regedit:
path: HKLM:\SYSTEM\CurrentControlSet\Services\LanmanWorkstation\Parameters
name: AllowInsecureGuestAuth
data: 1
type: dword
when: policy.allow_unauthenticated_guest_access|bool
- name: set connection profile to private
win_shell: Set-NetConnectionProfile -NetworkCategory Private
when:
- "'Windows 10' in ansible_distribution"
- name: Ensure local account password doesn't expire
win_user:
name: "{{ ansible_user }}"
password_never_expires: yes

View File

@@ -0,0 +1,6 @@
---
- name: change power plan to high performance
win_power_plan:
name: high performance
ignore_errors: yes

View File

@@ -0,0 +1,70 @@
---
- name: download script
raw: '(New-Object -TypeName System.Net.WebClient).DownloadFile("{{ powershell_script_url }}", "{{ powershell_upgrade_script_file }}")'
changed_when: False
check_mode: no
register: download_script
- name: set execution policy
raw: 'Set-ExecutionPolicy -ExecutionPolicy Unrestricted -Force'
changed_when: False
check_mode: no
ignore_errors: yes
- name: delete scheduled task if it exists
raw: 'SCHTASKS /Delete /TN upgrade'
args:
executable: cmd.exe
changed_when: False
check_mode: no
ignore_errors: yes
- name: create a scheduled task to run powershell script
raw: >
SCHTASKS /Create /SC MONTHLY /MO first /D SUN /TN upgrade /TR "powershell.exe -Command
'& {{ powershell_upgrade_script_file }} -Version {{ powershell_target_version }}
-Username {{ ansible_user }} -Password {{ ansible_password }}'"
args:
executable: cmd.exe
changed_when: False
check_mode: no
- name: run scheduled task
raw: 'SCHTASKS /Run /TN upgrade'
args:
executable: cmd.exe
changed_when: False
check_mode: no
- name: wait for system to reboot after upgrade
wait_for_connection:
delay: 300
sleep: 30
timeout: 300
- name: delete scheduled task
win_scheduled_task:
name: upgrade
state: absent
- name: delete script
win_file:
path: "{{ powershell_upgrade_script_file }}"
state: absent
- name: ensure auto login is disabled
win_regedit:
path: HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
name: AutoAdminLogon
data: 0
type: string
- name: ensure auto login creds are removed
win_regedit:
path: HKLM:\Software\Microsoft\Windows NT\CurrentVersion\Winlogon
name: "{{ item }}"
state: absent
loop:
- DefaultUserName
- DefaultPassword

View File

@@ -0,0 +1,96 @@
---
- name: remove default apps
win_shell: |
$ErrorActionPreference = "Stop"
$apps = @(
"Microsoft.3DBuilder",
"Microsoft.Appconnector",
"Microsoft.BingFinance",
"Microsoft.BingNews",
"Microsoft.BingSports",
"Microsoft.BingWeather",
"Microsoft.FreshPaint",
"Microsoft.Getstarted",
"Microsoft.MicrosoftOfficeHub",
"Microsoft.MicrosoftSolitaireCollection",
"Microsoft.MicrosoftStickyNotes",
"Microsoft.Office.OneNote",
"Microsoft.OneConnect",
"Microsoft.People",
"Microsoft.SkypeApp",
"Microsoft.Windows.Photos",
"Microsoft.WindowsAlarms",
"Microsoft.WindowsCalculator",
"Microsoft.WindowsCamera",
"Microsoft.WindowsMaps",
"Microsoft.WindowsPhone",
"Microsoft.WindowsSoundRecorder",
"Microsoft.XboxApp",
"Microsoft.ZuneMusic",
"Microsoft.ZuneVideo",
"Microsoft.WindowsCommunicationsApps",
"Microsoft.MinecraftUWP",
"Microsoft.MicrosoftPowerBIForWindows",
"Microsoft.NetworkSpeedTest",
"Microsoft.CommsPhone",
"Microsoft.ConnectivityStore",
"Microsoft.Messaging",
"Microsoft.Office.Sway",
"Microsoft.OneConnect",
"Microsoft.WindowsFeedbackHub",
"Microsoft.BingFoodAndDrink",
"Microsoft.BingTravel",
"Microsoft.BingHealthAndFitness",
"Microsoft.WindowsReadingList",
"Microsoft.MSPaint",
"Microsoft.Microsoft3DViewer",
"Microsoft.Print3D",
"9E2F88E3.Twitter",
"PandoraMediaInc.29680B314EFC2",
"Flipboard.Flipboard",
"ShazamEntertainmentLtd.Shazam",
"king.com.CandyCrushSaga",
"king.com.CandyCrushSodaSaga",
"king.com.*",
"ClearChannelRadioDigital.iHeartRadio",
"4DF9E0F8.Netflix",
"6Wunderkinder.Wunderlist",
"Drawboard.DrawboardPDF",
"2FE3CB00.PicsArt-PhotoStudio",
"D52A8D61.FarmVille2CountryEscape",
"TuneIn.TuneInRadio",
"GAMELOFTSA.Asphalt8Airborne",
"TheNewYorkTimes.NYTCrossword",
"DB6EA5DB.CyberLinkMediaSuiteEssentials",
"Facebook.Facebook",
"flaregamesGmbH.RoyalRevolt2",
"Playtika.CaesarsSlotsFreeCasino",
"A278AB0D.MarchofEmpires",
"KeeperSecurityInc.Keeper",
"ThumbmunkeysLtd.PhototasticCollage",
"XINGAG.XING",
"89006A2E.AutodeskSketchBook",
"D5EA27B7.Duolingo-LearnLanguagesforFree",
"46928bounde.EclipseManager",
"ActiproSoftwareLLC.562882FEEB491"
)
foreach ($app in $apps) {
Get-AppxPackage -Name $app -AllUsers | Remove-AppxPackage -AllUsers
Get-AppxProvisionedPackage -Online | Where-Object { $_.DisplayName -like $app } | Remove-AppxProvisionedPackage -Online
}
register: cleanup_win10_remove
until: cleanup_win10_remove is successful
retries: 5
delay: 1
ignore_errors: yes
- name: prevent suggested applications from returning
win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content
name: DisableWindowsConsumerFeatures
data: 1
datatype: dword
- name: reboot to effect pending changes
win_reboot:

View File

@@ -0,0 +1,30 @@
---
- name: remove user apps
script: RemoveUserApps.ps1
register: cleanup_win10_remove
until: cleanup_win10_remove is successful
retries: 3
delay: 1
ignore_errors: yes
#- name: disable windows store
# win_regedit:
# path: HKLM:\Software\Policies\Microsoft\WindowsStore
# name: AutoDownload
# data: 00000002
# type: dword
#
#- name: disable content delivery manager
# win_regedit:
# path: HKCU:\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager
# name: SilentInstalledAppsEnabled
# data: 00000000
# type: dword
#
#- name: disable windows store
# win_regedit:
# path: HKLM:\Software\Policies\Microsoft\Windows\CloudContent
# name: DisableWindowsConsumerFeatures
# data: 00000001
# type: dword

View File

@@ -0,0 +1,97 @@
---
- name: Setup the xWebAdministration module
win_psmodule:
name: DSCR_AppxPackage
state: present
- name: remove packages
win_dsc:
resource_name: cAppxProvisionedPackageSet
Ensure: Absent
PackageName:
- Microsoft.3DBuilder
- Microsoft.Appconnector
- Microsoft.BingFinance
- Microsoft.BingNews
- Microsoft.BingSports
- Microsoft.BingWeather
- Microsoft.FreshPaint
- Microsoft.Getstarted
- Microsoft.MicrosoftOfficeHub
- Microsoft.MicrosoftSolitaireCollection
- Microsoft.MicrosoftStickyNotes
- Microsoft.Office.OneNote
- Microsoft.OneConnect
- Microsoft.People
- Microsoft.SkypeApp
- Microsoft.Windows.Photos
- Microsoft.WindowsAlarms
- Microsoft.WindowsCalculator
- Microsoft.WindowsCamera
- Microsoft.WindowsMaps
- Microsoft.WindowsPhone
- Microsoft.WindowsSoundRecorder
- Microsoft.XboxApp
- Microsoft.ZuneMusic
- Microsoft.ZuneVideo
- Microsoft.WindowsCommunicationsApps
- Microsoft.MinecraftUWP
- Microsoft.MicrosoftPowerBIForWindows
- Microsoft.NetworkSpeedTest
- Microsoft.CommsPhone
- Microsoft.ConnectivityStore
- Microsoft.Messaging
- Microsoft.Office.Sway
- Microsoft.OneConnect
- Microsoft.WindowsFeedbackHub
- Microsoft.BingFoodAndDrink
- Microsoft.BingTravel
- Microsoft.BingHealthAndFitness
- Microsoft.WindowsReadingList
- Microsoft.MSPaint
- Microsoft.Microsoft3DViewer
- Microsoft.Print3D
- 9E2F88E3.Twitter
- PandoraMediaInc.29680B314EFC2
- Flipboard.Flipboard
- ShazamEntertainmentLtd.Shazam
- king.com.CandyCrushSaga
- king.com.CandyCrushSodaSaga
- king.com.*
- ClearChannelRadioDigital.iHeartRadio
- 4DF9E0F8.Netflix
- 6Wunderkinder.Wunderlist
- Drawboard.DrawboardPDF
- 2FE3CB00.PicsArt-PhotoStudio
- D52A8D61.FarmVille2CountryEscape
- TuneIn.TuneInRadio
- GAMELOFTSA.Asphalt8Airborne
- TheNewYorkTimes.NYTCrossword
- DB6EA5DB.CyberLinkMediaSuiteEssentials
- Facebook.Facebook
- flaregamesGmbH.RoyalRevolt2
- Playtika.CaesarsSlotsFreeCasino
- A278AB0D.MarchofEmpires
- KeeperSecurityInc.Keeper
- ThumbmunkeysLtd.PhototasticCollage
- XINGAG.XING
- 89006A2E.AutodeskSketchBook
- D5EA27B7.Duolingo-LearnLanguagesforFree
- 46928bounde.EclipseManager
- ActiproSoftwareLLC.562882FEEB491-
register: cleanup_win10_remove
until: cleanup_win10_remove is successful
retries: 3
delay: 1
ignore_errors: yes
- name: prevent suggested applications from returning
win_regedit:
path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\Cloud Content
name: DisableWindowsConsumerFeatures
data: 1
datatype: dword
- name: reboot to effect pending changes
win_reboot:

View File

@@ -0,0 +1,29 @@
---
- name: kill onedrive process
win_shell: Stop-Process -Name OneDrive
ignore_errors: yes
- name: uninstall onedrive
win_shell: '{{ ansible_env.SystemRoot }}\SysWOW64\OneDriveSetup.exe /uninstall'
ignore_errors: yes
- name: remove onedrive directories
win_file:
path: '{{ item }}'
state: absent
ignore_errors: yes
loop:
- '{{ ansible_env.USERPROFILE }}\OneDrive'
- '{{ ansible_env.LOCALAPPDATA }}\Microsoft\OneDrive'
- '{{ ansible_env.ProgramData }}\Microsoft OneDrive'
- C:\OneDriveTemp
- name: delete registry keys
win_regedit:
path: '{{ item }}'
state: absent
delete_key: yes
loop:
- HKCR:\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}
- HKCR:\Wow6432Node\CLSID\{018D5C66-4533-4307-9B53-224DE2ED1FE6}

View File

@@ -0,0 +1,5 @@
---
- name: run sysprep-shutdown scheduled task
win_shell: schtasks.exe /Run /TN "sysprep-shutdown"
ignore_errors: yes

View File

@@ -0,0 +1,7 @@
---
- name: remove essentials setup wizard from start up
win_regedit:
path: HKLM:\Software\Microsoft\Windows\CurrentVersion\Run
name: EssentialsRoleConfigWizard
state: absent

View File

@@ -0,0 +1,76 @@
---
- name: recompile .NET assemblies
win_dotnet_ngen:
#- name: enable custom answer file
# win_regedit:
# path: HKLM:\System\Setup
# name: UnattendFile
# data: C:\Windows\system32\sysprep\unattend.xml
# type: string
- name: ensure Panther directory exists
win_file:
path: c:\Windows\Panther
state: directory
- name: enable winrm
win_shell: '& $([scriptblock]::Create((New-Object Net.WebClient).DownloadString("https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1"))) -ForceNewSSLCert -EnableCredSSP'
ignore_errors: yes
when: "'Windows Server 2008' in ansible_distribution"
- name: copy unattend.xml
win_template:
src: unattend.xml.j2
dest: C:\Windows\system32\sysprep\unattend.xml
when:
- ('VMware' not in ansible_product_name) or ('VMware' in ansible_product_name and target_vagrant | bool)
- not target_ovirt | bool
- not ('KubeVirt' in ansible_system_vendor | default(''))
#- name: run sysprep
# win_shell: C:\Windows\system32\sysprep\sysprep.exe /generalize /shutdown /oobe /quiet
# args:
# executable: cmd
# async: 1200
# poll: 0
- name: create scheduled task to delete WinRM listeners and shutdown
win_scheduled_task:
name: sysprep-shutdown
username: SYSTEM
disallow_start_if_on_batteries: no
stop_if_going_on_batteries: no
actions:
- path: powershell.exe
arguments: Remove-Item -Path WSMan:\localhost\Listener\* -Recurse -Force
- path: C:\windows\system32\sysprep\sysprep.exe
arguments: /generalize /oobe /quiet /shutdown
when:
- ('VMware' not in ansible_product_name) or ('VMware' in ansible_product_name and target_vagrant | bool) or (target_ovirt | bool) or ('KubeVirt' in ansible_system_vendor | default(''))
- name: create scheduled task to delete WinRM listeners and shutdown
win_scheduled_task:
name: sysprep-shutdown
username: SYSTEM
disallow_start_if_on_batteries: no
stop_if_going_on_batteries: no
actions:
- path: powershell.exe
arguments: Remove-Item -Path WSMan:\localhost\Listener\* -Recurse -Force
- path: shutdown.exe
arguments: /s /t 10 /f /d p:4:1 /c "Ansible Shutdown"
when:
- "'VMware' in ansible_product_name"
- not target_vagrant | bool
- not target_ovirt | bool
- not ('KubeVirt' in ansible_system_vendor | default(''))
- name: set flag to recreate pagefile after next sysprep
win_shell: |
$system = Get-WmiObject -Class Win32_ComputerSystem -EnableAllPrivileges
if ($system -ne $null) {
$system.AutomaticManagedPagefile = $true
$system.Put()
}

View File

@@ -0,0 +1,43 @@
---
- name: check for available updates
win_updates:
category_names: "{{ win_update_category_names }}"
blacklist: "{{ win_update_blacklist | default(omit) }}"
state: searched
register: available_updates
- debug:
msg: |
{{ inventory_hostname }} has {{ available_updates.found_update_count }} updates available.
{% for key, value in available_updates.updates.items() %}
- {{ value.title }}
{% endfor %}
when: available_updates.updates is defined
- include_tasks: updates-with-retry.yml
when:
- available_updates.updates is defined
- available_updates.found_update_count > 0
- name: check for missing updates.
win_updates:
state: searched
register: available_updates
- name: list missing updates
debug:
var: available_updates
- name: check to see if update is finished
win_shell: gwmi -Class win32_computersystem -ComputerName 127.0.0.1 | select -ExpandProperty username -ErrorAction Stop
register: logon_status
until: logon_status is success
delay: 10
retries: 100
ignore_errors: yes
when: "'Windows 10' in ansible_distribution"
- name: reboot windows
win_reboot:
when: "'Windows 10' in ansible_distribution"

View File

@@ -0,0 +1,98 @@
---
- name: update over multiple reboots
block:
- name: check for available updates
win_updates:
category_names:
- CriticalUpdates
- DefinitionUpdates
- SecurityUpdates
- UpdateRollups
- Updates
state: searched
register: available_updates
- debug:
msg: |
{{ inventory_hostname }} has {{ available_updates.found_update_count }} updates available.
{% for key, value in available_updates.updates.items() %}
- {{ value.title }}
{% endfor %}
when: available_updates.updates is defined
- block:
- name: install windows updates using powershell script
script: win-updates.ps1
become: yes
become_method: runas
become_user: SYSTEM
when:
- available_updates.updates is defined
- available_updates.found_update_count > 0
rescue:
- name: reboot the system to recover from a failed update
win_reboot:
reboot_timeout: 7200
- name: wait for system to be responsive after update
wait_for_connection:
delay: 60
sleep: 10
timeout: 600
- name: check to see if reboot is required
win_reg_stat:
path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update
name: CustomRebootRequired
register: update_reboot_required_key
- name: reboot the system to continue with the update
win_reboot:
reboot_timeout: 7200
when: update_reboot_required_key.exists
- name: check for missing updates
win_updates:
category_names:
- CriticalUpdates
- DefinitionUpdates
- SecurityUpdates
- UpdateRollups
- Updates
state: searched
register: missing_updates
- debug:
msg: |
{{ inventory_hostname }} has {{ missing_updates.found_update_count }} updates still missing.
{% for key, value in missing_updates.updates.items() %}
- {{ value.title }}
{% endfor %}
when: missing_updates.updates is defined
- block:
- name: set update count
set_fact:
update_retry_count: '{{ update_retry_count | default(0) | int + 1 }}'
- name: still more updates - need to retry
fail:
msg: >
'{{ inventory_hostname }} has {{ missing_updates.found_update_count }} updates still missing.
{{ (update_retry_limit | int) - (update_retry_count | int) }} more retries left'
when: ((update_retry_limit | int) - (update_retry_count | int) > 0)
when: missing_updates.found_update_count > 0
- name: ensure the CustomRebootRequired key doesn't exist
win_regedit:
path: HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\WindowsUpdate\Auto Update
name: CustomRebootRequired
state: absent
rescue:
- debug:
msg: "Still more updates remaining - retrying..."
- include_tasks: updates-powershell.yml

View File

@@ -0,0 +1,74 @@
---
- name: ensure Windows ADK with DISM is installed
win_chocolatey:
name: windows-adk-deploy
state: present
version: 10.0.17134.0
register: install_windows_adk_deploy
- name: ensure PATH contains Windows ADK
win_path:
scope: machine
state: present
elements: "C:\\Program Files (x86)\\Windows Kits\\10\\Assessment and Deployment Kit\\Deployment Tools\\amd64\\DISM"
- name: download hotfix group 1
win_get_url:
url: '{{ item.url }}'
dest: '{{ hotfix_download_location }}\{{ item.file }}'
loop: "{{ hotfixes_group_1 }}"
- name: install hotfix group 1
win_hotfix:
source: '{{ hotfix_download_location }}\{{ item.file }}'
state: present
register: hotfix_install_group_1
loop: "{{ hotfixes_group_1 }}"
- name: debug hotfix installation result
debug:
var: hotfix_install_group_1
- name: ensure hotfix file is removed (group 1)
win_file:
path: '{{ hotfix_download_location }}\{{ item.file }}'
state: absent
loop: "{{ hotfixes_group_1 }}"
- name: reboot from starting update
win_reboot:
- name: check for available updates
win_updates:
category_names: "{{ win_update_category_names }}"
blacklist: "{{ win_update_blacklist | default(omit) }}"
state: searched
register: available_updates
- debug:
msg: |
{{ inventory_hostname }} has {{ available_updates.found_update_count }} updates available.
{% for key, value in available_updates.updates.items() %}
- {{ value.title }}
{% endfor %}
when: available_updates.updates is defined
- include_tasks: updates-with-retry.yml
when:
- available_updates.updates is defined
- available_updates.found_update_count > 0
- name: check for missing updates.
win_updates:
state: searched
register: available_updates
- name: list missing updates
debug:
var: available_updates
- name: make sure Windows ADK with DISM for Server 2008 R2 is not installed
win_chocolatey:
name: windows-adk-deploy
state: absent

View File

@@ -0,0 +1,84 @@
---
- name: update over multiple reboots
block:
- block:
- name: install all windows updates
win_updates:
category_names: "{{ win_update_category_names }}"
blacklist: "{{ (win_update_blacklist | default([])) + (failed_kb | default([])) }}"
whitelist: "{{ win_update_whitelist | default(omit) }}"
reboot: yes
register: installed_updates
rescue:
- name: reboot the system to recover from a failed update
win_reboot:
reboot_timeout: 7200
- name: set failed KB to skip
set_fact:
failed_kb: "{{ failed_kb|default([]) + [installed_updates.msg | regex_replace('^.*\\((KB.*)\\).*','\\1')] }}"
when:
- installed_updates.msg is defined
- ('Failed' in installed_updates.msg)
- ('KB' in installed_updates.msg)
- name: fail to retry
fail:
msg: "There are failed updates: {{ failed_kb | join(' ') }}"
when:
- failed_kb is defined
- failed_kb | length > 0
- name: wait for system to be responsive after update
wait_for_connection:
delay: 60
sleep: 10
timeout: 600
- name: work on any skipped KB
win_updates:
category_names: "{{ win_update_category_names }}"
blacklist: "{{ win_update_blacklist | default(omit) }}"
whitelist: "{{ failed_kb | default([]) }}"
reboot: yes
register: installed_updates_retry_skipped
when:
- failed_kb is defined
- failed_kb | length > 0
- name: check for missing updates
win_updates:
category_names: "{{ win_update_category_names }}"
blacklist: "{{ win_update_blacklist | default(omit) }}"
state: searched
register: missing_updates
- debug:
msg: |
{{ inventory_hostname }} has {{ missing_updates.found_update_count }} updates still missing.
{% for key, value in missing_updates.updates.items() %}
- {{ value.title }}
{% endfor %}
when: missing_updates.updates is defined
- name: still more updates - need to retry
fail:
msg: >
'{{ inventory_hostname }} has {{ missing_updates.found_update_count }} updates still missing.
{{ (update_retry_limit | int) - (update_retry_count | int) }} more retries left'
when:
- missing_updates.found_update_count > 0
- ((update_retry_limit | int) - (update_retry_count | int) >= 0)
rescue:
- name: set update count
set_fact:
update_retry_count: '{{ update_retry_count | default(0) | int + 1 }}'
- debug:
msg: "Still more updates remaining - retrying... ({{ update_retry_count }}/{{ update_retry_limit }})"
- include_tasks: updates-with-retry.yml
when: ((update_retry_limit | int) - (update_retry_count | int) >= 0)

View File

@@ -0,0 +1,89 @@
---
- name: disable firewall for Domain, Public and Private profiles
win_shell: Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled False
when: "'Windows Server 2012' in ansible_distribution"
- name: disable firewall for Domain, Public and Private profiles
win_shell: netsh advfirewall set allprofiles state off
when: "'Windows Server 2008' in ansible_distribution"
- name: get used space before update
win_shell: Get-PSDrive C | Select-Object Used | ConvertTo-Json
register: used_space_before_update
ignore_errors: yes
- name: update Windows Update Agent on 2008
win_package:
path: http://download.windowsupdate.com/windowsupdate/redist/standalone/7.6.7600.320/windowsupdateagent-7.6-x64.exe
arguments:
- /quiet
- /norestart
- /wuforce
creates_path: C:\Windows\System32\wuaueng.dll
creates_version: 7.6.7600.320
when: "'Windows Server 2008' in ansible_distribution"
- include_tasks: updates-all.yml
vars:
win_update_category_names:
- CriticalUpdates
- DefinitionUpdates
- SecurityUpdates
- UpdateRollups
- Updates
when:
- install_updates | bool
- "'Windows Server 2008' not in ansible_distribution"
#- include_tasks: updates-powershell.yml
# when:
# - install_updates | bool
# - "'Windows Server 2008' in ansible_distribution"
- include_tasks: updates-win2008r2.yml
vars:
win_update_category_names:
- CriticalUpdates
- DefinitionUpdates
- SecurityUpdates
- UpdateRollups
- Updates
hotfix_download_location: "{{ ansible_env.TEMP }}"
hotfixes_group_1:
- kb: KB3020369
file: Windows6.1-KB3020369-x64.msu
url: https://download.microsoft.com/download/F/D/3/FD3728D5-0D2F-44A6-B7DA-1215CC0C9B75/Windows6.1-KB3020369-x64.msu
- kb: KB3125574
file: windows6.1-kb3125574-v4-x64_2dafb1d203c8964239af3048b5dd4b1264cd93b9.msu
url: http://download.windowsupdate.com/d/msdownload/update/software/updt/2016/05/windows6.1-kb3125574-v4-x64_2dafb1d203c8964239af3048b5dd4b1264cd93b9.msu
- kb: KB4474419
file: windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu
url: http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/09/windows6.1-kb4474419-v3-x64_b5614c6cea5cb4e198717789633dca16308ef79c.msu
- kb: KB4490628
file: windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu
url: http://download.windowsupdate.com/c/msdownload/update/software/secu/2019/03/windows6.1-kb4490628-x64_d3de52d6987f7c8bdc2c015dca69eac96047c76e.msu
when:
- install_updates | bool
- "'Windows Server 2008' in ansible_distribution"
- name: get used space after update
win_shell: Get-PSDrive C | Select-Object Used | ConvertTo-Json
register: used_space_after_update
ignore_errors: yes
- debug:
msg:
- "Used space before update: {{ ((used_space_before_update.stdout | from_json)['Used']|int / (1024*1024*1024)) | round(2, 'floor') }} GB"
- "Used space after update: {{ ((used_space_after_update.stdout | from_json)['Used']|int / (1024*1024*1024)) | round(2, 'floor') }} GB"
when:
- used_space_before_update.stdout is defined
- used_space_after_update.stdout is defined
- name: enabled firewall for Domain, Public and Private profiles
win_shell: Set-NetFirewallProfile -Profile Domain,Public,Private -Enabled True
when: "'Windows Server 2012' in ansible_distribution"
- name: enable firewall for Domain, Public and Private profiles
win_shell: netsh advfirewall set allprofiles state on
when: "'Windows Server 2008' in ansible_distribution"

View File

@@ -0,0 +1,98 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="oobeSystem">
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<UserAccounts>
{% if unattend.administrator_password is defined %}
<AdministratorPassword>
<Value>{{ unattend.administrator_password }}</Value>
<PlainText>true</PlainText>
</AdministratorPassword>
{% endif %}
{% if unattend.local_accounts is defined %}
<LocalAccounts>
{% for local_account in unattend.local_accounts %}
<LocalAccount wcm:action="add">
{% if local_account.password is defined %}
<Password>
<Value>{{ local_account.password }}</Value>
<PlainText>true</PlainText>
</Password>
{% endif %}
{% if local_account.description is defined %}
<Description>{{ local_account.description }}</Description>
{% endif %}
{% if local_account.display_name is defined %}
<DisplayName>{{ local_account.display_name }}</DisplayName>
{% endif %}
{% if local_account.group is defined %}
<Group>{{ local_account.group }}</Group>
{% endif %}
{% if local_account.name is defined %}
<Name>{{ local_account.name }}</Name>
{% endif %}
</LocalAccount>
{% endfor %}
</LocalAccounts>
{% endif %}
</UserAccounts>
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<NetworkLocation>Home</NetworkLocation>
<ProtectYourPC>1</ProtectYourPC>
<HideLocalAccountScreen>true</HideLocalAccountScreen>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<SkipMachineOOBE>true</SkipMachineOOBE>
<SkipUserOOBE>true</SkipUserOOBE>
</OOBE>
{% if enable_auto_logon and unattend.local_accounts and unattend.local_accounts[0].name and unattend.local_accounts[0].password %}
<AutoLogon>
<Password>
<Value>{{ unattend.local_accounts[0].password }}</Value>
<PlainText>true</PlainText>
</Password>
<Username>{{ unattend.local_accounts[0].name }}</Username>
<Enabled>true</Enabled>
</AutoLogon>
{% endif %}
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c powershell -Command "& $([scriptblock]::Create((New-Object Net.WebClient).DownloadString('https://raw.githubusercontent.com/ansible/ansible/devel/examples/scripts/ConfigureRemotingForAnsible.ps1'))) -ForceNewSSLCert -EnableCredSSP"</CommandLine>
<Description>Enable winrm</Description>
<Order>1</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c powershell -Command "Enable-WSManCredSSP -Role Server -Force"</CommandLine>
<Description>Enable winrm server role</Description>
<Order>2</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c powershell -Command "Set-Item -Path 'WSMan:\localhost\Service\Auth\CredSSP' -Value $true"</CommandLine>
<Description>Enable credssp authentication</Description>
<Order>3</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
</FirstLogonCommands>
<ShowWindowsLive>false</ShowWindowsLive>
</component>
</settings>
<settings pass="specialize">
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<OEMInformation>
<HelpCustomized>false</HelpCustomized>
</OEMInformation>
<!-- Rename computer here. -->
<ComputerName>{{ settings.computer_name | default('windows') }}</ComputerName>
<TimeZone>{{ settings.time_zone | default('Central Standard Time') }}</TimeZone>
<RegisteredOwner/>
</component>
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Security-SPP-UX" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<SkipAutoActivation>{{ settings.skip_auto_activation | default('true') }}</SkipAutoActivation>
</component>
</settings>
<cpi:offlineImage xmlns:cpi="urn:schemas-microsoft-com:cpi" cpi:source="catalog:d:/sources/install_windows 7 ENTERPRISE.clg"/>
</unattend>

View File

@@ -0,0 +1 @@
localhost

View File

@@ -0,0 +1,10 @@
---
- hosts: localhost
remote_user: Administrator
vars:
ansible_port: 5986
ansible_connection: winrm
ansible_winrm_transport: credssp
ansible_winrm_server_cert_validation: ignore
roles:
- ansible-role-windows_template_build

View File

@@ -0,0 +1,22 @@
---
unattend:
administrator_password: "{{ local_administrator_password }}"
local_accounts:
- name: "{{ local_account_username }}"
display_name: "{{ local_account_username }}"
description: "{{ local_account_username }} user"
group: Administrators
password: "{{ local_account_password }}"
settings:
computer_name: wintemp
time_zone: Central Standard Time
skip_auto_activation: true
autologin_registry:
- name: AutoAdminLogon
data: 1
- name: DefaultUserName
data: "{{ unattend.local_accounts[0].name }}"
- name: DefaultPassword
data: "{{ unattend.local_accounts[0].password }}"