2 Commits

Author SHA1 Message Date
b4f62b465d Update packer windows-update plugin
All checks were successful
continuous-integration/drone/push Build is passing
2021-10-25 13:32:57 +02:00
060ac37dc0 Update VMware Tools 2021-10-25 13:12:00 +02:00
85 changed files with 998 additions and 943 deletions

View File

@@ -14,56 +14,54 @@ steps:
- name: Debugging information - name: Debugging information
image: bv11-cr01.bessems.eu/library/packer-extended image: bv11-cr01.bessems.eu/library/packer-extended
commands: commands:
- ansible --version
- ovftool --version
- packer --version
- yamllint --version - yamllint --version
- name: Kubernetes Bootstrap Appliance - packer --version
- pwsh --version
- ovftool --version
- name: Windows 10
image: bv11-cr01.bessems.eu/library/packer-extended image: bv11-cr01.bessems.eu/library/packer-extended
pull: always pull: always
commands: commands:
- sed -i -e "s/<<img-productkey>>/$${PRODUCTKEY}/" packer/preseed/Windows10/Autounattend.xml
- | - |
sed -i -e "s/<<img-password>>/$${SSH_PASSWORD}/g" \ sed -i -e "s/<<img-password>>/$${WINRM_PASSWORD}/g" \
packer/preseed/UbuntuServer22.04/user-data packer/preseed/Windows10/Autounattend.xml \
packer/preseed/Windows10/Sysprep_Unattend.xml
- | - |
yamllint -d "{extends: relaxed, rules: {line-length: disable}}" \ yamllint -d "{extends: relaxed, rules: {line-length: disable}}" scripts
ansible \
packer/preseed/UbuntuServer22.04/user-data \
scripts
- |
ansible-galaxy install \
-r ansible/requirements.yml
- | - |
packer init -upgrade \ packer init -upgrade \
./packer ./packer
- | - |
packer validate \ packer validate \
-var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \ -var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \
-var vm_guestos=k8sbootstrap \ -var vm_guestos=win10 \
-var repo_username=$${REPO_USERNAME} \ -var repo_username=$${REPO_USERNAME} \
-var repo_password=$${REPO_PASSWORD} \ -var repo_password=$${REPO_PASSWORD} \
-var vsphere_password=$${VSPHERE_PASSWORD} \ -var vsphere_password=$${VSPHERE_PASSWORD} \
-var ssh_password=$${SSH_PASSWORD} \ -var winrm_password=$${WINRM_PASSWORD} \
./packer ./packer
- | - |
packer build \ packer build \
-on-error=cleanup -timestamp-ui \ -on-error=cleanup \
-var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \ -var vm_name=$DRONE_BUILD_NUMBER-${DRONE_COMMIT_SHA:0:10} \
-var vm_guestos=k8sbootstrap \ -var vm_guestos=win10 \
-var repo_username=$${REPO_USERNAME} \ -var repo_username=$${REPO_USERNAME} \
-var repo_password=$${REPO_PASSWORD} \ -var repo_password=$${REPO_PASSWORD} \
-var vsphere_password=$${VSPHERE_PASSWORD} \ -var vsphere_password=$${VSPHERE_PASSWORD} \
-var ssh_password=$${SSH_PASSWORD} \ -var winrm_password=$${WINRM_PASSWORD} \
./packer ./packer
environment: environment:
VSPHERE_PASSWORD: VSPHERE_PASSWORD:
from_secret: vsphere_password from_secret: vsphere_password
SSH_PASSWORD: WINRM_PASSWORD:
from_secret: ssh_password from_secret: winrm_password
REPO_USERNAME: REPO_USERNAME:
from_secret: repo_username from_secret: repo_username
REPO_PASSWORD: REPO_PASSWORD:
from_secret: repo_password from_secret: repo_password
PRODUCTKEY:
from_secret: prodkey_win10
# PACKER_LOG: 1 # PACKER_LOG: 1
volumes: volumes:
- name: output - name: output

View File

@@ -1 +1 @@
# Packer.Images [![Build Status](https://ci.spamasaurus.com/api/badges/djpbessems/Packer.Images/status.svg?ref=refs/heads/Kubernetes.Bootstrap.Appliance)](https://ci.spamasaurus.com/djpbessems/Packer.Images) # Packer.Images [![Build Status](https://ci.spamasaurus.com/api/badges/djpbessems/Packer.Images/status.svg?ref=refs/heads/Windows10)](https://ci.spamasaurus.com/djpbessems/Packer.Images)

View File

@@ -1,3 +0,0 @@
[defaults]
deprecation_warnings = False
remote_tmp = /tmp/.ansible-${USER}/tmp

View File

@@ -1,11 +0,0 @@
---
- hosts: all
gather_facts: false
vars_files:
- metacluster.yml
become: true
roles:
- os
- firstboot
- appliance
- metacluster

View File

@@ -1,4 +0,0 @@
collections:
- ansible.utils
- community.general
- kubernetes.core

View File

@@ -1,27 +0,0 @@
---
- name: Initialize tempfolder
ansible.builtin.tempfile:
state: directory
register: archive
- name: Download & extract archived static binary
ansible.builtin.unarchive:
src: "{{ item.url }}"
dest: "{{ archive.path }}"
remote_src: yes
extra_opts: "{{ item.extra_opts | default(omit) }}"
- name: Install extracted binary
ansible.builtin.copy:
src: "{{ archive.path }}/{{ item.filename }}"
dest: /usr/local/bin/{{ item.filename }}
remote_src: yes
owner: root
group: root
mode: 0755
- name: Cleanup tempfolder
ansible.builtin.file:
path: "{{ archive.path }}"
state: absent
when: archive.path is defined

View File

@@ -1,46 +0,0 @@
# - name: Create folder structure(s)
# ansible.builtin.file:
# path: "{{ item }}"
# state: directory
# loop:
# - /foo
- name: Download & install static binaries
ansible.builtin.get_url:
url: "{{ item.url }}"
dest: /usr/local/bin/{{ item.filename }}
owner: root
group: root
mode: 0755
loop: "{{ dependencies.static_binaries | selectattr('archive', 'undefined') }}"
loop_control:
label: "{{ item.filename }}"
- name: Download, extract & install archived static binaries
include_tasks: dependencies.archive_compressed.yml
loop: "{{ dependencies.static_binaries | rejectattr('archive', 'undefined') | selectattr('archive', 'equalto', 'compressed') }}"
loop_control:
label: "{{ item.filename }}"
- name: Install ansible-galaxy collections
ansible.builtin.shell:
cmd: ansible-galaxy collection install {{ item }}
loop: "{{ dependencies.ansible_galaxy_collections }}"
- name: Install distro packages
ansible.builtin.apt:
pkg: "{{ dependencies.packages }}"
state: latest
update_cache: yes
install_recommends: no
- name: Upgrade all packages
ansible.builtin.apt:
name: '*'
state: latest
update_cache: yes
- name: Cleanup apt cache
ansible.builtin.apt:
autoremove: yes
purge: yes

View File

@@ -1,2 +0,0 @@
- name: Install & configure dependencies
import_tasks: dependencies.yml

View File

@@ -1,12 +0,0 @@
---
- hosts: 127.0.0.1
connection: local
gather_facts: false
# become: true
roles:
- vapp
- network
- users
- disks
- metacluster
- cleanup

View File

@@ -1,20 +0,0 @@
- name: Disable crontab job
ansible.builtin.cron:
name: firstboot
state: absent
- name: Restore extra tty
ansible.builtin.lineinfile:
path: /etc/systemd/logind.conf
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^NAutoVTs=', line: '#NAutoVTs=6'}
- { regexp: '^ReserveVT=', line: '#ReserveVT=6'}
- name: Unmask getty@tty1 service
ansible.builtin.systemd:
name: getty@tty1
enabled: yes
masked: no
- name: Reboot host
ansible.builtin.shell:
cmd: /usr/sbin/reboot now

View File

@@ -1,7 +0,0 @@
- name: Mount dynamic disk
ansible.posix.mount:
path: /mnt/blockstorage
src: /dev/sdb
fstype: ext4
state: mounted

View File

@@ -1,92 +0,0 @@
- name: Install K3s
ansible.builtin.command:
cmd: ./install.sh
chdir: /opt/metacluster/k3s
environment:
INSTALL_K3S_SKIP_DOWNLOAD: 'true'
INSTALL_K3S_EXEC: 'server --cluster-init --disable local-storage'
- name: Install kubectl tab-completion
ansible.builtin.command:
cmd: kubectl completion bash | tee /etc/bash_completion.d/kubectl
- name: Ensure API availability
ansible.utils.cli_parse:
command: curl -k https://{{ vapp['guestinfo.ipaddress'] }}:6443/livez?verbose
parser:
name: ansible.utils.json
set_fact: api_readycheck
ignore_errors: yes
until: api_readycheck.apiVersion is defined
retries: 3
delay: 30
- block:
- name: Initialize tempfile
ansible.builtin.tempfile:
state: file
register: kubeconfig
- name: Retrieve kubeconfig
ansible.builtin.command:
cmd: kubectl config view --raw
register: kubectl_config
- name: Store kubeconfig in tempfile
ansible.builtin.copy:
dest: "{{ kubeconfig.path }}"
content: "{{ kubectl_config.stdout }}"
mode: 0600
no_log: true
#- block:
# - name: Extract container images
# ansible.builtin.unarchive:
# src: /opt/metacluster/container-images/image-tarballs.tgz
# dest: /opt/metacluster/container-images
# list_files: yes
# register: imagetarballs
# - name: Import container images
# ansible.builtin.command:
# cmd: k3s ctr image import {{ item }}
# chdir: /opt/metacluster/container-images
# loop: "{{ imagetarballs.files }}"
# - name: Delete redundant files
# ansible.builtin.file:
# path: /opt/metacluster/container-images
# state: absent
- name: Install longhorn chart
kubernetes.core.helm:
name: longhorn
chart_ref: /opt/metacluster/helm-charts/longhorn
release_namespace: longhorn-system
create_namespace: yes
kubeconfig: "{{ kubeconfig.path }}"
values:
defaultSettings:
defaultDataPath: /mnt/blockstorage
defaultReplicaCount: 1
ingress:
enabled: true
host: storage.{{ vapp['guestinfo.fqdn'] }}
- name: Install harbor chart
kubernetes.core.helm:
name: harbor
chart_ref: /opt/metacluster/helm-charts/harbor
release_namespace: harbor
create_namespace: yes
kubeconfig: "{{ kubeconfig.path }}"
values:
# foo: bar
- name: Cleanup tempfile
ansible.builtin.file:
path: "{{ kubeconfig.path }}"
state: absent
when: kubeconfig.path is defined

