MyLab - itnett/FTD02H-N GitHub Wiki

To create a fully automated CI/CD environment on Windows 11 that sets up and tears down lab environments, follow these steps:

Step 1: Create a PowerShell Script for Environment Setup

setup-environment.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log-Message

To create a comprehensive CI/CD environment on Windows 11 that sets up and tears down various lab environments automatically, we'll follow these steps:

### Step 1: Prepare the Environment

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log-Message "Terraform applied

To create a comprehensive CI/CD environment on Windows 11 that sets up and tears down various lab environments, we will develop scripts to automate the installation, configuration, and management of software components such as VirtualBox, Docker, Minikube, WSL, and Terraform. The environment should be capable of deploying multiple lab configurations (e.g., `mylab1`, `mylab2`, etc.), ensuring that the system remains clean and well-managed.

### Step 1: Prepare the Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to

To create a comprehensive CI/CD environment on Windows 11 that automates the setup, configuration, and teardown of various lab environments, follow these steps:

### Step 1: Prepare the Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log

To create a comprehensive CI/CD environment on Windows 11 that automates the setup, configuration, and teardown of various lab environments, follow these steps:

### Step 1: Prepare the Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log



To create a fully automated CI/CD environment on Windows 11 that sets up and tears down lab environments, follow these steps:

### Step 1: Create a PowerShell Script for Environment Setup

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log-Message

To create a comprehensive CI/CD environment on Windows 11 that sets up and tears down various lab environments automatically, we'll follow these steps:

### Step 1: Prepare the Environment

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log-Message "Terraform applied

To create a comprehensive CI/CD environment on Windows 11 that sets up and tears down various lab environments, we will develop scripts to automate the installation, configuration, and management of software components such as VirtualBox, Docker, Minikube, WSL, and Terraform. The environment should be capable of deploying multiple lab configurations (e.g., `mylab1`, `mylab2`, etc.), ensuring that the system remains clean and well-managed.

### Step 1: Prepare the Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to

To create a comprehensive CI/CD environment on Windows 11 that automates the setup, configuration, and teardown of various lab environments, follow these steps:

### Step 1: Prepare the Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log

To create a comprehensive CI/CD environment on Windows 11 that automates the setup, configuration, and teardown of various lab environments, follow these steps:

### Step 1: Prepare the Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip = terraform output -raw vm_ip
    Log

To set up a clean CI/CD environment on Windows 11 that automates the creation and management of multiple lab environments, follow these detailed steps:

### Step 1: Prepare Environment Setup Script

Create a PowerShell script to set up the directory structure and initiate the installation of necessary software.

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

Create a PowerShell script to install necessary software using Chocolatey.

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

Create a bash script to configure Ansible within the WSL environment.

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

Create a Terraform configuration to set up a VirtualBox VM.

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

Create an Ansible playbook to configure the VM.

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

Create a PowerShell script to automate the entire setup process.

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1

To set up a clean CI/CD environment on Windows 11, follow these steps to automate the creation and management of multiple lab environments using PowerShell, Terraform, Ansible, and other necessary tools:

### Step 1: Prepare Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}

# Step 3: Apply Terraform configuration
Log-Message "Applying Terraform configuration..."
try {
    cd $basePath\terraform
    terraform init
    terraform apply -auto-approve
    $vm_ip =

To set up a clean CI/CD environment on Windows 11, follow these steps to automate the creation and management of multiple lab environments using PowerShell, Terraform, Ansible, and other necessary tools. The setup ensures the environment is clean and well-managed, with the ability to create, destroy, and manage various lab environments.

### Step 1: Prepare Environment Setup Script

Create a PowerShell script to set up the directory structure and initiate the installation of necessary software.

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

Create a PowerShell script to install necessary software using Chocolatey.

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

Create a bash script to configure Ansible within the WSL environment.

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

Create a Terraform configuration to set up a VirtualBox VM.

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

Create an Ansible playbook to configure the VM.

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

Create a PowerShell script to automate the entire setup process.

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Clean existing environment


To create a CI/CD environment on Windows 11 that automatically sets up, configures, and manages multiple lab environments using VirtualBox, Docker, Minikube, WSL, and Terraform, follow these steps:

### Step 1: Prepare Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1

# Path to download installers
$downloadPath = "C:\temp"

# Log file path
$logFile = "C:\lab\mylab\logs\install-software.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "C:\lab\mylab\logs")) {
    New-Item -ItemType Directory -Path "C:\lab\mylab\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Create the download directory if it does not exist
if (-Not (Test-Path -Path $downloadPath)) {
    try {
        New-Item -ItemType Directory -Path $downloadPath -Force
        Log-Message "Download directory created: $downloadPath"
    } catch {
        Log-Message "Failed to create download directory: $downloadPath - $_"
    }
}

# Install Chocolatey if not installed
if (-Not (Get-Command choco -ErrorAction SilentlyContinue)) {
    try {
        Set-ExecutionPolicy Bypass -Scope Process -Force; 
        [System.Net.ServicePointManager]::SecurityProtocol = [System.Net.ServicePointManager]::SecurityProtocol -bor 3072; 
        iex ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))
        Log-Message "Chocolatey installed."
    } catch {
        Log-Message "Failed to install Chocolatey: $_"
    }
}

# Install software
$software = @("virtualbox", "docker-desktop", "terraform", "git", "minikube")
foreach ($app in $software) {
    try {
        choco install $app -y
        Log-Message "$app installed."
    } catch {
        Log-Message "Failed to install $app: $_"
    }
}

