├── .gitignore ├── README.md ├── Vagrantfile ├── forensic └── .gitkeep ├── maldev └── .gitkeep ├── playbook ├── .yamllint.yml ├── ansible.cfg ├── group_vars │ └── all ├── install.yml ├── inventory.ini ├── requirements.yml ├── roles │ ├── add_kape │ │ ├── defaults │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── vars │ │ │ └── main.yml │ ├── base_settings │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ ├── chocolatey.yml │ │ │ ├── chocolatey_pkg.yml │ │ │ ├── dark_mode.yml │ │ │ ├── debloat.yml │ │ │ ├── download_latest_github_asset.yml │ │ │ ├── explorer.yml │ │ │ ├── hostname.yml │ │ │ ├── keyboard_layout.yml │ │ │ ├── main.yml │ │ │ ├── mouse.yml │ │ │ ├── network.yml │ │ │ ├── start_menu.yml │ │ │ ├── taskbar.yml │ │ │ ├── windows_features.yml │ │ │ └── wsl2.yml │ │ └── vars │ │ │ └── main.yml │ ├── install_flare │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ ├── flarem.xml │ │ │ ├── flarevm_forensic.xml │ │ │ ├── flarevm_maldev.xml │ │ │ └── flarevm_reverse.xml │ │ ├── tasks │ │ │ └── main.yml │ │ └── vars │ │ │ └── main.yml │ ├── install_psdecode │ │ ├── defaults │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── vars │ │ │ └── main.yml │ └── updates │ │ ├── defaults │ │ └── main.yml │ │ ├── tasks │ │ ├── main.yml │ │ ├── store_apps_update.yml │ │ └── windows_update.yml │ │ └── vars │ │ └── main.yml └── vars │ ├── forensic-lab.yml │ ├── maldev-lab.yml │ └── reverse-lab.yml ├── reverse └── .gitkeep └── vagrant ├── ConfigureRemotingForAnsible.ps1 └── Install-WMF3Hotfix.ps1 /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant 2 | forensic/* 3 | !forensic/.gitkeep 4 | reverse/* 5 | !reverse/.gitkeep 6 | maldev/* 7 | !maldev/.gitkeep 8 | playbook/roles/install_idapro 9 | playbook/roles/add_kape/files/KAPE.zip -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # 🔬 Security Lab 2 | 3 | This repository aims to simplify the installation process for a security lab tailored for tasks such as reverse engineering, forensics, and malware development. 4 | 5 | ## 📺 How does it works ? 6 | 7 | First, a box of your choose will be downloaded and deployed. Then, provisioning will be performed on the VM, including setting up default configurations (like dark mode and keyboard layouts), updates, and FlareVM configuration. 8 | 9 | The tools installed in the VM are sourced from the VM-Packages repository maintained by Mandiant, which is utilized by FlareVM. The configuration is highly customizable, allowing you to add or remove packages according to your requirements. 10 | 11 | The tools installed comes from [VM-Packages](https://github.com/mandiant/VM-Packages) repository of Mandiant, which is used by [FlareVM](https://github.com/mandiant/flare-vm). The configuration is highly customizable, allowing you to add or remove packages according to your requirements in `playbook/roles/install_flare/files/*.xml`. 12 | 13 | ## 🧭 Repository Structure 14 | 15 | This repository is structured as follows: 16 | 17 | ```text 18 | 📦SecLab 19 | ┣ 📜README.md 20 | ┣ 📜Vagrantfile 21 | ┣ 📂vagrant 22 | ┃ ┗ 📜*.ps1 23 | ┣ 📂playbook 24 | ┃ ┣ 📂groups_vars 25 | ┃ ┃ ┗ 📜all 26 | ┃ ┣ 📂roles 27 | ┃ ┃ ┗ ... 28 | ┃ ┣ 📂vars 29 | ┃ ┃ ┗ 📜*.yml 30 | ┃ ┣ 📜install.yml 31 | ┃ ┣ 📜inventory.ini 32 | ┃ ┗ 📜requirements.yml 33 | ┣ 📂forensic 34 | ┣ 📂maldev 35 | ┗ 📂reverse 36 | ``` 37 | 38 | - `Vagrantfile`: Responsible for deploying all VMs. 39 | - `vagrant`: Contains scripts executed on the VMs by vagrant. 40 | - `playbook`: Holds provisioning data. 41 | - `groups_vars`: Contains a file called `all` with default variables for all configured hosts. 42 | - `roles`: Contains different tasks performed on the hosts in each roles. 43 | - `vars`: Contains files for each VM, specifying configurations. 44 | - `install.yml`: References the roles to be executed. 45 | - `inventory.ini`: Lists all hosts in the inventory. 46 | - `requirements.yml`: Lists the requirements for the Ansible playbook. 47 | - The last three folders contain shared files for each VM. 48 | 49 | ## 🪛 Installation 50 | 51 | ### Dependency 52 | 53 | To set up your own lab, you'll need the following programs: 54 | - [Vagrant](https://developer.hashicorp.com/vagrant/downloads) 55 | - [Ansible](https://docs.ansible.com/ansible/latest/installation_guide/intro_installation.html) 56 | 57 | Once done, perform `ansible-galaxy install -r playbook/requirements.yml` to install the necessary requirements. 58 | 59 | > ⚠️ You need to provide your own ZIP file for KAPE, which should be placed in `playbook/roles/add_kape/files/KAPE.zip`. 60 | 61 | ### Default 62 | 63 | Run `vagrant up ` to download, install, and provision the target. If the box is already present, you can execute `vagrant up --provision`. 64 | 65 | > If you wish to modify the machine name, you'll need to replace it in both `Vagrantfile` and `playbook/inventory.ini`. 66 | 67 | ## ⚒️ Troubleshooting during installation 68 | 69 | ### Windows Defender 70 | 71 | If *Windows Defender* detects a threat, disable it manually, then run: 72 | 73 | ```text 74 | $ ansible-playbook --limit="" --inventory-file=playbook/inventory.ini -v playbook/install.yml -t flarevm 75 | ``` 76 | 77 | > If you want to disable it totally, follow the instructions outlined by [commando-vm](https://github.com/mandiant/commando-vm?tab=readme-ov-file#pre-install-procedures). 78 | 79 | ### Boxstarter 80 | 81 | If you encounter an error related to *Boxstarter*, execute the following command in the VM: 82 | 83 | ```text 84 | PS> Set-ExecutionPolicy Unrestricted -Force 85 | PS> C:\Users\vagrant\Downloads\flare-vm\install.ps1 -customConfig C:\Users\vagrant\Downloads\flare-vm\config.xml -password vagrant -noChecks -noGui -noWait 86 | ``` 87 | 88 | ### Other 89 | 90 | If any other error interrupts the installer, instead of running again the entire workflow, you can trigger specific parts using tags: 91 | 92 | ```text 93 | $ ansible-playbook --limit="" --inventory-file=playbook/inventory.ini -v playbook/install.yml -t 94 | ``` 95 | 96 | ## ⬇️ Upgrading packages 97 | 98 | To upgrade all packages to their latest versions, run: 99 | 100 | ```text 101 | C:\Users\vagrant> choco upgrade all -y 102 | ``` 103 | 104 | ## 💸 Renewing license 105 | 106 | As the VMs provided by Vagrant are specifically intended for development purposes, their licenses are valid for only 90 days. However, you can extend this period 90 days more with: 107 | 108 | ```text 109 | C:\Users\vagrant> slmgr /rearm 110 | ``` 111 | 112 | ## 📘 Office 113 | 114 | For manual installation of Office, use the following command: 115 | 116 | ```text 117 | PS> choco install microsoft-office-deployment --params "/64bit /DisableUpdate:TRUE /Exclude:Publisher,PowerPoint,OneDrive,Outlook,OneNote,Lync,Groove,Access" --force 118 | ``` -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | # -*- mode: ruby -*- 2 | # vi: set ft=ruby : 3 | 4 | Vagrant.configure("2") do |config| 5 | # Boxes at https://vagrantcloud.com/search. 6 | config.vm.box = "" 7 | 8 | boxes = [ 9 | { 10 | :name => "forensic-lab", 11 | :box => "gusztavvargadr/windows-11-22h2-enterprise", 12 | :ip => "192.168.56.110", 13 | :shared_folder => "./forensic", 14 | :memory => 6144 15 | }, 16 | { 17 | :name => "reverse-lab", 18 | :box => "gusztavvargadr/windows-11-22h2-enterprise", 19 | :ip => "192.168.56.120", 20 | :shared_folder => "./reverse", 21 | :memory => 4096 22 | }, 23 | { 24 | :name => "maldev-lab", 25 | :box => "gusztavvargadr/windows-11-22h2-enterprise", 26 | :ip => "192.168.56.130", 27 | :shared_folder => "./maldev", 28 | :memory => 6144 29 | } 30 | ] 31 | 32 | config.vm.provider "virtualbox" do |vb| 33 | vb.gui = true 34 | vb.memory = 4096 35 | vb.cpus = 2 36 | vb.customize ["modifyvm", :id, "--groups", "/Lab"] 37 | vb.customize ["modifyvm", :id, "--clipboard-mode", "bidirectional"] 38 | end 39 | 40 | boxes.each do |box| 41 | config.vm.define box[:name] do |target| 42 | # Boxes at https://vagrantcloud.com/search. 43 | target.vm.box = box[:box] 44 | target.vm.hostname = box[:name] 45 | 46 | target.vm.network "private_network", ip: box[:ip] 47 | target.vm.synced_folder box[:shared_folder], "/vagrant", automount: true 48 | 49 | target.vm.provider "virtualbox" do |vb| 50 | vb.name = box[:name] 51 | vb.memory = box[:memory] 52 | end 53 | 54 | target.vm.guest = :windows 55 | target.vm.communicator = "winrm" 56 | target.winrm.basic_auth_only = true 57 | target.winrm.transport = :plaintext 58 | 59 | target.vm.provision :shell, :path => "vagrant/Install-WMF3Hotfix.ps1", privileged: false 60 | target.vm.provision :shell, :path => "vagrant/ConfigureRemotingForAnsible.ps1", privileged: false 61 | target.vm.provision "ansible" do |ansible| 62 | ansible.playbook = "playbook/install.yml" 63 | ansible.inventory_path = "playbook/inventory.ini" 64 | ansible.verbose = true 65 | # ansible.limit = box[:name] 66 | ansible.host_vars = { 67 | box[:name] => { "ansible_winrm_scheme" => "http" }, 68 | } 69 | end 70 | end 71 | end 72 | end -------------------------------------------------------------------------------- /forensic/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naacbin/SecLab/c3e789cef2fb7d0da99c373fbdeb315a3e493c12/forensic/.gitkeep -------------------------------------------------------------------------------- /maldev/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naacbin/SecLab/c3e789cef2fb7d0da99c373fbdeb315a3e493c12/maldev/.gitkeep -------------------------------------------------------------------------------- /playbook/.yamllint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | extends: default 3 | rules: 4 | line-length: 5 | max: 180 6 | -------------------------------------------------------------------------------- /playbook/ansible.cfg: -------------------------------------------------------------------------------- 1 | [defaults] 2 | become = true 3 | roles_path = roles 4 | gather_facts = yes -------------------------------------------------------------------------------- /playbook/group_vars/all: -------------------------------------------------------------------------------- 1 | --- 2 | ansible_user: vagrant 3 | ansible_password: vagrant 4 | ansible_connection: winrm 5 | ansible_winrm_server_cert_validation: ignore 6 | 7 | default: false 8 | updates: false 9 | install_flarevm: true 10 | -------------------------------------------------------------------------------- /playbook/install.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Configure Windows lab VM 3 | hosts: all 4 | vars_files: 5 | - "./vars/{{ inventory_hostname }}.yml" 6 | roles: 7 | - role: base_settings 8 | when: default 9 | tags: ["default"] 10 | 11 | - role: updates 12 | when: updates 13 | tags: ["updates"] 14 | 15 | - role: install_psdecode 16 | when: install_psdecode 17 | tags: ["psdecode"] 18 | 19 | - role: add_kape 20 | when: add_kape 21 | tags: ["kape"] 22 | 23 | # - role: install_idapro 24 | # when: install_idapro 25 | # tags: ["idapro"] 26 | 27 | - role: install_flare 28 | when: install_flarevm 29 | tags: ["flarevm"] 30 | -------------------------------------------------------------------------------- /playbook/inventory.ini: -------------------------------------------------------------------------------- 1 | forensic-lab ansible_host=192.168.56.110 2 | reverse-lab ansible_host=192.168.56.120 3 | maldev-lab ansible_host=192.168.56.130 4 | -------------------------------------------------------------------------------- /playbook/requirements.yml: -------------------------------------------------------------------------------- 1 | --- 2 | collections: 3 | - name: chocolatey.chocolatey 4 | - name: community.windows 5 | - name: ansible.windows 6 | -------------------------------------------------------------------------------- /playbook/roles/add_kape/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for add_kape 3 | -------------------------------------------------------------------------------- /playbook/roles/add_kape/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # - name: Ensure .net6 for CLI is installed 3 | # chocolatey.chocolatey.win_chocolatey: 4 | # name: "{{ item }}" 5 | # ignore_checksums: true 6 | # state: present 7 | # package_params: Skip32Bit 8 | # with_items: 9 | # - dotnet-6.0-runtime 10 | # - dotnet-6.0-desktopruntime 11 | 12 | - name: Copy KAPE on target 13 | ansible.windows.win_copy: 14 | src: "{{ add_kape_file }}" 15 | dest: '%UserProfile%\Downloads\' 16 | throttle: 1 17 | 18 | - name: Unzip KAPE 19 | community.windows.win_unzip: 20 | src: "%UserProfile%\\Downloads\\{{ add_kape_file }}" 21 | dest: '%UserProfile%\Desktop' 22 | delete_archive: true 23 | -------------------------------------------------------------------------------- /playbook/roles/add_kape/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | add_kape_file: "KAPE.zip" 3 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | base_settings_customize_keyboard_layout: true 3 | base_settings_remove_bloatware: true 4 | base_settings_install_choco: true 5 | base_settings_install_choco_pkg: false 6 | base_settings_install_windows_features: false 7 | base_settings_install_wsl2: false 8 | base_settings_configure_explorer: true 9 | base_settings_configure_taskbar: true 10 | base_settings_configure_start_menu: true 11 | base_settings_configure_network: true 12 | base_settings_disable_mouse_acceleration: true 13 | base_settings_enable_dark_mode: true 14 | base_settings_configure_hostname: false 15 | 16 | 17 | base_settings_keyboard_layout: 'fr-FR' 18 | base_settings_bloatware: 19 | - Microsoft.BingNews 20 | - Microsoft.BingWeather 21 | - Microsoft.GamingApp 22 | - Microsoft.GetHelp 23 | - Microsoft.Getstarted 24 | - Microsoft.Messaging 25 | - Microsoft.Microsoft3DViewer 26 | - Microsoft.MicrosoftOfficeHub 27 | - Microsoft.MicrosoftSolitaireCollection 28 | - Microsoft.MicrosoftStickyNotes 29 | - Microsoft.MixedReality.Portal 30 | # - Microsoft.MSPaint 31 | - Microsoft.Office.OneNote 32 | - Microsoft.OneConnect 33 | - Microsoft.People 34 | - Microsoft.PowerAutomateDesktop 35 | - Microsoft.Print3D 36 | - Microsoft.ScreenSketch 37 | - Microsoft.SkypeApp 38 | - Microsoft.Todos 39 | - Microsoft.Windows.Photos 40 | - Microsoft.WindowsAlarms 41 | # - Microsoft.WindowsCalculator 42 | - Microsoft.Wallet 43 | - Microsoft.WindowsCamera 44 | # - microsoft.windowscommunicationsapps 45 | - Microsoft.WindowsFeedbackHub 46 | - Microsoft.WindowsMaps 47 | - Microsoft.WindowsSoundRecorder 48 | - Microsoft.Xbox 49 | - Microsoft.Xbox.TCUI 50 | - Microsoft.XboxApp 51 | - Microsoft.XboxGameOverlay 52 | - Microsoft.XboxSpeechToTextOverlay 53 | - Microsoft.YourPhone 54 | - Microsoft.ZuneMusic 55 | - Microsoft.ZuneVideo 56 | - MicrosoftTeams 57 | 58 | base_settings_choco_packages: 59 | - 7zip 60 | - Firefox 61 | - adobereader 62 | 63 | # List of features: "Get-WindowsOptionalFeature -Online" 64 | base_settings_windows_features: 65 | Microsoft-Hyper-V: true 66 | 67 | # List of valid distributions that can be installed: 68 | # wsl-alpine 69 | # wsl-archlinux 70 | # wsl-debiangnulinux 71 | # wsl-fedoraremix 72 | # wsl-kalilinux 73 | # wsl-opensuse 74 | # wsl-sles 75 | # wsl-ubuntu-2004 76 | base_settings_wsl2_distribution: 'wsl-ubuntu-2004' 77 | 78 | base_settings_custom_hostname: 'DESKTOP-LURTVE3' 79 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Reboot computer 3 | ansible.windows.win_reboot: 4 | listen: 'reboot' 5 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/chocolatey.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure .NET Framework 4.8 requirement is satisfied for Chocolatey CLI v2.0.0+. 3 | block: 4 | - name: Ensure chocolatey is installed. 5 | chocolatey.chocolatey.win_chocolatey: 6 | name: 'chocolatey' 7 | state: present 8 | 9 | - name: Install requirement Microsoft .NET Framework 4.8. 10 | chocolatey.chocolatey.win_chocolatey: 11 | name: 'netfx-4.8' 12 | state: present 13 | notify: 'reboot' 14 | 15 | - name: Ensure chocolatey v2.0.0+ is installed. 16 | chocolatey.chocolatey.win_chocolatey: 17 | name: 'chocolatey' 18 | state: latest 19 | force: true 20 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/chocolatey_pkg.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure configured chocolatey packages are installed. 3 | chocolatey.chocolatey.win_chocolatey: 4 | name: "{{ item.name | default(item) }}" 5 | ignore_checksums: true 6 | state: present 7 | loop: "{{ base_settings_choco_packages }}" 8 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/dark_mode.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure system dark mode is enabled. 3 | ansible.windows.win_regedit: 4 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' 5 | name: 'SystemUsesLightTheme' 6 | data: 0 7 | type: dword 8 | 9 | - name: Ensure apps dark mode is enabled. 10 | ansible.windows.win_regedit: 11 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes\Personalize' 12 | name: 'AppsUseLightTheme' 13 | data: 0 14 | type: dword 15 | 16 | - name: Ensure dark theme is set. 17 | ansible.windows.win_regedit: 18 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Themes' 19 | name: "{{ item }}" 20 | data: 'C:\\Windows\\resources\\Themes\\dark.theme' 21 | type: string 22 | with_items: 23 | - 'CurrentTheme' 24 | - 'ThemeMRU' 25 | 26 | - name: Ensure wallpaper is set. 27 | ansible.windows.win_regedit: 28 | path: 'HKCU:\Control Panel\Desktop' 29 | name: 'WallPaper' 30 | data: 'C:\\Windows\\Web\\Wallpaper\\Windows\\img19.jpg' 31 | type: string 32 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/debloat.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure bloatware removed. 3 | ansible.windows.win_package: 4 | product_id: "{{ item.name | default(item) }}" 5 | state: absent 6 | loop: "{{ base_settings_bloatware }}" 7 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/download_latest_github_asset.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: "Find latest release from {{ repo }}" 3 | ansible.windows.win_uri: 4 | url: "https://api.github.com/repos/{{ org }}/{{ repo }}/releases/latest" 5 | return_content: true 6 | register: latest_release 7 | 8 | - name: Set the filename and download url 9 | ansible.builtin.set_fact: 10 | filename: "{{ asset_file.name }}" 11 | download_url: "{{ asset_file.browser_download_url }}" 12 | vars: 13 | asset_file: "{{ latest_release.json.assets | selectattr('name', 'contains', extension) | join() }}" 14 | 15 | - name: "Download {{ filename }}" 16 | ansible.windows.win_get_url: 17 | url: "{{ download_url }}" 18 | dest: "{{ ansible_env[\"TEMP\"] }}\\{{ filename }}" 19 | throttle: 1 20 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/explorer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure Explorer's default layout and view set to 'List'. 3 | ansible.windows.win_regedit: 4 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Streams\Defaults' 5 | name: '{5C4F28B5-F869-4E84-8E60-F11DB97C5CC7}' 6 | data: >- 7 | hex:1c,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,f1,f1,f1,f1,14,00,00,00,00,00,00,00,00,00,00,00,00,00,00,00,e8,02,00,00,e4,02,00,00,31,53,50,53,05,d5,cd,d5,9c,2e,1b,10,93,97,08,00,2b,2c,f9,ae,83,00,00,00,22,00,00,00,00,47,00,72,00,6f,00,75,00,70,00,42,00,79,00,4b,00,65,00,79,00,3a,00,46,00,4d,00,54,00,49,00,44,00,00,00,08,00,00,00,4e,00,00,00,7b,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,2d,00,30,00,30,00,30,00,30,00,2d,00,30,00,30,00,30,00,30,00,2d,00,30,00,30,00,30,00,30,00,2d,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,30,00,7d,00,00,00,00,00,33,00,00,00,22,00,00,00,00,47,00,72,00,6f,00,75,00,70,00,42,00,79,00,44,00,69,00,72,00,65,00,63,00,74,00,69,00,6f,00,6e,00,00,00,13,00,00,00,01,00,00,00,73,00,00,00,0a,00,00,00,00,53,00,6f,00,72,00,74,00,00,00,42,00,00,00,1e,00,00,00,70,00,72,00,6f,00,70,00,34,00,32,00,39,00,34,00,39,00,36,00,37,00,32,00,39,00,35,00,00,00,00,00,34,00,00,00,02,00,00,00,30,f1,25,b7,ef,47,1a,10,a5,f1,02,60,8c,9e,eb,ac,04,00,00,00,01,00,00,00,30,f1,25,b7,ef,47,1a,10,a5,f1,02,60,8c,9e,eb,ac,0a,00,00,00,01,00,00,00,25,00,00,00,14,00,00,00,00,47,00,72,00,6f,00,75,00,70,00,56,00,69,00,65,00,77,00,00,00,0b,00,00,00,00,00,00,00,1b,00,00,00,0a,00,00,00,00,4d,00,6f,00,64,00,65,00,00,00,13,00,00,00,03,00,00,00,23,00,00,00,12,00,00,00,00,49,00,63,00,6f,00,6e,00,53,00,69,00,7a,00,65,00,00,00,13,00,00,00,10,00,00,00,bd,00,00,00,10,00,00,00,00,43,00,6f,00,6c,00,49,00,6e,00,66,00,6f,00,00,00,42,00,00,00,1e,00,00,00,70,00,72,00,6f,00,70,00,34,00,32,00,39,00,34,00,39,00,36,00,37,00,32,00,39,00,35,00,00,00,00,00,78,00,00,00,fd,df,df,fd,10,00,00,00,00,00,00,00,00,00,00,00,04,00,00,00,18,00,00,00,30,f1,25,b7,ef,47,1a,10,a5,f1,02,60,8c,9e,eb,ac,0a,00,00,00,10,01,00,00,30,f1,25,b7,ef,47,1a,10,a5,f1,02,60,8c,9e,eb,ac,0e,00,00,00,90,00,00,00,30,f1,25,b7,ef,47,1a,10,a5,f1,02,60,8c,9e,eb,ac,04,00,00,00,78,00,00,00,30,f1,25,b7,ef,47,1a,10,a5,f1,02,60,8c,9e,eb,ac,0c,00,00,00,50,00,00,00,2f,00,00,00,1e,00,00,00,00,47,00,72,00,6f,00,75,00,70,00,42,00,79,00,4b,00,65,00,79,00,3a,00,50,00,49,00,44,00,00,00,13,00,00,00,00,00,00,00,1f,00,00,00,0e,00,00,00,00,46,00,46,00,6c,00,61,00,67,00,73,00,00,00,13,00,00,00,01,00,20,41,31,00,00,00,20,00,00,00,00,4c,00,6f,00,67,00,69,00,63,00,61,00,6c,00,56,00,69,00,65,00,77,00,4d,00,6f,00,64,00,65,00,00,00,13,00,00,00,04,00,00,00,00,00,00,00,00,00,00,00 8 | type: binary 9 | 10 | - name: Ensure Explorer includes the file extension in file names. 11 | ansible.windows.win_regedit: 12 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 13 | name: 'HideFileExt' 14 | data: 0 15 | type: dword 16 | 17 | - name: Ensure Explorer open itself to the Computer view. 18 | ansible.windows.win_regedit: 19 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 20 | name: 'LaunchTo' 21 | data: 1 22 | type: dword 23 | 24 | - name: Ensure Ribbon menu is disabled in Windows Explorer. 25 | ansible.windows.win_regedit: 26 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Ribbon' 27 | name: 'MinimizedStateTabletModeOff' 28 | data: 1 29 | type: dword 30 | 31 | - name: Ensure Right-click Context Menu enabled. 32 | ansible.windows.win_regedit: 33 | path: 'HKCU:\Software\Classes\CLSID\{86ca1aa0-34aa-4e8b-a509-50c905bae2a2}\InprocServer32' 34 | data: '' 35 | type: none 36 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/hostname.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure configured hostname set. 3 | ansible.windows.win_hostname: 4 | name: "{{ base_settings_custom_hostname }}" 5 | register: restart 6 | 7 | - name: Ensure new hostname applied (Reboot). 8 | ansible.windows.win_reboot: 9 | when: restart.reboot_required 10 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/keyboard_layout.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: French layout 3 | ansible.windows.win_shell: | 4 | "Set-WinUserLanguageList -LanguageList {{ base_settings_keyboard_layout }} -Force" 5 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Customize keyboard layout 3 | ansible.builtin.import_tasks: keyboard_layout.yml 4 | when: base_settings_customize_keyboard_layout 5 | 6 | - name: Remove bloatware 7 | ansible.builtin.import_tasks: debloat.yml 8 | when: base_settings_remove_bloatware 9 | 10 | - name: Install latest chocolatey version 11 | ansible.builtin.import_tasks: chocolatey.yml 12 | when: base_settings_install_choco 13 | 14 | - name: Install chocolatey packages 15 | ansible.builtin.import_tasks: chocolatey_pkg.yml 16 | when: base_settings_install_choco_pkg 17 | 18 | - name: Install Windows features 19 | ansible.builtin.import_tasks: windows_features.yml 20 | when: base_settings_install_windows_features 21 | 22 | - name: Install WSL 2 23 | ansible.builtin.import_tasks: wsl2.yml 24 | when: base_settings_install_wsl2 25 | 26 | - name: Configure explorer 27 | ansible.builtin.import_tasks: explorer.yml 28 | when: base_settings_configure_explorer 29 | 30 | - name: Configure TaskBar 31 | ansible.builtin.import_tasks: taskbar.yml 32 | when: base_settings_configure_taskbar 33 | 34 | - name: Configure Start Menu 35 | ansible.builtin.import_tasks: start_menu.yml 36 | when: base_settings_configure_start_menu 37 | 38 | - name: Configure network 39 | ansible.builtin.import_tasks: network.yml 40 | when: base_settings_configure_network 41 | 42 | - name: Disable mouse acceleration 43 | ansible.builtin.import_tasks: mouse.yml 44 | when: base_settings_disable_mouse_acceleration 45 | 46 | - name: Enable dark mode 47 | ansible.builtin.import_tasks: dark_mode.yml 48 | when: base_settings_enable_dark_mode 49 | 50 | - name: Configure hostname 51 | ansible.builtin.import_tasks: hostname.yml 52 | when: base_settings_configure_hostname 53 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/mouse.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure mouse acceleration is disabled. 3 | ansible.windows.win_regedit: 4 | path: 'HKCU:\Control Panel\Mouse' 5 | name: "{{ item }}" 6 | data: 0 7 | type: string 8 | loop: 9 | - MouseSpeed 10 | - MouseThreshold1 11 | - MouseThreshold2 12 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/network.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Supress network location Prompt. 3 | ansible.windows.win_regedit: 4 | path: 'HKLM:\SYSTEM\CurrentControlSet\Control\Network\NewNetworkWindowOff' 5 | 6 | - name: Sets any network connections detected to Private. 7 | ansible.windows.win_powershell: 8 | script: | 9 | Get-NetConnectionProfile | Set-NetConnectionProfile -NetworkCategory "Private" 10 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/start_menu.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure Automatic Install of Suggested Apps disabled. 3 | ansible.windows.win_regedit: 4 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' 5 | name: 'SilentInstalledAppsEnabled' 6 | data: 0 7 | type: dword 8 | 9 | - name: Ensure App Suggestions in Start menu disabled. 10 | ansible.windows.win_regedit: 11 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' 12 | name: 'SystemPaneSuggestionsEnabled' 13 | data: 0 14 | type: dword 15 | 16 | - name: Ensure popup "tips" about Windows disabled. 17 | ansible.windows.win_regedit: 18 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' 19 | name: 'SoftLandingEnabled' 20 | data: 0 21 | type: dword 22 | 23 | - name: Ensure 'Windows Welcome Experience' disabled. 24 | ansible.windows.win_regedit: 25 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\ContentDeliveryManager' 26 | name: "{{ item }}" 27 | data: 0 28 | type: dword 29 | loop: 30 | - SubscribedContent-310093Enabled 31 | - SubscribedContent-338388Enabled 32 | - SubscribedContent-338389Enabled 33 | - SubscribedContent-88000326Enabled 34 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/taskbar.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure 'Search' unpinned from Taskbar. 3 | ansible.windows.win_regedit: 4 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Search' 5 | name: 'SearchboxTaskbarMode' 6 | data: 0 7 | type: dword 8 | 9 | - name: Ensure Task View, Chat and Cortana are unpinned from Taskbar. 10 | ansible.windows.win_regedit: 11 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced' 12 | name: "{{ item }}" 13 | data: 0 14 | type: dword 15 | loop: 16 | - ShowCortanaButton 17 | - ShowTaskViewButton 18 | - TaskbarDa 19 | - TaskbarMn 20 | 21 | - name: Ensure 'News and Interests' unpinned from Taskbar. 22 | ansible.windows.win_regedit: 23 | path: HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Feeds' 24 | name: 'EnableFeeds' 25 | data: 0 26 | type: dword 27 | state: present 28 | 29 | - name: Ensure 'People' unpinned from Taskbar. 30 | ansible.windows.win_regedit: 31 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced\People' 32 | name: 'PeopleBand' 33 | data: 0 34 | type: dword 35 | 36 | - name: Ensure 'Edge', 'Store' other built-in shortcuts unpinned from Taskbar. 37 | ansible.windows.win_regedit: 38 | path: 'HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Taskband' 39 | name: 'Favorites' 40 | state: absent 41 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/windows_features.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Windows optional features. 3 | ansible.windows.win_optional_feature: 4 | name: "{{ windows_feature.key }}" 5 | state: "{{ 'present' if windows_feature.value else 'absent' }}" 6 | include_parent: true 7 | loop: "{{ base_settings_windows_features | dict2items }}" 8 | loop_control: 9 | loop_var: windows_feature 10 | register: feature_status 11 | 12 | - name: Reboot if Windows optional feature requires it. 13 | ansible.windows.win_reboot: 14 | when: item.reboot_required 15 | loop: "{{ feature_status.results }}" 16 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/tasks/wsl2.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure Windows Subsystem for Linux enabled. 3 | ansible.windows.win_optional_feature: 4 | name: 5 | - Microsoft-Windows-Subsystem-Linux 6 | - VirtualMachinePlatform 7 | state: present 8 | register: wsl_status 9 | 10 | - name: Restart the machine to complete the WSL install. 11 | ansible.windows.win_reboot: 12 | when: wsl_status.reboot_required 13 | 14 | - name: Ensure Linux kernel update package installed. 15 | chocolatey.chocolatey.win_chocolatey: 16 | name: wsl2 17 | ignore_checksums: true 18 | state: present 19 | 20 | - name: Ensure WSL2 is installed with "{{ base_settings_wsl2_distribution }}". 21 | chocolatey.chocolatey.win_chocolatey: 22 | name: "{{ base_settings_wsl2_distribution }}" 23 | ignore_checksums: true 24 | state: present 25 | -------------------------------------------------------------------------------- /playbook/roles/base_settings/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for base_settings 3 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | install_flare_config_file: 'flarevm.xml' 3 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/files/flarem.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 141 | 142 | 143 | 151 | 152 | 153 | 161 | 162 | 163 | 169 | 170 | 171 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 196 | 197 | 198 | 199 | 200 | 201 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/files/flarevm_forensic.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 101 | 102 | 103 | 111 | 112 | 113 | 121 | 122 | 123 | 129 | 130 | 131 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | 147 | 148 | 149 | 150 | 156 | 157 | 158 | 159 | 160 | 161 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/files/flarevm_maldev.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 74 | 75 | 76 | 84 | 85 | 86 | 94 | 95 | 96 | 102 | 103 | 104 | 110 | 111 | 112 | 113 | 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | 129 | 130 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/files/flarevm_reverse.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 86 | 87 | 88 | 96 | 97 | 98 | 106 | 107 | 108 | 114 | 115 | 116 | 122 | 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | 141 | 142 | 143 | 144 | 145 | 146 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Create directory FlareVM 3 | ansible.windows.win_file: 4 | path: '%UserProfile%\Downloads\flare-vm' 5 | state: directory 6 | 7 | - name: Download FlareVM installer 8 | ansible.windows.win_get_url: 9 | url: 'https://raw.githubusercontent.com/mandiant/flare-vm/main/install.ps1' 10 | dest: '%UserProfile%\Downloads\flare-vm\install.ps1' 11 | throttle: 1 12 | 13 | - name: Set custom config 14 | ansible.windows.win_copy: 15 | src: "{{ install_flare_config_file }}" 16 | dest: '%UserProfile%\Downloads\flare-vm\config.xml' 17 | throttle: 1 18 | 19 | - name: Install FlareVM 20 | ansible.windows.win_shell: | 21 | Set-ExecutionPolicy Unrestricted -Force 22 | .\install.ps1 -customConfig C:\Users\vagrant\Downloads\flare-vm\config.xml -password vagrant -noChecks -noGui -noWait 23 | args: 24 | chdir: '%UserProfile%\Downloads\flare-vm' 25 | -------------------------------------------------------------------------------- /playbook/roles/install_flare/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for install_flare 3 | -------------------------------------------------------------------------------- /playbook/roles/install_psdecode/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # defaults file for install_psdecode 3 | -------------------------------------------------------------------------------- /playbook/roles/install_psdecode/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Set PSDecode module directory 3 | ansible.builtin.set_fact: 4 | path_psdecode: '%System32%\WindowsPowerShell\v1.0\Modules\PSDecode' 5 | 6 | - name: Create PSDecode module directory 7 | ansible.windows.win_file: 8 | path: "{{ path_psdecode }}" 9 | state: directory 10 | 11 | - name: Download PSDecode module 12 | ansible.windows.win_get_url: 13 | url: 'https://raw.githubusercontent.com/R3MRUM/PSDecode/master/PSDecode.psm1' 14 | # https://github.com/CybercentreCanada/assemblyline-service-overpower/blob/main/tools/PSDecode.psm1 15 | dest: "{{ path_psdecode }}\PSDecode.psm1" 16 | -------------------------------------------------------------------------------- /playbook/roles/install_psdecode/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for install_psdecode 3 | -------------------------------------------------------------------------------- /playbook/roles/updates/defaults/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | updates_categories: 3 | # You can install only specific updates by uncommenting it 4 | # * - installs all updates 5 | # - "*" 6 | - Critical Updates 7 | - Definition Updates 8 | - Developer Kits 9 | - Feature Packs 10 | - Security Updates 11 | - Service Packs 12 | - Tools 13 | - Update Rollups 14 | - Updates 15 | - Upgrades 16 | -------------------------------------------------------------------------------- /playbook/roles/updates/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Install Windows Updates 3 | ansible.builtin.import_tasks: windows_update.yml 4 | 5 | - name: Update Windows Store Apps 6 | ansible.builtin.import_tasks: store_apps_update.yml 7 | -------------------------------------------------------------------------------- /playbook/roles/updates/tasks/store_apps_update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Launch update of Microsoft Store apps 3 | ansible.windows.win_shell: | 4 | Get-CimInstance -Namespace "Root\cimv2\mdm\dmmap" -ClassName "MDM_EnterpriseModernAppManagement_AppManagement01" | Invoke-CimMethod -MethodName UpdateScanMethod 5 | -------------------------------------------------------------------------------- /playbook/roles/updates/tasks/windows_update.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Ensure Windows updates installed. 3 | ansible.windows.win_updates: 4 | category_names: "{{ item }}" 5 | reboot: true 6 | loop: "{{ updates_categories }}" 7 | -------------------------------------------------------------------------------- /playbook/roles/updates/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # vars file for update 3 | -------------------------------------------------------------------------------- /playbook/vars/forensic-lab.yml: -------------------------------------------------------------------------------- 1 | --- 2 | install_psdecode: true 3 | install_flare_config_file: 'flarevm_forensic.xml' 4 | add_kape: true 5 | install_idapro: false 6 | -------------------------------------------------------------------------------- /playbook/vars/maldev-lab.yml: -------------------------------------------------------------------------------- 1 | --- 2 | install_psdecode: false 3 | install_flare_config_file: 'flarevm_maldev.xml' 4 | add_kape: false 5 | install_idapro: true 6 | -------------------------------------------------------------------------------- /playbook/vars/reverse-lab.yml: -------------------------------------------------------------------------------- 1 | --- 2 | install_psdecode: true 3 | install_flare_config_file: 'flarevm_reverse.xml' 4 | add_kape: false 5 | install_idapro: true 6 | -------------------------------------------------------------------------------- /reverse/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/naacbin/SecLab/c3e789cef2fb7d0da99c373fbdeb315a3e493c12/reverse/.gitkeep -------------------------------------------------------------------------------- /vagrant/ConfigureRemotingForAnsible.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 | # IMPORTANT: This script uses self-signed certificates and authentication mechanisms 11 | # that are intended for development environments and evaluation purposes only. 12 | # Production environments and deployments that are exposed on the network should 13 | # use CA-signed certificates and secure authentication mechanisms such as Kerberos. 14 | # 15 | # To run this script in Powershell: 16 | # 17 | # [Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12 18 | # $url = "https://raw.githubusercontent.com/ansible/ansible-documentation/devel/examples/scripts/ConfigureRemotingForAnsible.ps1" 19 | # $file = "$env:temp\ConfigureRemotingForAnsible.ps1" 20 | # 21 | # (New-Object -TypeName System.Net.WebClient).DownloadFile($url, $file) 22 | # 23 | # powershell.exe -ExecutionPolicy ByPass -File $file 24 | # 25 | # All events are logged to the Windows EventLog, useful for unattended runs. 26 | # 27 | # Use option -Verbose in order to see the verbose output messages. 28 | # 29 | # Use option -CertValidityDays to specify how long this certificate is valid 30 | # starting from today. So you would specify -CertValidityDays 3650 to get 31 | # a 10-year valid certificate. 32 | # 33 | # Use option -ForceNewSSLCert if the system has been SysPreped and a new 34 | # SSL Certificate must be forced on the WinRM Listener when re-running this 35 | # script. This is necessary when a new SID and CN name is created. 36 | # 37 | # Use option -EnableCredSSP to enable CredSSP as an authentication option. 38 | # 39 | # Use option -DisableBasicAuth to disable basic authentication. 40 | # 41 | # Use option -SkipNetworkProfileCheck to skip the network profile check. 42 | # Without specifying this the script will only run if the device's interfaces 43 | # are in DOMAIN or PRIVATE zones. Provide this switch if you want to enable 44 | # WinRM on a device with an interface in PUBLIC zone. 45 | # 46 | # Use option -SubjectName to specify the CN name of the certificate. This 47 | # defaults to the system's hostname and generally should not be specified. 48 | 49 | # Written by Trond Hindenes 50 | # Updated by Chris Church 51 | # Updated by Michael Crilly 52 | # Updated by Anton Ouzounov 53 | # Updated by Nicolas Simond 54 | # Updated by Dag Wieërs 55 | # Updated by Jordan Borean 56 | # Updated by Erwan Quélin 57 | # Updated by David Norman 58 | # 59 | # Version 1.0 - 2014-07-06 60 | # Version 1.1 - 2014-11-11 61 | # Version 1.2 - 2015-05-15 62 | # Version 1.3 - 2016-04-04 63 | # Version 1.4 - 2017-01-05 64 | # Version 1.5 - 2017-02-09 65 | # Version 1.6 - 2017-04-18 66 | # Version 1.7 - 2017-11-23 67 | # Version 1.8 - 2018-02-23 68 | # Version 1.9 - 2018-09-21 69 | 70 | # Support -Verbose option 71 | [CmdletBinding()] 72 | 73 | Param ( 74 | [string]$SubjectName = $env:COMPUTERNAME, 75 | [int]$CertValidityDays = 1095, 76 | [switch]$SkipNetworkProfileCheck, 77 | $CreateSelfSignedCert = $true, 78 | [switch]$ForceNewSSLCert, 79 | [switch]$GlobalHttpFirewallAccess, 80 | [switch]$DisableBasicAuth = $false, 81 | [switch]$EnableCredSSP 82 | ) 83 | 84 | Function Write-ProgressLog { 85 | $Message = $args[0] 86 | Write-EventLog -LogName Application -Source $EventSource -EntryType Information -EventId 1 -Message $Message 87 | } 88 | 89 | Function Write-VerboseLog { 90 | $Message = $args[0] 91 | Write-Verbose $Message 92 | Write-ProgressLog $Message 93 | } 94 | 95 | Function Write-HostLog { 96 | $Message = $args[0] 97 | Write-Output $Message 98 | Write-ProgressLog $Message 99 | } 100 | 101 | Function New-LegacySelfSignedCert { 102 | Param ( 103 | [string]$SubjectName, 104 | [int]$ValidDays = 1095 105 | ) 106 | 107 | $hostnonFQDN = $env:computerName 108 | $hostFQDN = [System.Net.Dns]::GetHostByName(($env:computerName)).Hostname 109 | $SignatureAlgorithm = "SHA256" 110 | 111 | $name = New-Object -COM "X509Enrollment.CX500DistinguishedName.1" 112 | $name.Encode("CN=$SubjectName", 0) 113 | 114 | $key = New-Object -COM "X509Enrollment.CX509PrivateKey.1" 115 | $key.ProviderName = "Microsoft Enhanced RSA and AES Cryptographic Provider" 116 | $key.KeySpec = 1 117 | $key.Length = 4096 118 | $key.SecurityDescriptor = "D:PAI(A;;0xd01f01ff;;;SY)(A;;0xd01f01ff;;;BA)(A;;0x80120089;;;NS)" 119 | $key.MachineContext = 1 120 | $key.Create() 121 | 122 | $serverauthoid = New-Object -COM "X509Enrollment.CObjectId.1" 123 | $serverauthoid.InitializeFromValue("1.3.6.1.5.5.7.3.1") 124 | $ekuoids = New-Object -COM "X509Enrollment.CObjectIds.1" 125 | $ekuoids.Add($serverauthoid) 126 | $ekuext = New-Object -COM "X509Enrollment.CX509ExtensionEnhancedKeyUsage.1" 127 | $ekuext.InitializeEncode($ekuoids) 128 | 129 | $cert = New-Object -COM "X509Enrollment.CX509CertificateRequestCertificate.1" 130 | $cert.InitializeFromPrivateKey(2, $key, "") 131 | $cert.Subject = $name 132 | $cert.Issuer = $cert.Subject 133 | $cert.NotBefore = (Get-Date).AddDays(-1) 134 | $cert.NotAfter = $cert.NotBefore.AddDays($ValidDays) 135 | 136 | $SigOID = New-Object -ComObject X509Enrollment.CObjectId 137 | $SigOID.InitializeFromValue(([Security.Cryptography.Oid]$SignatureAlgorithm).Value) 138 | 139 | [string[]] $AlternativeName += $hostnonFQDN 140 | $AlternativeName += $hostFQDN 141 | $IAlternativeNames = New-Object -ComObject X509Enrollment.CAlternativeNames 142 | 143 | foreach ($AN in $AlternativeName) { 144 | $AltName = New-Object -ComObject X509Enrollment.CAlternativeName 145 | $AltName.InitializeFromString(0x3, $AN) 146 | $IAlternativeNames.Add($AltName) 147 | } 148 | 149 | $SubjectAlternativeName = New-Object -ComObject X509Enrollment.CX509ExtensionAlternativeNames 150 | $SubjectAlternativeName.InitializeEncode($IAlternativeNames) 151 | 152 | [String[]]$KeyUsage = ("DigitalSignature", "KeyEncipherment") 153 | $KeyUsageObj = New-Object -ComObject X509Enrollment.CX509ExtensionKeyUsage 154 | $KeyUsageObj.InitializeEncode([int][Security.Cryptography.X509Certificates.X509KeyUsageFlags]($KeyUsage)) 155 | $KeyUsageObj.Critical = $true 156 | 157 | $cert.X509Extensions.Add($KeyUsageObj) 158 | $cert.X509Extensions.Add($ekuext) 159 | $cert.SignatureInformation.HashAlgorithm = $SigOID 160 | $CERT.X509Extensions.Add($SubjectAlternativeName) 161 | $cert.Encode() 162 | 163 | $enrollment = New-Object -COM "X509Enrollment.CX509Enrollment.1" 164 | $enrollment.InitializeFromRequest($cert) 165 | $certdata = $enrollment.CreateRequest(0) 166 | $enrollment.InstallResponse(2, $certdata, 0, "") 167 | 168 | # extract/return the thumbprint from the generated cert 169 | $parsed_cert = New-Object System.Security.Cryptography.X509Certificates.X509Certificate2 170 | $parsed_cert.Import([System.Text.Encoding]::UTF8.GetBytes($certdata)) 171 | 172 | return $parsed_cert.Thumbprint 173 | } 174 | 175 | Function Enable-GlobalHttpFirewallAccess { 176 | Write-Verbose "Forcing global HTTP firewall access" 177 | # this is a fairly naive implementation; could be more sophisticated about rule matching/collapsing 178 | $fw = New-Object -ComObject HNetCfg.FWPolicy2 179 | 180 | # try to find/enable the default rule first 181 | $add_rule = $false 182 | $matching_rules = $fw.Rules | Where-Object { $_.Name -eq "Windows Remote Management (HTTP-In)" } 183 | $rule = $null 184 | If ($matching_rules) { 185 | If ($matching_rules -isnot [Array]) { 186 | Write-Verbose "Editing existing single HTTP firewall rule" 187 | $rule = $matching_rules 188 | } 189 | Else { 190 | # try to find one with the All or Public profile first 191 | Write-Verbose "Found multiple existing HTTP firewall rules..." 192 | $rule = $matching_rules | ForEach-Object { $_.Profiles -band 4 }[0] 193 | 194 | If (-not $rule -or $rule -is [Array]) { 195 | Write-Verbose "Editing an arbitrary single HTTP firewall rule (multiple existed)" 196 | # oh well, just pick the first one 197 | $rule = $matching_rules[0] 198 | } 199 | } 200 | } 201 | 202 | If (-not $rule) { 203 | Write-Verbose "Creating a new HTTP firewall rule" 204 | $rule = New-Object -ComObject HNetCfg.FWRule 205 | $rule.Name = "Windows Remote Management (HTTP-In)" 206 | $rule.Description = "Inbound rule for Windows Remote Management via WS-Management. [TCP 5985]" 207 | $add_rule = $true 208 | } 209 | 210 | $rule.Profiles = 0x7FFFFFFF 211 | $rule.Protocol = 6 212 | $rule.LocalPorts = 5985 213 | $rule.RemotePorts = "*" 214 | $rule.LocalAddresses = "*" 215 | $rule.RemoteAddresses = "*" 216 | $rule.Enabled = $true 217 | $rule.Direction = 1 218 | $rule.Action = 1 219 | $rule.Grouping = "Windows Remote Management" 220 | 221 | If ($add_rule) { 222 | $fw.Rules.Add($rule) 223 | } 224 | 225 | Write-Verbose "HTTP firewall rule $($rule.Name) updated" 226 | } 227 | 228 | # Setup error handling. 229 | Trap { 230 | $_ 231 | Exit 1 232 | } 233 | $ErrorActionPreference = "Stop" 234 | 235 | # Get the ID and security principal of the current user account 236 | $myWindowsID = [System.Security.Principal.WindowsIdentity]::GetCurrent() 237 | $myWindowsPrincipal = new-object System.Security.Principal.WindowsPrincipal($myWindowsID) 238 | 239 | # Get the security principal for the Administrator role 240 | $adminRole = [System.Security.Principal.WindowsBuiltInRole]::Administrator 241 | 242 | # Check to see if we are currently running "as Administrator" 243 | if (-Not $myWindowsPrincipal.IsInRole($adminRole)) { 244 | Write-Output "ERROR: You need elevated Administrator privileges in order to run this script." 245 | Write-Output " Start Windows PowerShell by using the Run as Administrator option." 246 | Exit 2 247 | } 248 | 249 | $EventSource = $MyInvocation.MyCommand.Name 250 | If (-Not $EventSource) { 251 | $EventSource = "Powershell CLI" 252 | } 253 | 254 | If ([System.Diagnostics.EventLog]::Exists('Application') -eq $False -or [System.Diagnostics.EventLog]::SourceExists($EventSource) -eq $False) { 255 | New-EventLog -LogName Application -Source $EventSource 256 | } 257 | 258 | # Detect PowerShell version. 259 | If ($PSVersionTable.PSVersion.Major -lt 3) { 260 | Write-ProgressLog "PowerShell version 3 or higher is required." 261 | Throw "PowerShell version 3 or higher is required." 262 | } 263 | 264 | # Find and start the WinRM service. 265 | Write-Verbose "Verifying WinRM service." 266 | If (!(Get-Service "WinRM")) { 267 | Write-ProgressLog "Unable to find the WinRM service." 268 | Throw "Unable to find the WinRM service." 269 | } 270 | ElseIf ((Get-Service "WinRM").Status -ne "Running") { 271 | Write-Verbose "Setting WinRM service to start automatically on boot." 272 | Set-Service -Name "WinRM" -StartupType Automatic 273 | Write-ProgressLog "Set WinRM service to start automatically on boot." 274 | Write-Verbose "Starting WinRM service." 275 | Start-Service -Name "WinRM" -ErrorAction Stop 276 | Write-ProgressLog "Started WinRM service." 277 | 278 | } 279 | 280 | # WinRM should be running; check that we have a PS session config. 281 | If (!(Get-PSSessionConfiguration -Verbose:$false) -or (!(Get-ChildItem WSMan:\localhost\Listener))) { 282 | If ($SkipNetworkProfileCheck) { 283 | Write-Verbose "Enabling PS Remoting without checking Network profile." 284 | Enable-PSRemoting -SkipNetworkProfileCheck -Force -ErrorAction Stop 285 | Write-ProgressLog "Enabled PS Remoting without checking Network profile." 286 | } 287 | Else { 288 | Write-Verbose "Enabling PS Remoting." 289 | Enable-PSRemoting -Force -ErrorAction Stop 290 | Write-ProgressLog "Enabled PS Remoting." 291 | } 292 | } 293 | Else { 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 | # We cannot use New-SelfSignedCertificate on 2012R2 and earlier 315 | $thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays 316 | Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint" 317 | 318 | # Create the hashtables of settings to be used. 319 | $valueset = @{ 320 | Hostname = $SubjectName 321 | CertificateThumbprint = $thumbprint 322 | } 323 | 324 | $selectorset = @{ 325 | Transport = "HTTPS" 326 | Address = "*" 327 | } 328 | 329 | Write-Verbose "Enabling SSL listener." 330 | New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset 331 | Write-ProgressLog "Enabled SSL listener." 332 | } 333 | Else { 334 | Write-Verbose "SSL listener is already active." 335 | 336 | # Force a new SSL cert on Listener if the $ForceNewSSLCert 337 | If ($ForceNewSSLCert) { 338 | 339 | # We cannot use New-SelfSignedCertificate on 2012R2 and earlier 340 | $thumbprint = New-LegacySelfSignedCert -SubjectName $SubjectName -ValidDays $CertValidityDays 341 | Write-HostLog "Self-signed SSL certificate generated; thumbprint: $thumbprint" 342 | 343 | $valueset = @{ 344 | CertificateThumbprint = $thumbprint 345 | Hostname = $SubjectName 346 | } 347 | 348 | # Delete the listener for SSL 349 | $selectorset = @{ 350 | Address = "*" 351 | Transport = "HTTPS" 352 | } 353 | Remove-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset 354 | 355 | # Add new Listener with new SSL cert 356 | New-WSManInstance -ResourceURI 'winrm/config/Listener' -SelectorSet $selectorset -ValueSet $valueset 357 | } 358 | } 359 | 360 | # Check for basic authentication. 361 | $basicAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object { $_.Name -eq "Basic" } 362 | 363 | If ($DisableBasicAuth) { 364 | If (($basicAuthSetting.Value) -eq $true) { 365 | Write-Verbose "Disabling basic auth support." 366 | Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $false 367 | Write-ProgressLog "Disabled basic auth support." 368 | } 369 | Else { 370 | Write-Verbose "Basic auth is already disabled." 371 | } 372 | } 373 | Else { 374 | If (($basicAuthSetting.Value) -eq $false) { 375 | Write-Verbose "Enabling basic auth support." 376 | Set-Item -Path "WSMan:\localhost\Service\Auth\Basic" -Value $true 377 | Write-ProgressLog "Enabled basic auth support." 378 | } 379 | Else { 380 | Write-Verbose "Basic auth is already enabled." 381 | } 382 | } 383 | 384 | # If EnableCredSSP if set to true 385 | If ($EnableCredSSP) { 386 | # Check for CredSSP authentication 387 | $credsspAuthSetting = Get-ChildItem WSMan:\localhost\Service\Auth | Where-Object { $_.Name -eq "CredSSP" } 388 | If (($credsspAuthSetting.Value) -eq $false) { 389 | Write-Verbose "Enabling CredSSP auth support." 390 | Enable-WSManCredSSP -role server -Force 391 | Write-ProgressLog "Enabled CredSSP auth support." 392 | } 393 | } 394 | 395 | If ($GlobalHttpFirewallAccess) { 396 | Enable-GlobalHttpFirewallAccess 397 | } 398 | 399 | # Configure firewall to allow WinRM HTTPS connections. 400 | $fwtest1 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" 401 | $fwtest2 = netsh advfirewall firewall show rule name="Allow WinRM HTTPS" profile=any 402 | If ($fwtest1.count -lt 5) { 403 | Write-Verbose "Adding firewall rule to allow WinRM HTTPS." 404 | netsh advfirewall firewall add rule profile=any name="Allow WinRM HTTPS" dir=in localport=5986 protocol=TCP action=allow 405 | Write-ProgressLog "Added firewall rule to allow WinRM HTTPS." 406 | } 407 | ElseIf (($fwtest1.count -ge 5) -and ($fwtest2.count -lt 5)) { 408 | Write-Verbose "Updating firewall rule to allow WinRM HTTPS for any profile." 409 | netsh advfirewall firewall set rule name="Allow WinRM HTTPS" new profile=any 410 | Write-ProgressLog "Updated firewall rule to allow WinRM HTTPS for any profile." 411 | } 412 | Else { 413 | Write-Verbose "Firewall rule already exists to allow WinRM HTTPS." 414 | } 415 | 416 | # Test a remoting connection to localhost, which should work. 417 | $httpResult = Invoke-Command -ComputerName "localhost" -ScriptBlock { $using:env:COMPUTERNAME } -ErrorVariable httpError -ErrorAction SilentlyContinue 418 | $httpsOptions = New-PSSessionOption -SkipCACheck -SkipCNCheck -SkipRevocationCheck 419 | 420 | $httpsResult = New-PSSession -UseSSL -ComputerName "localhost" -SessionOption $httpsOptions -ErrorVariable httpsError -ErrorAction SilentlyContinue 421 | 422 | If ($httpResult -and $httpsResult) { 423 | Write-Verbose "HTTP: Enabled | HTTPS: Enabled" 424 | } 425 | ElseIf ($httpsResult -and !$httpResult) { 426 | Write-Verbose "HTTP: Disabled | HTTPS: Enabled" 427 | } 428 | ElseIf ($httpResult -and !$httpsResult) { 429 | Write-Verbose "HTTP: Enabled | HTTPS: Disabled" 430 | } 431 | Else { 432 | Write-ProgressLog "Unable to establish an HTTP or HTTPS remoting session." 433 | Throw "Unable to establish an HTTP or HTTPS remoting session." 434 | } 435 | Write-VerboseLog "PS Remoting has been successfully configured for Ansible." 436 | -------------------------------------------------------------------------------- /vagrant/Install-WMF3Hotfix.ps1: -------------------------------------------------------------------------------- 1 | #Requires -Version 3.0 2 | <#PSScriptInfo 3 | .VERSION 1.0 4 | .GUID 6cf319d1-8c50-460b-99ee-71b11cf7270d 5 | .AUTHOR 6 | Jordan Borean 7 | .COPYRIGHT 8 | Jordan Borean 2017 9 | .TAGS 10 | PowerShell,Ansible,WinRM,WMF,Hotfix 11 | .LICENSEURI https://github.com/jborean93/ansible-windows/blob/master/LICENSE 12 | .PROJECTURI https://github.com/jborean93/ansible-windows 13 | .RELEASENOTES 14 | Version 1.0: 2017-09-27 15 | Initial script created 16 | #> 17 | 18 | <# 19 | .DESCRIPTION 20 | The script will install the WinRM hotfix KB2842230 which fixes the memory 21 | issues that occur when running over WinRM with WMF 3.0. 22 | The script will; 23 | 1. Detect if running on PS version 3.0 and exit if it is not 24 | 2. Check if KB2842230 is already installed and exit if it is 25 | 3. Download the hotfix from Microsoft server's based on the OS version 26 | 4. Extract the .msu file from the downloaded hotfix 27 | 5. Install the .msu silently 28 | 6. Detect if a reboot is required and prompt whether the user wants to restart 29 | 30 | Once the install is complete, if the install process returns an exit 31 | code of 3010, it will ask the user whether to restart the computer now 32 | or whether it will be done later. 33 | 34 | See https://github.com/jborean93/ansible-windows/tree/master/scripts for more 35 | details. 36 | .PARAMETER Verbose 37 | [switch] - Whether to display Verbose logs on the console 38 | .EXAMPLE 39 | powershell.exe -ExecutionPolicy ByPass -File Install-WMF3Hotfix.ps1 40 | .EXAMPLE 41 | powershell.exe -ExecutionPolicy ByPass -File Install-WMF3Hotfix.ps1 -Verbose 42 | #> 43 | 44 | [CmdletBinding()] 45 | Param() 46 | 47 | $ErrorActionPreference = "Stop" 48 | if ($verbose) { 49 | $VerbosePreference = "Continue" 50 | } 51 | 52 | Function Run-Process($executable, $arguments) { 53 | $process = New-Object -TypeName System.Diagnostics.Process 54 | $psi = $process.StartInfo 55 | $psi.FileName = $executable 56 | $psi.Arguments = $arguments 57 | Write-Verbose -Message "starting new process '$executable $arguments'" 58 | $process.Start() | Out-Null 59 | 60 | $process.WaitForExit() | Out-Null 61 | $exit_code = $process.ExitCode 62 | Write-Verbose -Message "process completed with exit code '$exit_code'" 63 | 64 | return $exit_code 65 | } 66 | 67 | Function Download-File($url, $path) { 68 | Write-Verbose -Message "downloading url '$url' to '$path'" 69 | $client = New-Object -TypeName System.Net.WebClient 70 | $client.DownloadFile($url, $path) 71 | } 72 | 73 | Function Extract-Zip($zip, $dest) { 74 | Write-Verbose -Message "extracting '$zip' to '$dest'" 75 | try { 76 | Add-Type -AssemblyName System.IO.Compression.FileSystem > $null 77 | $legacy = $false 78 | } catch { 79 | $legacy = $true 80 | } 81 | 82 | if ($legacy) { 83 | $shell = New-Object -ComObject Shell.Application 84 | $zip_src = $shell.NameSpace($zip) 85 | $zip_dest = $shell.NameSpace($dest) 86 | $zip_dest.CopyHere($zip_src.Items(), 1044) 87 | } else { 88 | [System.IO.Compression.ZipFile]::ExtractToDirectory($zip, $dest) 89 | } 90 | } 91 | 92 | $tmp_dir = $env:temp 93 | $kb = "KB2842230" 94 | if ($PSVersionTable.PSVersion.Major -ne 3) { 95 | Write-Verbose -Message "$kb is only applicable with Powershell v3, no action required" 96 | exit 0 97 | } 98 | 99 | $hotfix_installed = Get-Hotfix -Id $kb -ErrorAction SilentlyContinue 100 | if ($hotfix_installed -ne $null) { 101 | Write-Verbose -Message "$kb is already installed" 102 | exit 0 103 | } 104 | 105 | if (-not (Test-Path -Path $tmp_dir)) { 106 | New-Item -Path $tmp_dir -ItemType Directory > $null 107 | } 108 | $os_version = [Version](Get-Item -Path "$env:SystemRoot\System32\kernel32.dll").VersionInfo.ProductVersion 109 | $host_string = "$($os_version.Major).$($os_version.Minor)-$($env:PROCESSOR_ARCHITECTURE)" 110 | switch($host_string) { 111 | # These URLS point to the Ansible Core CI S3 bucket, MS no longer provide a link to Server 2008 so we need to 112 | # rely on this URL. There are no guarantees this will stay up in the future. 113 | "6.0-x86" { 114 | $url = "https://s3.amazonaws.com/ansible-ci-files/hotfixes/KB2842230/464091_intl_i386_zip.exe" 115 | } 116 | "6.0-AMD64" { 117 | $url = "https://s3.amazonaws.com/ansible-ci-files/hotfixes/KB2842230/464090_intl_x64_zip.exe" 118 | } 119 | "6.1-x86" { 120 | $url = "https://s3.amazonaws.com/ansible-ci-files/hotfixes/KB2842230/463983_intl_i386_zip.exe" 121 | } 122 | "6.1-AMD64" { 123 | $url = "https://s3.amazonaws.com/ansible-ci-files/hotfixes/KB2842230/463984_intl_x64_zip.exe" 124 | } 125 | "6.2-x86" { 126 | $url = "https://s3.amazonaws.com/ansible-ci-files/hotfixes/KB2842230/463940_intl_i386_zip.exe" 127 | } 128 | "6.2-AMD64" { 129 | $url = "https://s3.amazonaws.com/ansible-ci-files/hotfixes/KB2842230/463941_intl_x64_zip.exe" 130 | } 131 | } 132 | 133 | $filename = $url.Split("/")[-1] 134 | $compressed_file = "$tmp_dir\$($filename).zip" 135 | Download-File -url $url -path $compressed_file 136 | Extract-Zip -zip $compressed_file -dest $tmp_dir 137 | $file = Get-Item -Path "$tmp_dir\*$kb*.msu" 138 | if ($file -eq $null) { 139 | Write-Error -Message "unable to find extracted msu file for hotfix KB" 140 | exit 1 141 | } 142 | 143 | $exit_code = Run-Process -executable $file.FullName -arguments "/quiet /norestart" 144 | if ($exit_code -eq 3010) { 145 | Write-Verbose "need to restart computer after hotfix $kb install" 146 | Restart-Computer -Confirm 147 | } elseif ($exit_code -ne 0) { 148 | Write-Error -Message "failed to install hotfix $($kb): exit code $exit_code" 149 | } else { 150 | Write-Verbose -Message "hotfix $kb install complete" 151 | } 152 | exit $exit_code 153 | --------------------------------------------------------------------------------