View File

@@ -1,12 +0,0 @@
- name: Set hostname
ansible.builtin.hostname:
name: "{{ vapp['guestinfo.hostname'] }}"
- name: Create netplan configuration file
ansible.builtin.template:
src: netplan.j2
dest: /etc/netplan/00-installer-config.yaml
- name: Apply netplan configuration
ansible.builtin.shell:
cmd: /usr/sbin/netplan apply

View File

@@ -1,10 +0,0 @@
network:
version: 2
ethernets:
ens192:
addresses:
- {{ vapp['guestinfo.ipaddress'] }}/{{ vapp['guestinfo.prefixlength'] }}
gateway4: {{ vapp['guestinfo.gateway'] }}
nameservers:
addresses:
- {{ vapp['guestinfo.dnsserver'] }}

View File

@@ -1,25 +0,0 @@
- name: Set root password
ansible.builtin.user:
name: root
password: "{{ vapp['guestinfo.rootpw'] | password_hash('sha512', 65534 | random(seed=vapp['guestinfo.hostname']) | string) }}"
generate_ssh_key: yes
ssh_key_bits: 2048
ssh_key_file: .ssh/id_rsa
- name: Save root SSH publickey
ansible.builtin.lineinfile:
path: /root/.ssh/authorized_keys
line: "{{ vapp['guestinfo.rootsshkey'] }}"
- name: Disable SSH password authentication
ansible.builtin.lineinfile:
path: /etc/ssh/sshd_config
regex: "{{ item.regex }}"
line: "{{ item.line }}"
state: "{{ item.state }}"
loop:
- { regex: '^#PasswordAuthentication', line: 'PasswordAuthentication no', state: present}
- { regex: '^PasswordAuthentication yes', line: 'PasswordAuthentication yes', state: absent}
- name: Delete 'ubuntu' user
ansible.builtin.user:
name: ubuntu
state: absent
remove: yes

View File

@@ -1,21 +0,0 @@
- name: Store current ovfEnvironment
ansible.builtin.shell:
cmd: /usr/bin/vmtoolsd --cmd "info-get guestinfo.ovfEnv"
register: ovfenv
- name: Parse XML for vApp properties
community.general.xml:
xmlstring: "{{ ovfenv.stdout }}"
namespaces:
ns: http://schemas.dmtf.org/ovf/environment/1
xpath: /ns:Environment/ns:PropertySection/ns:Property
content: attribute
register: ovfenv
- name: Assign vApp properties to dictionary
ansible.builtin.set_fact:
vapp: >-
{{ vapp | default({}) |
combine({((item.values() | list)[0].values() | list)[0]:
((item.values() | list)[0].values() | list)[1]})
}}
loop: "{{ ovfenv.matches }}"
no_log: true

View File

@@ -1,26 +0,0 @@
- name: Create destination folder
ansible.builtin.file:
path: /opt/firstboot
state: directory
- name: Create firstboot script file
ansible.builtin.template:
src: firstboot.j2
dest: /opt/firstboot/firstboot.sh
owner: root
group: root
mode: o+x
- name: Create @reboot crontab job
ansible.builtin.cron:
name: firstboot
special_time: reboot
job: "/opt/firstboot/firstboot.sh"
- name: Copy payload folder
ansible.builtin.copy:
src: ansible_payload/
dest: /opt/firstboot/ansible/
owner: root
group: root
mode: '0644'

View File

@@ -1,4 +0,0 @@
#!/bin/bash
# Apply firstboot configuration w/ ansible
/usr/local/bin/ansible-playbook /opt/firstboot/ansible/playbook.yml | tee -a /var/log/firstboot.log > /dev/tty1

View File

@@ -1,4 +0,0 @@
- name: Zero-out disk
ansible.builtin.shell:
cmd: dd bs=1M count=$(df -m . | awk '/[0-9]%/{print $(NF-2)}') if=/dev/zero of=./zero; sync; sync; rm -f ./zero
chdir: /opt/metacluster

View File

@@ -1,44 +0,0 @@
- name: Create folder structure(s)
ansible.builtin.file:
path: "{{ item }}"
state: directory
loop:
- /opt/metacluster/helm-charts
- /opt/metacluster/container-images
- name: Add helm repositories
kubernetes.core.helm_repository:
name: "{{ item.name }}"
repo_url: "{{ item.url }}"
state: present
loop: "{{ platform.helm_repositories }}"
- name: Fetch helm charts
ansible.builtin.command:
cmd: helm fetch {{ item.value.helm.chart }} --untar --version {{ item.value.helm.version }}
chdir: /opt/metacluster/helm-charts
loop: "{{ lookup('ansible.builtin.dict', components) }}"
loop_control:
label: "{{ item.key }}"
- name: Parse helm charts for container images
ansible.builtin.shell:
cmd: "{{ item.value.helm.parse_logic }}"
chdir: /opt/metacluster/helm-charts/{{ item.key }}
register: containerimages
loop: "{{ lookup('ansible.builtin.dict', components) }}"
loop_control:
label: "{{ item.key }}"
#- name: Pull and store containerimages
# ansible.builtin.command:
# cmd: skopeo copy docker://{{ item }} docker-archive:./{{ ( item | regex_findall('[^/:]+'))[-2] }}.tar:{{ item }}
# chdir: /opt/metacluster/container-images
# loop: "{{ containerimages.results | map(attribute='stdout_lines') | flatten }}"
#- name: Compress tarballs
# community.general.archive:
# dest: /opt/metacluster/container-images/image-tarballs.tgz
# path: /opt/metacluster/container-images/*
# format: gz
# remove: yes

View File

@@ -1,28 +0,0 @@
- name: Create folder structure(s)
ansible.builtin.file:
path: "{{ item }}"
state: directory
loop:
- /var/lib/rancher/k3s/agent/images
- /opt/metacluster/k3s
- name: Download & install K3s binary
ansible.builtin.get_url:
url: https://github.com/k3s-io/k3s/releases/download/{{ platform.k3s.version }}/k3s
dest: /usr/local/bin/k3s
owner: root
group: root
mode: 0755
- name: Download K3s images tarball
ansible.builtin.get_url:
url: https://github.com/k3s-io/k3s/releases/download/{{ platform.k3s.version }}/k3s-airgap-images-amd64.tar.gz
dest: /var/lib/rancher/k3s/agent/images
- name: Download K3s install script
ansible.builtin.get_url:
url: https://get.k3s.io
dest: /opt/metacluster/k3s/install.sh
owner: root
group: root
mode: 0755

View File

@@ -1,6 +0,0 @@
- name: Pre-stage K3s components
import_tasks: k3s.yml
- name: Pre-stage meta components
import_tasks: components.yml
- name: Cleanup
import_tasks: cleanup.yml

View File

@@ -1,6 +0,0 @@
- name: Install ansible (w/ dependencies)
ansible.builtin.pip:
name: "{{ item }}"
executable: pip3
state: latest
loop: "{{ pip_packages }}"

View File

@@ -1,12 +0,0 @@
- name: Delete cloud-init package
ansible.builtin.apt:
name: cloud-init
state: absent
purge: yes
- name: Delete cloud-init files
ansible.builtin.file:
path: "{{ item }}"
state: absent
loop:
- /etc/cloud
- /var/lib/cloud

View File

@@ -1,5 +0,0 @@
- name: Enable crontab logging
ansible.builtin.lineinfile:
path: /etc/rsyslog.d/50-default.conf
regexp: '^#cron\.\*.*'
line: "cron.*\t\t\t\t./var/log/cron.log"

View File

@@ -1,20 +0,0 @@
- name: Disable tty logins
import_tasks: tty.yml
- name: Remove snapd
import_tasks: snapd.yml
- name: Remove cloud-init
import_tasks: cloud-init.yml
- name: Configure default logging
import_tasks: logging.yml
- name: Configure services
import_tasks: services.yml
- name: Install packages
import_tasks: packages.yml
- name: Install ansible
import_tasks: ansible.yml

View File

@@ -1,17 +0,0 @@
- name: Install additional packages
ansible.builtin.apt:
pkg: "{{ packages }}"
state: latest
update_cache: yes
install_recommends: no
- name: Upgrade all packages
ansible.builtin.apt:
name: '*'
state: latest
update_cache: yes
- name: Cleanup
ansible.builtin.apt:
autoremove: yes
purge: yes

View File

@@ -1,5 +0,0 @@
- name: Disable & mask networkd-wait-online
ansible.builtin.systemd:
name: systemd-networkd-wait-online
enabled: no
masked: yes

View File

@@ -1,16 +0,0 @@
- name: Delete snapd package
ansible.builtin.apt:
name: snapd
state: absent
purge: yes
- name: Delete leftover files
ansible.builtin.file:
path: /root/snap
state: absent
- name: Hold snapd package
ansible.builtin.dpkg_selections:
name: snapd
selection: hold
- name: Reload systemd unit configurations
ansible.builtin.systemd:
daemon_reload: yes

View File

@@ -1,13 +0,0 @@
- name: Disable extra tty
ansible.builtin.lineinfile:
path: /etc/systemd/logind.conf
regexp: "{{ item.regexp }}"
line: "{{ item.line }}"
loop:
- { regexp: '^#NAutoVTs=', line: 'NAutoVTs=1'}
- { regexp: '^#ReserveVT=', line: 'ReserveVT=11'}
- name: Mask getty@tty1 service
ansible.builtin.systemd:
name: getty@tty1
enabled: no
masked: yes

View File

@@ -1,11 +0,0 @@
packages:
- jq
# (python3-*) Dependency for installation of Ansible
- python3-pip
- python3-setuptools
- python3-wheel
pip_packages:
- pip
- ansible-core
- lxml

View File

@@ -1,58 +0,0 @@
platform:
k3s:
version: v1.24.1+k3s1
helm_repositories:
- name: longhorn
url: https://charts.longhorn.io
- name: harbor
url: https://helm.goharbor.io
- name: gitea-charts
url: https://dl.gitea.io/charts/
- name: argo
url: https://argoproj.github.io/argo-helm
components:
longhorn:
helm:
version: 1.3.0
chart: longhorn/longhorn
parse_logic: cat values.yaml | yq eval '.. | select(has("repository")) | .repository + ":" + .tag'
harbor:
helm:
version: 1.9.1 # (= Harbor v2.5.1)
chart: harbor/harbor
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /'
gitea:
helm:
version: v5.0.9 # (= Gitea v1.16.8)
chart: gitea-charts/gitea
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | sed '/:/!s/$/:latest/'
argo-cd:
helm:
version: 4.9.7 # (= ArgoCD v2.4.2)
chart: argo/argo-cd
parse_logic: helm template . | yq --no-doc eval '.. | .image? | select(.)' | sort -u | awk '!/ /'
dependencies:
ansible_galaxy_collections:
- ansible.utils
- community.general
- kubernetes.core
static_binaries:
- filename: helm
url: https://get.helm.sh/helm-v3.9.0-linux-amd64.tar.gz
archive: compressed
extra_opts: --strip-components=1
- filename: yq
url: http://github.com/mikefarah/yq/releases/download/v4.25.3/yq_linux_amd64
packages:
- skopeo