# Install WSL and Ubuntu
try {
    wsl --install -d Ubuntu
    Log-Message "WSL and Ubuntu installed."
} catch {
    Log-Message "Failed to install WSL and Ubuntu: $_"
}

Write-Output "All software installed. Please restart your computer to complete the installation."
Log-Message "All software installed. Please restart your computer to complete the installation."

Step 3: Configure Ansible in WSL

configure-ansible.sh

#!/bin/bash

LOGFILE="/mnt/c/lab/mylab/logs/configure-ansible.log"

# Function to log messages
log_message() {
    local MESSAGE=$1
    echo "$(date +'%Y-%m-%d %H:%M:%S') - $MESSAGE" | tee -a $LOGFILE
}

log_message "Starting Ansible configuration..."

# Update and upgrade the system
log_message "Updating and upgrading the system..."
sudo apt update && sudo apt upgrade -y
if [ $? -ne 0 ]; then
    log_message "Failed to update and upgrade the system."
    exit 1
else
    log_message "System updated and upgraded successfully."
fi

# Install Ansible
log_message "Installing Ansible..."
sudo apt install ansible -y
if [ $? -ne 0 ]; then
    log_message "Failed to install Ansible."
    exit 1
else
    log_message "Ansible installed successfully."
fi

# Verify Ansible installation
ANSIBLE_VERSION=$(ansible --version)
log_message "Ansible version: $ANSIBLE_VERSION"

Step 4: Create Terraform File

main.tf

provider "virtualbox" {}

resource "virtualbox_vm" "ubuntu_vm" {
  name   = "ubuntu-lab-vm"
  image  = "https://cloud-images.ubuntu.com/bionic/current/bionic-server-cloudimg-amd64-vagrant.box"
  cpus   = 2
  memory = "2048 mib"

  network_adapter {
    type           = "hostonly"
    host_interface = "vboxnet0"
  }

  disk {
    image = "${path.module}/../vbox/vms/ubuntu-lab-vm-disk.vdi"
    size  = "20 gib"
  }
}

output "vm_ip" {
  value = virtualbox_vm.ubuntu_vm.network_adapter.0.ipv4_address
}

Step 5: Create Ansible Playbook

playbook.yml

- name: Configure Ubuntu VM
  hosts: all
  become: yes
  tasks:
    - name: Update and upgrade apt packages
      apt:
        update_cache: yes
        upgrade: dist
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

    - name: Install Docker
      apt:
        name: docker.io
        state: present
      notify:
        - Start Docker
      register: result
      ignore_errors: yes
    - name: Log result
      debug:
        var: result

  handlers:
    - name: Start Docker
      service:
        name: docker
        state: started

Step 6: Create Script to Automate Entire Setup

deploy-lab.ps1

param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\deploy-lab.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Clean existing environment
Log-Message "Cleaning existing environment..."
if (Test-Path -Path $basePath) {
    Remove-Item -Recurse -Force -Path $basePath
}
Log-Message "Existing environment cleaned."

# Step 2: Run setup-environment script
Log-Message "Running setup-environment script..."
try {
    .\scripts\setup-environment.ps1 -LabName $LabName
} catch {
    Handle-Error "Failed to run setup-environment script: $_"
}



To create a comprehensive CI/CD environment on Windows 11 that automates the creation, configuration, and management of lab environments, follow these steps. This setup involves using PowerShell, Chocolatey, WSL, Ansible, Terraform, and VirtualBox.

### Step 1: Environment Setup Script

**`setup-environment.ps1`**
```powershell
param (
    [string]$LabName = "mylab1"
)

# Define base path
$basePath = "C:\lab\$LabName"

# Log file path
$logFile = "$basePath\logs\setup-environment.log"

# Create log directory if it does not exist
if (-Not (Test-Path -Path "$basePath\logs")) {
    New-Item -ItemType Directory -Path "$basePath\logs" -Force
}

# Function to log messages
function Log-Message {
    param (
        [string]$message
    )
    $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss"
    $logMessage = "$timestamp - $message"
    Write-Output $logMessage
    Add-Content -Path $logFile -Value $logMessage
}

# Function to handle errors
function Handle-Error {
    param (
        [string]$errorMessage
    )
    Log-Message "ERROR: $errorMessage"
    exit 1
}

# Step 1: Create Directory Structure
Log-Message "Creating directory structure..."
try {
    $dirs = @(
        "$basePath\ansible",
        "$basePath\docker",
        "$basePath\terraform",
        "$basePath\vbox\vms",
        "$basePath\vbox\iso",
        "$basePath\wsl",
        "$basePath\scripts",
        "$basePath\git"
    )

    foreach ($dir in $dirs) {
        if (-Not (Test-Path -Path $dir)) {
            New-Item -ItemType Directory -Path $dir -Force
        }
    }
    Log-Message "Directory structure created."
} catch {
    Handle-Error "Failed to create directory structure: $_"
}

# Step 2: Install Necessary Software
Log-Message "Installing necessary software..."
try {
    .\scripts\install-software.ps1
} catch {
    Handle-Error "Failed to install necessary software: $_"
}

# Step 3: Restart the computer to complete installations
Log-Message "Please restart your computer to complete the installation. After restart, run this script again."
Start-Sleep -Seconds 5
exit

Step 2: Install Necessary Software

install-software.ps1