View File

@@ -0,0 +1,16 @@
script = <<-EOH
$nic = get-netadapter
Get-NetAdapterBinding InterfaceAlias $nic.name ComponentID ms_tcpip6
EOH
control "ipv6" do
title 'Disabled network protocol IPv6'
desc '
This test assures that IPv6 is disabled
'
describe powershell(script) do
its('stdout') { should match 'False' }
end
end

View File

@@ -0,0 +1,29 @@
script = <<-EOH
# Initialize variable to empty array
$NonCompliantServices = @()
# Specify relevant services
$Services = @(
"wuauserv",
"W3SVC",
"XboxGipSvc",
"XblGameSave"
)
# Enumerate all services
$NonCompliantServices += Get-Service $Services -ErrorAction 'SilentlyContinue' | Where-Object {$_.StartType -ne 'Disabled'}
# Output; 'True' or list of noncompliant services
Write-Output ($True, $NonCompliantServices)[!($NonCompliantServices.Count -eq 0)]
EOH
control "disabled_services" do
title 'Disabled services'
desc '
This test assures that all unneeded services are set to "disabled".
'
describe powershell(script) do
its('stdout') { should match 'True' }
end
end

View File

@@ -0,0 +1,29 @@
script = <<-EOH
# Initialize variable to empty array
$LogicalDisks = @()
# Enumerate all logicaldisks
# DriveType:
# Unknown (0)
# No Root Directory (1)
# Removable Disk (2)
# Local Disk (3)
# Network Drive (4)
# Compact Disc (5)
# RAM Disk (6)
$LogicalDisks += Get-WmiObject -Class 'win32_logicaldisk' -Filter 'DriveType=3'
# Filter/Quantify
($LogicalDisks.Count -eq 1) -and (($LogicalDisks | Where-Object {$_.DeviceID -ne 'C:'}).Count -eq 0)
EOH
control "single_disk" do
title 'Single Disk'
desc '
This test assures that only a single disk (C:) is available
'
describe powershell(script) do
its('stdout') { should match 'True' }
end
end

View File

@@ -0,0 +1,54 @@
control "software_installed-7zip" do
title 'Included Default Applications: 7-Zip'
desc '
This test assures that the software application "7-Zip" is installed.
'
describe chocolatey_package('7zip.install') do
it { should be_installed }
end
end
# control "software_installed-dotnetfx" do
# title 'Included Default Applications: .NET'
# desc '
# This test assures that the software application ".NET" is installed.
# '
# describe chocolatey_package('dotnetfx') do
# it { should be_installed }
# end
# end
# control "software_installed-foxitreader" do
# title 'Included Default Applications: Foxit Reader'
# desc '
# This test assures that the software application "Foxit Reader" is installed.
# '
# describe chocolatey_package('foxitreader') do
# it { should be_installed }
# end
# end
# control "software_installed-notepadplusplus" do
# title 'Included Default Applications: Notepad++'
# desc '
# This test assures that the software application "Notepad++" is installed.
# '
# describe chocolatey_package('notepadplusplus') do
# it { should be_installed }
# end
# end
# control "software_installed-putty" do
# title 'Included Default Applications: Putty'
# desc '
# This test assures that the software application "PuTTy" is installed.
# '
# describe chocolatey_package('putty') do
# it { should be_installed }
# end
# end

View File

@@ -0,0 +1,10 @@
---
name: Windows 10 IoT Enterprise
title: Windows 10 IoT Enterprise InSpec Tests
summary: Unit test for Windows 10 IoT Enterprise
version: 1.0.0
maintainer: https://code.spamasaurus.com/djpbessems
copyright: https://code.spamasaurus.com/djpbessems
license: Proprietary
supports:
- platform-family: windows

View File

@@ -1,4 +0,0 @@
iso_url = "sn.itch.fyi/Repository/iso/Canonical/Ubuntu%20Server%2022.04/ubuntu-22.04-live-server-amd64.iso"
iso_checksum = "sha256:84AEAF7823C8C61BAA0AE862D0A06B03409394800000B3235854A6B38EB4856F"
// iso_url = "sn.itch.fyi/Repository/iso/Canonical/Ubuntu%20Server%2020.04/ubuntu-20.04.2-live-server-amd64.iso"
// iso_checksum = "sha256:D1F2BF834BBE9BB43FAF16F9BE992A6F3935E65BE0EDECE1DEE2AA6EB1767423"

View File

@@ -1,99 +0,0 @@
packer {
required_plugins {
}
}
source "vsphere-iso" "k8sbootstrap" {
vcenter_server = var.vcenter_server
username = var.vsphere_username
password = var.vsphere_password
insecure_connection = "true"
vm_name = "${var.vm_guestos}-${var.vm_name}"
datacenter = var.vsphere_datacenter
cluster = var.vsphere_cluster
host = var.vsphere_host
folder = var.vsphere_folder
datastore = var.vsphere_datastore
guest_os_type = "ubuntu64Guest"
boot_order = "disk,cdrom"
boot_command = [
"e<down><down><down><end>",
" autoinstall ds=nocloud;",
"<F10>"
]
boot_wait = "2s"
communicator = "ssh"
ssh_username = "ubuntu"
ssh_password = var.ssh_password
ssh_timeout = "20m"
ssh_handshake_attempts = "100"
ssh_pty = true
CPUs = 2
RAM = 4096
network_adapters {
network = var.vsphere_network
network_card = "vmxnet3"
}
storage {
disk_size = 51200
disk_thin_provisioned = true
}
disk_controller_type = ["pvscsi"]
usb_controller = ["xhci"]
cd_files = [
"packer/preseed/UbuntuServer22.04/user-data",
"packer/preseed/UbuntuServer22.04/meta-data"
]
cd_label = "cidata"
iso_url = local.iso_authenticatedurl
iso_checksum = var.iso_checksum
shutdown_command = "echo '${var.ssh_password}' | sudo -S shutdown -P now"
shutdown_timeout = "5m"
export {
images = false
output_directory = "/scratch/k8sbootstrap"
}
remove_cdrom = true
}
build {
sources = [
"source.vsphere-iso.k8sbootstrap"
]
provisioner "ansible" {
pause_before = "2m30s"
playbook_file = "ansible/playbook.yml"
user = "ubuntu"
ansible_env_vars = [
"ANSIBLE_CONFIG=ansible/ansible.cfg"
]
use_proxy = "false"
extra_arguments = [
"--extra-vars", "ansible_ssh_pass=${var.ssh_password}"
]
}
post-processor "shell-local" {
inline = [
"pwsh -command \"& scripts/Update-OvfConfiguration.ps1 \\",
" -OVFFile '/scratch/k8sbootstrap/${var.vm_guestos}-${var.vm_name}.ovf' \\",
" -Parameter @{'appliance.name'='${var.vm_guestos}';'appliance.version'='${var.vm_name}'}\"",
"pwsh -file scripts/Update-Manifest.ps1 \\",
" -ManifestFileName '/scratch/k8sbootstrap/${var.vm_guestos}-${var.vm_name}.mf'",
"ovftool --acceptAllEulas --allowExtraConfig --overwrite \\",
" '/scratch/k8sbootstrap/${var.vm_guestos}-${var.vm_name}.ovf' \\",
" /output/Kubernetes.Bootstrap.Appliance.ova"
]
}
}

View File

@@ -1,29 +0,0 @@
#cloud-config
autoinstall:
version: 1
locale: en_US
keyboard:
layout: en
variant: us
network:
network:
version: 2
ethernets:
ens192:
dhcp4: true
dhcp-identifier: mac
storage:
layout:
name: direct
identity:
hostname: packer-template
username: ubuntu
# password: $6$ZThRyfmSMh9499ar$KSZus58U/l58Efci0tiJEqDKFCpoy.rv25JjGRv5.iL33AQLTY2aljumkGiDAiX6LsjzVsGTgH85Tx4S.aTfx0
password: $6$rounds=4096$ZKfzRoaQOtc$M.fhOsI0gbLnJcCONXz/YkPfSoefP4i2/PQgzi2xHEi2x9CUhush.3VmYKL0XVr5JhoYvnLfFwqwR/1YYEqZy/
ssh:
install-server: yes
allow-pw: true
user-data:
disable_root: false
late-commands:
- echo 'ubuntu ALL=(ALL) NOPASSWD:ALL' > /target/etc/sudoers.d/ubuntu

View File

@@ -0,0 +1,159 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<servicing/>
<settings pass="windowsPE">
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<DiskConfiguration>
<Disk wcm:action="add">
<CreatePartitions>
<CreatePartition wcm:action="add">
<Order>1</Order>
<Type>Primary</Type>
<Extend>true</Extend>
</CreatePartition>
</CreatePartitions>
<ModifyPartitions>
<ModifyPartition wcm:action="add">
<Extend>false</Extend>
<Format>NTFS</Format>
<Letter>C</Letter>
<Order>1</Order>
<PartitionID>1</PartitionID>
<Label>Windows 10</Label>
</ModifyPartition>
</ModifyPartitions>
<DiskID>0</DiskID>
<WillWipeDisk>true</WillWipeDisk>
</Disk>
<WillShowUI>OnError</WillShowUI>
</DiskConfiguration>
<UserData>
<AcceptEula>true</AcceptEula>
<!-- <FullName>Spamasaurus Rex</FullName>
<Organization>Spamasaurus Rex</Organization> -->
<ProductKey>
<Key><<img-productkey>></Key>
<WillShowUI>Never</WillShowUI>
</ProductKey>
</UserData>
<ImageInstall>
<OSImage>
<InstallTo>
<DiskID>0</DiskID>
<PartitionID>1</PartitionID>
</InstallTo>
<WillShowUI>OnError</WillShowUI>
<InstallToAvailablePartition>false</InstallToAvailablePartition>
<InstallFrom>
<MetaData wcm:action="add">
<Key>/IMAGE/INDEX</Key>
<Value>3</Value>
</MetaData>
</InstallFrom>
</OSImage>
</ImageInstall>
</component>
<component xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" name="Microsoft-Windows-International-Core-WinPE" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<SetupUILanguage>
<UILanguage>en-US</UILanguage>
</SetupUILanguage>
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UILanguageFallback>en-US</UILanguageFallback>
<UserLocale>en-US</UserLocale>
</component>
</settings>
<settings pass="offlineServicing">
<component name="Microsoft-Windows-LUA-Settings" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS">
<EnableLUA>false</EnableLUA>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<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>
<AdministratorPassword>
<Value><<img-password>></Value>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<NetworkLocation>Home</NetworkLocation>
<ProtectYourPC>1</ProtectYourPC>
</OOBE>
<AutoLogon>
<Password>
<Value><<img-password>></Value>
<PlainText>true</PlainText>
</Password>
<Username>administrator</Username>
<Enabled>true</Enabled>
</AutoLogon>
<FirstLogonCommands>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine>
<Description>Set execution policy 64bit</Description>
<Order>1</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>C:\Windows\SysWOW64\cmd.exe /c powershell -Command "Set-ExecutionPolicy -ExecutionPolicy RemoteSigned -Force"</CommandLine>
<Description>Set execution policy 32bit</Description>
<Order>2</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c reg add "HKLM\System\CurrentControlSet\Control\Network\NewNetworkWindowOff"</CommandLine>
<Description>Disable new network prompt</Description>
<Order>3</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Set-NetworkProfile.ps1</CommandLine>
<Description>Set network profile to private</Description>
<Order>4</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Disable-WinRM.ps1</CommandLine>
<Description>Disable WinRM</Description>
<Order>5</Order>
<RequiresUserInput>true</RequiresUserInput>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c a:\Install-VMwareTools.cmd</CommandLine>
<Order>13</Order>
<Description>Install VMware Tools</Description>
</SynchronousCommand>
<SynchronousCommand wcm:action="add">
<CommandLine>cmd.exe /c C:\Windows\System32\WindowsPowerShell\v1.0\powershell.exe -File a:\Enable-WinRM.ps1</CommandLine>
<Description>Enable WinRM</Description>
<Order>99</Order>
</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>packer-template</ComputerName>
<TimeZone>W. Europe 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>true</SkipAutoActivation>
</component>
</settings>
</unattend>

View File

@@ -0,0 +1,42 @@
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
<settings pass="generalize">
<component name="Microsoft-Windows-Security-SPP" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<SkipRearm>1</SkipRearm>
</component>
<component name="Microsoft-Windows-PnpSysprep" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<PersistAllDeviceInstalls>true</PersistAllDeviceInstalls>
<DoNotCleanUpNonPresentDevices>true</DoNotCleanUpNonPresentDevices>
</component>
</settings>
<settings pass="oobeSystem">
<component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<InputLocale>en-US</InputLocale>
<SystemLocale>en-US</SystemLocale>
<UILanguage>en-US</UILanguage>
<UserLocale>en-US</UserLocale>
</component>
<component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<OOBE>
<HideEULAPage>true</HideEULAPage>
<HideLocalAccountScreen>true</HideLocalAccountScreen>
<HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
<HideOnlineAccountScreens>true</HideOnlineAccountScreens>
<HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
<NetworkLocation>Work</NetworkLocation>
<ProtectYourPC>1</ProtectYourPC>
<SkipMachineOOBE>true</SkipMachineOOBE>
<SkipUserOOBE>true</SkipUserOOBE>
</OOBE>
<TimeZone>UTC</TimeZone>
<UserAccounts>
<AdministratorPassword>
<Value><<img-password>></Value>
<PlainText>true</PlainText>
</AdministratorPassword>
</UserAccounts>
</component>
</settings>
<settings pass="specialize">
</settings>
</unattend>

View File

@@ -1,12 +1,9 @@
variable "vcenter_server" {} variable "vcenter_server" {}
variable "vsphere_username" {} variable "vsphere_username" {}
variable "vsphere_password" { variable "vsphere_password" {}
sensitive = true
}
variable "vsphere_host" {} variable "vsphere_host" {}
variable "vsphere_datacenter" {} variable "vsphere_datacenter" {}
variable "vsphere_cluster" {}
variable "vsphere_templatefolder" {} variable "vsphere_templatefolder" {}
variable "vsphere_folder" {} variable "vsphere_folder" {}
@@ -15,17 +12,7 @@ variable "vsphere_network" {}
variable "vm_name" {} variable "vm_name" {}
variable "vm_guestos" {} variable "vm_guestos" {}
variable "ssh_password" { variable "winrm_password" {}
sensitive = true
}
variable "iso_url" {}
variable "iso_checksum" {}
variable "repo_username" {} variable "repo_username" {}
variable "repo_password" { variable "repo_password" {}
sensitive = true
}
local "iso_authenticatedurl" {
expression = "https://${var.repo_username}:${var.repo_password}@${var.iso_url}"
sensitive = true
}

View File

@@ -1,9 +1,8 @@
vcenter_server = "bv11-vc.bessems.lan" vcenter_server = "bv11-vc.bessems.lan"
vsphere_username = "administrator@vsphere.local" vsphere_username = "administrator@vsphere.local"
vsphere_datacenter = "DeSchakel" vsphere_datacenter = "DeSchakel"
vsphere_cluster = "Cluster.Legacy"
vsphere_host = "bv11-esx.bessems.lan" vsphere_host = "bv11-esx.bessems.lan"
vsphere_datastore = "ESX00.SSD01" vsphere_datastore = "Datastore01.SSD"
vsphere_folder = "/Packer" vsphere_folder = "/Packer"
vsphere_templatefolder = "/Templates" vsphere_templatefolder = "/Templates"
vsphere_network = "LAN" vsphere_network = "LAN"

133
packer/windows10.pkr.hcl Normal file
View File

@@ -0,0 +1,133 @@
packer {
required_plugins {
windows-update = {
version = ">= 0.14.0"
source = "github.com/rgl/windows-update"
}
}
}
source "vsphere-iso" "win10" {
vcenter_server = var.vcenter_server
username = var.vsphere_username
password = var.vsphere_password
insecure_connection = "true"
vm_name = "${var.vm_guestos}-${var.vm_name}"
datacenter = var.vsphere_datacenter
host = var.vsphere_host
folder = var.vsphere_folder
datastore = var.vsphere_datastore
guest_os_type = "windows9_64Guest"
boot_order = "disk,cdrom"
boot_command = [""]
boot_wait = "5m"
communicator = "winrm"
winrm_username = "administrator"
winrm_password = var.winrm_password
winrm_timeout = "10m"
CPUs = 2
RAM = 8192
network_adapters {
network = var.vsphere_network
network_card = "vmxnet3"
}
storage {
disk_size = 20480
disk_thin_provisioned = true
}
disk_controller_type = ["lsilogic-sas"]
usb_controller = ["xhci"]
floppy_files = [
"packer/preseed/Windows10/Autounattend.xml",
"packer/preseed/Windows10/Sysprep_Unattend.xml",
"scripts/Set-NetworkProfile.ps1",
"scripts/Disable-WinRM.ps1",
"scripts/Enable-WinRM.ps1",
"scripts/Install-VMwareTools.cmd"
]
iso_checksum = "sha256:8D1663B71280533824CF95C7AB48ADAF5A187C38FCFF5B16A569F903688916D0"
iso_paths = [
"ISO-files/VMware-tools-windows-11.3.5-18557794/VMware-tools-windows-11.3.5-18557794.iso"
]
iso_url = "https://${var.repo_username}:${var.repo_password}@sn.itch.fyi/Repository/iso/Microsoft/Windows%2010/20H2/en_windows_10_enterprise_20H2_x64.iso"
shutdown_command = "C:\\Windows\\System32\\Sysprep\\sysprep.exe /generalize /oobe /unattend:A:\\Sysprep_Unattend.xml"
shutdown_timeout = "1h"
export {
images = false
output_directory = "/scratch/win10"
}
remove_cdrom = true
}
build {
sources = ["source.vsphere-iso.win10"]
provisioner "windows-update" {
filters = [
"exclude:$_.Title -like '*Preview*'",
"include:$true"
]
}
provisioner "powershell" {
inline = [
"[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12",
"Invoke-Expression ((New-Object Net.WebClient).DownloadString('https://chocolatey.org/install.ps1'))"
]
}
provisioner "powershell" {
inline = [
"choco config set --name=limit-output --value=LimitOutput",
"choco install -y 7zip.install",
"choco install -y sysinternals",
"choco install -y firefox"
]
}
provisioner "windows-update" {
filters = [
"exclude:$_.Title -like '*Preview*'",
"include:$true"
]
}
provisioner "powershell" {
inline = [
"New-Item -Path 'C:\\Payload\\Scripts' -ItemType 'Directory' -Force:$True -Confirm:$False"
]
}
provisioner "file" {
destination = "C:\\Payload\\"
source = "scripts/Windows10/payload/"
}
provisioner "powershell" {
scripts = [
"scripts/Windows10/Register-ScheduledTask.ps1"
]
}
post-processor "shell-local" {
inline = [
"pwsh -command \"& scripts/Update-OvfConfiguration.ps1 \\",
" -OVFFile '/scratch/win10/${var.vm_guestos}-${var.vm_name}.ovf' \\",
" -Parameter @{'appliance.name'='${var.vm_guestos}';'appliance.version'='${var.vm_name}'}\"",
"pwsh -file scripts/Update-Manifest.ps1 \\",
" -ManifestFileName '/scratch/win10/${var.vm_guestos}-${var.vm_name}.mf'",
"ovftool --acceptAllEulas --allowExtraConfig --overwrite \\",
" '/scratch/win10/${var.vm_guestos}-${var.vm_name}.ovf' \\",
" /output/Windows10.ova"
]
}
}

View File

@@ -0,0 +1,8 @@
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=block
netsh advfirewall firewall set rule group="Windows Remote Management" new enable=yes
$winrmService = Get-Service -Name WinRM
if ($winrmService.Status -eq "Running"){
Disable-PSRemoting -Force
}
Stop-Service winrm
Set-Service -Name winrm -StartupType Disabled

18
scripts/Enable-WinRM.ps1 Normal file
View File

@@ -0,0 +1,18 @@
$NetworkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"))
$Connections = $NetworkListManager.GetNetworkConnections()
$Connections | ForEach-Object { $_.GetNetwork().SetCategory(1) }
Enable-PSRemoting -Force
winrm quickconfig -q
winrm quickconfig -transport:http
winrm set winrm/config '@{MaxTimeoutms="1800000"}'
winrm set winrm/config/winrs '@{MaxMemoryPerShellMB="800"}'
winrm set winrm/config/service '@{AllowUnencrypted="true"}'
winrm set winrm/config/service/auth '@{Basic="true"}'
winrm set winrm/config/client/auth '@{Basic="true"}'
winrm set winrm/config/listener?Address=*+Transport=HTTP '@{Port="5985"}'
netsh advfirewall firewall set rule group="Windows Remote Administration" new enable=yes
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" new enable=yes action=allow
netsh advfirewall firewall set rule name="Windows Remote Management (HTTP-In)" profile=public new remoteip=any
Set-Service winrm -startuptype "auto"
Restart-Service winrm

View File

@@ -0,0 +1,2 @@
@rem Silent mode, basic UI, no reboot
e:\setup64 /s /v "/qb REBOOT=R"

View File

@@ -0,0 +1,73 @@
<?xml version="1.0" encoding="utf-8" ?>
<BlockList>
<!-- services to disable -->
<Services>
<Name>MVMCP2VAgent</Name>
<Name>VMTools</Name>
<Name> VMUpgradeHelper </Name>
<Name> vmvss </Name>
<Name>vmdesched</Name>
<Name>Virtual Server</Name>
<!-- Virtual Machine Helper -->
<Name>vmh</Name>
<!-- Xen-specific service -->
<Name>xensvc</Name>
</Services>
<!-- drivers to disable -->
<Drivers>
<Name>vmx_svga</Name>
<Name>vmmouse</Name>
<Name>vmscsi</Name>
<Name>amdpcn</Name>
<Name>PCnet</Name>
<Name>VMMEMCTL</Name>
<Name> pvscsi </Name>
<Name> vmci </Name>
<Name> vmmouse </Name>
<Name> vmaudio </Name>
<Name> vmrawdsk </Name>
<Name> vmxnet </Name>
<Name> vmxnet3ndis6 </Name>
<Name> vm3dmp </Name>
<Name> vmdebug </Name>
<Name> vmxnet3ndis5 </Name>
<Name>cirrus</Name>
<!-- storage drivers -->
<Name>buslogic</Name>
<Name>symc810</Name>
<Name>cpqarray</Name>
<Name>pcntn4m</Name>
<Name>cpqnf3</Name>
<Name>MRaidNT</Name>
<Name>Symc8XX</Name>
<!-- VIA chipset drivers -->
<Name>viaide</Name>
<Name>VIAudio</Name>
<Name>VIAPFD</Name>
<Name>viafilter</Name>
<Name>viaagp</Name>
<Name>viaagp1</Name>
<!-- network drivers: Intel(R) PRO/100 -->
<Name>E100B</Name>
<!-- tape drivers -->
<Name>4mmdat</Name>
<Name>4mmdat-SeSFT</Name>
<Name>SCSIChanger</Name>
<!-- Virtual Machine Monitor -->
<Name>vmm</Name>
<!-- Xen-specific drivers -->
<Name>xenevtchn</Name>
<Name>xenvbd</Name>
<Name>xennet</Name>
</Drivers>
<Programs>
<Name>ProMON</Name>
<Name>s3tray2</Name>
<Name>VMwareTray</Name>
<Name>VMwareUser</Name>
</Programs>
</BlockList>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
scripts/MVMC/MvmcCmdlet.dll Normal file

Binary file not shown.

Binary file not shown.

BIN
scripts/MVMC/Sshlib_x64.dll Normal file

Binary file not shown.

BIN
scripts/MVMC/Sshlib_x86.dll Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -0,0 +1,23 @@
# You cannot enable Windows PowerShell Remoting on network connections that are set to Public
# Spin through all the network locations and if they are set to Public, set them to Private
# using the INetwork interface:
# http://msdn.microsoft.com/en-us/library/windows/desktop/aa370750(v=vs.85).aspx
# For more info, see:
# http://blogs.msdn.com/b/powershell/archive/2009/04/03/setting-network-location-to-private.aspx
# Network location feature was only introduced in Windows Vista - no need to bother with this
# if the operating system is older than Vista
if([environment]::OSVersion.version.Major -lt 6) { return }
# You cannot change the network location if you are joined to a domain, so abort
if(1,3,4,5 -contains (Get-WmiObject win32_computersystem).DomainRole) { return }
# Get network connections
$networkListManager = [Activator]::CreateInstance([Type]::GetTypeFromCLSID([Guid]"{DCB00C01-570F-4A9B-8D69-199FDBA5723B}"))
$connections = $networkListManager.GetNetworkConnections()
$connections |foreach {
Write-Host $_.GetNetwork().GetName()"category was previously set to"$_.GetNetwork().GetCategory()
$_.GetNetwork().SetCategory(1)
Write-Host $_.GetNetwork().GetName()"changed to category"$_.GetNetwork().GetCategory()
}

View File

@@ -47,77 +47,7 @@ $GetContentSplat = @{
} }
$XML = [xml](Get-Content @GetContentSplat) $XML = [xml](Get-Content @GetContentSplat)
$NS = [System.Xml.XmlNamespaceManager]$XML.NameTable $NS = [System.Xml.XmlNamespaceManager]$XML.NameTable
[void]$NS.AddNamespace('ns', $XML.DocumentElement.xmlns) [void]$NS.AddNamespace('Any', $XML.DocumentElement.xmlns)
[void]$NS.AddNamespace('ovf', $XML.DocumentElement.ovf)
[void]$NS.AddNamespace('rasd', $XML.DocumentElement.rasd)
[void]$NS.AddNamespace('vmw', $XML.DocumentElement.vmw)
# Create copy of existing 'Item/ResourceType'=17 (=Hard disk) node
$XMLDiskTemplate = $XML.SelectSingleNode("//ns:VirtualHardwareSection/ns:Item/rasd:ResourceType[.='17']", $NS).ParentNode.CloneNode($True)
ForEach ($Disk in $OVFConfig.DynamicDisks) {
# Determine next free available 'diskId'
$XMLDisks = $XML.SelectNodes("//ns:DiskSection/ns:Disk[contains(@ovf:diskId,'vmdisk')]", $NS)
$DiskId = 1
While ($XMLDisks.DiskId -contains "vmdisk$($DiskId)") {
$DiskId++
}
# Add new 'Disk' node (under 'DiskSection')
$XMLDisk = $XML.CreateElement('Disk', $XML.DocumentElement.xmlns)
$PowersMap = @{
KB = 10
MB = 20
GB = 30
TB = 40
PB = 50
}
If ($PowersMap.Keys -notcontains $Disk.UnitSize) {
# Invalid UnitSize; skipping adding new disk
Continue
}
[void]$XMLDisk.SetAttribute('capacityAllocationUnits', $NS.LookupNamespace('ovf'), "byte * 2^$($PowersMap[$Disk.UnitSize])")
[void]$XMLDisk.SetAttribute('format', $NS.LookupNamespace('ovf'), 'http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized')
[void]$XMLDisk.SetAttribute('diskId', $NS.LookupNamespace('ovf'), "vmdisk$($DiskId)")
[void]$XMLDisk.SetAttribute('capacity', $NS.LookupNamespace('ovf'), '${{vmconfig.disksize.{0}}}' -f $DiskId)
[void]$XMLDisk.SetAttribute('populatedSize', $NS.LookupNamespace('ovf'), 0)
[void]$XML.SelectSingleNode('//ns:DiskSection', $NS).AppendChild($XMLDisk)
# Add new 'Item/ResourceType' node (under 'VirtualHardwareSection')
$XMLDiskItem = $XMLDiskTemplate.CloneNode($True)
$XMLDiskItem.SelectSingleNode('rasd:AddressOnParent', $NS).InnerText = ($DiskId - 1)
$XMLDiskItem.SelectSingleNode('rasd:ElementName', $NS).InnerText = "Hard Disk $($DiskId)"
$XMLDiskItem.SelectSingleNode('rasd:HostResource', $NS).InnerText = "ovf:/disk/vmdisk$($DiskId)"
# Determine next free available and highest 'InstanceID'
$InstanceIDs = $XML.SelectNodes('//ns:VirtualHardwareSection/ns:Item/rasd:InstanceID', $NS).InnerText
$InstanceID = 1
While ($InstanceIDs -contains $InstanceID) {
$InstanceID++
}
$HighestInstanceID = ($InstanceIDs | Measure-Object -Maximum).Maximum
$XMLDiskItem.SelectSingleNode('rasd:InstanceID', $NS).InnerText = $InstanceID
[void]$XML.SelectSingleNode('//ns:VirtualHardwareSection', $NS).InsertAfter(
$XMLDiskItem,
$XML.SelectSingleNode("//ns:VirtualHardwareSection/ns:Item/rasd:InstanceID[.='$($HighestInstanceID)']", $NS).ParentNode
)
$OVFConfig.PropertyCategories[0].ProductProperties += @{
Key = "vmconfig.disksize.$($DiskId)"
Type = If ([boolean]$Disk.Constraints.Minimum -or [boolean]$Disk.Constraints.Maximum) {
"Int($($Disk.Constraints.Minimum)..$($Disk.Constraints.Maximum))"
}
Else {
'Int'
}
Label = "Disk $($DiskId) size*"
Description = "$($Disk.Description) (in $($Disk.UnitSize))".Trim()
DefaultValue = "$($Disk.Constraints.Minimum)"
Configurations = '*'
UserConfigurable = 'true'
}
}
Write-Host "Inserted $($OVFConfig.DynamicDisks.Count) new node(s) into 'DiskSection' and 'VirtualHardwareSection' respectively"
If ($OVFConfig.DeploymentConfigurations.Count -gt 0) { If ($OVFConfig.DeploymentConfigurations.Count -gt 0) {
$XMLSection = $XML.CreateElement('DeploymentOptionSection', $XML.DocumentElement.xmlns) $XMLSection = $XML.CreateElement('DeploymentOptionSection', $XML.DocumentElement.xmlns)
@@ -128,72 +58,52 @@ If ($OVFConfig.DeploymentConfigurations.Count -gt 0) {
ForEach ($Configuration in $OVFConfig.DeploymentConfigurations) { ForEach ($Configuration in $OVFConfig.DeploymentConfigurations) {
$XMLConfig = $XML.CreateElement('Configuration', $XML.DocumentElement.xmlns) $XMLConfig = $XML.CreateElement('Configuration', $XML.DocumentElement.xmlns)
[void]$XMLConfig.SetAttribute('id', $NS.LookupNamespace('ovf'), $Configuration.Id) $XMLConfigAttrId = $XML.CreateAttribute('id', $XML.DocumentElement.ovf)
$XMLConfigAttrId.Value = $Configuration.Id
$XMLConfigLabel = $XML.CreateElement('Label', $XML.DocumentElement.xmlns) $XMLConfigLabel = $XML.CreateElement('Label', $XML.DocumentElement.xmlns)
$XMLConfigLabel.InnerText = $Configuration.Label $XMLConfigLabel.InnerText = $Configuration.Label
$XMLConfigDescription = $XML.CreateElement('Description', $XML.DocumentElement.xmlns) $XMLConfigDescription = $XML.CreateElement('Description', $XML.DocumentElement.xmlns)
$XMLConfigDescription.InnerText = $Configuration.Description $XMLConfigDescription.InnerText = $Configuration.Description
[void]$XMLConfig.Attributes.Append($XMLConfigAttrId)
[void]$XMLConfig.AppendChild($XMLConfigLabel) [void]$XMLConfig.AppendChild($XMLConfigLabel)
[void]$XMLConfig.AppendChild($XMLConfigDescription) [void]$XMLConfig.AppendChild($XMLConfigDescription)
[void]$XMLSection.AppendChild($XMLConfig) [void]$XMLSection.AppendChild($XMLConfig)
} }
[void]$XML.SelectSingleNode('//ns:Envelope', $NS).InsertAfter($XMLSection, $XML.SelectSingleNode('//ns:NetworkSection', $NS)) [void]$XML.SelectSingleNode('//Any:Envelope', $NS).InsertAfter($XMLSection, $XML.SelectSingleNode('//Any:NetworkSection', $NS))
Write-Host "Inserted 'DeploymentOptionSection' with $($Configuration.Count) nodes" Write-Host "Inserted 'DeploymentOptionSection' with $($Configuration.Count) nodes"
If ($OVFConfig.DeploymentConfigurations.Count -eq $OVFConfig.DeploymentConfigurations.Size.Count) {
# Create copies of existing 'Item/ResourceType' nodes
$XMLCPUTemplate = $XML.SelectSingleNode("//ns:VirtualHardwareSection/ns:Item/rasd:ResourceType[.='3']", $NS).ParentNode.CloneNode($True)
$XMLMemoryTemplate = $XML.SelectSingleNode("//ns:VirtualHardwareSection/ns:Item/rasd:ResourceType[.='4']", $NS).ParentNode.CloneNode($True)
# Delete existing nodes
ForEach ($Node in $XML.SelectNodes("//ns:VirtualHardwareSection/ns:Item/rasd:ResourceType[.='3' or .='4']", $NS).ParentNode) {
[void]$Node.ParentNode.RemoveChild($Node)
}
# Add adjusted 'Item/ResourceType' nodes
ForEach ($Configuration in $OVFConfig.DeploymentConfigurations) {
$XMLCPU = $XMLCPUTemplate.CloneNode($True)
[void]$XMLCPU.SetAttribute('configuration', $NS.LookupNamespace('ovf'), $Configuration.Id)
$XMLCPU.SelectSingleNode('rasd:ElementName', $NS).InnerText = '{0} virtual CPU(s)' -f $Configuration.Size.CPU
$XMLCPU.SelectSingleNode('rasd:VirtualQuantity', $NS).InnerText = $Configuration.Size.CPU
$XMLMemory = $XMLMemoryTemplate.CloneNode($True)
[void]$XMLMemory.SetAttribute('configuration', $NS.LookupNamespace('ovf'), $Configuration.Id)
$XMLMemory.SelectSingleNode('rasd:ElementName', $NS).InnerText = '{0}MB of memory' -f $Configuration.Size.Memory
$XMLMemory.SelectSingleNode('rasd:VirtualQuantity', $NS).InnerText = $Configuration.Size.Memory
[void]$XML.SelectSingleNode('//ns:VirtualHardwareSection', $NS).InsertAfter(
$XMLCPU,
$XML.SelectSingleNode('//ns:VirtualHardwareSection/ns:System', $NS)
)
[void]$XML.SelectSingleNode('//ns:VirtualHardwareSection', $NS).InsertAfter(
$XMLMemory,
$XML.SelectSingleNode('//ns:VirtualHardwareSection/ns:System', $NS)
)
}
}
} }
[void]$XML.SelectSingleNode('//ns:VirtualHardwareSection', $NS).SetAttribute('transport', $NS.LookupNamespace('ovf'), 'com.vmware.guestInfo') $XMLAttrTransport = $XML.CreateAttribute('transport', $XML.DocumentElement.ovf)
$XMLAttrTransport.Value = 'com.vmware.guestInfo'
[void]$XML.SelectSingleNode('//Any:VirtualHardwareSection', $NS).Attributes.Append($XMLAttrTransport)
ForEach ($ExtraConfig in $OVFConfig.AdvancedOptions) { ForEach ($ExtraConfig in $OVFConfig.AdvancedOptions) {
$XMLExtraConfig = $XML.CreateElement('vmw:ExtraConfig', $XML.DocumentElement.vmw) $XMLExtraConfig = $XML.CreateElement('vmw:ExtraConfig', $XML.DocumentElement.vmw)
[void]$XMLExtraConfig.SetAttribute('required', $NS.LookupNamespace('ovf'), "$([boolean]$ExtraConfig.Required)".ToLower()) $XMLExtraConfigAttrRequired = $XML.CreateAttribute('required', $XML.DocumentElement.ovf)
[void]$XMLExtraConfig.SetAttribute('key', $NS.LookupNamespace('vmw'), $ExtraConfig.Key) $XMLExtraConfigAttrRequired.Value = "$([boolean]$ExtraConfig.Required)".ToLower()
[void]$XMLExtraConfig.SetAttribute('value', $NS.LookupNamespace('vmw'), $ExtraConfig.Value) $XMLExtraConfigAttrKey = $XML.CreateAttribute('key', $XML.DocumentElement.vmw)
$XMLExtraConfigAttrKey.Value = $ExtraConfig.Key
$XMLExtraConfigAttrValue = $XML.CreateAttribute('value', $XML.DocumentElement.vmw)
$XMLExtraConfigAttrValue.Value = $ExtraConfig.Value
[void]$XML.SelectSingleNode('//ns:VirtualHardwareSection', $NS).AppendChild($XMLExtraConfig) [void]$XMLExtraConfig.Attributes.Append($XMLExtraConfigAttrRequired)
[void]$XMLExtraConfig.Attributes.Append($XMLExtraConfigAttrKey)
[void]$XMLExtraConfig.Attributes.Append($XMLExtraConfigAttrValue)
[void]$XML.SelectSingleNode('//Any:VirtualHardwareSection', $NS).AppendChild($XMLExtraConfig)
} }
Write-Host "Added $($OVFConfig.AdvancedOptions.Count) 'vmw:ExtraConfig' node(s)" Write-Host "Added $($OVFConfig.AdvancedOptions.Count) 'vmw:ExtraConfig' nodes"
$XMLProductSection = $XML.SelectSingleNode('//ns:ProductSection', $NS) $XMLProductSection = $XML.SelectSingleNode('//Any:ProductSection', $NS)
If ($XMLProductSection -eq $Null) { If ($XMLProductSection -eq $Null) {
$XMLProductSection = $XML.CreateElement('ProductSection', $XML.DocumentElement.xmlns) $XMLProductSection = $XML.CreateElement('ProductSection', $XML.DocumentElement.xmlns)
[void]$XML.SelectSingleNode('//ns:VirtualSystem', $NS).AppendChild($XMLProductSection) [void]$XML.SelectSingleNode('//Any:VirtualSystem', $NS).AppendChild($XMLProductSection)
Write-Host "Inserted 'ProductSection'" Write-Host "Inserted 'ProductSection'"
} Else { } Else {
ForEach ($Child in $XMLProductSection.SelectNodes('//ns:ProductSection/child::*', $NS)) { ForEach ($Child in $XMLProductSection.SelectNodes('//Any:ProductSection/child::*', $NS)) {
[void]$Child.ParentNode.RemoveChild($Child) [void]$Child.ParentNode.RemoveChild($Child)
} }
Write-Host "Destroyed pre-existing children in 'ProductSection'" Write-Host "Destroyed pre-existing children in 'ProductSection'"
@@ -214,13 +124,15 @@ ForEach ($Category in $OVFConfig.PropertyCategories) {
ForEach ($Property in $Category.ProductProperties) { ForEach ($Property in $Category.ProductProperties) {
$XMLProperty = $XML.CreateElement('Property', $XML.DocumentElement.xmlns) $XMLProperty = $XML.CreateElement('Property', $XML.DocumentElement.xmlns)
[void]$XMLProperty.SetAttribute('key', $NS.LookupNamespace('ovf'), $Property.Key) $XMLPropertyAttrKey = $XML.CreateAttribute('key', $XML.DocumentElement.ovf)
$XMLPropertyAttrKey.Value = $Property.Key
$XMLPropertyAttrType = $XML.CreateAttribute('type', $XML.DocumentElement.ovf)
Switch -regex ($Property.Type) { Switch -regex ($Property.Type) {
'^boolean' { '^boolean' {
[void]$XMLProperty.SetAttribute('type', $NS.LookupNamespace('ovf'), 'boolean') $XMLPropertyAttrType.Value = 'boolean'
} }
'^int' { '^int' {
[void]$XMLProperty.SetAttribute('type', $NS.LookupNamespace('ovf'), 'uint16') $XMLPropertyAttrType.Value = 'uint8'
$Qualifiers = @() $Qualifiers = @()
If ($Property.Type -match '^int\((\d*)\.\.(\d*)\)') { If ($Property.Type -match '^int\((\d*)\.\.(\d*)\)') {
If ($Matches[1]) { If ($Matches[1]) {
@@ -229,16 +141,23 @@ ForEach ($Category in $OVFConfig.PropertyCategories) {
If ($Matches[2]) { If ($Matches[2]) {
$Qualifiers += "MaxValue($($Matches[2]))" $Qualifiers += "MaxValue($($Matches[2]))"
} }
[void]$XMLProperty.SetAttribute('qualifiers', $NS.LookupNamespace('ovf'), $Qualifiers -join ' ') $XMLPropertyAttrQualifiers = $XML.CreateAttribute('qualifiers', $XML.DocumentElement.ovf)
$XMLPropertyAttrQualifiers.Value = $Qualifiers -join ' '
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrQualifiers)
} }
} }
'^ip' { '^ip' {
[void]$XMLProperty.SetAttribute('type', $NS.LookupNamespace('ovf'), 'string') $XMLPropertyAttrType.Value = 'string'
[void]$XMLProperty.SetAttribute('qualifiers', $NS.LookupNamespace('vmw'), 'Ip') $XMLPropertyAttrQualifiers = $XML.CreateAttribute('qualifiers', $XML.DocumentElement.vmw)
$XMLPropertyAttrQualifiers.Value = 'Ip'
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrQualifiers)
} }
'^password' { '^password' {
[void]$XMLProperty.SetAttribute('type', $NS.LookupNamespace('ovf'), 'string') $XMLPropertyAttrType.Value = 'string'
[void]$XMLProperty.SetAttribute('password', $NS.LookupNamespace('ovf'), 'true') $XMLPropertyAttrPassword = $XML.CreateAttribute('password', $XML.DocumentElement.ovf)
$XMLPropertyAttrPassword.Value = 'true'
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrPassword)
$Qualifiers = @() $Qualifiers = @()
If ($Property.Type -match '^password\((\d*)\.\.(\d*)\)') { If ($Property.Type -match '^password\((\d*)\.\.(\d*)\)') {
If ($Matches[1]) { If ($Matches[1]) {
@@ -247,11 +166,13 @@ ForEach ($Category in $OVFConfig.PropertyCategories) {
If ($Matches[2]) { If ($Matches[2]) {
$Qualifiers += "MaxLen($($Matches[2]))" $Qualifiers += "MaxLen($($Matches[2]))"
} }
[void]$XMLProperty.SetAttribute('qualifiers', $NS.LookupNamespace('ovf'), $Qualifiers -join ' ') $XMLPropertyAttrQualifiers = $XML.CreateAttribute('qualifiers', $XML.DocumentElement.ovf)
$XMLPropertyAttrQualifiers.Value = $Qualifiers -join ' '
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrQualifiers)
} }
} }
'^string' { '^string' {
[void]$XMLProperty.SetAttribute('type', $NS.LookupNamespace('ovf'), 'string') $XMLPropertyAttrType.Value = 'string'
$Qualifiers = @() $Qualifiers = @()
If ($Property.Type -match '^string\((\d*)\.\.(\d*)\)') { If ($Property.Type -match '^string\((\d*)\.\.(\d*)\)') {
If ($Matches[1]) { If ($Matches[1]) {
@@ -260,19 +181,28 @@ ForEach ($Category in $OVFConfig.PropertyCategories) {
If ($Matches[2]) { If ($Matches[2]) {
$Qualifiers += "MaxLen($($Matches[2]))" $Qualifiers += "MaxLen($($Matches[2]))"
} }
[void]$XMLProperty.SetAttribute('qualifiers', $NS.LookupNamespace('ovf'), $Qualifiers -join ' ') $XMLPropertyAttrQualifiers = $XML.CreateAttribute('qualifiers', $XML.DocumentElement.ovf)
$XMLPropertyAttrQualifiers.Value = $Qualifiers -join ' '
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrQualifiers)
} ElseIf ($Property.Type -match '^string\[(.*)\]') { } ElseIf ($Property.Type -match '^string\[(.*)\]') {
[void]$XMLProperty.SetAttribute('qualifiers', $NS.LookupNamespace('ovf'), "ValueMap{$($Matches[1] -replace '","', '", "')}") $XMLPropertyAttrQualifiers = $XML.CreateAttribute('qualifiers', $XML.DocumentElement.ovf)
$XMLPropertyAttrQualifiers.Value = "ValueMap{$($Matches[1] -replace '","', '", "')}"
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrQualifiers)
} }
} }
} }
[void]$XMLProperty.SetAttribute('userConfigurable', $NS.LookupNamespace('ovf'), "$([boolean]$Property.UserConfigurable)".ToLower()) $XMLPropertyAttrUserConfigurable = $XML.CreateAttribute('userConfigurable', $XML.DocumentElement.ovf)
$XMLPropertyAttrUserConfigurable.Value = "$([boolean]$Property.UserConfigurable)".ToLower()
$XMLPropertyAttrValue = $XML.CreateAttribute('value', $XML.DocumentElement.ovf)
If ($Property.Type -eq 'boolean') { If ($Property.Type -eq 'boolean') {
[void]$XMLProperty.SetAttribute('value', $NS.LookupNamespace('ovf'), "$([boolean]$Property.DefaultValue)".ToLower()) $XMLPropertyAttrValue.Value = "$([boolean]$Property.DefaultValue)".ToLower()
} Else { } Else {
[void]$XMLProperty.SetAttribute('value', $NS.LookupNamespace('ovf'), $Property.DefaultValue) $XMLPropertyAttrValue.Value = $Property.DefaultValue
} }
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrKey)
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrType)
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrUserConfigurable)
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrValue)
If ($Property.Label) { If ($Property.Label) {
$XMLPropertyLabel = $XML.CreateElement('Label', $XML.DocumentElement.xmlns) $XMLPropertyLabel = $XML.CreateElement('Label', $XML.DocumentElement.xmlns)
@@ -286,19 +216,30 @@ ForEach ($Category in $OVFConfig.PropertyCategories) {
} }
If (($Property.Configurations.Count -eq 1) -and ($Property.Configurations -eq '*')) { If (($Property.Configurations.Count -eq 1) -and ($Property.Configurations -eq '*')) {
[void]$XMLProperty.SetAttribute('configuration', $NS.LookupNamespace('ovf'), $OVFConfig.DeploymentConfigurations.Id -join ' ') $XMLPropertyAttrConfiguration = $XML.CreateAttribute('configuration', $XML.DocumentElement.ovf)
$XMLPropertyAttrConfiguration.Value = $OVFConfig.DeploymentConfigurations.Id -join ' '
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrConfiguration)
} ElseIf ($Property.Configurations.Count -gt 0) { } ElseIf ($Property.Configurations.Count -gt 0) {
[void]$XMLProperty.SetAttribute('configuration', $NS.LookupNamespace('ovf'), $Property.Configurations -join ' ') $XMLPropertyAttrConfiguration = $XML.CreateAttribute('configuration', $XML.DocumentElement.ovf)
$XMLPropertyAttrConfiguration.Value = $Property.Configurations -join ' '
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrConfiguration)
} }
If ($Property.Value.Count -eq 1) { If ($Property.Value.Count -eq 1) {
[void]$XMLProperty.SetAttribute('value', $NS.LookupNamespace('ovf'), $Property.Value) $XMLPropertyAttrValue = $XML.CreateAttribute('value', $XML.DocumentElement.ovf)
$XMLPropertyAttrValue.Value = $Property.Value
[void]$XMLProperty.Attributes.Append($XMLPropertyAttrValue)
} ElseIf ($Property.Value.Count -gt 1) { } ElseIf ($Property.Value.Count -gt 1) {
ForEach ($Value in $Property.Value) { ForEach ($Value in $Property.Value) {
$XMLValue = $XML.CreateElement('Value', $XML.DocumentElement.xmlns) $XMLValue = $XML.CreateElement('Value', $XML.DocumentElement.xmlns)
[void]$XMLValue.SetAttribute('value', $NS.LookupNamespace('ovf'), $Value) $XMLValueAttrValue = $XML.CreateAttribute('value', $XML.DocumentElement.ovf)
[void]$XMLValue.SetAttribute('configuration', $NS.LookupNamespace('ovf'), $Value) $XMLValueAttrValue.Value = $Value
$XMLValueAttrConfiguration = $XML.CreateAttribute('configuration', $XML.DocumentElement.ovf)
$XMLValueAttrConfiguration.Value = $Value
[void]$XMLValue.Attributes.Append($XMLValueAttrValue)
[void]$XMLValue.Attributes.Append($XMLValueAttrConfiguration)
[void]$XMLProperty.AppendChild($XMLValue) [void]$XMLProperty.AppendChild($XMLValue)
} }
@@ -309,4 +250,4 @@ ForEach ($Category in $OVFConfig.PropertyCategories) {
Write-Host "Inserted $($Category.ProductProperties.Count) new node(s) into 'ProductSection'" Write-Host "Inserted $($Category.ProductProperties.Count) new node(s) into 'ProductSection'"
} }
$XML.Save($SourceFile.FullName) $XML.Save($SourceFile.FullName)

View File

@@ -1,51 +1,21 @@
DeploymentConfigurations: DeploymentConfigurations:
- Id: domainmember
- Id: small Label: Domain member
Label: 'Ubuntu Server 22.04 [SMALL: 1 vCPU/2GB RAM]' Description: Windows 10 client joined to an Active Directory domain
Description: Ubuntu Server 22.04.x - Id: standalone
Size: Label: Stand-alone
CPU: 1 Description: Stand-alone Windows 10 client
Memory: 2048
- Id: medium
Label: 'Ubuntu Server 22.04 [MEDIUM: 2 vCPU/4GB RAM]'
Description: Ubuntu Server 22.04.x
Size:
CPU: 2
Memory: 4096
DynamicDisks:
- Description: Longhorn persistent storage
UnitSize: GB
Constraints:
Minium: 100
Maximum: ''
PropertyCategories: PropertyCategories:
- Name: 0) Deployment information
# - Name: 0) Deployment information
# ProductProperties:
# - Key: deployment.type
# Type: string
# Value:
# - small
# - medium
# UserConfigurable: false
- Name: 1) Kubernetes
ProductProperties: ProductProperties:
- Key: guestinfo.fqdn - Key: deployment.type
Type: string(1..) Type: string
Label: Appliance FQDN* Value:
Description: 'Respective subdomains will be available for each component (e.g. storage.example.org); this address should already be configured as a wildcard record within your DNS zone.' - domainmember
DefaultValue: 'example.org' - standalone
Configurations: '*' UserConfigurable: false
UserConfigurable: true - Name: 1) Operating System
- Name: 2) Operating System
ProductProperties: ProductProperties:
- Key: guestinfo.hostname - Key: guestinfo.hostname
Type: string(1..15) Type: string(1..15)
Label: Hostname* Label: Hostname*
@@ -53,26 +23,24 @@ PropertyCategories:
DefaultValue: '' DefaultValue: ''
Configurations: '*' Configurations: '*'
UserConfigurable: true UserConfigurable: true
- Key: guestinfo.administratorpw
- Key: guestinfo.rootpw
Type: password(7..) Type: password(7..)
Label: Local root password* Label: Local administrator password*
Description: '' Description: Must meet password complexity rules
DefaultValue: '' DefaultValue: password
Configurations: '*' Configurations:
- standalone
UserConfigurable: true UserConfigurable: true
- Key: guestinfo.ntpserver
- Key: guestinfo.rootsshkey Type: string(1..)
Type: password(1..) Label: Time server*
Label: Local root SSH public key* Description: A comma-separated list of timeservers
Description: This line should start with 'ssh-rsa AAAAB3N' DefaultValue: 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org
DefaultValue: '' Configurations:
Configurations: '*' - standalone
UserConfigurable: true UserConfigurable: true
- Name: 2) Networking
- Name: 3) Networking
ProductProperties: ProductProperties:
- Key: guestinfo.ipaddress - Key: guestinfo.ipaddress
Type: ip Type: ip
Label: IP Address* Label: IP Address*
@@ -80,7 +48,6 @@ PropertyCategories:
DefaultValue: '' DefaultValue: ''
Configurations: '*' Configurations: '*'
UserConfigurable: true UserConfigurable: true
- Key: guestinfo.prefixlength - Key: guestinfo.prefixlength
Type: int(8..32) Type: int(8..32)
Label: Subnet prefix length* Label: Subnet prefix length*
@@ -88,7 +55,6 @@ PropertyCategories:
DefaultValue: '24' DefaultValue: '24'
Configurations: '*' Configurations: '*'
UserConfigurable: true UserConfigurable: true
- Key: guestinfo.dnsserver - Key: guestinfo.dnsserver
Type: ip Type: ip
Label: DNS server* Label: DNS server*
@@ -96,7 +62,6 @@ PropertyCategories:
DefaultValue: '' DefaultValue: ''
Configurations: '*' Configurations: '*'
UserConfigurable: true UserConfigurable: true
- Key: guestinfo.gateway - Key: guestinfo.gateway
Type: ip Type: ip
Label: Gateway* Label: Gateway*
@@ -104,15 +69,32 @@ PropertyCategories:
DefaultValue: '' DefaultValue: ''
Configurations: '*' Configurations: '*'
UserConfigurable: true UserConfigurable: true
- Name: 3) Active Directory membership
- Key: guestinfo.ntpserver ProductProperties:
- Key: addsconfig.domainname
Type: string(1..) Type: string(1..)
Label: Time server* Label: Domain name*
Description: A comma-separated list of timeservers Description: Must be able to be resolved through provided DNS server
DefaultValue: 0.pool.ntp.org,1.pool.ntp.org,2.pool.ntp.org DefaultValue: example.org
Configurations: '*' Configurations:
- domainmember
UserConfigurable: true
- Key: addsconfig.username
Type: string(1..)
Label: Domain account username*
Description: ''
DefaultValue: username
Configurations:
- domainmember
UserConfigurable: true
- Key: addsconfig.password
Type: password(1..)
Label: Domain account password*
Description: ''
DefaultValue: password
Configurations:
- domainmember
UserConfigurable: true UserConfigurable: true
AdvancedOptions: AdvancedOptions:
- Key: appliance.name - Key: appliance.name
Value: "{{ appliance.name }}" Value: "{{ appliance.name }}"

View File

@@ -0,0 +1,7 @@
[CmdletBinding()]
Param(
# No parameters
)
# Create scheduled task
& schtasks.exe /Create /TN 'FirstBoot' /SC ONSTART /RU SYSTEM /TR "powershell.exe -file C:\Payload\Apply-FirstBootConfig.ps1"

View File

@@ -0,0 +1,244 @@
[CmdletBinding()]
Param(
# No parameters
)
$SetLocationSplat = @{
Path = $PSScriptRoot
}
Set-Location @SetLocationSplat
$NewEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
ErrorAction = 'SilentlyContinue'
}
New-EventLog @NewEventLogSplat
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Information'
EventID = 1
Message = "FirstBoot sequence initiated [working directory: '$PWD']"
}
Write-EventLog @WriteEventLogSplat
$VMwareToolsExecutable = "C:\Program Files\VMware\VMware Tools\vmtoolsd.exe"
[xml]$ovfEnv = & $VMwareToolsExecutable --cmd "info-get guestinfo.ovfEnv" | Out-String
$ovfProperties = $ovfEnv.ChildNodes.NextSibling.PropertySection.Property
$ovfPropertyValues = @{}
foreach ($ovfProperty in $ovfProperties) {
$ovfPropertyValues[$ovfProperty.key] = $ovfProperty.Value
}
# Check for mandatory values
Switch ($ovfPropertyValues['deployment.type']) {
'domainmember' {
$MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.gateway', 'addsconfig.domainname', 'addsconfig.username', 'addsconfig.password'), @()
}
'standalone' {
$MandatoryProperties, $MissingProperties = @('guestinfo.hostname', 'guestinfo.ipaddress', 'guestinfo.prefixlength', 'guestinfo.gateway', 'guestinfo.administratorpw', 'guestinfo.ntpserver'), @()
}
default {
# Mandatory values missing, cannot provision.
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Error'
EventID = 66
Message = "Unexpected or no value set for property 'deployment.type', cannot provision."
}
Write-EventLog @WriteEventLogSplat
& schtasks.exe /Change /TN 'FirstBoot' /DISABLE
Stop-Computer -Force
Exit
}
}
ForEach ($Property in $MandatoryProperties) {
If (!$ovfPropertyValues[$Property]) {
$MissingProperties += $Property
}
}
If ($MissingProperties.Length -gt 0) {
# Mandatory values missing, cannot provision.
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Error'
EventID = 66
Message = "Missing values for mandatory properties $(($MissingProperties | ForEach-Object {"'{0}'" -f $_}) -join ', '), cannot provision."
}
Write-EventLog @WriteEventLogSplat
& schtasks.exe /Change /TN 'FirstBoot' /DISABLE
Stop-Computer -Force
Exit
}
# Set hostname and description
If ($Env:ComputerName -ne $ovfPropertyValues['guestinfo.hostname']) {
$RenameComputerSplat = @{
NewName = $ovfPropertyValues['guestinfo.hostname']
Force = $True
Confirm = $False
}
Rename-Computer @RenameComputerSplat
$SetCimInstanceSplat = @{
InputObject = (Get-CimInstance -ClassName 'Win32_OperatingSystem')
Property = @{
Description = $ovfPropertyValues['guestinfo.hostname']
}
}
Set-CimInstance @SetCimInstanceSplat
# Restart the computer to apply changes
Restart-Computer -Force
Exit
}
# Configure network interface
If ((Get-WmiObject -Class 'Win32_NetworkAdapterConfiguration').IPAddress -NotContains $ovfPropertyValues['guestinfo.ipaddress']) {
$NewNetIPAddressSplat = @{
InterfaceAlias = (Get-NetAdapter).Name
AddressFamily = 'IPv4'
IPAddress = $ovfPropertyValues['guestinfo.ipaddress']
PrefixLength = $ovfPropertyValues['guestinfo.prefixlength']
DefaultGateway = $ovfPropertyValues['guestinfo.gateway']
}
$IPAddress = New-NetIPAddress @NewNetIPAddressSplat
# Wait for network connection to become available
$Timestamp, $TimeoutMinutes = (Get-Date), 5
Do {
If ($Timestamp.AddMinutes($TimeoutMinutes) -lt (Get-Date)) {
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Warning'
EventID = 13
Message = "Timeout after $($TimeoutMinutes) minutes waiting for network connection to become available."
}
Write-EventLog @WriteEventLogSplat
Break
}
Start-Sleep -Milliseconds 250
$GetNetIPAddressSplat = @{
IPAddress = $ovfPropertyValues['guestinfo.ipaddress']
InterfaceIndex = $IPAddress.InterfaceIndex
AddressFamily = 'IPv4'
ErrorAction = 'SilentlyContinue'
}
} Until ((Get-NetIPAddress @GetNetIPAddressSplat).AddressState -eq 'Preferred')
$OldErrorActionPreference, $ErrorActionPreference = $ErrorActionPreference, 'SilentlyContinue'
$TestNetConnectionSplat = @{
ComputerName = ([IPAddress]$ovfPropertyValues['guestinfo.dnsserver']).IPAddressToString
InformationLevel = 'Quiet'
}
$SetDnsClientServerAddressSplat = @{
InterfaceAlias = (Get-NetAdapter).Name
ServerAddresses = If (
[boolean]($ovfPropertyValues['guestinfo.dnsserver'] -as [IPaddress]) -and (Test-NetConnection @TestNetConnectionSplat)) {
($ovfPropertyValues['guestinfo.dnsserver'])
} else {
('127.0.0.1')
}
Validate = $False
}
Set-DnsClientServerAddress @SetDnsClientServerAddressSplat
$ErrorActionPreference, $OldErrorActionPreference = $OldErrorActionPreference, $NULL
}
Switch ($ovfPropertyValues['deployment.type']) {
'domainmember' {
# Join Active Directory domain as member
If (!(Get-WmiObject -Class Win32_ComputerSystem).PartOfDomain) {
$AddComputerSplat = @{
DomainName = $ovfPropertyValues['addsconfig.domainname']
Credential = New-Object System.Management.Automation.PSCredential(
$ovfPropertyValues['addsconfig.username'],
(ConvertTo-SecureString $ovfPropertyValues['addsconfig.password'] -AsPlainText -Force)
)
# OUPath = $ovfPropertyValues['addsconfig.organizationalunit']
Restart = $True
Force = $True
Confirm = $False
}
Add-Computer @AddComputerSplat
# Previous cmdlet performs a reboot on completion; so these are commented out
# Restart-Computer -Force
# Exit
}
}
'standalone' {
# Change password of built-in Administrator
$BuiltinAdministrator = (Get-LocalUser | Where-Object {$_.SID -match '-500'})
$ConvertToSecureStringSplat = @{
String = $ovfPropertyValues['guestinfo.administratorpw']
AsPlainText = $True
Force = $True
}
$SetLocalUserSplat = @{
InputObject = $BuiltinAdministrator
Password = ConvertTo-SecureString @ConvertToSecureStringSplat
PasswordNeverExpires = $True
AccountNeverExpires = $True
### This setting is not allowed on the last administrator
# UserMayChangePassword = $False
Confirm = $False
}
Set-LocalUser @SetLocalUserSplat
$EnableLocalUserSplat = @{
InputObject = $BuiltinAdministrator
Confirm = $False
}
Enable-LocalUser @EnableLocalUserSplat
}
}
# Iterate through and invoke all payload scripts
#! TODO: add registry values to determine which scripts have already been invoked (in case of intermediate reboots)
$GetItemSplat = @{
Path = "$($PSScriptRoot)\Scripts\*.ps1"
}
ForEach ($Script in (Get-Item @GetItemSplat)) {
Try {
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Information'
EventID = 4
Message = "Running script: '$($Script.FullName)'"
}
Write-EventLog @WriteEventLogSplat
& $Script.FullName -Parameter $ovfPropertyValues
}
Catch {
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Error'
EventID = 66
Message = @"
Error occurred while executing script '$($Script.Name)':
$($_.Exception.Message)
"@
}
Write-EventLog @WriteEventLogSplat
}
}
$WriteEventLogSplat = @{
LogName = 'Application'
Source = 'FirstBoot'
EntryType = 'Information'
EventID = 42
Message = 'FirstBoot sequence applied and finished'
}
Write-EventLog @WriteEventLogSplat
& schtasks.exe /Change /TN 'FirstBoot' /DISABLE