From f37af1e3407b4e735aa91133ed5a5a4553a2cfd2 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 19 Dec 2023 06:12:47 -0500 Subject: [PATCH 001/103] Adding the configure scripts --- testing/configure/download_files.ps1 | 13 ++++++++++ testing/configure/import_wec_gpo.ps1 | 22 ++++++++++++++++ testing/configure/link_wec_gpo.ps1 | 34 +++++++++++++++++++++++++ testing/configure/start_wec_service.ps1 | 19 ++++++++++++++ testing/configure/wec_wirewall.ps1 | 16 ++++++++++++ 5 files changed, 104 insertions(+) create mode 100644 testing/configure/download_files.ps1 create mode 100644 testing/configure/import_wec_gpo.ps1 create mode 100644 testing/configure/link_wec_gpo.ps1 create mode 100644 testing/configure/start_wec_service.ps1 create mode 100644 testing/configure/wec_wirewall.ps1 diff --git a/testing/configure/download_files.ps1 b/testing/configure/download_files.ps1 new file mode 100644 index 00000000..bafae835 --- /dev/null +++ b/testing/configure/download_files.ps1 @@ -0,0 +1,13 @@ +# Downloads latest release and unzips it in $USER\Downloads\LME + +$apiUrl = "https://api.github.com/repos/cisagov/LME/releases/latest" +$latestRelease = Invoke-RestMethod -Uri $apiUrl +$zipFileUrl = $latestRelease.assets | Where-Object { $_.content_type -eq 'application/zip' } | Select-Object -ExpandProperty browser_download_url +$downloadPath = "$env:USERPROFILE\Downloads\" + $latestRelease.name + ".zip" +$extractPath = "$env:USERPROFILE\Downloads\LME" + +Invoke-WebRequest -Uri $zipFileUrl -OutFile $downloadPath +if (-not (Test-Path -Path $extractPath)) { + New-Item -ItemType Directory -Path $extractPath +} +Expand-Archive -LiteralPath $downloadPath -DestinationPath $extractPath diff --git a/testing/configure/import_wec_gpo.ps1 b/testing/configure/import_wec_gpo.ps1 new file mode 100644 index 00000000..515fb244 --- /dev/null +++ b/testing/configure/import_wec_gpo.ps1 @@ -0,0 +1,22 @@ +$GPOBackupPath = "$env:USERPROFILE\Downloads\LME\Chapter 1 Files\Group Policy Objects" + +$gpoNames = @("LME-WEC-Client", "LME-WEC-Server") + +foreach ($gpoName in $gpoNames) { + $gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue + if (-not $gpo) { + New-GPO -Name $gpoName | Out-Null + Write-Host "Created GPO: $gpoName" + } else { + Write-Host "GPO $gpoName already exists." + } + + try { + Import-GPO -BackupGpoName $gpoName -TargetName $gpoName -Path $GPOBackupPath -CreateIfNeeded -ErrorAction Stop + Write-Host "Imported settings into GPO: $gpoName" + } catch { + Throw "Failed to import GPO: $gpoName. The GPODisplayName in bkupinfo.xml may not match or other import error occurred." + } +} + +Write-Host "LME GPOs have been created and imported successfully." diff --git a/testing/configure/link_wec_gpo.ps1 b/testing/configure/link_wec_gpo.ps1 new file mode 100644 index 00000000..177346f3 --- /dev/null +++ b/testing/configure/link_wec_gpo.ps1 @@ -0,0 +1,34 @@ +# This script will ask the user for 2 things: the domain name, and the name of the OU for their 'hosts' +# After that information is collected it will link the GPO's created with the import_gpo script to the Domain Controllers OU and the custom host OU. + +Import-Module ActiveDirectory + +$domain = Read-Host "Enter your domain (e.g., 'lme.local')" +$domainDN = $domain -replace '\.', ',DC=' -replace '^', 'DC=' + +$customOUExists = Read-Host "Have you created a custom OU for your hosts? (yes/no)" +if ($customOUExists -ne "yes") { + Write-Host "No custom OU specified. Exiting the script." + exit +} + +$ClientOUCustomName = Read-Host "Enter the name of your custom OU (e.g., MyComputers)" +$ClientOUDistinguishedName = "OU=$ClientOUCustomName,$domainDN" + +$GPONameClient = "LME-WEC-Client" +$GPONameServer = "LME-WEC-Server" +$ServerOUDistinguishedName = "OU=Domain Controllers,$domainDN" + +try { + New-GPLink -Name $GPONameClient -Target $ClientOUDistinguishedName + Write-Host "GPO '$GPONameClient' linked to OU '$ClientOUCustomName'." +} catch { + Write-Host "Error linking GPO '$GPONameClient' to OU '$ClientOUCustomName': $_" +} + +try { + New-GPLink -Name $GPONameServer -Target $ServerOUDistinguishedName + Write-Host "GPO '$GPONameServer' linked to OU 'Domain Controllers'." +} catch { + Write-Host "Error linking GPO '$GPONameServer' to OU 'Domain Controllers': $_" +} diff --git a/testing/configure/start_wec_service.ps1 b/testing/configure/start_wec_service.ps1 new file mode 100644 index 00000000..9ed7815e --- /dev/null +++ b/testing/configure/start_wec_service.ps1 @@ -0,0 +1,19 @@ +# Start WEC using custom wec xml file + +try { + Start-Service -Name "Wecsvc" + Write-Host "WEC service started successfully." +} catch { + Write-Host "Failed to start WEC service: $_" +} + +$ConfigFilePath = "$env:USERPROFILE\Downloads\LME\Chapter 1 Files\lme_wec_config.xml" + +try { + Start-Process -FilePath "wecutil.exe" -ArgumentList "cs `"$ConfigFilePath`"" -Verb RunAs + Write-Host "wecutil command executed successfully." +} catch { + Write-Host "Failed to execute wecutil command: $_" +} + + diff --git a/testing/configure/wec_wirewall.ps1 b/testing/configure/wec_wirewall.ps1 new file mode 100644 index 00000000..a148fa89 --- /dev/null +++ b/testing/configure/wec_wirewall.ps1 @@ -0,0 +1,16 @@ +# Asks user to provide subnet - then creates a inbound allow firewall rule for 5985. Run on WEC server. + +$inboundRuleName = "WinRM TCP In 5985" +$clientSubnet = Read-Host "Enter your subnet (e.g., 10.1.0.0/24)" + +if (-not (Get-NetFirewallRule -Name $inboundRuleName -ErrorAction SilentlyContinue)) { + New-NetFirewallRule -DisplayName $inboundRuleName ` + -Direction Inbound -Protocol TCP ` + -LocalPort 5985 -Action Allow ` + -RemoteAddress $clientSubnet ` + -Description "Allow inbound TCP 5985 for WinRM from clients subnet" +} else { + Write-Host "Inbound rule '$inboundRuleName' already exists." +} + +Write-Host "Inbound WinRM rule has been configured." From a93311f6798b3157d396292343f9b597884765f3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 19 Dec 2023 07:15:33 -0500 Subject: [PATCH 002/103] Add scripts to zip and copy to a container for downloading in the server --- .../copy_files/copy_file_to_container.ps1 | 74 +++++++++++++++ .../copy_files/create_blob_container.ps1 | 95 +++++++++++++++++++ .../copy_files/zip_my_parents_parent.ps1 | 34 +++++++ 3 files changed, 203 insertions(+) create mode 100644 testing/configure/copy_files/copy_file_to_container.ps1 create mode 100644 testing/configure/copy_files/create_blob_container.ps1 create mode 100644 testing/configure/copy_files/zip_my_parents_parent.ps1 diff --git a/testing/configure/copy_files/copy_file_to_container.ps1 b/testing/configure/copy_files/copy_file_to_container.ps1 new file mode 100644 index 00000000..b8019c5d --- /dev/null +++ b/testing/configure/copy_files/copy_file_to_container.ps1 @@ -0,0 +1,74 @@ +<# +.SYNOPSIS +Uploads a file to an Azure Blob Storage container and outputs the SAS URL. + +.DESCRIPTION +This script uploads a specified file to a given Azure Blob Storage container and generates a Shared Access Signature (SAS) URL for the uploaded item. +It requires the local file path, container name, storage account name, and storage account key as mandatory parameters. +This script is useful for automating the process of uploading files to Azure Blob Storage and obtaining a SAS URL for accessing the uploaded file. + +.PARAMETER LocalFilePath +The full local file path of the file to be uploaded. + +.PARAMETER ContainerName +The name of the Azure Blob Storage container where the file will be uploaded. + +.PARAMETER StorageAccountName +The name of the Azure Storage account. + +.PARAMETER StorageAccountKey +The key for the Azure Storage account. + +.OUTPUTS +Shared Access Signature (SAS) URL of the uploaded file. + +.EXAMPLE +.\YourScriptName.ps1 -LocalFilePath "C:\path\to\file.txt" -ContainerName "examplecontainer" -StorageAccountName "examplestorageaccount" -StorageAccountKey "examplekey" + +This example uploads 'file.txt' from the local path to 'examplecontainer' in the Azure Storage account named 'examplestorageaccount' and outputs the SAS URL for the uploaded file. + +.NOTES +- Ensure that the Azure CLI is installed and configured with the necessary permissions to access the specified Azure Storage account and container. +- The SAS URL provides access to the file with read permissions and is valid for 1 day. +#> + +param( + [Parameter(Mandatory=$true)] + [string]$LocalFilePath, + + [Parameter(Mandatory=$true)] + [string]$ContainerName, + + [Parameter(Mandatory=$true)] + [string]$StorageAccountName, + + [Parameter(Mandatory=$true)] + [string]$StorageAccountKey +) + +# Upload file to the blob container +az storage blob upload ` + --container-name $ContainerName ` + --file $LocalFilePath ` + --name (Split-Path $LocalFilePath -Leaf) ` + --account-name $StorageAccountName ` + --account-key $StorageAccountKey + + +$BlobName = (Split-Path $LocalFilePath -Leaf) +$ExpiryTime = "$(Get-Date).AddDays(1).ToString('yyyy-MM-ddTHH:mm:ssZ')" + +# Generate SAS URL for the blob +$SasUrl = az storage blob generate-sas ` + --account-name $StorageAccountName ` + --account-key $StorageAccountKey ` + --container-name $ContainerName ` + --name $BlobName ` + --permissions r ` + --expiry $ExpiryTime ` + --output tsv + +# Set the full url var for returing to the user for use in the next script +$ContainerUrl = "https://$StorageAccountName.blob.core.windows.net/$ContainerName/$BlobName?$SasUrl" + +$ContainerUrl diff --git a/testing/configure/copy_files/create_blob_container.ps1 b/testing/configure/copy_files/create_blob_container.ps1 new file mode 100644 index 00000000..689e0f14 --- /dev/null +++ b/testing/configure/copy_files/create_blob_container.ps1 @@ -0,0 +1,95 @@ +<# +.SYNOPSIS +This script creates a new Azure Storage Account and Blob Container within a specified Azure Resource Group. + +.DESCRIPTION +Automates the creation of a unique Azure Storage Account and Blob Container. +Requires the Azure Resource Group name as a mandatory argument. +Generates unique names for the storage account and container, creates the storage account, retrieves the storage account key, +creates a blob container, and saves the configuration to a 'config.ps1' file in the script's directory. + +.PARAMETER ResourceGroupName +The name of the Azure Resource Group for the storage account and blob container. + +.EXAMPLE +.\CreateAzureStorage.ps1 -ResourceGroupName "YourResourceGroupName" + +Replace "YourResourceGroupName" with the name of your Azure Resource Group. + +.NOTES +- Requires Azure CLI and Azure account login. +- Ensure appropriate permissions in Azure. +- Handle the generated 'config.ps1' file securely. + +#> + + +param( + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName +) + +function New-AzureName { + param ( + [Parameter(Mandatory=$true)] + [string]$Prefix + ) + + # Ensuring the prefix is lowercase as Azure Storage Account names must be all lowercase + $Prefix = $Prefix.ToLower() + + # Generate a string of random lowercase letters and numbers + $randomCharacters = -join ((48..57) + (97..122) | Get-Random -Count (24 - $Prefix.Length) | ForEach-Object { [char]$_ }) + + return $Prefix + $randomCharacters +} + +# Get the location of the resource group +$Location = (az group show --name $ResourceGroupName --query location --output tsv) + +# Generate a unique storage account name +$StorageAccountName = New-AzureName -Prefix "st" + +# Generate a container name +$ContainerName = New-AzureName -Prefix "container" + +# Create a new storage account +az storage account create ` + --name $StorageAccountName ` + --resource-group $ResourceGroupName ` + --location $Location ` + --sku Standard_LRS + +# Wait for a moment to ensure the storage account is available +Start-Sleep -Seconds 10 + +# Get the storage account key +$StorageAccountKey = (az storage account keys list ` + --resource-group $ResourceGroupName ` + --account-name $StorageAccountName ` + --query '[0].value' ` + --output tsv) + +# Create a blob container +az storage container create ` + --name $ContainerName ` + --account-name $StorageAccountName ` + --account-key $StorageAccountKey + +# Output the created resources' details +Write-Host "Created Storage Account: $StorageAccountName" +Write-Host "StorageAccountKey: $StorageAccountKey" +Write-Host "Created Container: $ContainerName" + +# Define the file path in the same directory as the running script +$filePath = Join-Path -Path $PSScriptRoot -ChildPath "config.ps1" + +# Write the variables as PowerShell script to the file +@" +`$StorageAccountName = '$StorageAccountName' +`$StorageAccountKey = '$StorageAccountKey' +`$ContainerName = '$ContainerName' +"@ | Set-Content -Path $filePath + + + diff --git a/testing/configure/copy_files/zip_my_parents_parent.ps1 b/testing/configure/copy_files/zip_my_parents_parent.ps1 new file mode 100644 index 00000000..ef034496 --- /dev/null +++ b/testing/configure/copy_files/zip_my_parents_parent.ps1 @@ -0,0 +1,34 @@ +<# +.SYNOPSIS +Zips the parent of the parent directory of the script and outputs the path of the ZIP file. + +.DESCRIPTION +This script compresses the parent directory of the parent of its location into a ZIP file. +It then outputs the full path of the created ZIP file. This is useful for quickly archiving the contents of the parent directory. + +.EXAMPLE +This example demonstrates how to execute the script and capture the path of the created ZIP file. +# Define the path to this zip script +$zipScriptPath = "C:\path\to\zip_my_parents_parent.ps1" + +# Execute the zip script and capture the output (filename of the zip file) +$zipFilePath = & $zipScriptPath + +.NOTES +- Ensure that PowerShell 5.0 or later is installed, as this script uses the Compress-Archive cmdlet. +- The script assumes read and write permissions in the script's and its parent directory. +#> +# Get the full path of the script's parent directory +$scriptParentDir = Split-Path -Parent $PSScriptRoot + +# Get the name of the parent directory +$parentDirName = Split-Path -Leaf $scriptParentDir + +# Define the destination path for the zip file (adjacent to the parent directory) +$destinationZipPath = Join-Path -Path (Split-Path -Parent $scriptParentDir) -ChildPath ("$parentDirName.zip") + +# Create the zip file +Compress-Archive -Path "$scriptParentDir\*" -DestinationPath $destinationZipPath -Force + +# Output the path of the created zip file +$destinationZipPath From 2d5d146d49798ca8a838328925747ffecf91c7ef Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 19 Dec 2023 07:54:46 -0500 Subject: [PATCH 003/103] Grab the expiry time properly in copy file --- .../configure/copy_files/copy_file_to_container.ps1 | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/testing/configure/copy_files/copy_file_to_container.ps1 b/testing/configure/copy_files/copy_file_to_container.ps1 index b8019c5d..04e01b72 100644 --- a/testing/configure/copy_files/copy_file_to_container.ps1 +++ b/testing/configure/copy_files/copy_file_to_container.ps1 @@ -23,7 +23,7 @@ The key for the Azure Storage account. Shared Access Signature (SAS) URL of the uploaded file. .EXAMPLE -.\YourScriptName.ps1 -LocalFilePath "C:\path\to\file.txt" -ContainerName "examplecontainer" -StorageAccountName "examplestorageaccount" -StorageAccountKey "examplekey" +.\copy_file_to_container.ps1 -LocalFilePath "C:\path\to\file.txt" -ContainerName "examplecontainer" -StorageAccountName "examplestorageaccount" -StorageAccountKey "examplekey" This example uploads 'file.txt' from the local path to 'examplecontainer' in the Azure Storage account named 'examplestorageaccount' and outputs the SAS URL for the uploaded file. @@ -33,16 +33,16 @@ This example uploads 'file.txt' from the local path to 'examplecontainer' in the #> param( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$LocalFilePath, - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$ContainerName, - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$StorageAccountName, - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$StorageAccountKey ) @@ -56,7 +56,7 @@ az storage blob upload ` $BlobName = (Split-Path $LocalFilePath -Leaf) -$ExpiryTime = "$(Get-Date).AddDays(1).ToString('yyyy-MM-ddTHH:mm:ssZ')" +$ExpiryTime = (Get-Date).AddDays(1).ToString('yyyy-MM-ddTHH:mm:ssZ') # Generate SAS URL for the blob $SasUrl = az storage blob generate-sas ` From d2d34138c95650b6b00cb792ac35a470d7e649d7 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 19 Dec 2023 07:56:06 -0500 Subject: [PATCH 004/103] Overwrite the blob if it exists --- testing/configure/copy_files/copy_file_to_container.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/configure/copy_files/copy_file_to_container.ps1 b/testing/configure/copy_files/copy_file_to_container.ps1 index 04e01b72..fb84f83f 100644 --- a/testing/configure/copy_files/copy_file_to_container.ps1 +++ b/testing/configure/copy_files/copy_file_to_container.ps1 @@ -52,7 +52,8 @@ az storage blob upload ` --file $LocalFilePath ` --name (Split-Path $LocalFilePath -Leaf) ` --account-name $StorageAccountName ` - --account-key $StorageAccountKey + --account-key $StorageAccountKey ` + --overwrite ` $BlobName = (Split-Path $LocalFilePath -Leaf) From 89ddba1a5d373ec65b7661c95e6f2c0e76afe51d Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 19 Dec 2023 08:34:34 -0500 Subject: [PATCH 005/103] Add the script to download file into DC --- .../copy_files/copy_file_to_container.ps1 | 4 +- .../copy_files/download_in_container.ps1 | 71 +++++++++++++++++++ 2 files changed, 73 insertions(+), 2 deletions(-) create mode 100644 testing/configure/copy_files/download_in_container.ps1 diff --git a/testing/configure/copy_files/copy_file_to_container.ps1 b/testing/configure/copy_files/copy_file_to_container.ps1 index fb84f83f..19b275b6 100644 --- a/testing/configure/copy_files/copy_file_to_container.ps1 +++ b/testing/configure/copy_files/copy_file_to_container.ps1 @@ -70,6 +70,6 @@ $SasUrl = az storage blob generate-sas ` --output tsv # Set the full url var for returing to the user for use in the next script -$ContainerUrl = "https://$StorageAccountName.blob.core.windows.net/$ContainerName/$BlobName?$SasUrl" +$FullUrl = "https://${StorageAccountName}.blob.core.windows.net/${ContainerName}/${BlobName}?${SasUrl}" -$ContainerUrl +$FullUrl diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 new file mode 100644 index 00000000..4485fe59 --- /dev/null +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -0,0 +1,71 @@ +<# +.SYNOPSIS +Downloads a file to a specified Azure VM's user directory. + +.DESCRIPTION +This script downloads a file from a given URL to a specified Azure Virtual Machine (VM). +It places the file in the Downloads directory of a specified user's profile on the VM. +The script requires details of the VM, the resource group, the file URL, the local filename for saving, +and the VM's username. + +.PARAMETER VMName +The name of the Azure Virtual Machine. + +.PARAMETER ResourceGroupName +The name of the Azure Resource Group that contains the VM. + +.PARAMETER FileDownloadUrl +The URL of the file to be downloaded. + +.PARAMETER DestinationFilePath +The local file path where the file will be saved. Only the filename is used. + +.PARAMETER VMUsername +The username on the VM to whose Downloads directory the file will be saved. + +.EXAMPLE +.\download_in_container.ps1 ` + -VMName "DC1" ` + -ResourceGroupName "YourResourceGroupName" ` + -FileDownloadUrl "http://example.com/file.ext" ` + -DestinationFilePath "filename.ext" ` + -VMUsername "username" + +This example downloads a file from "http://example.com/file.ext" to the "Downloads" directory of the user "username" on the VM "DC1" in the resource group "YourResourceGroupName". + +.NOTES +Ensure that the Azure CLI is installed and configured with the necessary permissions to access the specified Azure VM. +#> + +param( + [Parameter(Mandatory=$true)] + [string]$VMName, + + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName, + + [Parameter(Mandatory=$true)] + [string]$FileDownloadUrl, + + [Parameter(Mandatory=$true)] + [string]$DestinationFilePath, # This will be stripped to only the filename + + [Parameter(Mandatory=$true)] + [string]$VMUsername # Username on the VM +) + +# Extract just the filename from the destination file path +$DestinationFileName = Split-Path -Leaf $DestinationFilePath + +# Set the destination path in the VM's user Downloads directory +$DestinationPath = "C:\Users\$VMUsername\Downloads\$DestinationFileName" + +$DownloadScript = @" +Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath' +"@ + +az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DownloadScript From 1d62f031a93a6174e2f212706751c08e83f4ba70 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 19 Dec 2023 09:55:58 -0500 Subject: [PATCH 006/103] Script that unzips the files in a container --- .../configure/copy_files/extract_archive.ps1 | 64 +++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 testing/configure/copy_files/extract_archive.ps1 diff --git a/testing/configure/copy_files/extract_archive.ps1 b/testing/configure/copy_files/extract_archive.ps1 new file mode 100644 index 00000000..381f96bc --- /dev/null +++ b/testing/configure/copy_files/extract_archive.ps1 @@ -0,0 +1,64 @@ +<# +.SYNOPSIS +Unzips a file on a specified Azure Virtual Machine. + +.DESCRIPTION +This script unzips a specified zip file on an Azure Virtual Machine (VM). It takes the VM's username and a filename (with optional path), +strips the path, constructs the full paths in the VM's 'Downloads' directory, strips the extension from the filename for the extraction path, +and unzips the file. The script requires the VM name, resource group name, username on the VM, and the filename of the zip file. + +.PARAMETER VMName +The name of the Azure Virtual Machine where the file will be unzipped. + +.PARAMETER ResourceGroupName +The name of the Azure Resource Group that contains the VM. + +.PARAMETER VMUsername +The username on the VM where the file will be unzipped. + +.PARAMETER Filename +The name (and optional path) of the zip file to be unzipped. + +.EXAMPLE +.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -VMUsername "username" -Filename "C:\path\to\filename.zip" + +This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. + +.NOTES +- Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. +- The VM should have the necessary permissions to read the zip file and write to the extraction directory. +#> + +param( + [Parameter(Mandatory=$true)] + [string]$VMName, + + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName, + + [Parameter(Mandatory=$true)] + [string]$VMUsername, + + [Parameter(Mandatory=$true)] + [string]$Filename +) + +# Extract just the filename (ignoring any provided path) +$JustFilename = Split-Path -Leaf $Filename + +# Construct the full path for the zip file +$ZipFilePath = "C:\Users\$VMUsername\Downloads\$JustFilename" + +# Extract the filename without extension for the extraction directory +$FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) +$ExtractToPath = "C:\Users\$VMUsername\Downloads\$FileBaseName" # Extract to a subdirectory named after the file + +$UnzipScript = @" +Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' +"@ + +az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $UnzipScript From 8f8ab453f4ed57c98903234b236bd4a0eed3d039 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 20 Dec 2023 05:30:31 -0500 Subject: [PATCH 007/103] Adds username argument to download files --- testing/configure/download_files.ps1 | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/testing/configure/download_files.ps1 b/testing/configure/download_files.ps1 index bafae835..67fd5f2c 100644 --- a/testing/configure/download_files.ps1 +++ b/testing/configure/download_files.ps1 @@ -1,10 +1,19 @@ -# Downloads latest release and unzips it in $USER\Downloads\LME +param( + [string]$username = $env:USERPROFILE +) + +# Base directory path - use provided username or default to USERPROFILE +$baseDirectoryPath = if ($username -and ($username -ne $env:USERPROFILE)) { + "C:\Users\$username" +} else { + $env:USERPROFILE +} $apiUrl = "https://api.github.com/repos/cisagov/LME/releases/latest" $latestRelease = Invoke-RestMethod -Uri $apiUrl $zipFileUrl = $latestRelease.assets | Where-Object { $_.content_type -eq 'application/zip' } | Select-Object -ExpandProperty browser_download_url -$downloadPath = "$env:USERPROFILE\Downloads\" + $latestRelease.name + ".zip" -$extractPath = "$env:USERPROFILE\Downloads\LME" +$downloadPath = "$baseDirectoryPath\Downloads\" + $latestRelease.name + ".zip" +$extractPath = "$baseDirectoryPath\Downloads\LME" Invoke-WebRequest -Uri $zipFileUrl -OutFile $downloadPath if (-not (Test-Path -Path $extractPath)) { From eb59d3a621c0d250fda52ac2f9d13a71c402f2e3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 20 Dec 2023 05:51:12 -0500 Subject: [PATCH 008/103] Add script to run scripts in container --- .../copy_files/run_script_in_container.ps1 | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 testing/configure/copy_files/run_script_in_container.ps1 diff --git a/testing/configure/copy_files/run_script_in_container.ps1 b/testing/configure/copy_files/run_script_in_container.ps1 new file mode 100644 index 00000000..17a031c5 --- /dev/null +++ b/testing/configure/copy_files/run_script_in_container.ps1 @@ -0,0 +1,54 @@ +<# +.SYNOPSIS +Executes a specified PowerShell script with arguments on an Azure Virtual Machine. + +.DESCRIPTION +This script remotely executes a PowerShell script that is already present on an Azure Virtual Machine (VM), +passing specified arguments to it. It uses Azure's 'az vm run-command invoke' to run the specified script +located on the VM. The script requires the VM name, resource group name, the full path of the script on the VM, +and a string of arguments to pass to the script. + +.PARAMETER ResourceGroupName +The name of the Azure Resource Group that contains the VM. + +.PARAMETER VMName +The name of the Azure Virtual Machine where the script will be executed. + +.PARAMETER ScriptPathOnVM +The full path of the PowerShell script on the Azure VM that needs to be executed. + +.PARAMETER ScriptArguments +A string of arguments that will be passed to the script. + +.EXAMPLE +.\run_script_in_container.ps1 -ResourceGroupName "YourResourceGroupName" -VMName "VMName" -ScriptPathOnVM "C:\path\to\your\script.ps1" -ScriptArguments "-Arg1 value1 -Arg2 value2" + +This example executes a script located at 'C:\path\to\your\script.ps1' on the VM named "VMName" in the resource group "YourResourceGroupName", passing it the arguments "-Arg1 value1 -Arg2 value2". + +.NOTES +- Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. +- The specified script must exist on the VM and the VM should have the necessary permissions to execute it. +#> + +param( + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName, + + [Parameter(Mandatory=$true)] + [string]$VMName, + + [Parameter(Mandatory=$true)] + [string]$ScriptPathOnVM, # The full path of the script on the VM + + [string]$ScriptArguments # Arguments to pass to the script +) + +$InvokeScriptCommand = @" +& '$ScriptPathOnVM' $ScriptArguments +"@ + +az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $InvokeScriptCommand From 67dbfa6392ff90f55297a89d6dc9d0fe54c58d88 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 20 Dec 2023 06:14:48 -0500 Subject: [PATCH 009/103] Adds username argument to gpo script --- testing/configure/import_wec_gpo.ps1 | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/testing/configure/import_wec_gpo.ps1 b/testing/configure/import_wec_gpo.ps1 index 515fb244..dc310016 100644 --- a/testing/configure/import_wec_gpo.ps1 +++ b/testing/configure/import_wec_gpo.ps1 @@ -1,4 +1,15 @@ -$GPOBackupPath = "$env:USERPROFILE\Downloads\LME\Chapter 1 Files\Group Policy Objects" +param( + [string]$username = $env:USERPROFILE +) + +# Determine the base directory path based on the provided username +$baseDirectoryPath = if ($username -and ($username -ne $env:USERPROFILE)) { + "C:\Users\$username" +} else { + $env:USERPROFILE +} + +$GPOBackupPath = "$baseDirectoryPath\Downloads\LME\Chapter 1 Files\Group Policy Objects" $gpoNames = @("LME-WEC-Client", "LME-WEC-Server") @@ -20,3 +31,4 @@ foreach ($gpoName in $gpoNames) { } Write-Host "LME GPOs have been created and imported successfully." + From 072f2bed112a4b1d314d7969c5a7130486e05fd6 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 20 Dec 2023 12:26:15 -0500 Subject: [PATCH 010/103] Modifies the url name in the client GPO --- .../import_wec_gpo_update_server_name.ps1 | 22 +++++++++++++++++++ .../{wec_wirewall.ps1 => wec_firewall.ps1} | 0 2 files changed, 22 insertions(+) create mode 100644 testing/configure/import_wec_gpo_update_server_name.ps1 rename testing/configure/{wec_wirewall.ps1 => wec_firewall.ps1} (100%) diff --git a/testing/configure/import_wec_gpo_update_server_name.ps1 b/testing/configure/import_wec_gpo_update_server_name.ps1 new file mode 100644 index 00000000..e16cde4a --- /dev/null +++ b/testing/configure/import_wec_gpo_update_server_name.ps1 @@ -0,0 +1,22 @@ +# Query the registry to find the key path +$HKEY_USERSKeys = reg query HKEY_USERS /s /f "SubscriptionManager" /k + +# Extract the first key path that contains "EventForwarding" +$HKEY_USERSKeyPath = ($HKEY_USERSKeys -split "\r\n" | Where-Object { $_ -match "HKEY_USERS\\.*EventForwarding" }) -replace "HKEY_USERS\\", "HKU\" | Select-Object -First 1 + +# Ensure the key path is not null or empty +if (-not [string]::IsNullOrWhiteSpace($HKEY_USERSKeyPath)) { + # Display the current value + $oldValue = reg query "$HKEY_USERSKeyPath" /v "1" + Write-Host "Old Value: $oldValue" + + # Change the SubscriptionManager key value + $newData = "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" + reg add "$HKEY_USERSKeyPath" /v "1" /t REG_SZ /d "$newData" /f + + # Requery to confirm the change + $newValue = reg query "$HKEY_USERSKeyPath" /v "1" + Write-Host "New Value: $newValue" +} else { + Write-Host "Registry key path not found." +} \ No newline at end of file diff --git a/testing/configure/wec_wirewall.ps1 b/testing/configure/wec_firewall.ps1 similarity index 100% rename from testing/configure/wec_wirewall.ps1 rename to testing/configure/wec_firewall.ps1 From 11d479de3ed001552cc3622e7f2c34badf0538f3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 21 Dec 2023 10:06:51 -0500 Subject: [PATCH 011/103] Adds the functionality for chapter 1 and first half of chapter 2 --- .../import_wec_gpo_update_server_name.ps1 | 2 +- .../configure/install_sysmon_in_sysvol.ps1 | 70 +++++++++++++++++++ testing/configure/link_create_ou.ps1 | 22 ++++++ testing/configure/link_wec_gpo.ps1 | 17 ++--- .../list_computers_forwarding_events.ps1 | 27 +++++++ testing/configure/move_computers_to_ou.ps1 | 22 ++++++ .../start_wec_service_provisioner.ps1 | 24 +++++++ 7 files changed, 171 insertions(+), 13 deletions(-) create mode 100644 testing/configure/install_sysmon_in_sysvol.ps1 create mode 100644 testing/configure/link_create_ou.ps1 create mode 100644 testing/configure/list_computers_forwarding_events.ps1 create mode 100644 testing/configure/move_computers_to_ou.ps1 create mode 100644 testing/configure/start_wec_service_provisioner.ps1 diff --git a/testing/configure/import_wec_gpo_update_server_name.ps1 b/testing/configure/import_wec_gpo_update_server_name.ps1 index e16cde4a..c83799de 100644 --- a/testing/configure/import_wec_gpo_update_server_name.ps1 +++ b/testing/configure/import_wec_gpo_update_server_name.ps1 @@ -18,5 +18,5 @@ if (-not [string]::IsNullOrWhiteSpace($HKEY_USERSKeyPath)) { $newValue = reg query "$HKEY_USERSKeyPath" /v "1" Write-Host "New Value: $newValue" } else { - Write-Host "Registry key path not found." + Write-Error "Registry key path not found." } \ No newline at end of file diff --git a/testing/configure/install_sysmon_in_sysvol.ps1 b/testing/configure/install_sysmon_in_sysvol.ps1 new file mode 100644 index 00000000..3cc002e9 --- /dev/null +++ b/testing/configure/install_sysmon_in_sysvol.ps1 @@ -0,0 +1,70 @@ +param( + [string]$DomainName = "lme.local", # Default domain name + [string]$VMUsername = "admin.ackbar" # Default VM username +) + +# Define the SYSVOL path +$destinationPath = "C:\Windows\SYSVOL\SYSVOL\$DomainName\LME\Sysmon" +$tempPath = Join-Path $env:TEMP "SysmonTemp" + +# Create the LME and Sysmon directories +New-Item -ItemType Directory -Path $destinationPath -Force +New-Item -ItemType Directory -Path $tempPath -Force + +# Copy update.bat from the user's download directory +$updateBatSource = "C:\Users\$VMUsername\Downloads\LME\Chapter 2 Files\GPO Deployment\update.bat" +Copy-Item -Path $updateBatSource -Destination $destinationPath + +# Download URL for Sysmon +$url = "https://download.sysinternals.com/files/Sysmon.zip" + +# Download file path +$zipFilePath = Join-Path $tempPath "Sysmon.zip" + +# Download the file +Invoke-WebRequest -Uri $url -OutFile $zipFilePath + +# Unzip the file to temp directory +Expand-Archive -Path $zipFilePath -DestinationPath $tempPath + +# Copy only Sysmon64.exe to destination +Copy-Item -Path "$tempPath\Sysmon64.exe" -Destination $destinationPath + +# Clean up: remove temp directory and zip file +Remove-Item -Path $tempPath -Recurse -Force + +# Download URL for the Sysmon configuration file +$xmlUrl = "https://raw.githubusercontent.com/SwiftOnSecurity/sysmon-config/master/sysmonconfig-export.xml" + +# Destination file path for the Sysmon configuration file +$xmlFilePath = Join-Path $destinationPath "sysmon.xml" + +# Download and rename the file +Invoke-WebRequest -Uri $xmlUrl -OutFile $xmlFilePath + +# Define the destination path for Sigcheck +$sigcheckDestinationPath = "C:\Windows\SYSVOL\SYSVOL\$DomainName\LME" + +# Download URL for Sigcheck +$sigcheckUrl = "https://download.sysinternals.com/files/Sigcheck.zip" + +# Temporary path for Sigcheck zip file +$sigcheckTempPath = Join-Path $env:TEMP "SigcheckTemp" + +# Ensure the temporary directory exists +New-Item -ItemType Directory -Path $sigcheckTempPath -Force + +# Download file path for Sigcheck +$sigcheckZipFilePath = Join-Path $sigcheckTempPath "Sigcheck.zip" + +# Download the Sigcheck zip file +Invoke-WebRequest -Uri $sigcheckUrl -OutFile $sigcheckZipFilePath + +# Unzip the Sigcheck file to temporary directory +Expand-Archive -Path $sigcheckZipFilePath -DestinationPath $sigcheckTempPath + +# Copy only Sigcheck64.exe to the destination +Copy-Item -Path "$sigcheckTempPath\sigcheck64.exe" -Destination $sigcheckDestinationPath + +# Clean up: remove temporary directory and zip file +Remove-Item -Path $sigcheckTempPath -Recurse -Force diff --git a/testing/configure/link_create_ou.ps1 b/testing/configure/link_create_ou.ps1 new file mode 100644 index 00000000..4e926df8 --- /dev/null +++ b/testing/configure/link_create_ou.ps1 @@ -0,0 +1,22 @@ +param( + [string]$Domain = "lme.local", + [string]$ClientOUCustomName = "LMETestClients" +) + +Import-Module ActiveDirectory + +# Split the domain into parts and construct the ParentContainerDN +$domainParts = $Domain -split "\." +$ParentContainerDN = $domainParts | ForEach-Object { "DC=$_" } -join "," + +# Define the distinguished name (DN) for the new OU +$NewOUDN = "OU=$ClientOUCustomName,$ParentContainerDN" + +# Check if the OU already exists +if (-not (Get-ADOrganizationalUnit -Filter "DistinguishedName -eq '$NewOUDN'" -ErrorAction SilentlyContinue)) { + # Create the new OU + New-ADOrganizationalUnit -Name $ClientOUCustomName -Path $ParentContainerDN + Write-Host "Organizational Unit '$ClientOUCustomName' created successfully under $ParentContainerDN." +} else { + Write-Host "Organizational Unit '$ClientOUCustomName' already exists under $ParentContainerDN." +} diff --git a/testing/configure/link_wec_gpo.ps1 b/testing/configure/link_wec_gpo.ps1 index 177346f3..a6acba78 100644 --- a/testing/configure/link_wec_gpo.ps1 +++ b/testing/configure/link_wec_gpo.ps1 @@ -1,18 +1,11 @@ -# This script will ask the user for 2 things: the domain name, and the name of the OU for their 'hosts' -# After that information is collected it will link the GPO's created with the import_gpo script to the Domain Controllers OU and the custom host OU. +param( + [string]$Domain = "lme.local", + [string]$ClientOUCustomName = "LMETestClients" +) Import-Module ActiveDirectory -$domain = Read-Host "Enter your domain (e.g., 'lme.local')" -$domainDN = $domain -replace '\.', ',DC=' -replace '^', 'DC=' - -$customOUExists = Read-Host "Have you created a custom OU for your hosts? (yes/no)" -if ($customOUExists -ne "yes") { - Write-Host "No custom OU specified. Exiting the script." - exit -} - -$ClientOUCustomName = Read-Host "Enter the name of your custom OU (e.g., MyComputers)" +$domainDN = $Domain -replace '\.', ',DC=' -replace '^', 'DC=' $ClientOUDistinguishedName = "OU=$ClientOUCustomName,$domainDN" $GPONameClient = "LME-WEC-Client" diff --git a/testing/configure/list_computers_forwarding_events.ps1 b/testing/configure/list_computers_forwarding_events.ps1 new file mode 100644 index 00000000..4233270d --- /dev/null +++ b/testing/configure/list_computers_forwarding_events.ps1 @@ -0,0 +1,27 @@ +# Execute 'wecutil gr lme' command and capture the output +$wecutilOutput = wecutil gr lme + +# Split the output into individual lines +$lines = $wecutilOutput -split "`r`n" | Where-Object { $_ -match "\S" } # Exclude empty lines + +# Initialize a list to store active computer names +$activeComputers = @() + +# Process each line to extract computer names with active status +$isActive = $false +foreach ($line in $lines) { + if ($line -match "RunTimeStatus: Active") { + $isActive = $true + } elseif ($line -match "\.local") { + if ($isActive) { + if ($line -match "(\S+\.local)") { + $activeComputers += $matches[1] + } + } + $isActive = $false + } +} + +# Display the active computer names +Write-Host "Active Computers Forwarding Events:" +$activeComputers | ForEach-Object { Write-Host $_ } diff --git a/testing/configure/move_computers_to_ou.ps1 b/testing/configure/move_computers_to_ou.ps1 new file mode 100644 index 00000000..6040ba50 --- /dev/null +++ b/testing/configure/move_computers_to_ou.ps1 @@ -0,0 +1,22 @@ +# Import the Active Directory module +Import-Module ActiveDirectory + +# Define the DN of the Computers container +$computersContainerDN = "CN=Computers,DC=lme,DC=local" + +# Define the DN of the target OU +$targetOUDN = "OU=LMETestClients,DC=lme,DC=local" + +# Get the computer accounts in the Computers container +$computers = Get-ADComputer -Filter * -SearchBase $computersContainerDN + +# Move each computer to the target OU +foreach ($computer in $computers) { + try { + # Move the computer to the target OU + Move-ADObject -Identity $computer.DistinguishedName -TargetPath $targetOUDN + Write-Host "Moved $($computer.Name) to $targetOUDN" + } catch { + Write-Host "Failed to move $($computer.Name): $_" + } +} \ No newline at end of file diff --git a/testing/configure/start_wec_service_provisioner.ps1 b/testing/configure/start_wec_service_provisioner.ps1 new file mode 100644 index 00000000..c68ee0f9 --- /dev/null +++ b/testing/configure/start_wec_service_provisioner.ps1 @@ -0,0 +1,24 @@ +# PowerShell script to configure Windows Event Collector + +param( + [string]$xmlFilePath = "C:\Users\admin.ackbar\Downloads\LME\Chapter 1 Files\lme_wec_config.xml" +) + +# Check if Windows Event Collector Service is running and start it if not +$wecService = Get-Service -Name "Wecsvc" +if ($wecService.Status -ne 'Running') { + Start-Service -Name "Wecsvc" + Write-Host "Windows Event Collector Service started." +} else { + Write-Host "Windows Event Collector Service is already running." +} + +# Check if the XML configuration file exists +if (Test-Path -Path $xmlFilePath) { + # Run the wecutil command to configure the collector + wecutil cs $xmlFilePath + Write-Host "wecutil command executed successfully with config file: $xmlFilePath" +} else { + Write-Host "Configuration file not found at $xmlFilePath" +} + From ea0ba16b1b18b2b4e12746f1182b2ea8ef2e629f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 22 Dec 2023 05:33:52 -0500 Subject: [PATCH 012/103] Imports the sysmon GPO --- testing/configure/import_sysmon_gpo.ps1 | 34 +++++++++++++++++++++++++ testing/configure/link_sysmon_gpo.ps1 | 18 +++++++++++++ 2 files changed, 52 insertions(+) create mode 100644 testing/configure/import_sysmon_gpo.ps1 create mode 100644 testing/configure/link_sysmon_gpo.ps1 diff --git a/testing/configure/import_sysmon_gpo.ps1 b/testing/configure/import_sysmon_gpo.ps1 new file mode 100644 index 00000000..83109761 --- /dev/null +++ b/testing/configure/import_sysmon_gpo.ps1 @@ -0,0 +1,34 @@ +param( + [string]$username = $env:USERPROFILE +) + +# Determine the base directory path based on the provided username +$baseDirectoryPath = if ($username -and ($username -ne $env:USERPROFILE)) { + "C:\Users\$username" +} else { + $env:USERPROFILE +} + +$GPOBackupPath = "$baseDirectoryPath\Downloads\LME\Chapter 2 Files\GPO Deployment\Group Policy Objects" + +$gpoNames = @("LME-Sysmon-Task") + +foreach ($gpoName in $gpoNames) { + $gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue + if (-not $gpo) { + New-GPO -Name $gpoName | Out-Null + Write-Host "Created GPO: $gpoName" + } else { + Write-Host "GPO $gpoName already exists." + } + + try { + Import-GPO -BackupGpoName $gpoName -TargetName $gpoName -Path $GPOBackupPath -CreateIfNeeded -ErrorAction Stop + Write-Host "Imported settings into GPO: $gpoName" + } catch { + Throw "Failed to import GPO: $gpoName. The GPODisplayName in bkupinfo.xml may not match or other import error occurred." + } +} + +Write-Host "LME Sysmon GPOs have been created and imported successfully." + diff --git a/testing/configure/link_sysmon_gpo.ps1 b/testing/configure/link_sysmon_gpo.ps1 new file mode 100644 index 00000000..1315f2cc --- /dev/null +++ b/testing/configure/link_sysmon_gpo.ps1 @@ -0,0 +1,18 @@ +param( + [string]$Domain = "lme.local", + [string]$ClientOUCustomName = "LMETestClients" +) + +Import-Module ActiveDirectory + +$domainDN = $Domain -replace '\.', ',DC=' -replace '^', 'DC=' +$OUDistinguishedName = "OU=$ClientOUCustomName,$domainDN" + +$GPOName = "LME-Sysmon-Task" + +try { + New-GPLink -Name $GPOName -Target $OUDistinguishedName + Write-Host "GPO '$GPOName' linked to OU '$ClientOUCustomName'." +} catch { + Write-Host "Error linking GPO '$GPOName' to OU '$ClientOUCustomName': $_" +} From daf3018f6d7f4817aae71714ec93125c1fd1852e Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 22 Dec 2023 07:34:22 -0500 Subject: [PATCH 013/103] Update the variables for sysmon gpo --- testing/configure/sysmon_gpo_update_vars.ps1 | 43 ++++++++++++++++++++ 1 file changed, 43 insertions(+) create mode 100644 testing/configure/sysmon_gpo_update_vars.ps1 diff --git a/testing/configure/sysmon_gpo_update_vars.ps1 b/testing/configure/sysmon_gpo_update_vars.ps1 new file mode 100644 index 00000000..b76fbeda --- /dev/null +++ b/testing/configure/sysmon_gpo_update_vars.ps1 @@ -0,0 +1,43 @@ +param( + [string]$gpoName = "LME-Sysmon-Task", + [string]$domainName = "lme.local" +) + +# Get the FQDN of the current server +$fqdn = [System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName + +# Get the GPO object +$gpo = Get-GPO -Name $gpoName + +# Check if GPO is found +if ($null -eq $gpo) { + Write-Host "GPO not found" + exit +} + +# Get the GUID of the GPO +$gpoGuid = $gpo.Id + +# Define the path to the XML file +$xmlFilePath = "C:\Windows\SYSVOL\sysvol\$domainName\Policies\{$gpoGuid}\Machine\Preferences\ScheduledTasks\ScheduledTasks.xml" + +# Get current time and add 5 minutes +$newStartTime = (Get-Date).AddMinutes(5).ToString("yyyy-MM-ddTHH:mm:ss") + +# Load the XML file +$xml = [xml](Get-Content -Path $xmlFilePath) + +# Find the task with name "LME-Sysmon-Task" +$task = $xml.ScheduledTasks.TaskV2 | Where-Object { $_.Properties.name -eq "LME-Sysmon-Task" } + +# Update the start time in the XML +$task.Properties.Task.Triggers.CalendarTrigger.StartBoundary = $newStartTime + +# Update the command path +$task.Properties.Task.Actions.Exec.Command = "\\$fqdn\sysvol\$domainName\LME\Sysmon\update.bat" + +# Save the modified XML back to the file +$xml.Save($xmlFilePath) + +# Output the new start time for verification +Write-Host "New start time set to: $newStartTime" \ No newline at end of file From fe5ca778515c8b4b7ce602c5c6593048bb353493 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 22 Dec 2023 09:54:17 -0500 Subject: [PATCH 014/103] Name the scripts so they are grouped together in a listing --- testing/configure/{link_create_ou.ps1 => create_ou.ps1} | 0 .../configure/{import_sysmon_gpo.ps1 => sysmon_import_gpo.ps1} | 0 ...{install_sysmon_in_sysvol.ps1 => sysmon_install_in_sysvol.ps1} | 0 testing/configure/{link_sysmon_gpo.ps1 => sysmon_link_gpo.ps1} | 0 ..._gpo_update_server_name.ps1 => wec_gpo_update_server_name.ps1} | 0 testing/configure/{import_wec_gpo.ps1 => wec_import_gpo.ps1} | 0 testing/configure/{link_wec_gpo.ps1 => wec_link_gpo.ps1} | 0 ...rt_wec_service_provisioner.ps1 => wec_service_provisioner.ps1} | 0 .../configure/{start_wec_service.ps1 => wec_start_service.ps1} | 0 9 files changed, 0 insertions(+), 0 deletions(-) rename testing/configure/{link_create_ou.ps1 => create_ou.ps1} (100%) rename testing/configure/{import_sysmon_gpo.ps1 => sysmon_import_gpo.ps1} (100%) rename testing/configure/{install_sysmon_in_sysvol.ps1 => sysmon_install_in_sysvol.ps1} (100%) rename testing/configure/{link_sysmon_gpo.ps1 => sysmon_link_gpo.ps1} (100%) rename testing/configure/{import_wec_gpo_update_server_name.ps1 => wec_gpo_update_server_name.ps1} (100%) rename testing/configure/{import_wec_gpo.ps1 => wec_import_gpo.ps1} (100%) rename testing/configure/{link_wec_gpo.ps1 => wec_link_gpo.ps1} (100%) rename testing/configure/{start_wec_service_provisioner.ps1 => wec_service_provisioner.ps1} (100%) rename testing/configure/{start_wec_service.ps1 => wec_start_service.ps1} (100%) diff --git a/testing/configure/link_create_ou.ps1 b/testing/configure/create_ou.ps1 similarity index 100% rename from testing/configure/link_create_ou.ps1 rename to testing/configure/create_ou.ps1 diff --git a/testing/configure/import_sysmon_gpo.ps1 b/testing/configure/sysmon_import_gpo.ps1 similarity index 100% rename from testing/configure/import_sysmon_gpo.ps1 rename to testing/configure/sysmon_import_gpo.ps1 diff --git a/testing/configure/install_sysmon_in_sysvol.ps1 b/testing/configure/sysmon_install_in_sysvol.ps1 similarity index 100% rename from testing/configure/install_sysmon_in_sysvol.ps1 rename to testing/configure/sysmon_install_in_sysvol.ps1 diff --git a/testing/configure/link_sysmon_gpo.ps1 b/testing/configure/sysmon_link_gpo.ps1 similarity index 100% rename from testing/configure/link_sysmon_gpo.ps1 rename to testing/configure/sysmon_link_gpo.ps1 diff --git a/testing/configure/import_wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 similarity index 100% rename from testing/configure/import_wec_gpo_update_server_name.ps1 rename to testing/configure/wec_gpo_update_server_name.ps1 diff --git a/testing/configure/import_wec_gpo.ps1 b/testing/configure/wec_import_gpo.ps1 similarity index 100% rename from testing/configure/import_wec_gpo.ps1 rename to testing/configure/wec_import_gpo.ps1 diff --git a/testing/configure/link_wec_gpo.ps1 b/testing/configure/wec_link_gpo.ps1 similarity index 100% rename from testing/configure/link_wec_gpo.ps1 rename to testing/configure/wec_link_gpo.ps1 diff --git a/testing/configure/start_wec_service_provisioner.ps1 b/testing/configure/wec_service_provisioner.ps1 similarity index 100% rename from testing/configure/start_wec_service_provisioner.ps1 rename to testing/configure/wec_service_provisioner.ps1 diff --git a/testing/configure/start_wec_service.ps1 b/testing/configure/wec_start_service.ps1 similarity index 100% rename from testing/configure/start_wec_service.ps1 rename to testing/configure/wec_start_service.ps1 From 26cad546d307026af1e724a8ea090b93c94f7bae Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 05:55:27 -0500 Subject: [PATCH 015/103] Echos the file download url --- testing/configure/copy_files/download_in_container.ps1 | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index 4485fe59..49dd74c5 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -53,6 +53,7 @@ param( [Parameter(Mandatory=$true)] [string]$VMUsername # Username on the VM ) +Write-Host $FileDownloadUrl # Extract just the filename from the destination file path $DestinationFileName = Split-Path -Leaf $DestinationFilePath From 3b80b443854d913dee4f6465dc77ab786447eae3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 07:27:13 -0500 Subject: [PATCH 016/103] Expands the domain name correctly in create ou --- testing/configure/create_ou.ps1 | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/configure/create_ou.ps1 b/testing/configure/create_ou.ps1 index 4e926df8..5cf02284 100644 --- a/testing/configure/create_ou.ps1 +++ b/testing/configure/create_ou.ps1 @@ -7,7 +7,8 @@ Import-Module ActiveDirectory # Split the domain into parts and construct the ParentContainerDN $domainParts = $Domain -split "\." -$ParentContainerDN = $domainParts | ForEach-Object { "DC=$_" } -join "," +$ParentContainerDN = ($domainParts | ForEach-Object { "DC=$_" }) -join "," + # Define the distinguished name (DN) for the new OU $NewOUDN = "OU=$ClientOUCustomName,$ParentContainerDN" From 5ad0a5ec1053cfb106529b4d7a834389979cd235 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 08:01:42 -0500 Subject: [PATCH 017/103] Write the url output of copy file to container to a different output stream --- .../copy_files/copy_file_to_container.ps1 | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/testing/configure/copy_files/copy_file_to_container.ps1 b/testing/configure/copy_files/copy_file_to_container.ps1 index 19b275b6..bac7ec33 100644 --- a/testing/configure/copy_files/copy_file_to_container.ps1 +++ b/testing/configure/copy_files/copy_file_to_container.ps1 @@ -47,14 +47,16 @@ param( ) # Upload file to the blob container -az storage blob upload ` +$UploadResponse = az storage blob upload ` --container-name $ContainerName ` --file $LocalFilePath ` --name (Split-Path $LocalFilePath -Leaf) ` --account-name $StorageAccountName ` --account-key $StorageAccountKey ` - --overwrite ` + --overwrite +# Write the upload response to the standard output stream +Write-Host $UploadResponse $BlobName = (Split-Path $LocalFilePath -Leaf) $ExpiryTime = (Get-Date).AddDays(1).ToString('yyyy-MM-ddTHH:mm:ssZ') @@ -69,7 +71,11 @@ $SasUrl = az storage blob generate-sas ` --expiry $ExpiryTime ` --output tsv -# Set the full url var for returing to the user for use in the next script +# Write the SAS URL generation response to the standard output stream +Write-Host "SAS URL generated successfully." + +# Set the full url var for returning to the user for use in the next script $FullUrl = "https://${StorageAccountName}.blob.core.windows.net/${ContainerName}/${BlobName}?${SasUrl}" -$FullUrl +# Output the FullUrl to the success output stream +Write-Output $FullUrl From 8f710577cf850a8dbec257b9219de64c9a06399a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 08:33:05 -0500 Subject: [PATCH 018/103] Create a new LME folder for our scripts and files --- .../copy_files/create_lme_directory.ps1 | 25 +++++++++++++++++++ .../copy_files/download_in_container.ps1 | 13 +++------- 2 files changed, 28 insertions(+), 10 deletions(-) create mode 100644 testing/configure/copy_files/create_lme_directory.ps1 diff --git a/testing/configure/copy_files/create_lme_directory.ps1 b/testing/configure/copy_files/create_lme_directory.ps1 new file mode 100644 index 00000000..8bef9b66 --- /dev/null +++ b/testing/configure/copy_files/create_lme_directory.ps1 @@ -0,0 +1,25 @@ +# Define the directory path +$directoryPath = "C:\lme" + +# Create the directory if it doesn't already exist +if (-not (Test-Path -Path $directoryPath)) { + New-Item -Path $directoryPath -ItemType Directory +} + +# Define the security principal for 'All Users' +$allUsers = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") + +# Get the current ACL of the directory +$acl = Get-Acl -Path $directoryPath + +# Define the rights (read and execute) +$rights = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute + +# Create the rule (allowing read and execute access) +$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($allUsers, $rights, 'ContainerInherit, ObjectInherit', 'None', 'Allow') + +# Add the rule to the ACL +$acl.AddAccessRule($accessRule) + +# Set the ACL back to the directory +Set-Acl -Path $directoryPath -AclObject $acl diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index 49dd74c5..5e3cf867 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -20,16 +20,12 @@ The URL of the file to be downloaded. .PARAMETER DestinationFilePath The local file path where the file will be saved. Only the filename is used. -.PARAMETER VMUsername -The username on the VM to whose Downloads directory the file will be saved. - .EXAMPLE .\download_in_container.ps1 ` -VMName "DC1" ` -ResourceGroupName "YourResourceGroupName" ` -FileDownloadUrl "http://example.com/file.ext" ` - -DestinationFilePath "filename.ext" ` - -VMUsername "username" + -DestinationFilePath "filename.ext" This example downloads a file from "http://example.com/file.ext" to the "Downloads" directory of the user "username" on the VM "DC1" in the resource group "YourResourceGroupName". @@ -48,10 +44,7 @@ param( [string]$FileDownloadUrl, [Parameter(Mandatory=$true)] - [string]$DestinationFilePath, # This will be stripped to only the filename - - [Parameter(Mandatory=$true)] - [string]$VMUsername # Username on the VM + [string]$DestinationFilePath # This will be stripped to only the filename ) Write-Host $FileDownloadUrl @@ -59,7 +52,7 @@ Write-Host $FileDownloadUrl $DestinationFileName = Split-Path -Leaf $DestinationFilePath # Set the destination path in the VM's user Downloads directory -$DestinationPath = "C:\Users\$VMUsername\Downloads\$DestinationFileName" +$DestinationPath = "C:\lme\$DestinationFileName" $DownloadScript = @" Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath' From 55f76af28c84db8571f6668bebb89870a5218fab Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 08:52:06 -0500 Subject: [PATCH 019/103] Set path for extract to lme --- testing/configure/copy_files/extract_archive.ps1 | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/testing/configure/copy_files/extract_archive.ps1 b/testing/configure/copy_files/extract_archive.ps1 index 381f96bc..c4684119 100644 --- a/testing/configure/copy_files/extract_archive.ps1 +++ b/testing/configure/copy_files/extract_archive.ps1 @@ -13,14 +13,11 @@ The name of the Azure Virtual Machine where the file will be unzipped. .PARAMETER ResourceGroupName The name of the Azure Resource Group that contains the VM. -.PARAMETER VMUsername -The username on the VM where the file will be unzipped. - .PARAMETER Filename The name (and optional path) of the zip file to be unzipped. .EXAMPLE -.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -VMUsername "username" -Filename "C:\path\to\filename.zip" +.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "C:\path\to\filename.zip" This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. @@ -36,9 +33,6 @@ param( [Parameter(Mandatory=$true)] [string]$ResourceGroupName, - [Parameter(Mandatory=$true)] - [string]$VMUsername, - [Parameter(Mandatory=$true)] [string]$Filename ) @@ -47,11 +41,11 @@ param( $JustFilename = Split-Path -Leaf $Filename # Construct the full path for the zip file -$ZipFilePath = "C:\Users\$VMUsername\Downloads\$JustFilename" +$ZipFilePath = "C:\lme\$JustFilename" # Extract the filename without extension for the extraction directory $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) -$ExtractToPath = "C:\Users\$VMUsername\Downloads\$FileBaseName" # Extract to a subdirectory named after the file +$ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory named after the file $UnzipScript = @" Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' From 70a2754edf21356eea0c10a899cb778d0002b87a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 09:15:56 -0500 Subject: [PATCH 020/103] Update paths for scripts to /lme --- testing/configure/download_files.ps1 | 12 ++++++------ testing/configure/sysmon_import_gpo.ps1 | 10 +++++----- testing/configure/sysmon_install_in_sysvol.ps1 | 5 ++--- testing/configure/wec_import_gpo.ps1 | 10 +++++----- testing/configure/wec_service_provisioner.ps1 | 2 +- 5 files changed, 19 insertions(+), 20 deletions(-) diff --git a/testing/configure/download_files.ps1 b/testing/configure/download_files.ps1 index 67fd5f2c..1d5cedfb 100644 --- a/testing/configure/download_files.ps1 +++ b/testing/configure/download_files.ps1 @@ -1,19 +1,19 @@ param( - [string]$username = $env:USERPROFILE + [string]$directory = $env:USERPROFILE ) # Base directory path - use provided username or default to USERPROFILE -$baseDirectoryPath = if ($username -and ($username -ne $env:USERPROFILE)) { - "C:\Users\$username" +$baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { + "C:\$directory" } else { - $env:USERPROFILE + "$env:USERPROFILE\Downloads\" } $apiUrl = "https://api.github.com/repos/cisagov/LME/releases/latest" $latestRelease = Invoke-RestMethod -Uri $apiUrl $zipFileUrl = $latestRelease.assets | Where-Object { $_.content_type -eq 'application/zip' } | Select-Object -ExpandProperty browser_download_url -$downloadPath = "$baseDirectoryPath\Downloads\" + $latestRelease.name + ".zip" -$extractPath = "$baseDirectoryPath\Downloads\LME" +$downloadPath = "$baseDirectoryPath\" + $latestRelease.name + ".zip" +$extractPath = "$baseDirectoryPath\LME" Invoke-WebRequest -Uri $zipFileUrl -OutFile $downloadPath if (-not (Test-Path -Path $extractPath)) { diff --git a/testing/configure/sysmon_import_gpo.ps1 b/testing/configure/sysmon_import_gpo.ps1 index 83109761..e8e95519 100644 --- a/testing/configure/sysmon_import_gpo.ps1 +++ b/testing/configure/sysmon_import_gpo.ps1 @@ -1,15 +1,15 @@ param( - [string]$username = $env:USERPROFILE + [string]$directory = $env:USERPROFILE ) # Determine the base directory path based on the provided username -$baseDirectoryPath = if ($username -and ($username -ne $env:USERPROFILE)) { - "C:\Users\$username" +$baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { + "C:\$directory" } else { - $env:USERPROFILE + "$env:USERPROFILE\Downloads" } -$GPOBackupPath = "$baseDirectoryPath\Downloads\LME\Chapter 2 Files\GPO Deployment\Group Policy Objects" +$GPOBackupPath = "$baseDirectoryPath\LME\Chapter 2 Files\GPO Deployment\Group Policy Objects" $gpoNames = @("LME-Sysmon-Task") diff --git a/testing/configure/sysmon_install_in_sysvol.ps1 b/testing/configure/sysmon_install_in_sysvol.ps1 index 3cc002e9..41b59777 100644 --- a/testing/configure/sysmon_install_in_sysvol.ps1 +++ b/testing/configure/sysmon_install_in_sysvol.ps1 @@ -1,6 +1,5 @@ param( - [string]$DomainName = "lme.local", # Default domain name - [string]$VMUsername = "admin.ackbar" # Default VM username + [string]$DomainName = "lme.local" # Default domain name ) # Define the SYSVOL path @@ -12,7 +11,7 @@ New-Item -ItemType Directory -Path $destinationPath -Force New-Item -ItemType Directory -Path $tempPath -Force # Copy update.bat from the user's download directory -$updateBatSource = "C:\Users\$VMUsername\Downloads\LME\Chapter 2 Files\GPO Deployment\update.bat" +$updateBatSource = "C:\lme\LME\Chapter 2 Files\GPO Deployment\update.bat" Copy-Item -Path $updateBatSource -Destination $destinationPath # Download URL for Sysmon diff --git a/testing/configure/wec_import_gpo.ps1 b/testing/configure/wec_import_gpo.ps1 index dc310016..2830ecda 100644 --- a/testing/configure/wec_import_gpo.ps1 +++ b/testing/configure/wec_import_gpo.ps1 @@ -1,15 +1,15 @@ param( - [string]$username = $env:USERPROFILE + [string]$directory = $env:USERPROFILE ) # Determine the base directory path based on the provided username -$baseDirectoryPath = if ($username -and ($username -ne $env:USERPROFILE)) { - "C:\Users\$username" +$baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { + "C:\$directory" } else { - $env:USERPROFILE + "$env:USERPROFILE\Downloads" } -$GPOBackupPath = "$baseDirectoryPath\Downloads\LME\Chapter 1 Files\Group Policy Objects" +$GPOBackupPath = "$baseDirectoryPath\LME\Chapter 1 Files\Group Policy Objects" $gpoNames = @("LME-WEC-Client", "LME-WEC-Server") diff --git a/testing/configure/wec_service_provisioner.ps1 b/testing/configure/wec_service_provisioner.ps1 index c68ee0f9..81fd348b 100644 --- a/testing/configure/wec_service_provisioner.ps1 +++ b/testing/configure/wec_service_provisioner.ps1 @@ -1,7 +1,7 @@ # PowerShell script to configure Windows Event Collector param( - [string]$xmlFilePath = "C:\Users\admin.ackbar\Downloads\LME\Chapter 1 Files\lme_wec_config.xml" + [string]$xmlFilePath = "C:\lme\LME\Chapter 1 Files\lme_wec_config.xml" ) # Check if Windows Event Collector Service is running and start it if not From 68e8e2b5081c9a0e410c23f0edc81a1437eff24f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 27 Dec 2023 05:41:28 -0500 Subject: [PATCH 021/103] Fix the wec server name setting --- .../configure/wec_gpo_update_server_name.ps1 | 27 +++++-------------- 1 file changed, 7 insertions(+), 20 deletions(-) diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index c83799de..4dc681c4 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,22 +1,9 @@ -# Query the registry to find the key path -$HKEY_USERSKeys = reg query HKEY_USERS /s /f "SubscriptionManager" /k +# To set the GP registry value +Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=https://dc1.lme.local:5986/wsman/SubscriptionManager/WEC,Refresh=60" -Type String -# Extract the first key path that contains "EventForwarding" -$HKEY_USERSKeyPath = ($HKEY_USERSKeys -split "\r\n" | Where-Object { $_ -match "HKEY_USERS\\.*EventForwarding" }) -replace "HKEY_USERS\\", "HKU\" | Select-Object -First 1 +# To get the GP registry value to confirm it's set +$registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -# Ensure the key path is not null or empty -if (-not [string]::IsNullOrWhiteSpace($HKEY_USERSKeyPath)) { - # Display the current value - $oldValue = reg query "$HKEY_USERSKeyPath" /v "1" - Write-Host "Old Value: $oldValue" - - # Change the SubscriptionManager key value - $newData = "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" - reg add "$HKEY_USERSKeyPath" /v "1" /t REG_SZ /d "$newData" /f - - # Requery to confirm the change - $newValue = reg query "$HKEY_USERSKeyPath" /v "1" - Write-Host "New Value: $newValue" -} else { - Write-Error "Registry key path not found." -} \ No newline at end of file +# Output the retrieved registry value +Write-Host "Set the subscription manager url value to: " +$registryValue \ No newline at end of file From 6265149b5efb70c341ad6512ff7ef3972b310e45 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 28 Dec 2023 06:57:10 -0500 Subject: [PATCH 022/103] Adds the scripts to install chapter 1 and 2 --- testing/configure/install_chapter_1.ps1 | 32 +++++++++++++++++++ testing/configure/install_chapter_2.ps1 | 18 +++++++++++ .../configure/wec_gpo_update_server_name.ps1 | 9 ++++-- 3 files changed, 57 insertions(+), 2 deletions(-) create mode 100644 testing/configure/install_chapter_1.ps1 create mode 100644 testing/configure/install_chapter_2.ps1 diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 new file mode 100644 index 00000000..3bf66666 --- /dev/null +++ b/testing/configure/install_chapter_1.ps1 @@ -0,0 +1,32 @@ +param ( + [Parameter( + HelpMessage="Path to the configuration directory. Default is 'C:\lme\configure'." + )] + [string]$configurePath = "C:\lme\configure" +) + +# Exit the script on any error +$ErrorActionPreference = 'Stop' + +# Change directory to the configure directory +Set-Location -Path $configurePath + +# Run the scripts and check for failure +.\copy_files\create_lme_directory.ps1 +.\download_files.ps1 -directory lme +.\wec_import_gpo.ps1 -directory lme +.\wec_gpo_update_server_name.ps1 +.\create_ou.ps1 +.\wec_link_gpo.ps1 +.\wec_service_provisioner.ps1 + +# Run the wevtutil and wecutil commands +wevtutil set-log ForwardedEvents /q:true /e:true +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +wecutil rs lme +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } +wecutil gr lme +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } + +# Run the move_computers_to_ou script +.\move_computers_to_ou.ps1 diff --git a/testing/configure/install_chapter_2.ps1 b/testing/configure/install_chapter_2.ps1 new file mode 100644 index 00000000..17e90ff1 --- /dev/null +++ b/testing/configure/install_chapter_2.ps1 @@ -0,0 +1,18 @@ +param ( + [Parameter( + HelpMessage="Path to the configuration directory. Default is 'C:\lme\configure'." + )] + [string]$configurePath = "C:\lme\configure" +) + +# Exit the script on any error +$ErrorActionPreference = 'Stop' + +# Change directory to the configure directory +Set-Location -Path $configurePath + +# Run the scripts and check for failure +.\sysmon_install_in_sysvol.ps1 +.\sysmon_import_gpo.ps1 -directory lme +.\sysmon_gpo_update_vars.ps1 +.\sysmon_link_gpo.ps1 diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index 4dc681c4..265b5d89 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,9 +1,14 @@ +# Query the registry to find the key path +#$HKEY_USERSKeys = reg query HKEY_USERS /s /f "SubscriptionManager" /k + +HKEY_USERS\S-1-5-21-1874110181-726158762-2826089689-500\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\LME.LOCAL{083A2CE3-3021-4F4D-9765-35EB888E62CF}Machine\Software\Policies\Microsoft\Windows\EventLog\Event +Forwarding\SubscriptionManager # To set the GP registry value -Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=https://dc1.lme.local:5986/wsman/SubscriptionManager/WEC,Refresh=60" -Type String +Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" -Type String # To get the GP registry value to confirm it's set $registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" # Output the retrieved registry value Write-Host "Set the subscription manager url value to: " -$registryValue \ No newline at end of file +$registryValue From c89aa888470ef7a0f7544672aa659e6a27cfda69 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 28 Dec 2023 08:53:12 -0500 Subject: [PATCH 023/103] Allows azure to download in linux and windows --- .../copy_files/download_in_container.ps1 | 76 ++++++++----------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index 5e3cf867..a995c8ce 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -1,38 +1,3 @@ -<# -.SYNOPSIS -Downloads a file to a specified Azure VM's user directory. - -.DESCRIPTION -This script downloads a file from a given URL to a specified Azure Virtual Machine (VM). -It places the file in the Downloads directory of a specified user's profile on the VM. -The script requires details of the VM, the resource group, the file URL, the local filename for saving, -and the VM's username. - -.PARAMETER VMName -The name of the Azure Virtual Machine. - -.PARAMETER ResourceGroupName -The name of the Azure Resource Group that contains the VM. - -.PARAMETER FileDownloadUrl -The URL of the file to be downloaded. - -.PARAMETER DestinationFilePath -The local file path where the file will be saved. Only the filename is used. - -.EXAMPLE -.\download_in_container.ps1 ` - -VMName "DC1" ` - -ResourceGroupName "YourResourceGroupName" ` - -FileDownloadUrl "http://example.com/file.ext" ` - -DestinationFilePath "filename.ext" - -This example downloads a file from "http://example.com/file.ext" to the "Downloads" directory of the user "username" on the VM "DC1" in the resource group "YourResourceGroupName". - -.NOTES -Ensure that the Azure CLI is installed and configured with the necessary permissions to access the specified Azure VM. -#> - param( [Parameter(Mandatory=$true)] [string]$VMName, @@ -44,20 +9,45 @@ param( [string]$FileDownloadUrl, [Parameter(Mandatory=$true)] - [string]$DestinationFilePath # This will be stripped to only the filename + [string]$DestinationFilePath, # This will be stripped to only the filename + + [Parameter()] + [string]$username = "admin.ackbar", + + [Parameter()] + [ValidateSet("Windows","Linux","linux")] + [string]$os = "Windows" ) Write-Host $FileDownloadUrl +# Convert the OS parameter to lowercase for consistent comparison +$os = $os.ToLower() + # Extract just the filename from the destination file path $DestinationFileName = Split-Path -Leaf $DestinationFilePath -# Set the destination path in the VM's user Downloads directory -$DestinationPath = "C:\lme\$DestinationFileName" - -$DownloadScript = @" -Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath' -"@ - +# Set the destination path depending on the OS +if ($os -eq "linux") { + $DestinationPath = "/home/$username/lme/$DestinationFileName" + # Create the lme directory if it doesn't exist + $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" + az vm run-command invoke ` + --command-id RunShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DirectoryCreationScript +} else { + $DestinationPath = "C:\lme\$DestinationFileName" +} + +# The download script +$DownloadScript = if ($os -eq "linux") { + "curl -o '$DestinationPath' '$FileDownloadUrl'" +} else { + "Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath'" +} + +# Execute the download script az vm run-command invoke ` --command-id RunPowerShellScript ` --resource-group $ResourceGroupName ` From 3047296f6a44e41850b92a1aa2719d9a68f9d7a2 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 28 Dec 2023 09:12:56 -0500 Subject: [PATCH 024/103] Adds linux install scripts. --- .../copy_files/download_in_container.ps1 | 20 +++++-- .../configure/copy_files/extract_archive.ps1 | 55 ++++++++++++++----- testing/configure/linux_install_lme.exp | 46 ++++++++++++++++ testing/configure/linux_install_lme.sh | 21 +++++++ testing/configure/linux_update_system.sh | 3 + 5 files changed, 125 insertions(+), 20 deletions(-) create mode 100644 testing/configure/linux_install_lme.exp create mode 100644 testing/configure/linux_install_lme.sh create mode 100644 testing/configure/linux_update_system.sh diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index a995c8ce..80b9743f 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -47,9 +47,17 @@ $DownloadScript = if ($os -eq "linux") { "Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath'" } -# Execute the download script -az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $DownloadScript +# Execute the download script with the appropriate command based on OS +if ($os -eq "linux") { + az vm run-command invoke ` + --command-id RunShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DownloadScript +} else { + az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DownloadScript +} diff --git a/testing/configure/copy_files/extract_archive.ps1 b/testing/configure/copy_files/extract_archive.ps1 index c4684119..bfcbd591 100644 --- a/testing/configure/copy_files/extract_archive.ps1 +++ b/testing/configure/copy_files/extract_archive.ps1 @@ -17,7 +17,7 @@ The name of the Azure Resource Group that contains the VM. The name (and optional path) of the zip file to be unzipped. .EXAMPLE -.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "C:\path\to\filename.zip" +.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "filename.zip" This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. @@ -34,25 +34,52 @@ param( [string]$ResourceGroupName, [Parameter(Mandatory=$true)] - [string]$Filename + [string]$Filename, + + [Parameter()] + [string]$username = "admin.ackbar", + + [Parameter()] + [ValidateSet("Windows","Linux","linux")] + [string]$os = "Windows" ) +# Convert the OS parameter to lowercase for consistent comparison +$os = $os.ToLower() + # Extract just the filename (ignoring any provided path) $JustFilename = Split-Path -Leaf $Filename -# Construct the full path for the zip file -$ZipFilePath = "C:\lme\$JustFilename" +# Set paths depending on the OS +if ($os -eq "linux") { + $ZipFilePath = "/home/$username/lme/$JustFilename" + $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) + $ExtractToPath = "/home/$username/lme/$FileBaseName" # Extract to a subdirectory -# Extract the filename without extension for the extraction directory -$FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) -$ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory named after the file + $UnzipScript = @" + unzip '$ZipFilePath' -d '$ExtractToPath' +"@ +} else { + $ZipFilePath = "C:\lme\$JustFilename" + $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) + $ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory -$UnzipScript = @" -Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' + $UnzipScript = @" + Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' "@ +} -az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $UnzipScript +# Execute the unzip script with the appropriate command based on OS +if ($os -eq "linux") { + az vm run-command invoke ` + --command-id RunShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $UnzipScript +} else { + az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $UnzipScript +} diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp new file mode 100644 index 00000000..2dd52a1f --- /dev/null +++ b/testing/configure/linux_install_lme.exp @@ -0,0 +1,46 @@ +#!/usr/bin/expect + +# Change to the LME directory containing files for the Linux server +cd /opt/lme/Chapter\ 3\ Files/ + +# Adjust the timeout if necessary +set timeout 60 +set expect_out(buffer_size) 100000 + +log_file -a output.log + +spawn ./deploy.sh install + +expect "Proceed? \\\[Y/n\\\] " +send "y\r" + +expect { + -re "Enter the IP of this Linux server.*10.1.0.5" { + sleep 1 + send "\r" + } +} + +sleep 1 +expect -re {Windows Event Collector} +sleep 1 +send "ls1.lme.local\r" + +sleep 1 +# Use braces for regular expressions and ensure correct escaping +# continue with self signed certificates? ([y]es/[n]o): y +expect -re {continue with self signed certificates.*: y} +sleep 1 +send "\r" +sleep 1 + +expect -re {Skip Docker Install\? \(\[y\]es/\[n\]o\): n} +sleep 1 +send "\r" +set timeout 600 + +expect eof + +log_file + +exec cat output.log diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh new file mode 100644 index 00000000..aa47dfb2 --- /dev/null +++ b/testing/configure/linux_install_lme.sh @@ -0,0 +1,21 @@ +#!/bin/bash + +# Default username +username="admin.ackbar" + +# Parse flag-based arguments +while getopts "u:" opt; do + case $opt in + u) username=$OPTARG ;; + \?) echo "Invalid option -$OPTARG" >&2; exit 1 ;; + esac +done + +# Download a copy of the LME files +sudo git clone https://github.com/cisagov/lme.git /opt/lme/ +# Execute script with root privileges +sudo ./linux_install_lme.exp + +# Replace 'admin.ackbar' with the specified username +sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ +sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh new file mode 100644 index 00000000..8dabc52f --- /dev/null +++ b/testing/configure/linux_update_system.sh @@ -0,0 +1,3 @@ +# Install Git client to be able to clone the LME repository +sudo apt update +sudo apt install git curl zip net-tools jq expect -y \ No newline at end of file From 5c12a1f3e578f472ad005ecf48b4fd2fcdda0c14 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 29 Dec 2023 08:00:44 -0500 Subject: [PATCH 025/103] Adds winlogbeat installer --- testing/configure/chown_dc1_private_key.ps1 | 21 +++++ .../configure/linux_authorize_private_key.sh | 4 + testing/configure/linux_install_lme.exp | 1 - testing/configure/linux_install_lme.sh | 4 +- testing/configure/linux_make_private_key.exp | 16 ++++ testing/configure/winlogbeat_install.ps1 | 85 +++++++++++++++++++ 6 files changed, 129 insertions(+), 2 deletions(-) create mode 100644 testing/configure/chown_dc1_private_key.ps1 create mode 100644 testing/configure/linux_authorize_private_key.sh create mode 100644 testing/configure/linux_make_private_key.exp create mode 100644 testing/configure/winlogbeat_install.ps1 diff --git a/testing/configure/chown_dc1_private_key.ps1 b/testing/configure/chown_dc1_private_key.ps1 new file mode 100644 index 00000000..d1ecc149 --- /dev/null +++ b/testing/configure/chown_dc1_private_key.ps1 @@ -0,0 +1,21 @@ +# Path to the private key +$privateKeyPath = "C:\lme\id_rsa" + +# Define the SYSTEM account +$systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM") + +# Get the current ACL of the file +$acl = Get-Acl -Path $privateKeyPath + +# Clear any existing Access Rules (optional - do this if you want to restrict access to SYSTEM only) +$acl.SetAccessRuleProtection($true, $false) +$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } + +# Create a new Access Rule granting FullControl to SYSTEM +$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($systemAccount, "FullControl", "Allow") + +# Add the Access Rule to the ACL +$acl.AddAccessRule($accessRule) + +# Set the updated ACL back to the file +Set-Acl -Path $privateKeyPath -AclObject $acl diff --git a/testing/configure/linux_authorize_private_key.sh b/testing/configure/linux_authorize_private_key.sh new file mode 100644 index 00000000..ebe55b76 --- /dev/null +++ b/testing/configure/linux_authorize_private_key.sh @@ -0,0 +1,4 @@ +#!/usr/bin/env bash +cat /home/admin.ackbar/.ssh/id_rsa.pub >> /home/admin.ackbar/.ssh/authorized_keys +chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* +perl -p -i -e 's/root\@LS1/admin.ackbar\@DC1/' /home/admin.ackbar/.ssh/authorized_keys diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 2dd52a1f..3a6051cd 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -28,7 +28,6 @@ send "ls1.lme.local\r" sleep 1 # Use braces for regular expressions and ensure correct escaping -# continue with self signed certificates? ([y]es/[n]o): y expect -re {continue with self signed certificates.*: y} sleep 1 send "\r" diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index aa47dfb2..8fb21544 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -1,5 +1,8 @@ #!/bin/bash +# Change to the directory where the script is located +cd "$(dirname "$0")" || exit 1 + # Default username username="admin.ackbar" @@ -16,6 +19,5 @@ sudo git clone https://github.com/cisagov/lme.git /opt/lme/ # Execute script with root privileges sudo ./linux_install_lme.exp -# Replace 'admin.ackbar' with the specified username sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip diff --git a/testing/configure/linux_make_private_key.exp b/testing/configure/linux_make_private_key.exp new file mode 100644 index 00000000..16fd6ec9 --- /dev/null +++ b/testing/configure/linux_make_private_key.exp @@ -0,0 +1,16 @@ +#!/usr/bin/expect + +spawn ssh-keygen -t rsa -b 4096 +sleep 1 +expect -re {Enter file in which to save the key} +send "/home/admin.ackbar/.ssh/id_rsa\r" +sleep 1 +expect -re {empty for no passphrase} +send "\r" +sleep 1 +expect -re {Enter same passphrase again} +send "\r" + +set timeout 60 + +expect eof diff --git a/testing/configure/winlogbeat_install.ps1 b/testing/configure/winlogbeat_install.ps1 new file mode 100644 index 00000000..fbf3a198 --- /dev/null +++ b/testing/configure/winlogbeat_install.ps1 @@ -0,0 +1,85 @@ +param ( + [Parameter()] + [string]$baseDirectory = "C:\lme", + + [Parameter()] + [string]$winlogbeatVersion = "winlogbeat-8.5.0-windows-x86_64" +) + +# Source and destination directories +$sourceDir = "$baseDirectory\files_for_windows\tmp" +$destinationDir = "C:\Program Files" + +# Copying files from source to destination +Copy-Item -Path "$sourceDir\*" -Destination $destinationDir -Recurse -Force + +# Winlogbeat url +$url = "https://artifacts.elastic.co/downloads/beats/winlogbeat/$winlogbeatVersion.zip" + +# Destination path where the file will be saved +$winlogbeatDestination = "$baseDirectory\$winlogbeatVersion.zip" + +# Create the base directory if it does not exist +if (-not (Test-Path $baseDirectory)) { + New-Item -ItemType Directory -Path $baseDirectory +} + +# Download the file +Invoke-WebRequest -Uri $url -OutFile $winlogbeatDestination + +# Unzip destination +$unzipDestination = "C:\Program Files\lme\$winlogbeatVersion" + +# Unzip the file +Expand-Archive -LiteralPath $winlogbeatDestination -DestinationPath $unzipDestination + +# Define the nested directory path +$nestedDir = Join-Path -Path $unzipDestination -ChildPath $winlogbeatVersion + +# Move the contents of the nested directory up one level and remove the nested directory +if (Test-Path $nestedDir) { + Get-ChildItem -Path $nestedDir -Recurse | Move-Item -Destination $unzipDestination + Remove-Item -Path $nestedDir -Force -Recurse +} + + +# Define the path of the winlogbeat.yml file in C:\Program Files\lme +$winlogbeatYmlSource = "C:\Program Files\lme\winlogbeat.yml" + +# Define the destination path of the winlogbeat.yml file +$winlogbeatYmlDestination = Join-Path -Path $unzipDestination -ChildPath "winlogbeat.yml" + +# Move the winlogbeat.yml file to the destination directory, overwriting if it exists +Move-Item -Path $winlogbeatYmlSource -Destination $winlogbeatYmlDestination -Force + +# Set execution policy to Unrestricted for this process +Set-ExecutionPolicy Unrestricted -Scope Process + +# Define the full path of the install script +$installScriptPath = Join-Path -Path $unzipDestination -ChildPath "install-service-winlogbeat.ps1" + +# Check if the install script exists +if (Test-Path $installScriptPath) { + # Change directory to the unzip destination + Push-Location -Path $unzipDestination + + # Run the install script + .\install-service-winlogbeat.ps1 + + # Return to the previous directory + Pop-Location +} +else { + Write-Host "The installation script was not found at $installScriptPath" +} + +Start-Sleep -Seconds 5 + +# Start the winlogbeat service +try { + Start-Service -Name "winlogbeat" + Write-Host "Winlogbeat service started successfully." +} +catch { + Write-Host "Failed to start Winlogbeat service: $_" +} From 2daf25bf95db64e868718cbc21446fb5ba9151bf Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 29 Dec 2023 14:41:19 -0500 Subject: [PATCH 026/103] emove garbage in update server name --- testing/configure/wec_gpo_update_server_name.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index 265b5d89..c158a17c 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,8 +1,3 @@ -# Query the registry to find the key path -#$HKEY_USERSKeys = reg query HKEY_USERS /s /f "SubscriptionManager" /k - -HKEY_USERS\S-1-5-21-1874110181-726158762-2826089689-500\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\LME.LOCAL{083A2CE3-3021-4F4D-9765-35EB888E62CF}Machine\Software\Policies\Microsoft\Windows\EventLog\Event -Forwarding\SubscriptionManager # To set the GP registry value Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" -Type String From eaea87c2e2856f75eaa4806418be21f937bd06f4 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 3 Jan 2024 07:34:54 -0500 Subject: [PATCH 027/103] Tweak several scripts to get the scp of files_for_windows --- testing/configure/chown_dc1_private_key.ps1 | 2 +- testing/configure/install_chapter_1.ps1 | 4 +- .../configure/linux_authorize_private_key.sh | 2 +- testing/configure/trust_ls1_ssh_key.ps1 | 59 +++++++++++++++++++ 4 files changed, 62 insertions(+), 5 deletions(-) create mode 100644 testing/configure/trust_ls1_ssh_key.ps1 diff --git a/testing/configure/chown_dc1_private_key.ps1 b/testing/configure/chown_dc1_private_key.ps1 index d1ecc149..e8a8fece 100644 --- a/testing/configure/chown_dc1_private_key.ps1 +++ b/testing/configure/chown_dc1_private_key.ps1 @@ -7,7 +7,7 @@ $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", # Get the current ACL of the file $acl = Get-Acl -Path $privateKeyPath -# Clear any existing Access Rules (optional - do this if you want to restrict access to SYSTEM only) +# Clear any existing Access Rules $acl.SetAccessRuleProtection($true, $false) $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 3bf66666..828142d1 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -15,6 +15,7 @@ Set-Location -Path $configurePath .\copy_files\create_lme_directory.ps1 .\download_files.ps1 -directory lme .\wec_import_gpo.ps1 -directory lme +Start-Sleep 10 .\wec_gpo_update_server_name.ps1 .\create_ou.ps1 .\wec_link_gpo.ps1 @@ -22,11 +23,8 @@ Set-Location -Path $configurePath # Run the wevtutil and wecutil commands wevtutil set-log ForwardedEvents /q:true /e:true -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } wecutil rs lme -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } wecutil gr lme -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Run the move_computers_to_ou script .\move_computers_to_ou.ps1 diff --git a/testing/configure/linux_authorize_private_key.sh b/testing/configure/linux_authorize_private_key.sh index ebe55b76..c699d816 100644 --- a/testing/configure/linux_authorize_private_key.sh +++ b/testing/configure/linux_authorize_private_key.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash cat /home/admin.ackbar/.ssh/id_rsa.pub >> /home/admin.ackbar/.ssh/authorized_keys -chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* +sudo chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* perl -p -i -e 's/root\@LS1/admin.ackbar\@DC1/' /home/admin.ackbar/.ssh/authorized_keys diff --git a/testing/configure/trust_ls1_ssh_key.ps1 b/testing/configure/trust_ls1_ssh_key.ps1 new file mode 100644 index 00000000..62baef4c --- /dev/null +++ b/testing/configure/trust_ls1_ssh_key.ps1 @@ -0,0 +1,59 @@ +# Ensure the .ssh directory exists +if (-not (Test-Path -Path $sshDirectory)) { + New-Item -ItemType Directory -Path $sshDirectory +} + +# Function to set ACL for the directory, granting FullControl to SYSTEM and applying inheritance +function Set-SystemOnlyAclForDirectory { + param ( + [string]$path + ) + + $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM") + $acl = Get-Acl -Path $path + $acl.SetAccessRuleProtection($true, $false) # Enable ACL protection, disable inheritance + $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } # Clear existing rules + + # Create and add the Access Rule for SYSTEM with inheritance + $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($systemAccount, "FullControl", "ContainerInherit,ObjectInherit", "None", "Allow") + $acl.AddAccessRule($accessRule) + + # Apply the updated ACL to the directory + Set-Acl -Path $path -AclObject $acl +} + +# Function to set ACL for a file, granting FullControl only to SYSTEM +function Set-SystemOnlyAclForFile { + param ( + [string]$path + ) + + $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM") + $acl = Get-Acl -Path $path + $acl.SetAccessRuleProtection($true, $false) # Enable ACL protection, disable inheritance + $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } # Clear existing rules + + # Create and add the Access Rule for SYSTEM + $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($systemAccount, "FullControl", "Allow") + $acl.AddAccessRule($accessRule) + + # Apply the updated ACL to the file + Set-Acl -Path $path -AclObject $acl +} + +# Set ACL for the .ssh directory with inheritance +Set-SystemOnlyAclForDirectory -path $sshDirectory + +# Ensure the known_hosts file exists +if (-not (Test-Path -Path $knownHostsFile)) { + New-Item -ItemType File -Path $knownHostsFile +} + +# Set ACL for the known_hosts file without inheritance +Set-SystemOnlyAclForFile -path $knownHostsFile + +# Run ssh-keyscan and append output to known_hosts +ssh-keyscan $sshHost | Out-File -FilePath $knownHostsFile -Append -Encoding UTF8 + +# Output the contents of the known_hosts file +Get-Content -Path $knownHostsFile From a4467fde13d43efb6acf4384ac76daca4c01977d Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 4 Jan 2024 07:36:56 -0500 Subject: [PATCH 028/103] Adds installer script to run all the scripts --- testing/InstallTestbed.ps1 | 311 ++++++++++++++++++ .../copy_file_to_container.ps1 | 0 .../create_blob_container.ps1 | 0 .../download_in_container.ps1 | 0 .../extract_archive.ps1 | 0 .../azure_scripts/lib/utilityFunctions.ps1 | 98 ++++++ .../run_script_in_container.ps1 | 0 .../zip_my_parents_parent.ps1 | 0 .../{copy_files => }/create_lme_directory.ps1 | 0 testing/configure/install_chapter_1.ps1 | 2 +- testing/configure/trust_ls1_ssh_key.ps1 | 7 + 11 files changed, 417 insertions(+), 1 deletion(-) create mode 100644 testing/InstallTestbed.ps1 rename testing/configure/{copy_files => azure_scripts}/copy_file_to_container.ps1 (100%) rename testing/configure/{copy_files => azure_scripts}/create_blob_container.ps1 (100%) rename testing/configure/{copy_files => azure_scripts}/download_in_container.ps1 (100%) rename testing/configure/{copy_files => azure_scripts}/extract_archive.ps1 (100%) create mode 100644 testing/configure/azure_scripts/lib/utilityFunctions.ps1 rename testing/configure/{copy_files => azure_scripts}/run_script_in_container.ps1 (100%) rename testing/configure/{copy_files => azure_scripts}/zip_my_parents_parent.ps1 (100%) rename testing/configure/{copy_files => }/create_lme_directory.ps1 (100%) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 new file mode 100644 index 00000000..f86575fb --- /dev/null +++ b/testing/InstallTestbed.ps1 @@ -0,0 +1,311 @@ +param ( + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName +) + +$VMUsername = "admin.ackbar" +#$ResourceGroupName = "LME-cbaxley-t2" +$VMName = "DC1" +$LinuxVMName = "LS1" + +$Password = Get-Content "password.txt" + +$libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" + +# Check if the library file exists +if (Test-Path -Path $libraryPath) { + # Dot-source the library script + . $libraryPath +} else { + Write-Error "Library script not found at path: $libraryPath" +} + +# Create a container to keep files for the VM +Write-Host "Creating a container to keep files for the VM..." +./configure/azure_scripts/create_blob_container.ps1 ` + -ResourceGroupName $ResourceGroupName + +# Source the variables from the file +Write-Host "Sourcing the variables from the file..." +. ./configure/azure_scripts/config.ps1 + +# Zip up the installer scripts for the VM +Write-Host "Zipping up the installer scripts for the VM..." +./configure/azure_scripts/zip_my_parents_parent.ps1 + +# Upload the zip file to the container and get a key to download it +Write-Host "Uploading the zip file to the container and getting a key to download it..." +$FileDownloadUrl = ./configure/azure_scripts/copy_file_to_container.ps1 ` + -LocalFilePath "configure.zip" ` + -ContainerName $ContainerName ` + -StorageAccountName $StorageAccountName ` + -StorageAccountKey $StorageAccountKey + +Write-Host "File download URL: $FileDownloadUrl" + +Write-Host "Changing directory to the azure scripts..." +Set-Location configure/azure_scripts + +# Make our directory on the VM +Write-Host "Making our directory on the VM..." +$createDirResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name $VMName ` + --resource-group $ResourceGroupName ` + --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" + +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") + +# Download the zip file to the VM +Write-Host "Downloading the zip file to the VM..." +.\download_in_container.ps1 ` + -VMName $VmName ` + -ResourceGroupName $ResourceGroupName ` + -FileDownloadUrl "$FileDownloadUrl" ` + -DestinationFilePath "configure.zip" + +# Extract the zip file +Write-Host "Extracting the zip file..." +.\extract_archive.ps1 ` + -VMName $VMName ` + -ResourceGroupName $ResourceGroupName ` + -FileName "configure.zip" + +# Run the install script for chapter 1 +Write-Host "Running the install script for chapter 1..." +$installChapter1Response = .\run_script_in_container.ps1 ` + -ResourceGroupName $ResourceGroupName ` + -VMName $VMName ` + -ScriptPathOnVM "C:\lme\configure\install_chapter_1.ps1" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter1Response") + +# Todo: Loop these for number of vms +# Update the group policy on the remote machines +Write-Host "Updating the group policy on the remote machines..." +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C1" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C2" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + +# Wait for the services to start +Write-Host "Waiting for the services to start..." +Start-Sleep 20 + +# See if we can see the forwarding computers in the DC +write-host "Seeing if we can see the forwarding computers in the DC..." +$listForwardingComputersResponse = .\run_script_in_container.ps1 ` + -ResourceGroupName $ResourceGroupName ` + -VMName $VMName ` + -ScriptPathOnVM "C:\lme\configure\list_computers_forwarding_events.ps1" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$listForwardingComputersResponse") + +# Install the sysmon service on DC1 from chapter 2 +Write-Host "Installing the sysmon service on DC1 from chapter 2..." +$installChapter2Response = .\run_script_in_container.ps1 ` + -ResourceGroupName $ResourceGroupName ` + -VMName $VMName ` + -ScriptPathOnVM "C:\lme\configure\install_chapter_2.ps1" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter2Response") + +# Update the group policy on the remote machines +Write-Host "Updating the group policy on the remote machines..." +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C1" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C2" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + +# Wait for the services to start +Write-Host "Waiting for the services to start..." +Start-Sleep 20 + + +# See if you can see sysmon running on the machine +Write-Host "Seeing if you can see sysmon running on a machine..." +$showSysmonResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C1" ` + --resource-group $ResourceGroupName ` + --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") + + +# Download the installers on LS1 +Write-Host "Downloading the installers on LS1..." +.\download_in_container.ps1 ` + -VMName $LinuxVMName ` + -ResourceGroupName $ResourceGroupName ` + -FileDownloadUrl "$FileDownloadUrl" ` + -DestinationFilePath "configure.zip" ` + -os "linux" + +# Install unzip on LS1 +Write-Host "Installing unzip on LS1..." +$installUnzipResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts 'apt-get install unzip -y' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installUnzipResponse") + +# Unzip the file on LS1 +Write-Host "Unzipping the file on LS1..." +.\extract_archive.ps1 ` + -VMName $LinuxVMName ` + -ResourceGroupName $ResourceGroupName ` + -FileName "configure.zip" ` + -os "linux" + +# Make the installer files executable and update the system packages on LS1 +Write-Host "Making the installer files executable and updating the system packages on LS1..." +$updateLinuxResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts 'chmod +x /home/admin.ackbar/lme/configure/* && /home/admin.ackbar/lme/configure/linux_update_system.sh' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$updateLinuxResponse") + +# Run the lme installer on LS1 +Write-Host "Running the lme installer on LS1..." +# Todo: We need to check the output from this and see if we need to reboot +# It should include this line "## logstash_system:" if it completed successfully +$installLmeResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") + +# Have to check for the reboot thing here +Write-Host "Rebooting ${LinuxVMName}..." +az vm restart ` + --resource-group $ResourceGroupName ` + --name $LinuxVMName + +# Run the lme installer on LS1 +Write-Host "Running the lme installer on LS1..." +az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") + +# Capture the output of the install script +Write-Host "Capturing the output of the install script for ES passwords..." +$jsonResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts 'tail -n10 "/opt/lme/Chapter 3 Files/output.log" | head -n4' + +# Todo: Extract the output and write this to a file for later use +Format-AzVmRunCommandOutput -JsonResponse "$jsonResponse" + +# Generate key using expect on linux +Write-Host "Generating key using expect on linux..." +az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' + +# Add the public key to the authorized_keys file on LS1 +Write-Host "Adding the public key to the authorized_keys file on LS1..." +$authorizePrivateKeyResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts '/home/admin.ackbar/lme/configure/linux_authorize_private_key.sh' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$authorizePrivateKeyResponse") + +# Cat the private key and capture that to the azure shell +Write-Host "Cat the private key and capture that to the azure shell..." +$jsonResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroupName ` + --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' + +$privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" + +# Save the private key to a file +Write-Host "Saving the private key to a file..." +$filePath = ".\id_rsa" +Set-Content -Path $filePath -Value $privateKey + +# Upload the private key to the container and get a key to download it +Write-Host "Uploading the private key to the container and getting a key to download it..." +$KeyDownloadUrl = ./copy_file_to_container.ps1 ` + -LocalFilePath "id_rsa" ` + -ContainerName $ContainerName ` + -StorageAccountName $StorageAccountName ` + -StorageAccountKey $StorageAccountKey + +# Download the private key to DC1 +Write-Host "Downloading the private key to DC1..." +.\download_in_container.ps1 ` + -VMName $VmName ` + -ResourceGroupName $ResourceGroupName ` + -FileDownloadUrl "$KeyDownloadUrl" ` + -DestinationFilePath "id_rsa" + +# Change the ownership of the private key file on DC1 +Write-Host "Changing the ownership of the private key file on DC1..." +$chownPrivateKeyResponse = .\run_script_in_container.ps1 ` + -ResourceGroupName $ResourceGroupName ` + -VMName $VMName ` + -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") + +# Trust the key from ls1 so we can scp interactively +# Todo: We may not need this +#.\run_script_in_container.ps1 ` +# -ResourceGroupName $ResourceGroupName ` +# -VMName $VMName ` +# -ScriptPathOnVM "C:\lme\configure\trust_ls1_ssh_key.ps1" +# + +# Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 +Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." +$scpResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name $VMName ` + --resource-group $ResourceGroupName ` + --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1.lme.local:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") + +# Extract the files on DC1 +Write-Host "Extracting the files on DC1..." +.\extract_archive.ps1 ` + -VMName $VMName ` + -ResourceGroupName $ResourceGroupName ` + -FileName "files_for_windows.zip" + +# Install winlogbeat on DC1 +Write-Host "Installing winlogbeat on DC1..." +$installWinlogbeatResponse = .\run_script_in_container.ps1 ` + -ResourceGroupName $ResourceGroupName ` + -VMName $VMName ` + -ScriptPathOnVM "C:\lme\configure\winlogbeat_install.ps1" + +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") + +Write-Host "Insttall completed." diff --git a/testing/configure/copy_files/copy_file_to_container.ps1 b/testing/configure/azure_scripts/copy_file_to_container.ps1 similarity index 100% rename from testing/configure/copy_files/copy_file_to_container.ps1 rename to testing/configure/azure_scripts/copy_file_to_container.ps1 diff --git a/testing/configure/copy_files/create_blob_container.ps1 b/testing/configure/azure_scripts/create_blob_container.ps1 similarity index 100% rename from testing/configure/copy_files/create_blob_container.ps1 rename to testing/configure/azure_scripts/create_blob_container.ps1 diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 similarity index 100% rename from testing/configure/copy_files/download_in_container.ps1 rename to testing/configure/azure_scripts/download_in_container.ps1 diff --git a/testing/configure/copy_files/extract_archive.ps1 b/testing/configure/azure_scripts/extract_archive.ps1 similarity index 100% rename from testing/configure/copy_files/extract_archive.ps1 rename to testing/configure/azure_scripts/extract_archive.ps1 diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 new file mode 100644 index 00000000..f0fcb887 --- /dev/null +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -0,0 +1,98 @@ +function Format-AzVmRunCommandOutput { + param ( + [Parameter(Mandatory=$true)] + [string]$JsonResponse + ) + + # Convert JSON string to PowerShell object + $responseObj = $JsonResponse | ConvertFrom-Json + + # Initialize an array to hold the results + $results = @() + + # Check if there is any response + if ($responseObj -and $responseObj.value) { + foreach ($item in $responseObj.value) { + # Process the stdout and stderr content + if ($item.message) { + # Extracting and cleaning up the messages + $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 + $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 + $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 + + # Create a custom object with stdout and stderr + $output = New-Object PSObject -Property @{ + StdOut = $stdout + StdErr = $stderr + } + + # Add the custom object to the results array + $results += $output + } + } + } else { + # Return a message if no valid response is found + $results += "No response or invalid response received." + } + + # Return the results array + return $results +} + +function Show-FormattedOutput { + param ( + [Parameter(Mandatory=$true)] + [Object[]]$FormattedOutput + ) + + foreach ($item in $FormattedOutput) { + if ($item -is [string]) { + # Handle string messages (like error or informational messages) + Write-Host $item + } + elseif ($item -is [PSCustomObject]) { + # Handle custom objects with StdOut and StdErr + Write-Host "Output (stdout):" + Write-Host $item.StdOut + Write-Host "Error (stderr):" + Write-Host $item.StdErr + } + } +} + +function ExtractPrivateKeyFromJson { + param ( + [Parameter(Mandatory=$true)] + [string]$jsonResponse + ) + + try { + # Convert the JSON string to a PowerShell object + $responseObj = $jsonResponse | ConvertFrom-Json + + # Extract the 'message' field + $message = $responseObj.value[0].message + + # Define the start and end markers for the private key + $startMarker = "-----BEGIN OPENSSH PRIVATE KEY-----" + $endMarker = "-----END OPENSSH PRIVATE KEY-----" + + # Find the positions of the start and end markers + $startPosition = $message.IndexOf($startMarker) + $endPosition = $message.IndexOf($endMarker) + + if ($startPosition -lt 0 -or $endPosition -lt 0) { + Write-Error "Private key markers not found in the JSON response." + return $null + } + + # Extract the private key, including the markers + $privateKey = $message.Substring($startPosition, $endPosition - $startPosition + $endMarker.Length) + + # Return the private key + return $privateKey + } catch { + Write-Error "An error occurred while extracting the private key: $_" + return $null + } +} \ No newline at end of file diff --git a/testing/configure/copy_files/run_script_in_container.ps1 b/testing/configure/azure_scripts/run_script_in_container.ps1 similarity index 100% rename from testing/configure/copy_files/run_script_in_container.ps1 rename to testing/configure/azure_scripts/run_script_in_container.ps1 diff --git a/testing/configure/copy_files/zip_my_parents_parent.ps1 b/testing/configure/azure_scripts/zip_my_parents_parent.ps1 similarity index 100% rename from testing/configure/copy_files/zip_my_parents_parent.ps1 rename to testing/configure/azure_scripts/zip_my_parents_parent.ps1 diff --git a/testing/configure/copy_files/create_lme_directory.ps1 b/testing/configure/create_lme_directory.ps1 similarity index 100% rename from testing/configure/copy_files/create_lme_directory.ps1 rename to testing/configure/create_lme_directory.ps1 diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 828142d1..74b77f02 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -12,7 +12,7 @@ $ErrorActionPreference = 'Stop' Set-Location -Path $configurePath # Run the scripts and check for failure -.\copy_files\create_lme_directory.ps1 +.\create_lme_directory.ps1 .\download_files.ps1 -directory lme .\wec_import_gpo.ps1 -directory lme Start-Sleep 10 diff --git a/testing/configure/trust_ls1_ssh_key.ps1 b/testing/configure/trust_ls1_ssh_key.ps1 index 62baef4c..3bfaa327 100644 --- a/testing/configure/trust_ls1_ssh_key.ps1 +++ b/testing/configure/trust_ls1_ssh_key.ps1 @@ -1,3 +1,10 @@ +param ( + [string]$sshHost = "ls1" +) + +$sshDirectory = "C:\Windows\System32\config\systemprofile\.ssh" +$knownHostsFile = Join-Path -Path $sshDirectory -ChildPath "known_hosts" + # Ensure the .ssh directory exists if (-not (Test-Path -Path $sshDirectory)) { New-Item -ItemType Directory -Path $sshDirectory From 03444bfb3eaf3e77594877948dda3504ecb88496 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 4 Jan 2024 09:32:32 -0500 Subject: [PATCH 029/103] Fixes the formatting method for az output --- .../azure_scripts/lib/utilityFunctions.ps1 | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index f0fcb887..560d8237 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -4,38 +4,43 @@ function Format-AzVmRunCommandOutput { [string]$JsonResponse ) - # Convert JSON string to PowerShell object - $responseObj = $JsonResponse | ConvertFrom-Json - - # Initialize an array to hold the results + # Initialize an empty array to hold the results $results = @() - # Check if there is any response - if ($responseObj -and $responseObj.value) { - foreach ($item in $responseObj.value) { - # Process the stdout and stderr content - if ($item.message) { - # Extracting and cleaning up the messages - $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 - $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 - $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 - - # Create a custom object with stdout and stderr - $output = New-Object PSObject -Property @{ - StdOut = $stdout - StdErr = $stderr + try { + $responseObj = $JsonResponse | ConvertFrom-Json + + if ($responseObj -and $responseObj.value) { + foreach ($item in $responseObj.value) { + if ($item.message) { + $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 + $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 + $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 + + $results += New-Object PSObject -Property @{ + StdOut = $stdout + StdErr = $stderr + } } - - # Add the custom object to the results array - $results += $output } } - } else { - # Return a message if no valid response is found - $results += "No response or invalid response received." + } + catch { + # Return a custom object indicating an error + $results += New-Object PSObject -Property @{ + StdOut = "Error: Invalid JSON response" + StdErr = "" + } + } + + # Ensure that something is always returned + if (-not $results) { + $results += New-Object PSObject -Property @{ + StdOut = "No data or invalid data received." + StdErr = "" + } } - # Return the results array return $results } From 486a2a137d546702f6d4c69ae6449fa0873b6161 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 5 Jan 2024 06:54:37 -0500 Subject: [PATCH 030/103] Clean up the scripts and add documentation --- testing/InstallTestbed.ps1 | 84 ++++++++----------- .../azure_scripts/create_blob_container.ps1 | 2 +- .../azure_scripts/download_in_container.ps1 | 42 ++++++++++ .../azure_scripts/lib/utilityFunctions.ps1 | 33 ++++++-- testing/configure/create_ou.ps1 | 2 +- testing/configure/download_files.ps1 | 1 + testing/configure/install_chapter_2.ps1 | 2 +- testing/configure/linux_install_lme.sh | 9 +- testing/configure/move_computers_to_ou.ps1 | 24 +++++- testing/configure/sysmon_link_gpo.ps1 | 2 +- testing/configure/wec_link_gpo.ps1 | 8 +- 11 files changed, 141 insertions(+), 68 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index f86575fb..91ff0b9c 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -1,22 +1,25 @@ param ( - [Parameter(Mandatory=$true)] - [string]$ResourceGroupName -) + [Parameter(Mandatory = $true)] + [string]$ResourceGroupName, -$VMUsername = "admin.ackbar" -#$ResourceGroupName = "LME-cbaxley-t2" -$VMName = "DC1" -$LinuxVMName = "LS1" + [string]$VMUsername = "admin.ackbar", + [string]$VMName = "DC1", + [string]$LinuxVMName = "LS1", + [int]$numberOfClients = 2 +) -$Password = Get-Content "password.txt" +# If you were to need the password from the SetupTestbed.ps1 script, you could use this: +# $Password = Get-Content "password.txt" +# Define our library path $libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" # Check if the library file exists if (Test-Path -Path $libraryPath) { # Dot-source the library script . $libraryPath -} else { +} +else { Write-Error "Library script not found at path: $libraryPath" } @@ -58,18 +61,21 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Download the zip file to the VM Write-Host "Downloading the zip file to the VM..." -.\download_in_container.ps1 ` +$downloadZipFileResponse = .\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") + # Extract the zip file Write-Host "Extracting the zip file..." -.\extract_archive.ps1 ` +$extractArchiveResponse = .\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroupName $ResourceGroupName ` -FileName "configure.zip" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") # Run the install script for chapter 1 Write-Host "Running the install script for chapter 1..." @@ -82,19 +88,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Todo: Loop these for number of vms # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C1" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") - -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C2" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") +Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients # Wait for the services to start Write-Host "Waiting for the services to start..." @@ -118,25 +112,12 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C1" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") - -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C2" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") +Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients # Wait for the services to start Write-Host "Waiting for the services to start..." Start-Sleep 20 - # See if you can see sysmon running on the machine Write-Host "Seeing if you can see sysmon running on a machine..." $showSysmonResponse = az vm run-command invoke ` @@ -146,15 +127,15 @@ $showSysmonResponse = az vm run-command invoke ` --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") - # Download the installers on LS1 Write-Host "Downloading the installers on LS1..." -.\download_in_container.ps1 ` +$downloadLinuxZipFileResponse = .\download_in_container.ps1 ` -VMName $LinuxVMName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" ` -os "linux" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadLinuxZipFileResponse") # Install unzip on LS1 Write-Host "Installing unzip on LS1..." @@ -167,11 +148,12 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Unzip the file on LS1 Write-Host "Unzipping the file on LS1..." -.\extract_archive.ps1 ` +$extractLinuxArchiveResponse = .\extract_archive.ps1 ` -VMName $LinuxVMName ` -ResourceGroupName $ResourceGroupName ` -FileName "configure.zip" ` -os "linux" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractLinuxArchiveResponse") # Make the installer files executable and update the system packages on LS1 Write-Host "Making the installer files executable and updating the system packages on LS1..." @@ -210,22 +192,23 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Capture the output of the install script Write-Host "Capturing the output of the install script for ES passwords..." -$jsonResponse = az vm run-command invoke ` +$getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts 'tail -n10 "/opt/lme/Chapter 3 Files/output.log" | head -n4' # Todo: Extract the output and write this to a file for later use -Format-AzVmRunCommandOutput -JsonResponse "$jsonResponse" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") # Generate key using expect on linux Write-Host "Generating key using expect on linux..." -az vm run-command invoke ` +$generateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") # Add the public key to the authorized_keys file on LS1 Write-Host "Adding the public key to the authorized_keys file on LS1..." @@ -261,11 +244,12 @@ $KeyDownloadUrl = ./copy_file_to_container.ps1 ` # Download the private key to DC1 Write-Host "Downloading the private key to DC1..." -.\download_in_container.ps1 ` +$downloadPrivateKeyResponse = .\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$KeyDownloadUrl" ` -DestinationFilePath "id_rsa" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") # Change the ownership of the private key file on DC1 Write-Host "Changing the ownership of the private key file on DC1..." @@ -276,12 +260,11 @@ $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") # Trust the key from ls1 so we can scp interactively -# Todo: We may not need this +# Todo: It seems we don't need this but leaving it here for now #.\run_script_in_container.ps1 ` # -ResourceGroupName $ResourceGroupName ` # -VMName $VMName ` # -ScriptPathOnVM "C:\lme\configure\trust_ls1_ssh_key.ps1" -# # Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." @@ -294,10 +277,11 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Extract the files on DC1 Write-Host "Extracting the files on DC1..." -.\extract_archive.ps1 ` +$extractFilesForWindowsResponse = .\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroupName $ResourceGroupName ` -FileName "files_for_windows.zip" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") # Install winlogbeat on DC1 Write-Host "Installing winlogbeat on DC1..." @@ -308,4 +292,6 @@ $installWinlogbeatResponse = .\run_script_in_container.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") -Write-Host "Insttall completed." +Write-Host "Install completed." + +(Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut \ No newline at end of file diff --git a/testing/configure/azure_scripts/create_blob_container.ps1 b/testing/configure/azure_scripts/create_blob_container.ps1 index 689e0f14..1c6ac4a9 100644 --- a/testing/configure/azure_scripts/create_blob_container.ps1 +++ b/testing/configure/azure_scripts/create_blob_container.ps1 @@ -12,7 +12,7 @@ creates a blob container, and saves the configuration to a 'config.ps1' file in The name of the Azure Resource Group for the storage account and blob container. .EXAMPLE -.\CreateAzureStorage.ps1 -ResourceGroupName "YourResourceGroupName" +.\create_blob_container.ps1 -ResourceGroupName "YourResourceGroupName" Replace "YourResourceGroupName" with the name of your Azure Resource Group. diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index 80b9743f..8b80df43 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -1,3 +1,45 @@ +<# +.SYNOPSIS +This script automates the file download process on a specified VM based on its OS type. + +.DESCRIPTION +The script takes parameters for VM name, resource group, file URL, destination file path, username, and OS type. It processes these parameters to download a file to a VM, either running Windows or Linux. The script determines the appropriate command to create a directory (if necessary) and download the file to the specified VM, handling differences in command syntax and file path conventions based on the OS. + +.PARAMETER VMName +The name of the Virtual Machine where the file will be downloaded. + +.PARAMETER ResourceGroupName +The name of the Azure resource group where the VM is located. + +.PARAMETER FileDownloadUrl +The URL of the file to be downloaded. + +.PARAMETER DestinationFilePath +The complete path where the file should be downloaded on the VM. This path is processed to extract just the filename. + +.PARAMETER username +The username for the VM, used in constructing the file path for Linux systems. Default is 'admin.ackbar'. + +.PARAMETER os +The operating system type of the VM. Accepts 'Windows', 'Linux', or 'linux'. Default is 'Windows'. + +.EXAMPLE +.\download_in_container.ps1 ` + -VMName "MyVM" ` + -ResourceGroupName "MyResourceGroup" ` + -FileDownloadUrl "http://example.com/file.zip" ` + -DestinationFilePath "C:\path\to\file.zip" + +This example downloads a file from 'http://example.com/file.zip' to 'C:\path\to\file.zip' + on the VM named 'MyVM' in the 'MyResourceGroup'. + +.NOTES +- Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. +- The specified script must exist on the VM and the VM should have the necessary permissions to execute it. + + #> +#> + param( [Parameter(Mandatory=$true)] [string]$VMName, diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 560d8237..073e6d1b 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -1,6 +1,6 @@ function Format-AzVmRunCommandOutput { param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$JsonResponse ) @@ -46,7 +46,7 @@ function Format-AzVmRunCommandOutput { function Show-FormattedOutput { param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [Object[]]$FormattedOutput ) @@ -67,7 +67,7 @@ function Show-FormattedOutput { function ExtractPrivateKeyFromJson { param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$jsonResponse ) @@ -96,8 +96,31 @@ function ExtractPrivateKeyFromJson { # Return the private key return $privateKey - } catch { + } + catch { Write-Error "An error occurred while extracting the private key: $_" return $null } -} \ No newline at end of file +} + +function Invoke-GPUpdateOnVMs { + param( + [Parameter(Mandatory = $true)] + [string]$ResourceGroupName, + [int]$numberOfClients = 2 + ) + + for ($i = 1; $i -le $numberOfClients; $i++) { + $vmName = "C$i" # Dynamically create VM name + + # Invoke the command on the VM + $gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name $vmName ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" + + # Call the existing Show-FormattedOutput function + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + } +} diff --git a/testing/configure/create_ou.ps1 b/testing/configure/create_ou.ps1 index 5cf02284..2407cd46 100644 --- a/testing/configure/create_ou.ps1 +++ b/testing/configure/create_ou.ps1 @@ -1,6 +1,6 @@ param( [string]$Domain = "lme.local", - [string]$ClientOUCustomName = "LMETestClients" + [string]$ClientOUCustomName = "LMEClients" ) Import-Module ActiveDirectory diff --git a/testing/configure/download_files.ps1 b/testing/configure/download_files.ps1 index 1d5cedfb..84cd8626 100644 --- a/testing/configure/download_files.ps1 +++ b/testing/configure/download_files.ps1 @@ -9,6 +9,7 @@ $baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { "$env:USERPROFILE\Downloads\" } +# Todo: Allow for downloading a version by adding a parameter for the version number $apiUrl = "https://api.github.com/repos/cisagov/LME/releases/latest" $latestRelease = Invoke-RestMethod -Uri $apiUrl $zipFileUrl = $latestRelease.assets | Where-Object { $_.content_type -eq 'application/zip' } | Select-Object -ExpandProperty browser_download_url diff --git a/testing/configure/install_chapter_2.ps1 b/testing/configure/install_chapter_2.ps1 index 17e90ff1..9d5fa89a 100644 --- a/testing/configure/install_chapter_2.ps1 +++ b/testing/configure/install_chapter_2.ps1 @@ -11,7 +11,7 @@ $ErrorActionPreference = 'Stop' # Change directory to the configure directory Set-Location -Path $configurePath -# Run the scripts and check for failure +# Run the sysmon install scripts .\sysmon_install_in_sysvol.ps1 .\sysmon_import_gpo.ps1 -directory lme .\sysmon_gpo_update_vars.ps1 diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 8fb21544..575657e5 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -16,8 +16,13 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ + # Execute script with root privileges sudo ./linux_install_lme.exp -sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ -sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip +if [ -f "/opt/lme/files_for_windows.zip" ]; then + sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ + sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip +else + echo "Warn: files_for_windows.zip does not exist. Probably because the LME install requires a reboot." +fi diff --git a/testing/configure/move_computers_to_ou.ps1 b/testing/configure/move_computers_to_ou.ps1 index 6040ba50..d65322ac 100644 --- a/testing/configure/move_computers_to_ou.ps1 +++ b/testing/configure/move_computers_to_ou.ps1 @@ -1,11 +1,27 @@ -# Import the Active Directory module +param( + [string]$Domain = "lme.local", + [string]$ClientOUCustomName = "LMEClients", + [string]$CurrentCN = "Computers" +) + +# Import the Active Directory module Import-Module ActiveDirectory -# Define the DN of the Computers container -$computersContainerDN = "CN=Computers,DC=lme,DC=local" +# Split the domain into its parts +$domainParts = $Domain -split '\.' + +# Construct the domain DN, starting with 'DC=' +$domainDN = 'DC=' + ($domainParts -join ',DC=') + +# Define the DN of the existing Computers container +$computersContainerDN = "CN=$CurrentCN,$domainDN" # Define the DN of the target OU -$targetOUDN = "OU=LMETestClients,DC=lme,DC=local" +$targetOUDN = "OU=$ClientOUCustomName,$domainDN" + +# Output the DNs for verification +Write-Host "Current Computers Container DN: $computersContainerDN" +Write-Host "Target OU DN: $targetOUDN" # Get the computer accounts in the Computers container $computers = Get-ADComputer -Filter * -SearchBase $computersContainerDN diff --git a/testing/configure/sysmon_link_gpo.ps1 b/testing/configure/sysmon_link_gpo.ps1 index 1315f2cc..1cbb0450 100644 --- a/testing/configure/sysmon_link_gpo.ps1 +++ b/testing/configure/sysmon_link_gpo.ps1 @@ -1,6 +1,6 @@ param( [string]$Domain = "lme.local", - [string]$ClientOUCustomName = "LMETestClients" + [string]$ClientOUCustomName = "LMEClients" ) Import-Module ActiveDirectory diff --git a/testing/configure/wec_link_gpo.ps1 b/testing/configure/wec_link_gpo.ps1 index a6acba78..f78e4584 100644 --- a/testing/configure/wec_link_gpo.ps1 +++ b/testing/configure/wec_link_gpo.ps1 @@ -1,16 +1,16 @@ param( [string]$Domain = "lme.local", - [string]$ClientOUCustomName = "LMETestClients" + [string]$ClientOUCustomName = "LMEClients" ) Import-Module ActiveDirectory -$domainDN = $Domain -replace '\.', ',DC=' -replace '^', 'DC=' -$ClientOUDistinguishedName = "OU=$ClientOUCustomName,$domainDN" +$DomainDN = $Domain -replace '\.', ',DC=' -replace '^', 'DC=' +$ClientOUDistinguishedName = "OU=$ClientOUCustomName,$DomainDN" $GPONameClient = "LME-WEC-Client" $GPONameServer = "LME-WEC-Server" -$ServerOUDistinguishedName = "OU=Domain Controllers,$domainDN" +$ServerOUDistinguishedName = "OU=Domain Controllers,$DomainDN" try { New-GPLink -Name $GPONameClient -Target $ClientOUDistinguishedName From 54c3a0b98c7aafd9aae4e6f80261389a50fc7160 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 5 Jan 2024 09:06:36 -0500 Subject: [PATCH 031/103] Fixes outputting format errors --- testing/InstallTestbed.ps1 | 2 +- .../azure_scripts/lib/utilityFunctions.ps1 | 28 ++++++++------ .../configure/wec_gpo_update_server_name.ps1 | 37 ++++++++++++++++++- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 91ff0b9c..5da87f32 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -196,7 +196,7 @@ $getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` - --scripts 'tail -n10 "/opt/lme/Chapter 3 Files/output.log" | head -n4' + --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' # Todo: Extract the output and write this to a file for later use Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 073e6d1b..111b54ea 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -4,36 +4,40 @@ function Format-AzVmRunCommandOutput { [string]$JsonResponse ) - # Initialize an empty array to hold the results $results = @() try { $responseObj = $JsonResponse | ConvertFrom-Json if ($responseObj -and $responseObj.value) { + $stdout = "" + $stderr = "" + foreach ($item in $responseObj.value) { - if ($item.message) { - $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 - $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 - $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 - - $results += New-Object PSObject -Property @{ - StdOut = $stdout - StdErr = $stderr - } + if ($item.code -like "ComponentStatus/StdOut/*") { + $stdout += $item.message + } + elseif ($item.code -like "ComponentStatus/StdErr/*") { + $stderr += $item.message + } + } + + # Add a result only if there is actual content + if ($stdout -or $stderr) { + $results += New-Object PSObject -Property @{ + StdOut = $stdout.Trim() + StdErr = $stderr.Trim() } } } } catch { - # Return a custom object indicating an error $results += New-Object PSObject -Property @{ StdOut = "Error: Invalid JSON response" StdErr = "" } } - # Ensure that something is always returned if (-not $results) { $results += New-Object PSObject -Property @{ StdOut = "No data or invalid data received." diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index c158a17c..f6936380 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,5 +1,38 @@ -# To set the GP registry value -Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" -Type String +<# +.SYNOPSIS +This script sets and retrieves a Group Policy (GP) registry value for Windows Event Log Event Forwarding. + +.DESCRIPTION +The script is used to configure the Subscription Manager URL for Windows Event Log Event Forwarding in a Group Policy setting. It sets the registry value for the Subscription Manager URL using the specified domain, port, and protocol, and then retrieves the value to confirm the setting. This is useful in environments where centralized event log management is required. + +.PARAMETER domain +The domain for the Subscription Manager URL. Default is 'dc1.lme.local'. + +.PARAMETER port +The port number for the Subscription Manager URL. Default is 5985. + +.PARAMETER protocol +The protocol for the Subscription Manager URL. Default is 'http'. + +.EXAMPLE +.\wec_gpo_update_server_name.ps1 +Executes the script with default parameters. + +.EXAMPLE +.\wec_gpo_update_server_name.ps1 -domain "customdomain.local" -port 1234 -protocol "https" +Executes the script with custom domain, port, and protocol. + +#> + +param( + [string]$domain = "dc1.lme.local", + [int]$port = 5985, + [string]$protocol = "http" +) + +# Construct the Subscription Manager URL using the provided parameters +$subscriptionManagerUrl = "Server=$protocol://$domain:$port/wsman/SubscriptionManager/WEC,Refresh=60" +Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value $subscriptionManagerUrl -Type String # To get the GP registry value to confirm it's set $registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" From b4e2d87bd2892a265d2d7ceb085ee01014376d93 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 5 Jan 2024 09:49:53 -0500 Subject: [PATCH 032/103] Fixes hanging on adding ls1 to domain --- testing/SetupTestbed.ps1 | 87 ++++++++++++++++++++++++++++++++++++---- 1 file changed, 80 insertions(+), 7 deletions(-) diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 4c5a347b..c07d75b5 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -57,6 +57,19 @@ param ( [switch]$NoPrompt ) +# Define our library path +$libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" + +# Check if the library file exists +if (Test-Path -Path $libraryPath) { + # Dot-source the library script + . $libraryPath +} +else { + Write-Error "Library script not found at path: $libraryPath" +} + + #DEFAULTS: #Desired Netowrk Mapping: $VNetPrefix = "10.1.0.0/16" @@ -366,13 +379,73 @@ it is likely that the DNS entry was still successfully added. To verify, log on to DC1 and run 'Resolve-DnsName ls1' in PowerShell. If it returns NXDOMAIN, you'll need to add it manually." Write-Output "The time is $(Get-Date)." -az vm run-command create ` +#az vm run-command create ` +# --resource-group $ResourceGroup ` +# --location $Location ` +# --run-as-user $DomainName\$VMAdmin ` +# --run-as-password $VMPassword ` +# --run-command-name "addDNSRecord" ` +# --vm-name DC1 ` +# --script "Add-DnsServerResourceRecordA -Name `"LS1`" -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00" + + +# Define the PowerShell script with the DomainName variable interpolated +$scriptContent = @" +`$scriptBlock = { + Add-DnsServerResourceRecordA -Name LS1 -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00 +} +`$job = Start-Job -ScriptBlock `$scriptBlock +`$timeout = 30 +if (Wait-Job -Job `$job -Timeout `$timeout) { + Receive-Job -Job `$job + Write-Host 'The script completed within the timeout period.' +} else { + Stop-Job -Job `$job + Remove-Job -Job `$job + Write-Host 'The script timed out after `$timeout seconds.' +} +"@ + +# Convert the script to a Base64-encoded string +$bytes = [System.Text.Encoding]::Unicode.GetBytes($scriptContent) +$encodedScript = [Convert]::ToBase64String($bytes) + + +# Run the encoded script on the Azure VM +Write-Output "`nAdding script to add DNS entry for Linux server. No output expected..." +$createDnsScriptResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name DC1 ` + --resource-group $ResourceGroup ` + --scripts "Set-Content -Path 'C:\AddDnsRecord.ps1' -Value ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('$encodedScript')))" + +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDnsScriptResponse") + + +Write-Output "`nRunning script to add DNS entry for Linux server. It could time out or not. Check output of the next command..." +$addDnsRecordResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name DC1 ` + --resource-group $ResourceGroup ` + --scripts "C:\AddDnsRecord.ps1" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDnsRecordResponse") + +Write-Host "Checking if ls1 resolves..." +$resolveLs1Response = az vm run-command invoke ` + --command-id RunPowerShellScript ` --resource-group $ResourceGroup ` - --location $Location ` - --run-as-user $DomainName\$VMAdmin ` - --run-as-password $VMPassword ` - --run-command-name "addDNSRecord" ` - --vm-name DC1 ` - --script "Add-DnsServerResourceRecordA -Name `"LS1`" -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00" + --name DC1 ` + --scripts "Resolve-DnsName ls1" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$resolveLs1Response") + +Write-Host "Removing the Dns script. No output expected..." +$removeDnsRecordScriptResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name DC1 ` + --resource-group $ResourceGroup ` + --scripts "Remove-Item -Path 'C:\AddDnsRecord.ps1' -Force" + +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$removeDnsRecordScriptResponse") + Write-Output "Done." From ac65188c479c96ddf2250dea861f1b854e241b4b Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Mon, 8 Jan 2024 17:18:16 -0500 Subject: [PATCH 033/103] Fix formatting errors on responses --- testing/InstallTestbed.ps1 | 7 ++--- testing/SetupTestbed.ps1 | 14 ++-------- .../azure_scripts/download_in_container.ps1 | 3 +- .../azure_scripts/lib/utilityFunctions.ps1 | 28 +++++++++++++------ .../configure/wec_gpo_update_server_name.ps1 | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 5da87f32..cd565f5b 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -57,6 +57,7 @@ $createDirResponse = az vm run-command invoke ` --resource-group $ResourceGroupName ` --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") # Download the zip file to the VM @@ -66,7 +67,6 @@ $downloadZipFileResponse = .\download_in_container.ps1 ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") # Extract the zip file @@ -95,7 +95,7 @@ Write-Host "Waiting for the services to start..." Start-Sleep 20 # See if we can see the forwarding computers in the DC -write-host "Seeing if we can see the forwarding computers in the DC..." +write-host "Checking if we can see the forwarding computers in the DC..." $listForwardingComputersResponse = .\run_script_in_container.ps1 ` -ResourceGroupName $ResourceGroupName ` -VMName $VMName ` @@ -183,7 +183,7 @@ az vm restart ` # Run the lme installer on LS1 Write-Host "Running the lme installer on LS1..." -az vm run-command invoke ` +$installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` @@ -226,7 +226,6 @@ $jsonResponse = az vm run-command invoke ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' - $privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" # Save the private key to a file diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index c07d75b5..4c3004b9 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -242,8 +242,8 @@ Set-NetworkRules -AllowedSourcesList $AllowedSourcesList # Create the VMs # ################## $VMPassword = Get-RandomPassword 12 -Write-Output "`nWriting $VMAdmin password to password.txt" -echo $VMPassword > password.txt +Write-Output "`nWriting $VMAdmin password to ${ResourceGroup}.password.txt" +echo $VMPassword > "${ResourceGroup}.password.txt" Write-Output "`nCreating DC1..." az vm create ` @@ -379,15 +379,6 @@ it is likely that the DNS entry was still successfully added. To verify, log on to DC1 and run 'Resolve-DnsName ls1' in PowerShell. If it returns NXDOMAIN, you'll need to add it manually." Write-Output "The time is $(Get-Date)." -#az vm run-command create ` -# --resource-group $ResourceGroup ` -# --location $Location ` -# --run-as-user $DomainName\$VMAdmin ` -# --run-as-password $VMPassword ` -# --run-command-name "addDNSRecord" ` -# --vm-name DC1 ` -# --script "Add-DnsServerResourceRecordA -Name `"LS1`" -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00" - # Define the PowerShell script with the DomainName variable interpolated $scriptContent = @" @@ -444,7 +435,6 @@ $removeDnsRecordScriptResponse = az vm run-command invoke ` --name DC1 ` --resource-group $ResourceGroup ` --scripts "Remove-Item -Path 'C:\AddDnsRecord.ps1' -Force" - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$removeDnsRecordScriptResponse") diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index 8b80df43..6d9cb75e 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -73,7 +73,8 @@ if ($os -eq "linux") { $DestinationPath = "/home/$username/lme/$DestinationFileName" # Create the lme directory if it doesn't exist $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" - az vm run-command invoke ` + # We don't want to output this until we fix it so we can put all of the output from thw whole script into one json object + $CreateDirectoryResponse = az vm run-command invoke ` --command-id RunShellScript ` --resource-group $ResourceGroupName ` --name $VMName ` diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 111b54ea..ce12e20a 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -8,32 +8,41 @@ function Format-AzVmRunCommandOutput { try { $responseObj = $JsonResponse | ConvertFrom-Json +# Write-Host "Converted JSON object: $responseObj" if ($responseObj -and $responseObj.value) { $stdout = "" $stderr = "" foreach ($item in $responseObj.value) { +# Write-Host "Processing item: $($item.code)" + + # Check for StdOut and StdErr if ($item.code -like "ComponentStatus/StdOut/*") { - $stdout += $item.message + $stdout += $item.message + "`n" + } elseif ($item.code -like "ComponentStatus/StdErr/*") { + $stderr += $item.message + "`n" } - elseif ($item.code -like "ComponentStatus/StdErr/*") { - $stderr += $item.message + + # Additional case to handle other types of 'code' + # This ensures that all messages are captured + else { + $stdout += $item.message + "`n" } } - # Add a result only if there is actual content if ($stdout -or $stderr) { $results += New-Object PSObject -Property @{ - StdOut = $stdout.Trim() - StdErr = $stderr.Trim() + StdOut = $stdout + StdErr = $stderr } } } - } - catch { + } catch { + $errorMessage = $_.Exception.Message + Write-Host "Error: $errorMessage" $results += New-Object PSObject -Property @{ - StdOut = "Error: Invalid JSON response" + StdOut = "Error: $errorMessage" StdErr = "" } } @@ -48,6 +57,7 @@ function Format-AzVmRunCommandOutput { return $results } + function Show-FormattedOutput { param ( [Parameter(Mandatory = $true)] diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index f6936380..49006b1f 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -31,7 +31,7 @@ param( ) # Construct the Subscription Manager URL using the provided parameters -$subscriptionManagerUrl = "Server=$protocol://$domain:$port/wsman/SubscriptionManager/WEC,Refresh=60" +$subscriptionManagerUrl = "Server=${protocol}://${domain}:${port}/wsman/SubscriptionManager/WEC,Refresh=60" Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value $subscriptionManagerUrl -Type String # To get the GP registry value to confirm it's set From 61a1085f803b67e96c5b0d4d6b29893eb1f04dd3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 9 Jan 2024 09:46:49 -0500 Subject: [PATCH 034/103] Update linux expect script for different prompts. --- testing/TestbedOnlyLinux.ps1 | 246 ++++++++++++++++++++++++ testing/configure/linux_install_lme.exp | 16 +- 2 files changed, 259 insertions(+), 3 deletions(-) create mode 100644 testing/TestbedOnlyLinux.ps1 diff --git a/testing/TestbedOnlyLinux.ps1 b/testing/TestbedOnlyLinux.ps1 new file mode 100644 index 00000000..bdbbe06b --- /dev/null +++ b/testing/TestbedOnlyLinux.ps1 @@ -0,0 +1,246 @@ +<# + Creates a "blank slate" for testing/configuring LME. + + Creates the following: + - A resource group + - A virtual network, subnet, and network security group + - "LS1," a Linux server + + This script should do all the work for you, simply specify a new resource group, + and optionally Auto-shutdown configuration each time you run it. + Be sure to copy the username/password it outputs at the end. + After completion, login to the VMs using ssh to configure/test LME. + + Example: ./TestbedOnlyLinux.ps1 -Location centralus -ResourceGroup YourResourceGroup -AutoShutdownTime 0000 -AllowedSources "x.x.x.x/32" -y +#> + +param ( + [Parameter( + HelpMessage = "Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900). Convert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" + )] + $AutoShutdownTime = $null, + + [Parameter( + HelpMessage = "Auto-shutdown notification email" + )] + $AutoShutdownEmail = $null, + + [Alias("l")] + [Parameter( + HelpMessage = "Location where the cluster will be built. Default westus" + )] + [string]$Location = "westus", + + [Alias("g")] + [Parameter(Mandatory = $true)] + [string]$ResourceGroup, + + [Alias("s")] + [Parameter(Mandatory = $true, + HelpMessage = "XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc... Comma-Separated list of CIDR prefixes or IP ranges to whitelist" + )] + [string]$AllowedSources, + + [Alias("y")] + [Parameter( + HelpMessage = "Run the script with no prompt (useful for automated runs)" + )] + [switch]$NoPrompt +) + +#DEFAULTS: +#Desired Netowrk Mapping: +$VNetPrefix = "10.1.0.0/16" +$SubnetPrefix = "10.1.0.0/24" +$LsIP = "10.1.0.5" + +#Domain information: +$VMAdmin = "admin.ackbar" + +#Port options: https://learn.microsoft.com/en-us/cli/azure/network/nsg/rule?view=azure-cli-latest#az-network-nsg-rule-create +$Ports = 22, 3389 +$Priorities = 1001, 1002 +$Protocols = "Tcp", "Tcp" + + +function Get-RandomPassword { + param ( + [Parameter(Mandatory)] + [int]$Length + ) + $TokenSet = @{ + L = [Char[]]'abcdefghijkmnopqrstuvwxyz' + U = [Char[]]'ABCDEFGHIJKMNPQRSTUVWXYZ' + N = [Char[]]'23456789' + } + + $Lower = Get-Random -Count 5 -InputObject $TokenSet.L + $Upper = Get-Random -Count 5 -InputObject $TokenSet.U + $Number = Get-Random -Count 5 -InputObject $TokenSet.N + + $StringSet = $Lower + $Number + $Upper + + (Get-Random -Count $Length -InputObject $StringSet) -join '' +} + +function Set-AutoShutdown { + param ( + [Parameter(Mandatory)] + [string]$VMName + ) + + Write-Output "`nCreating Auto-Shutdown Rule for $VMName at time $AutoShutdownTime..." + if ($null -ne $AutoShutdownEmail) { + az vm auto-shutdown ` + -g $ResourceGroup ` + -n $VMName ` + --time $AutoShutdownTime ` + --email $AutoShutdownEmail + } + else { + az vm auto-shutdown ` + -g $ResourceGroup ` + -n $VMName ` + --time $AutoShutdownTime + } +} + +function Set-NetworkRules { + param ( + [Parameter(Mandatory)] + $AllowedSourcesList + ) + + if ($Ports.length -ne $Priorities.length) { + Write-Output "Priorities and Ports length should be equal!" + exit -1 + } + if ($Ports.length -ne $Protocols.length) { + Write-Output "Protocols and Ports length should be equal!" + exit -1 + } + + for ($i = 0; $i -le $Ports.length - 1; $i++) { + $port = $Ports[$i] + $priority = $Priorities[$i] + $protocol = $Protocols[$i] + Write-Output "`nCreating Network Port $port rule..." + + az network nsg rule create --name Network_Port_Rule_$port ` + --resource-group $ResourceGroup ` + --nsg-name NSG1 ` + --priority $priority ` + --direction Inbound ` + --access Allow ` + --protocol $protocol ` + --source-address-prefixes $AllowedSourcesList ` + --destination-address-prefixes '*' ` + --destination-port-ranges $port ` + --description "Allow inbound from $sources on $port via $protocol connections." + } +} + + +######################## +# Validation of Globals # +######################## +$AllowedSourcesList = $AllowedSources -Split "," +if ($AllowedSourcesList.length -lt 1) { + Write-Output "**ERROR**: Variable AllowedSources must be set (set with -AllowedSources or -s)" + exit -1 +} + +if ($null -ne $AutoShutdownTime) { + if (-not( $AutoShutdownTime -match '^([01][0-9]|2[0-3])[0-5][0-9]$')) { + Write-Output "**ERROR** Invalid time" + Write-Output "Enter the Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900), `n`tConvert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" + exit -1 + } +} + +################ +# Confirmation # +################ +Write-Output "Supplied configuration:`n" + +Write-Output "Location: $Location" +Write-Output "Resource group: $ResourceGroup" +Write-Output "Allowed sources (IP's): $AllowedSourcesList" +Write-Output "Auto-shutdown time: $AutoShutdownTime" +Write-Output "Auto-shutdown e-mail: $AutoShutdownEmail" + +if (-Not$NoPrompt) { + do { + $Proceed = Read-Host "`nProceed? (Y/n)" + } until ($Proceed -eq "y" -or $Proceed -eq "Y" -or $Proceed -eq "n" -or $Proceed -eq "N") + + if ($Proceed -eq "n" -or $Proceed -eq "N") { + Write-Output "Setup canceled" + exit + } +} + +######################## +# Setup resource group # +######################## +Write-Output "`nCreating resource group..." +az group create --name $ResourceGroup --location $Location + +################# +# Setup network # +################# + +Write-Output "`nCreating virtual network..." +az network vnet create --resource-group $ResourceGroup ` + --name VNet1 ` + --address-prefix $VNetPrefix ` + --subnet-name SNet1 ` + --subnet-prefix $SubnetPrefix + +Write-Output "`nCreating nsg..." +az network nsg create --name NSG1 ` + --resource-group $ResourceGroup ` + --location $Location + +Set-NetworkRules -AllowedSourcesList $AllowedSourcesList + +################## +# Create the VMs # +################## +$VMPassword = Get-RandomPassword 12 +Write-Output "`nWriting $VMAdmin password to password.txt" +$VMPassword | Out-File -FilePath password.txt -Encoding UTF8 + + + +Write-Output "`nCreating LS1..." +az vm create ` + --name LS1 ` + --resource-group $ResourceGroup ` + --nsg NSG1 ` + --image Ubuntu2204 ` + --admin-username $VMAdmin ` + --admin-password $VMPassword ` + --vnet-name VNet1 ` + --subnet SNet1 ` + --public-ip-sku Standard ` + --size Standard_E2d_v4 ` + --os-disk-size-gb 128 ` + --private-ip-address $LsIP + + +########################### +# Configure Auto-Shutdown # +########################### + +if ($null -ne $AutoShutdownTime) { + Set-AutoShutdown "LS1" +} + +Write-Output "`nVM login info:" +Write-Output "Username: $( $VMAdmin )" +Write-Output "Password: $( $VMPassword )" +Write-Output "SAVE THE ABOVE INFO`n" + +Write-Output "The time is $( Get-Date )." +Write-Output "Done." diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 3a6051cd..57aba5aa 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -2,6 +2,8 @@ # Change to the LME directory containing files for the Linux server cd /opt/lme/Chapter\ 3\ Files/ +pwd + # Adjust the timeout if necessary set timeout 60 @@ -10,12 +12,20 @@ set expect_out(buffer_size) 100000 log_file -a output.log spawn ./deploy.sh install +sleep 1 +expect { + -re {OK.*} { + send "\r" + } + -re {Proceed.*} { + send "y\r" + } +} + -expect "Proceed? \\\[Y/n\\\] " -send "y\r" expect { - -re "Enter the IP of this Linux server.*10.1.0.5" { + -re "Enter the IP of this Linux server.*" { sleep 1 send "\r" } From 89552ab93506969a0d4152b815b86635a953600f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 10 Jan 2024 06:28:23 -0500 Subject: [PATCH 035/103] Handle the reboot message for linux expect script --- testing/configure/linux_install_lme.exp | 15 ++++++++------- testing/configure/linux_install_lme.sh | 10 ++++++---- 2 files changed, 14 insertions(+), 11 deletions(-) diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 57aba5aa..245b3b52 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -2,8 +2,6 @@ # Change to the LME directory containing files for the Linux server cd /opt/lme/Chapter\ 3\ Files/ -pwd - # Adjust the timeout if necessary set timeout 60 @@ -14,17 +12,20 @@ log_file -a output.log spawn ./deploy.sh install sleep 1 expect { - -re {OK.*} { + -re {.*OK.*} { send "\r" } - -re {Proceed.*} { + -re {.*Proceed.*} { send "y\r" } } - expect { + -re {.*Please reboot and re-run this script to finish the install.*} { + send_user "Reboot required. Exiting...\n" + exit + } -re "Enter the IP of this Linux server.*" { sleep 1 send "\r" @@ -37,10 +38,10 @@ sleep 1 send "ls1.lme.local\r" sleep 1 -# Use braces for regular expressions and ensure correct escaping + expect -re {continue with self signed certificates.*: y} sleep 1 -send "\r" +send "y\r" sleep 1 expect -re {Skip Docker Install\? \(\[y\]es/\[n\]o\): n} diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 575657e5..dbe42353 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -1,7 +1,10 @@ #!/bin/bash # Change to the directory where the script is located -cd "$(dirname "$0")" || exit 1 +script_dir=$(dirname "$0") +cd $script_dir || exit 1 +# We need to get the full path of the script dir for below +script_dir=$(pwd) # Default username username="admin.ackbar" @@ -16,13 +19,12 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ - # Execute script with root privileges -sudo ./linux_install_lme.exp +sudo "$script_dir/linux_install_lme.exp" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip else - echo "Warn: files_for_windows.zip does not exist. Probably because the LME install requires a reboot." + echo "files_for_windows.zip does not exist. Probably because the LME install requires a reboot." fi From e398c0a10296c7c6b78a1f8c294ea7ffa5fdf65f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 05:55:27 -0500 Subject: [PATCH 036/103] Echos the file download url --- testing/configure/copy_files/download_in_container.ps1 | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 testing/configure/copy_files/download_in_container.ps1 diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 new file mode 100644 index 00000000..e69de29b From 65a347e71086271efc607a4bc813a11b93589769 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 08:33:05 -0500 Subject: [PATCH 037/103] Create a new LME folder for our scripts and files --- .../copy_files/create_lme_directory.ps1 | 25 ++++++++ .../copy_files/download_in_container.ps1 | 64 +++++++++++++++++++ 2 files changed, 89 insertions(+) create mode 100644 testing/configure/copy_files/create_lme_directory.ps1 diff --git a/testing/configure/copy_files/create_lme_directory.ps1 b/testing/configure/copy_files/create_lme_directory.ps1 new file mode 100644 index 00000000..8bef9b66 --- /dev/null +++ b/testing/configure/copy_files/create_lme_directory.ps1 @@ -0,0 +1,25 @@ +# Define the directory path +$directoryPath = "C:\lme" + +# Create the directory if it doesn't already exist +if (-not (Test-Path -Path $directoryPath)) { + New-Item -Path $directoryPath -ItemType Directory +} + +# Define the security principal for 'All Users' +$allUsers = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") + +# Get the current ACL of the directory +$acl = Get-Acl -Path $directoryPath + +# Define the rights (read and execute) +$rights = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute + +# Create the rule (allowing read and execute access) +$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($allUsers, $rights, 'ContainerInherit, ObjectInherit', 'None', 'Allow') + +# Add the rule to the ACL +$acl.AddAccessRule($accessRule) + +# Set the ACL back to the directory +Set-Acl -Path $directoryPath -AclObject $acl diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index e69de29b..e8ec08df 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -0,0 +1,64 @@ +<# +.SYNOPSIS +Downloads a file to a specified Azure VM's user directory. + +.DESCRIPTION +This script downloads a file from a given URL to a specified Azure Virtual Machine (VM). +It places the file in the Downloads directory of a specified user's profile on the VM. +The script requires details of the VM, the resource group, the file URL, the local filename for saving, +and the VM's username. + +.PARAMETER VMName +The name of the Azure Virtual Machine. + +.PARAMETER ResourceGroupName +The name of the Azure Resource Group that contains the VM. + +.PARAMETER FileDownloadUrl +The URL of the file to be downloaded. + +.PARAMETER DestinationFilePath +The local file path where the file will be saved. Only the filename is used. + +.EXAMPLE +.\download_in_container.ps1 ` + -VMName "DC1" ` + -ResourceGroupName "YourResourceGroupName" ` + -FileDownloadUrl "http://example.com/file.ext" ` + -DestinationFilePath "filename.ext" + +This example downloads a file from "http://example.com/file.ext" to the "Downloads" directory of the user "username" on the VM "DC1" in the resource group "YourResourceGroupName". + +.NOTES +Ensure that the Azure CLI is installed and configured with the necessary permissions to access the specified Azure VM. +#> + +param( + [Parameter(Mandatory=$true)] + [string]$VMName, + + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName, + + [Parameter(Mandatory=$true)] + [string]$FileDownloadUrl, + + [Parameter(Mandatory=$true)] + [string]$DestinationFilePath # This will be stripped to only the filename +) + +# Extract just the filename from the destination file path +$DestinationFileName = Split-Path -Leaf $DestinationFilePath + +# Set the destination path in the VM's user Downloads directory +$DestinationPath = "C:\lme\$DestinationFileName" + +$DownloadScript = @" +Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath' +"@ + +az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DownloadScript From f74a823e96f444a6d34563a10e682f369e1f4dc4 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 08:52:06 -0500 Subject: [PATCH 038/103] Set path for extract to lme --- .../azure_scripts/extract_archive.ps1 | 55 +++++-------------- 1 file changed, 14 insertions(+), 41 deletions(-) diff --git a/testing/configure/azure_scripts/extract_archive.ps1 b/testing/configure/azure_scripts/extract_archive.ps1 index bfcbd591..c4684119 100644 --- a/testing/configure/azure_scripts/extract_archive.ps1 +++ b/testing/configure/azure_scripts/extract_archive.ps1 @@ -17,7 +17,7 @@ The name of the Azure Resource Group that contains the VM. The name (and optional path) of the zip file to be unzipped. .EXAMPLE -.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "filename.zip" +.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "C:\path\to\filename.zip" This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. @@ -34,52 +34,25 @@ param( [string]$ResourceGroupName, [Parameter(Mandatory=$true)] - [string]$Filename, - - [Parameter()] - [string]$username = "admin.ackbar", - - [Parameter()] - [ValidateSet("Windows","Linux","linux")] - [string]$os = "Windows" + [string]$Filename ) -# Convert the OS parameter to lowercase for consistent comparison -$os = $os.ToLower() - # Extract just the filename (ignoring any provided path) $JustFilename = Split-Path -Leaf $Filename -# Set paths depending on the OS -if ($os -eq "linux") { - $ZipFilePath = "/home/$username/lme/$JustFilename" - $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) - $ExtractToPath = "/home/$username/lme/$FileBaseName" # Extract to a subdirectory +# Construct the full path for the zip file +$ZipFilePath = "C:\lme\$JustFilename" - $UnzipScript = @" - unzip '$ZipFilePath' -d '$ExtractToPath' -"@ -} else { - $ZipFilePath = "C:\lme\$JustFilename" - $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) - $ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory +# Extract the filename without extension for the extraction directory +$FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) +$ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory named after the file - $UnzipScript = @" - Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' +$UnzipScript = @" +Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' "@ -} -# Execute the unzip script with the appropriate command based on OS -if ($os -eq "linux") { - az vm run-command invoke ` - --command-id RunShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $UnzipScript -} else { - az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $UnzipScript -} +az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $UnzipScript From e4609c5601ac88d78e23b06182cf2fb47e4de08a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 09:15:56 -0500 Subject: [PATCH 039/103] Update paths for scripts to /lme --- testing/configure/wec_import_gpo.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/configure/wec_import_gpo.ps1 b/testing/configure/wec_import_gpo.ps1 index 2830ecda..6dcbaa33 100644 --- a/testing/configure/wec_import_gpo.ps1 +++ b/testing/configure/wec_import_gpo.ps1 @@ -4,7 +4,7 @@ param( # Determine the base directory path based on the provided username $baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { - "C:\$directory" + "C:$directory" } else { "$env:USERPROFILE\Downloads" } From ca696d886c9620988de649589a8ff7015c20f12f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 26 Dec 2023 09:43:19 -0500 Subject: [PATCH 040/103] Update paths for scripts to /lme --- testing/configure/wec_import_gpo.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/configure/wec_import_gpo.ps1 b/testing/configure/wec_import_gpo.ps1 index 6dcbaa33..2830ecda 100644 --- a/testing/configure/wec_import_gpo.ps1 +++ b/testing/configure/wec_import_gpo.ps1 @@ -4,7 +4,7 @@ param( # Determine the base directory path based on the provided username $baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { - "C:$directory" + "C:\$directory" } else { "$env:USERPROFILE\Downloads" } From a49f9852c5a7e63fd106581cf08081c56eb7f546 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 27 Dec 2023 05:41:28 -0500 Subject: [PATCH 041/103] Fix the wec server name setting --- .../configure/wec_gpo_update_server_name.ps1 | 39 ++----------------- 1 file changed, 3 insertions(+), 36 deletions(-) diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index 49006b1f..4dc681c4 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,42 +1,9 @@ -<# -.SYNOPSIS -This script sets and retrieves a Group Policy (GP) registry value for Windows Event Log Event Forwarding. - -.DESCRIPTION -The script is used to configure the Subscription Manager URL for Windows Event Log Event Forwarding in a Group Policy setting. It sets the registry value for the Subscription Manager URL using the specified domain, port, and protocol, and then retrieves the value to confirm the setting. This is useful in environments where centralized event log management is required. - -.PARAMETER domain -The domain for the Subscription Manager URL. Default is 'dc1.lme.local'. - -.PARAMETER port -The port number for the Subscription Manager URL. Default is 5985. - -.PARAMETER protocol -The protocol for the Subscription Manager URL. Default is 'http'. - -.EXAMPLE -.\wec_gpo_update_server_name.ps1 -Executes the script with default parameters. - -.EXAMPLE -.\wec_gpo_update_server_name.ps1 -domain "customdomain.local" -port 1234 -protocol "https" -Executes the script with custom domain, port, and protocol. - -#> - -param( - [string]$domain = "dc1.lme.local", - [int]$port = 5985, - [string]$protocol = "http" -) - -# Construct the Subscription Manager URL using the provided parameters -$subscriptionManagerUrl = "Server=${protocol}://${domain}:${port}/wsman/SubscriptionManager/WEC,Refresh=60" -Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value $subscriptionManagerUrl -Type String +# To set the GP registry value +Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=https://dc1.lme.local:5986/wsman/SubscriptionManager/WEC,Refresh=60" -Type String # To get the GP registry value to confirm it's set $registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" # Output the retrieved registry value Write-Host "Set the subscription manager url value to: " -$registryValue +$registryValue \ No newline at end of file From b2feae73385a2e25fce5cb89c8ecbbeccdae0540 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 28 Dec 2023 06:57:10 -0500 Subject: [PATCH 042/103] Adds the scripts to install chapter 1 and 2 --- testing/configure/install_chapter_1.ps1 | 6 ++++-- testing/configure/install_chapter_2.ps1 | 2 +- testing/configure/wec_gpo_update_server_name.ps1 | 9 +++++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 74b77f02..3bf66666 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -12,10 +12,9 @@ $ErrorActionPreference = 'Stop' Set-Location -Path $configurePath # Run the scripts and check for failure -.\create_lme_directory.ps1 +.\copy_files\create_lme_directory.ps1 .\download_files.ps1 -directory lme .\wec_import_gpo.ps1 -directory lme -Start-Sleep 10 .\wec_gpo_update_server_name.ps1 .\create_ou.ps1 .\wec_link_gpo.ps1 @@ -23,8 +22,11 @@ Start-Sleep 10 # Run the wevtutil and wecutil commands wevtutil set-log ForwardedEvents /q:true /e:true +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } wecutil rs lme +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } wecutil gr lme +if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Run the move_computers_to_ou script .\move_computers_to_ou.ps1 diff --git a/testing/configure/install_chapter_2.ps1 b/testing/configure/install_chapter_2.ps1 index 9d5fa89a..17e90ff1 100644 --- a/testing/configure/install_chapter_2.ps1 +++ b/testing/configure/install_chapter_2.ps1 @@ -11,7 +11,7 @@ $ErrorActionPreference = 'Stop' # Change directory to the configure directory Set-Location -Path $configurePath -# Run the sysmon install scripts +# Run the scripts and check for failure .\sysmon_install_in_sysvol.ps1 .\sysmon_import_gpo.ps1 -directory lme .\sysmon_gpo_update_vars.ps1 diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index 4dc681c4..265b5d89 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,9 +1,14 @@ +# Query the registry to find the key path +#$HKEY_USERSKeys = reg query HKEY_USERS /s /f "SubscriptionManager" /k + +HKEY_USERS\S-1-5-21-1874110181-726158762-2826089689-500\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\LME.LOCAL{083A2CE3-3021-4F4D-9765-35EB888E62CF}Machine\Software\Policies\Microsoft\Windows\EventLog\Event +Forwarding\SubscriptionManager # To set the GP registry value -Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=https://dc1.lme.local:5986/wsman/SubscriptionManager/WEC,Refresh=60" -Type String +Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" -Type String # To get the GP registry value to confirm it's set $registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" # Output the retrieved registry value Write-Host "Set the subscription manager url value to: " -$registryValue \ No newline at end of file +$registryValue From 1222979593200854488872ac2f6d225804ae820e Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 28 Dec 2023 08:53:12 -0500 Subject: [PATCH 043/103] Allows azure to download in linux and windows --- .../copy_files/download_in_container.ps1 | 76 ++++++++----------- 1 file changed, 33 insertions(+), 43 deletions(-) diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index e8ec08df..4f51560f 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -1,38 +1,3 @@ -<# -.SYNOPSIS -Downloads a file to a specified Azure VM's user directory. - -.DESCRIPTION -This script downloads a file from a given URL to a specified Azure Virtual Machine (VM). -It places the file in the Downloads directory of a specified user's profile on the VM. -The script requires details of the VM, the resource group, the file URL, the local filename for saving, -and the VM's username. - -.PARAMETER VMName -The name of the Azure Virtual Machine. - -.PARAMETER ResourceGroupName -The name of the Azure Resource Group that contains the VM. - -.PARAMETER FileDownloadUrl -The URL of the file to be downloaded. - -.PARAMETER DestinationFilePath -The local file path where the file will be saved. Only the filename is used. - -.EXAMPLE -.\download_in_container.ps1 ` - -VMName "DC1" ` - -ResourceGroupName "YourResourceGroupName" ` - -FileDownloadUrl "http://example.com/file.ext" ` - -DestinationFilePath "filename.ext" - -This example downloads a file from "http://example.com/file.ext" to the "Downloads" directory of the user "username" on the VM "DC1" in the resource group "YourResourceGroupName". - -.NOTES -Ensure that the Azure CLI is installed and configured with the necessary permissions to access the specified Azure VM. -#> - param( [Parameter(Mandatory=$true)] [string]$VMName, @@ -44,19 +9,44 @@ param( [string]$FileDownloadUrl, [Parameter(Mandatory=$true)] - [string]$DestinationFilePath # This will be stripped to only the filename + [string]$DestinationFilePath, # This will be stripped to only the filename + + [Parameter()] + [string]$username = "admin.ackbar", + + [Parameter()] + [ValidateSet("Windows","Linux","linux")] + [string]$os = "Windows" ) +# Convert the OS parameter to lowercase for consistent comparison +$os = $os.ToLower() + # Extract just the filename from the destination file path $DestinationFileName = Split-Path -Leaf $DestinationFilePath -# Set the destination path in the VM's user Downloads directory -$DestinationPath = "C:\lme\$DestinationFileName" - -$DownloadScript = @" -Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath' -"@ - +# Set the destination path depending on the OS +if ($os -eq "linux") { + $DestinationPath = "/home/$username/lme/$DestinationFileName" + # Create the lme directory if it doesn't exist + $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" + az vm run-command invoke ` + --command-id RunShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DirectoryCreationScript +} else { + $DestinationPath = "C:\lme\$DestinationFileName" +} + +# The download script +$DownloadScript = if ($os -eq "linux") { + "curl -o '$DestinationPath' '$FileDownloadUrl'" +} else { + "Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath'" +} + +# Execute the download script az vm run-command invoke ` --command-id RunPowerShellScript ` --resource-group $ResourceGroupName ` From b8efb21101d298983a5bf923861223f139c9efaa Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 28 Dec 2023 09:12:56 -0500 Subject: [PATCH 044/103] Adds linux install scripts. --- .../azure_scripts/extract_archive.ps1 | 55 ++++++++++++++----- .../copy_files/download_in_container.ps1 | 20 +++++-- testing/configure/linux_install_lme.exp | 22 ++------ testing/configure/linux_install_lme.sh | 17 ++---- 4 files changed, 65 insertions(+), 49 deletions(-) diff --git a/testing/configure/azure_scripts/extract_archive.ps1 b/testing/configure/azure_scripts/extract_archive.ps1 index c4684119..bfcbd591 100644 --- a/testing/configure/azure_scripts/extract_archive.ps1 +++ b/testing/configure/azure_scripts/extract_archive.ps1 @@ -17,7 +17,7 @@ The name of the Azure Resource Group that contains the VM. The name (and optional path) of the zip file to be unzipped. .EXAMPLE -.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "C:\path\to\filename.zip" +.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "filename.zip" This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. @@ -34,25 +34,52 @@ param( [string]$ResourceGroupName, [Parameter(Mandatory=$true)] - [string]$Filename + [string]$Filename, + + [Parameter()] + [string]$username = "admin.ackbar", + + [Parameter()] + [ValidateSet("Windows","Linux","linux")] + [string]$os = "Windows" ) +# Convert the OS parameter to lowercase for consistent comparison +$os = $os.ToLower() + # Extract just the filename (ignoring any provided path) $JustFilename = Split-Path -Leaf $Filename -# Construct the full path for the zip file -$ZipFilePath = "C:\lme\$JustFilename" +# Set paths depending on the OS +if ($os -eq "linux") { + $ZipFilePath = "/home/$username/lme/$JustFilename" + $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) + $ExtractToPath = "/home/$username/lme/$FileBaseName" # Extract to a subdirectory -# Extract the filename without extension for the extraction directory -$FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) -$ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory named after the file + $UnzipScript = @" + unzip '$ZipFilePath' -d '$ExtractToPath' +"@ +} else { + $ZipFilePath = "C:\lme\$JustFilename" + $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) + $ExtractToPath = "C:\lme\$FileBaseName" # Extract to a subdirectory -$UnzipScript = @" -Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' + $UnzipScript = @" + Expand-Archive -Path '$ZipFilePath' -DestinationPath '$ExtractToPath' "@ +} -az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $UnzipScript +# Execute the unzip script with the appropriate command based on OS +if ($os -eq "linux") { + az vm run-command invoke ` + --command-id RunShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $UnzipScript +} else { + az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $UnzipScript +} diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 index 4f51560f..1d6ab366 100644 --- a/testing/configure/copy_files/download_in_container.ps1 +++ b/testing/configure/copy_files/download_in_container.ps1 @@ -46,9 +46,17 @@ $DownloadScript = if ($os -eq "linux") { "Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath'" } -# Execute the download script -az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $DownloadScript +# Execute the download script with the appropriate command based on OS +if ($os -eq "linux") { + az vm run-command invoke ` + --command-id RunShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DownloadScript +} else { + az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroupName ` + --name $VMName ` + --scripts $DownloadScript +} diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 245b3b52..2dd52a1f 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -10,23 +10,12 @@ set expect_out(buffer_size) 100000 log_file -a output.log spawn ./deploy.sh install -sleep 1 -expect { - -re {.*OK.*} { - send "\r" - } - -re {.*Proceed.*} { - send "y\r" - } -} +expect "Proceed? \\\[Y/n\\\] " +send "y\r" expect { - -re {.*Please reboot and re-run this script to finish the install.*} { - send_user "Reboot required. Exiting...\n" - exit - } - -re "Enter the IP of this Linux server.*" { + -re "Enter the IP of this Linux server.*10.1.0.5" { sleep 1 send "\r" } @@ -38,10 +27,11 @@ sleep 1 send "ls1.lme.local\r" sleep 1 - +# Use braces for regular expressions and ensure correct escaping +# continue with self signed certificates? ([y]es/[n]o): y expect -re {continue with self signed certificates.*: y} sleep 1 -send "y\r" +send "\r" sleep 1 expect -re {Skip Docker Install\? \(\[y\]es/\[n\]o\): n} diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index dbe42353..aa47dfb2 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -1,11 +1,5 @@ #!/bin/bash -# Change to the directory where the script is located -script_dir=$(dirname "$0") -cd $script_dir || exit 1 -# We need to get the full path of the script dir for below -script_dir=$(pwd) - # Default username username="admin.ackbar" @@ -20,11 +14,8 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ # Execute script with root privileges -sudo "$script_dir/linux_install_lme.exp" +sudo ./linux_install_lme.exp -if [ -f "/opt/lme/files_for_windows.zip" ]; then - sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ - sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip -else - echo "files_for_windows.zip does not exist. Probably because the LME install requires a reboot." -fi +# Replace 'admin.ackbar' with the specified username +sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ +sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip From ec19b8dbfc03aa796a93f843b18498b206bd3248 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 29 Dec 2023 08:00:44 -0500 Subject: [PATCH 045/103] Adds winlogbeat installer --- testing/configure/chown_dc1_private_key.ps1 | 2 +- testing/configure/linux_authorize_private_key.sh | 2 +- testing/configure/linux_install_lme.exp | 1 - testing/configure/linux_install_lme.sh | 4 +++- 4 files changed, 5 insertions(+), 4 deletions(-) diff --git a/testing/configure/chown_dc1_private_key.ps1 b/testing/configure/chown_dc1_private_key.ps1 index e8a8fece..d1ecc149 100644 --- a/testing/configure/chown_dc1_private_key.ps1 +++ b/testing/configure/chown_dc1_private_key.ps1 @@ -7,7 +7,7 @@ $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", # Get the current ACL of the file $acl = Get-Acl -Path $privateKeyPath -# Clear any existing Access Rules +# Clear any existing Access Rules (optional - do this if you want to restrict access to SYSTEM only) $acl.SetAccessRuleProtection($true, $false) $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } diff --git a/testing/configure/linux_authorize_private_key.sh b/testing/configure/linux_authorize_private_key.sh index c699d816..ebe55b76 100644 --- a/testing/configure/linux_authorize_private_key.sh +++ b/testing/configure/linux_authorize_private_key.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash cat /home/admin.ackbar/.ssh/id_rsa.pub >> /home/admin.ackbar/.ssh/authorized_keys -sudo chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* +chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* perl -p -i -e 's/root\@LS1/admin.ackbar\@DC1/' /home/admin.ackbar/.ssh/authorized_keys diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 2dd52a1f..3a6051cd 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -28,7 +28,6 @@ send "ls1.lme.local\r" sleep 1 # Use braces for regular expressions and ensure correct escaping -# continue with self signed certificates? ([y]es/[n]o): y expect -re {continue with self signed certificates.*: y} sleep 1 send "\r" diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index aa47dfb2..8fb21544 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -1,5 +1,8 @@ #!/bin/bash +# Change to the directory where the script is located +cd "$(dirname "$0")" || exit 1 + # Default username username="admin.ackbar" @@ -16,6 +19,5 @@ sudo git clone https://github.com/cisagov/lme.git /opt/lme/ # Execute script with root privileges sudo ./linux_install_lme.exp -# Replace 'admin.ackbar' with the specified username sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip From eda0bfe8736cd0a3b599d04694474e456d645ff6 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 29 Dec 2023 14:41:19 -0500 Subject: [PATCH 046/103] emove garbage in update server name --- testing/configure/wec_gpo_update_server_name.ps1 | 5 ----- 1 file changed, 5 deletions(-) diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index 265b5d89..c158a17c 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,8 +1,3 @@ -# Query the registry to find the key path -#$HKEY_USERSKeys = reg query HKEY_USERS /s /f "SubscriptionManager" /k - -HKEY_USERS\S-1-5-21-1874110181-726158762-2826089689-500\Software\Microsoft\Windows\CurrentVersion\Group Policy Objects\LME.LOCAL{083A2CE3-3021-4F4D-9765-35EB888E62CF}Machine\Software\Policies\Microsoft\Windows\EventLog\Event -Forwarding\SubscriptionManager # To set the GP registry value Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" -Type String From 4160a7530d8c2becc7ea585d856501a039dc5bce Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 3 Jan 2024 07:34:54 -0500 Subject: [PATCH 047/103] Tweak several scripts to get the scp of files_for_windows --- testing/configure/chown_dc1_private_key.ps1 | 2 +- testing/configure/install_chapter_1.ps1 | 4 +--- testing/configure/linux_authorize_private_key.sh | 2 +- testing/configure/trust_ls1_ssh_key.ps1 | 7 ------- 4 files changed, 3 insertions(+), 12 deletions(-) diff --git a/testing/configure/chown_dc1_private_key.ps1 b/testing/configure/chown_dc1_private_key.ps1 index d1ecc149..e8a8fece 100644 --- a/testing/configure/chown_dc1_private_key.ps1 +++ b/testing/configure/chown_dc1_private_key.ps1 @@ -7,7 +7,7 @@ $systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", # Get the current ACL of the file $acl = Get-Acl -Path $privateKeyPath -# Clear any existing Access Rules (optional - do this if you want to restrict access to SYSTEM only) +# Clear any existing Access Rules $acl.SetAccessRuleProtection($true, $false) $acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 3bf66666..828142d1 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -15,6 +15,7 @@ Set-Location -Path $configurePath .\copy_files\create_lme_directory.ps1 .\download_files.ps1 -directory lme .\wec_import_gpo.ps1 -directory lme +Start-Sleep 10 .\wec_gpo_update_server_name.ps1 .\create_ou.ps1 .\wec_link_gpo.ps1 @@ -22,11 +23,8 @@ Set-Location -Path $configurePath # Run the wevtutil and wecutil commands wevtutil set-log ForwardedEvents /q:true /e:true -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } wecutil rs lme -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } wecutil gr lme -if ($LASTEXITCODE -ne 0) { exit $LASTEXITCODE } # Run the move_computers_to_ou script .\move_computers_to_ou.ps1 diff --git a/testing/configure/linux_authorize_private_key.sh b/testing/configure/linux_authorize_private_key.sh index ebe55b76..c699d816 100644 --- a/testing/configure/linux_authorize_private_key.sh +++ b/testing/configure/linux_authorize_private_key.sh @@ -1,4 +1,4 @@ #!/usr/bin/env bash cat /home/admin.ackbar/.ssh/id_rsa.pub >> /home/admin.ackbar/.ssh/authorized_keys -chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* +sudo chown admin.ackbar:admin.ackbar /home/admin.ackbar/.ssh/* perl -p -i -e 's/root\@LS1/admin.ackbar\@DC1/' /home/admin.ackbar/.ssh/authorized_keys diff --git a/testing/configure/trust_ls1_ssh_key.ps1 b/testing/configure/trust_ls1_ssh_key.ps1 index 3bfaa327..62baef4c 100644 --- a/testing/configure/trust_ls1_ssh_key.ps1 +++ b/testing/configure/trust_ls1_ssh_key.ps1 @@ -1,10 +1,3 @@ -param ( - [string]$sshHost = "ls1" -) - -$sshDirectory = "C:\Windows\System32\config\systemprofile\.ssh" -$knownHostsFile = Join-Path -Path $sshDirectory -ChildPath "known_hosts" - # Ensure the .ssh directory exists if (-not (Test-Path -Path $sshDirectory)) { New-Item -ItemType Directory -Path $sshDirectory From 91b8e1cf84d029b179e3a2f997d597283000224a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 4 Jan 2024 07:36:56 -0500 Subject: [PATCH 048/103] Adds installer script to run all of the scripts --- testing/InstallTestbed.ps1 | 91 ++++++++++------- .../azure_scripts/download_in_container.ps1 | 46 +-------- .../azure_scripts/lib/utilityFunctions.ps1 | 98 ++++++------------- .../copy_files/create_lme_directory.ps1 | 25 ----- .../copy_files/download_in_container.ps1 | 62 ------------ testing/configure/install_chapter_1.ps1 | 2 +- testing/configure/trust_ls1_ssh_key.ps1 | 7 ++ 7 files changed, 90 insertions(+), 241 deletions(-) delete mode 100644 testing/configure/copy_files/create_lme_directory.ps1 delete mode 100644 testing/configure/copy_files/download_in_container.ps1 diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index cd565f5b..f86575fb 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -1,25 +1,22 @@ param ( - [Parameter(Mandatory = $true)] - [string]$ResourceGroupName, - - [string]$VMUsername = "admin.ackbar", - [string]$VMName = "DC1", - [string]$LinuxVMName = "LS1", - [int]$numberOfClients = 2 + [Parameter(Mandatory=$true)] + [string]$ResourceGroupName ) -# If you were to need the password from the SetupTestbed.ps1 script, you could use this: -# $Password = Get-Content "password.txt" +$VMUsername = "admin.ackbar" +#$ResourceGroupName = "LME-cbaxley-t2" +$VMName = "DC1" +$LinuxVMName = "LS1" + +$Password = Get-Content "password.txt" -# Define our library path $libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" # Check if the library file exists if (Test-Path -Path $libraryPath) { # Dot-source the library script . $libraryPath -} -else { +} else { Write-Error "Library script not found at path: $libraryPath" } @@ -57,25 +54,22 @@ $createDirResponse = az vm run-command invoke ` --resource-group $ResourceGroupName ` --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") # Download the zip file to the VM Write-Host "Downloading the zip file to the VM..." -$downloadZipFileResponse = .\download_in_container.ps1 ` +.\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") # Extract the zip file Write-Host "Extracting the zip file..." -$extractArchiveResponse = .\extract_archive.ps1 ` +.\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroupName $ResourceGroupName ` -FileName "configure.zip" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") # Run the install script for chapter 1 Write-Host "Running the install script for chapter 1..." @@ -88,14 +82,26 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Todo: Loop these for number of vms # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C1" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C2" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") # Wait for the services to start Write-Host "Waiting for the services to start..." Start-Sleep 20 # See if we can see the forwarding computers in the DC -write-host "Checking if we can see the forwarding computers in the DC..." +write-host "Seeing if we can see the forwarding computers in the DC..." $listForwardingComputersResponse = .\run_script_in_container.ps1 ` -ResourceGroupName $ResourceGroupName ` -VMName $VMName ` @@ -112,12 +118,25 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C1" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + +$gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C2" ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") # Wait for the services to start Write-Host "Waiting for the services to start..." Start-Sleep 20 + # See if you can see sysmon running on the machine Write-Host "Seeing if you can see sysmon running on a machine..." $showSysmonResponse = az vm run-command invoke ` @@ -127,15 +146,15 @@ $showSysmonResponse = az vm run-command invoke ` --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") + # Download the installers on LS1 Write-Host "Downloading the installers on LS1..." -$downloadLinuxZipFileResponse = .\download_in_container.ps1 ` +.\download_in_container.ps1 ` -VMName $LinuxVMName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" ` -os "linux" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadLinuxZipFileResponse") # Install unzip on LS1 Write-Host "Installing unzip on LS1..." @@ -148,12 +167,11 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Unzip the file on LS1 Write-Host "Unzipping the file on LS1..." -$extractLinuxArchiveResponse = .\extract_archive.ps1 ` +.\extract_archive.ps1 ` -VMName $LinuxVMName ` -ResourceGroupName $ResourceGroupName ` -FileName "configure.zip" ` -os "linux" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractLinuxArchiveResponse") # Make the installer files executable and update the system packages on LS1 Write-Host "Making the installer files executable and updating the system packages on LS1..." @@ -183,7 +201,7 @@ az vm restart ` # Run the lme installer on LS1 Write-Host "Running the lme installer on LS1..." -$installLmeResponse = az vm run-command invoke ` +az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` @@ -192,23 +210,22 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Capture the output of the install script Write-Host "Capturing the output of the install script for ES passwords..." -$getElasticsearchPasswordsResponse = az vm run-command invoke ` +$jsonResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` - --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' + --scripts 'tail -n10 "/opt/lme/Chapter 3 Files/output.log" | head -n4' # Todo: Extract the output and write this to a file for later use -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") +Format-AzVmRunCommandOutput -JsonResponse "$jsonResponse" # Generate key using expect on linux Write-Host "Generating key using expect on linux..." -$generateKeyResponse = az vm run-command invoke ` +az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") # Add the public key to the authorized_keys file on LS1 Write-Host "Adding the public key to the authorized_keys file on LS1..." @@ -226,6 +243,7 @@ $jsonResponse = az vm run-command invoke ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' + $privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" # Save the private key to a file @@ -243,12 +261,11 @@ $KeyDownloadUrl = ./copy_file_to_container.ps1 ` # Download the private key to DC1 Write-Host "Downloading the private key to DC1..." -$downloadPrivateKeyResponse = .\download_in_container.ps1 ` +.\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$KeyDownloadUrl" ` -DestinationFilePath "id_rsa" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") # Change the ownership of the private key file on DC1 Write-Host "Changing the ownership of the private key file on DC1..." @@ -259,11 +276,12 @@ $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") # Trust the key from ls1 so we can scp interactively -# Todo: It seems we don't need this but leaving it here for now +# Todo: We may not need this #.\run_script_in_container.ps1 ` # -ResourceGroupName $ResourceGroupName ` # -VMName $VMName ` # -ScriptPathOnVM "C:\lme\configure\trust_ls1_ssh_key.ps1" +# # Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." @@ -276,11 +294,10 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Extract the files on DC1 Write-Host "Extracting the files on DC1..." -$extractFilesForWindowsResponse = .\extract_archive.ps1 ` +.\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroupName $ResourceGroupName ` -FileName "files_for_windows.zip" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") # Install winlogbeat on DC1 Write-Host "Installing winlogbeat on DC1..." @@ -291,6 +308,4 @@ $installWinlogbeatResponse = .\run_script_in_container.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") -Write-Host "Install completed." - -(Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut \ No newline at end of file +Write-Host "Insttall completed." diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index 6d9cb75e..1d6ab366 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -1,45 +1,3 @@ -<# -.SYNOPSIS -This script automates the file download process on a specified VM based on its OS type. - -.DESCRIPTION -The script takes parameters for VM name, resource group, file URL, destination file path, username, and OS type. It processes these parameters to download a file to a VM, either running Windows or Linux. The script determines the appropriate command to create a directory (if necessary) and download the file to the specified VM, handling differences in command syntax and file path conventions based on the OS. - -.PARAMETER VMName -The name of the Virtual Machine where the file will be downloaded. - -.PARAMETER ResourceGroupName -The name of the Azure resource group where the VM is located. - -.PARAMETER FileDownloadUrl -The URL of the file to be downloaded. - -.PARAMETER DestinationFilePath -The complete path where the file should be downloaded on the VM. This path is processed to extract just the filename. - -.PARAMETER username -The username for the VM, used in constructing the file path for Linux systems. Default is 'admin.ackbar'. - -.PARAMETER os -The operating system type of the VM. Accepts 'Windows', 'Linux', or 'linux'. Default is 'Windows'. - -.EXAMPLE -.\download_in_container.ps1 ` - -VMName "MyVM" ` - -ResourceGroupName "MyResourceGroup" ` - -FileDownloadUrl "http://example.com/file.zip" ` - -DestinationFilePath "C:\path\to\file.zip" - -This example downloads a file from 'http://example.com/file.zip' to 'C:\path\to\file.zip' - on the VM named 'MyVM' in the 'MyResourceGroup'. - -.NOTES -- Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. -- The specified script must exist on the VM and the VM should have the necessary permissions to execute it. - - #> -#> - param( [Parameter(Mandatory=$true)] [string]$VMName, @@ -60,7 +18,6 @@ param( [ValidateSet("Windows","Linux","linux")] [string]$os = "Windows" ) -Write-Host $FileDownloadUrl # Convert the OS parameter to lowercase for consistent comparison $os = $os.ToLower() @@ -73,8 +30,7 @@ if ($os -eq "linux") { $DestinationPath = "/home/$username/lme/$DestinationFileName" # Create the lme directory if it doesn't exist $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" - # We don't want to output this until we fix it so we can put all of the output from thw whole script into one json object - $CreateDirectoryResponse = az vm run-command invoke ` + az vm run-command invoke ` --command-id RunShellScript ` --resource-group $ResourceGroupName ` --name $VMName ` diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index ce12e20a..f0fcb887 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -1,66 +1,47 @@ function Format-AzVmRunCommandOutput { param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [string]$JsonResponse ) - $results = @() - - try { - $responseObj = $JsonResponse | ConvertFrom-Json -# Write-Host "Converted JSON object: $responseObj" - - if ($responseObj -and $responseObj.value) { - $stdout = "" - $stderr = "" - - foreach ($item in $responseObj.value) { -# Write-Host "Processing item: $($item.code)" - - # Check for StdOut and StdErr - if ($item.code -like "ComponentStatus/StdOut/*") { - $stdout += $item.message + "`n" - } elseif ($item.code -like "ComponentStatus/StdErr/*") { - $stderr += $item.message + "`n" - } + # Convert JSON string to PowerShell object + $responseObj = $JsonResponse | ConvertFrom-Json - # Additional case to handle other types of 'code' - # This ensures that all messages are captured - else { - $stdout += $item.message + "`n" - } - } + # Initialize an array to hold the results + $results = @() - if ($stdout -or $stderr) { - $results += New-Object PSObject -Property @{ + # Check if there is any response + if ($responseObj -and $responseObj.value) { + foreach ($item in $responseObj.value) { + # Process the stdout and stderr content + if ($item.message) { + # Extracting and cleaning up the messages + $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 + $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 + $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 + + # Create a custom object with stdout and stderr + $output = New-Object PSObject -Property @{ StdOut = $stdout StdErr = $stderr } - } - } - } catch { - $errorMessage = $_.Exception.Message - Write-Host "Error: $errorMessage" - $results += New-Object PSObject -Property @{ - StdOut = "Error: $errorMessage" - StdErr = "" - } - } - if (-not $results) { - $results += New-Object PSObject -Property @{ - StdOut = "No data or invalid data received." - StdErr = "" + # Add the custom object to the results array + $results += $output + } } + } else { + # Return a message if no valid response is found + $results += "No response or invalid response received." } + # Return the results array return $results } - function Show-FormattedOutput { param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [Object[]]$FormattedOutput ) @@ -81,7 +62,7 @@ function Show-FormattedOutput { function ExtractPrivateKeyFromJson { param ( - [Parameter(Mandatory = $true)] + [Parameter(Mandatory=$true)] [string]$jsonResponse ) @@ -110,31 +91,8 @@ function ExtractPrivateKeyFromJson { # Return the private key return $privateKey - } - catch { + } catch { Write-Error "An error occurred while extracting the private key: $_" return $null } -} - -function Invoke-GPUpdateOnVMs { - param( - [Parameter(Mandatory = $true)] - [string]$ResourceGroupName, - [int]$numberOfClients = 2 - ) - - for ($i = 1; $i -le $numberOfClients; $i++) { - $vmName = "C$i" # Dynamically create VM name - - # Invoke the command on the VM - $gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name $vmName ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" - - # Call the existing Show-FormattedOutput function - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") - } -} +} \ No newline at end of file diff --git a/testing/configure/copy_files/create_lme_directory.ps1 b/testing/configure/copy_files/create_lme_directory.ps1 deleted file mode 100644 index 8bef9b66..00000000 --- a/testing/configure/copy_files/create_lme_directory.ps1 +++ /dev/null @@ -1,25 +0,0 @@ -# Define the directory path -$directoryPath = "C:\lme" - -# Create the directory if it doesn't already exist -if (-not (Test-Path -Path $directoryPath)) { - New-Item -Path $directoryPath -ItemType Directory -} - -# Define the security principal for 'All Users' -$allUsers = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") - -# Get the current ACL of the directory -$acl = Get-Acl -Path $directoryPath - -# Define the rights (read and execute) -$rights = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute - -# Create the rule (allowing read and execute access) -$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($allUsers, $rights, 'ContainerInherit, ObjectInherit', 'None', 'Allow') - -# Add the rule to the ACL -$acl.AddAccessRule($accessRule) - -# Set the ACL back to the directory -Set-Acl -Path $directoryPath -AclObject $acl diff --git a/testing/configure/copy_files/download_in_container.ps1 b/testing/configure/copy_files/download_in_container.ps1 deleted file mode 100644 index 1d6ab366..00000000 --- a/testing/configure/copy_files/download_in_container.ps1 +++ /dev/null @@ -1,62 +0,0 @@ -param( - [Parameter(Mandatory=$true)] - [string]$VMName, - - [Parameter(Mandatory=$true)] - [string]$ResourceGroupName, - - [Parameter(Mandatory=$true)] - [string]$FileDownloadUrl, - - [Parameter(Mandatory=$true)] - [string]$DestinationFilePath, # This will be stripped to only the filename - - [Parameter()] - [string]$username = "admin.ackbar", - - [Parameter()] - [ValidateSet("Windows","Linux","linux")] - [string]$os = "Windows" -) - -# Convert the OS parameter to lowercase for consistent comparison -$os = $os.ToLower() - -# Extract just the filename from the destination file path -$DestinationFileName = Split-Path -Leaf $DestinationFilePath - -# Set the destination path depending on the OS -if ($os -eq "linux") { - $DestinationPath = "/home/$username/lme/$DestinationFileName" - # Create the lme directory if it doesn't exist - $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" - az vm run-command invoke ` - --command-id RunShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $DirectoryCreationScript -} else { - $DestinationPath = "C:\lme\$DestinationFileName" -} - -# The download script -$DownloadScript = if ($os -eq "linux") { - "curl -o '$DestinationPath' '$FileDownloadUrl'" -} else { - "Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath'" -} - -# Execute the download script with the appropriate command based on OS -if ($os -eq "linux") { - az vm run-command invoke ` - --command-id RunShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $DownloadScript -} else { - az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` - --name $VMName ` - --scripts $DownloadScript -} diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 828142d1..74b77f02 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -12,7 +12,7 @@ $ErrorActionPreference = 'Stop' Set-Location -Path $configurePath # Run the scripts and check for failure -.\copy_files\create_lme_directory.ps1 +.\create_lme_directory.ps1 .\download_files.ps1 -directory lme .\wec_import_gpo.ps1 -directory lme Start-Sleep 10 diff --git a/testing/configure/trust_ls1_ssh_key.ps1 b/testing/configure/trust_ls1_ssh_key.ps1 index 62baef4c..3bfaa327 100644 --- a/testing/configure/trust_ls1_ssh_key.ps1 +++ b/testing/configure/trust_ls1_ssh_key.ps1 @@ -1,3 +1,10 @@ +param ( + [string]$sshHost = "ls1" +) + +$sshDirectory = "C:\Windows\System32\config\systemprofile\.ssh" +$knownHostsFile = Join-Path -Path $sshDirectory -ChildPath "known_hosts" + # Ensure the .ssh directory exists if (-not (Test-Path -Path $sshDirectory)) { New-Item -ItemType Directory -Path $sshDirectory From 38823a99f2a9ff70a4568ba0aef5d723ef18bd7f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 4 Jan 2024 09:32:32 -0500 Subject: [PATCH 049/103] Fixes the formatting method for az output --- .../azure_scripts/lib/utilityFunctions.ps1 | 55 ++++++++++--------- 1 file changed, 30 insertions(+), 25 deletions(-) diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index f0fcb887..560d8237 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -4,38 +4,43 @@ function Format-AzVmRunCommandOutput { [string]$JsonResponse ) - # Convert JSON string to PowerShell object - $responseObj = $JsonResponse | ConvertFrom-Json - - # Initialize an array to hold the results + # Initialize an empty array to hold the results $results = @() - # Check if there is any response - if ($responseObj -and $responseObj.value) { - foreach ($item in $responseObj.value) { - # Process the stdout and stderr content - if ($item.message) { - # Extracting and cleaning up the messages - $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 - $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 - $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 - - # Create a custom object with stdout and stderr - $output = New-Object PSObject -Property @{ - StdOut = $stdout - StdErr = $stderr + try { + $responseObj = $JsonResponse | ConvertFrom-Json + + if ($responseObj -and $responseObj.value) { + foreach ($item in $responseObj.value) { + if ($item.message) { + $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 + $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 + $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 + + $results += New-Object PSObject -Property @{ + StdOut = $stdout + StdErr = $stderr + } } - - # Add the custom object to the results array - $results += $output } } - } else { - # Return a message if no valid response is found - $results += "No response or invalid response received." + } + catch { + # Return a custom object indicating an error + $results += New-Object PSObject -Property @{ + StdOut = "Error: Invalid JSON response" + StdErr = "" + } + } + + # Ensure that something is always returned + if (-not $results) { + $results += New-Object PSObject -Property @{ + StdOut = "No data or invalid data received." + StdErr = "" + } } - # Return the results array return $results } From 9d9afa0f5cbca9e0f34df0989a6f88308cc4b347 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 5 Jan 2024 06:54:37 -0500 Subject: [PATCH 050/103] Clean up the scripts and add documentation --- testing/InstallTestbed.ps1 | 84 ++++++++----------- .../azure_scripts/download_in_container.ps1 | 42 ++++++++++ .../azure_scripts/lib/utilityFunctions.ps1 | 33 ++++++-- testing/configure/install_chapter_2.ps1 | 2 +- testing/configure/linux_install_lme.sh | 9 +- 5 files changed, 113 insertions(+), 57 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index f86575fb..91ff0b9c 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -1,22 +1,25 @@ param ( - [Parameter(Mandatory=$true)] - [string]$ResourceGroupName -) + [Parameter(Mandatory = $true)] + [string]$ResourceGroupName, -$VMUsername = "admin.ackbar" -#$ResourceGroupName = "LME-cbaxley-t2" -$VMName = "DC1" -$LinuxVMName = "LS1" + [string]$VMUsername = "admin.ackbar", + [string]$VMName = "DC1", + [string]$LinuxVMName = "LS1", + [int]$numberOfClients = 2 +) -$Password = Get-Content "password.txt" +# If you were to need the password from the SetupTestbed.ps1 script, you could use this: +# $Password = Get-Content "password.txt" +# Define our library path $libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" # Check if the library file exists if (Test-Path -Path $libraryPath) { # Dot-source the library script . $libraryPath -} else { +} +else { Write-Error "Library script not found at path: $libraryPath" } @@ -58,18 +61,21 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Download the zip file to the VM Write-Host "Downloading the zip file to the VM..." -.\download_in_container.ps1 ` +$downloadZipFileResponse = .\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") + # Extract the zip file Write-Host "Extracting the zip file..." -.\extract_archive.ps1 ` +$extractArchiveResponse = .\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroupName $ResourceGroupName ` -FileName "configure.zip" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") # Run the install script for chapter 1 Write-Host "Running the install script for chapter 1..." @@ -82,19 +88,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Todo: Loop these for number of vms # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C1" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") - -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C2" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") +Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients # Wait for the services to start Write-Host "Waiting for the services to start..." @@ -118,25 +112,12 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C1" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") - -$gpupdateResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C2" ` - --resource-group $ResourceGroupName ` - --scripts "gpupdate /force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") +Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients # Wait for the services to start Write-Host "Waiting for the services to start..." Start-Sleep 20 - # See if you can see sysmon running on the machine Write-Host "Seeing if you can see sysmon running on a machine..." $showSysmonResponse = az vm run-command invoke ` @@ -146,15 +127,15 @@ $showSysmonResponse = az vm run-command invoke ` --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") - # Download the installers on LS1 Write-Host "Downloading the installers on LS1..." -.\download_in_container.ps1 ` +$downloadLinuxZipFileResponse = .\download_in_container.ps1 ` -VMName $LinuxVMName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" ` -os "linux" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadLinuxZipFileResponse") # Install unzip on LS1 Write-Host "Installing unzip on LS1..." @@ -167,11 +148,12 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Unzip the file on LS1 Write-Host "Unzipping the file on LS1..." -.\extract_archive.ps1 ` +$extractLinuxArchiveResponse = .\extract_archive.ps1 ` -VMName $LinuxVMName ` -ResourceGroupName $ResourceGroupName ` -FileName "configure.zip" ` -os "linux" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractLinuxArchiveResponse") # Make the installer files executable and update the system packages on LS1 Write-Host "Making the installer files executable and updating the system packages on LS1..." @@ -210,22 +192,23 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Capture the output of the install script Write-Host "Capturing the output of the install script for ES passwords..." -$jsonResponse = az vm run-command invoke ` +$getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts 'tail -n10 "/opt/lme/Chapter 3 Files/output.log" | head -n4' # Todo: Extract the output and write this to a file for later use -Format-AzVmRunCommandOutput -JsonResponse "$jsonResponse" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") # Generate key using expect on linux Write-Host "Generating key using expect on linux..." -az vm run-command invoke ` +$generateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") # Add the public key to the authorized_keys file on LS1 Write-Host "Adding the public key to the authorized_keys file on LS1..." @@ -261,11 +244,12 @@ $KeyDownloadUrl = ./copy_file_to_container.ps1 ` # Download the private key to DC1 Write-Host "Downloading the private key to DC1..." -.\download_in_container.ps1 ` +$downloadPrivateKeyResponse = .\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$KeyDownloadUrl" ` -DestinationFilePath "id_rsa" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") # Change the ownership of the private key file on DC1 Write-Host "Changing the ownership of the private key file on DC1..." @@ -276,12 +260,11 @@ $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") # Trust the key from ls1 so we can scp interactively -# Todo: We may not need this +# Todo: It seems we don't need this but leaving it here for now #.\run_script_in_container.ps1 ` # -ResourceGroupName $ResourceGroupName ` # -VMName $VMName ` # -ScriptPathOnVM "C:\lme\configure\trust_ls1_ssh_key.ps1" -# # Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." @@ -294,10 +277,11 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Extract the files on DC1 Write-Host "Extracting the files on DC1..." -.\extract_archive.ps1 ` +$extractFilesForWindowsResponse = .\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroupName $ResourceGroupName ` -FileName "files_for_windows.zip" +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") # Install winlogbeat on DC1 Write-Host "Installing winlogbeat on DC1..." @@ -308,4 +292,6 @@ $installWinlogbeatResponse = .\run_script_in_container.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") -Write-Host "Insttall completed." +Write-Host "Install completed." + +(Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut \ No newline at end of file diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index 1d6ab366..8225d7d7 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -1,3 +1,45 @@ +<# +.SYNOPSIS +This script automates the file download process on a specified VM based on its OS type. + +.DESCRIPTION +The script takes parameters for VM name, resource group, file URL, destination file path, username, and OS type. It processes these parameters to download a file to a VM, either running Windows or Linux. The script determines the appropriate command to create a directory (if necessary) and download the file to the specified VM, handling differences in command syntax and file path conventions based on the OS. + +.PARAMETER VMName +The name of the Virtual Machine where the file will be downloaded. + +.PARAMETER ResourceGroupName +The name of the Azure resource group where the VM is located. + +.PARAMETER FileDownloadUrl +The URL of the file to be downloaded. + +.PARAMETER DestinationFilePath +The complete path where the file should be downloaded on the VM. This path is processed to extract just the filename. + +.PARAMETER username +The username for the VM, used in constructing the file path for Linux systems. Default is 'admin.ackbar'. + +.PARAMETER os +The operating system type of the VM. Accepts 'Windows', 'Linux', or 'linux'. Default is 'Windows'. + +.EXAMPLE +.\download_in_container.ps1 ` + -VMName "MyVM" ` + -ResourceGroupName "MyResourceGroup" ` + -FileDownloadUrl "http://example.com/file.zip" ` + -DestinationFilePath "C:\path\to\file.zip" + +This example downloads a file from 'http://example.com/file.zip' to 'C:\path\to\file.zip' + on the VM named 'MyVM' in the 'MyResourceGroup'. + +.NOTES +- Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. +- The specified script must exist on the VM and the VM should have the necessary permissions to execute it. + + #> +#> + param( [Parameter(Mandatory=$true)] [string]$VMName, diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 560d8237..073e6d1b 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -1,6 +1,6 @@ function Format-AzVmRunCommandOutput { param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$JsonResponse ) @@ -46,7 +46,7 @@ function Format-AzVmRunCommandOutput { function Show-FormattedOutput { param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [Object[]]$FormattedOutput ) @@ -67,7 +67,7 @@ function Show-FormattedOutput { function ExtractPrivateKeyFromJson { param ( - [Parameter(Mandatory=$true)] + [Parameter(Mandatory = $true)] [string]$jsonResponse ) @@ -96,8 +96,31 @@ function ExtractPrivateKeyFromJson { # Return the private key return $privateKey - } catch { + } + catch { Write-Error "An error occurred while extracting the private key: $_" return $null } -} \ No newline at end of file +} + +function Invoke-GPUpdateOnVMs { + param( + [Parameter(Mandatory = $true)] + [string]$ResourceGroupName, + [int]$numberOfClients = 2 + ) + + for ($i = 1; $i -le $numberOfClients; $i++) { + $vmName = "C$i" # Dynamically create VM name + + # Invoke the command on the VM + $gpupdateResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name $vmName ` + --resource-group $ResourceGroupName ` + --scripts "gpupdate /force" + + # Call the existing Show-FormattedOutput function + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$gpupdateResponse") + } +} diff --git a/testing/configure/install_chapter_2.ps1 b/testing/configure/install_chapter_2.ps1 index 17e90ff1..9d5fa89a 100644 --- a/testing/configure/install_chapter_2.ps1 +++ b/testing/configure/install_chapter_2.ps1 @@ -11,7 +11,7 @@ $ErrorActionPreference = 'Stop' # Change directory to the configure directory Set-Location -Path $configurePath -# Run the scripts and check for failure +# Run the sysmon install scripts .\sysmon_install_in_sysvol.ps1 .\sysmon_import_gpo.ps1 -directory lme .\sysmon_gpo_update_vars.ps1 diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 8fb21544..575657e5 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -16,8 +16,13 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ + # Execute script with root privileges sudo ./linux_install_lme.exp -sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ -sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip +if [ -f "/opt/lme/files_for_windows.zip" ]; then + sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ + sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip +else + echo "Warn: files_for_windows.zip does not exist. Probably because the LME install requires a reboot." +fi From 2574f6b20f7c91bee75d6693089cc338a6ac2d11 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 5 Jan 2024 09:06:36 -0500 Subject: [PATCH 051/103] Fixes outputting format errors --- testing/InstallTestbed.ps1 | 2 +- .../azure_scripts/lib/utilityFunctions.ps1 | 28 ++++++++------ .../configure/wec_gpo_update_server_name.ps1 | 37 ++++++++++++++++++- 3 files changed, 52 insertions(+), 15 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 91ff0b9c..5da87f32 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -196,7 +196,7 @@ $getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` - --scripts 'tail -n10 "/opt/lme/Chapter 3 Files/output.log" | head -n4' + --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' # Todo: Extract the output and write this to a file for later use Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 073e6d1b..111b54ea 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -4,36 +4,40 @@ function Format-AzVmRunCommandOutput { [string]$JsonResponse ) - # Initialize an empty array to hold the results $results = @() try { $responseObj = $JsonResponse | ConvertFrom-Json if ($responseObj -and $responseObj.value) { + $stdout = "" + $stderr = "" + foreach ($item in $responseObj.value) { - if ($item.message) { - $stdout = $item.message -split '\n\[stdout\]\n' | Select-Object -Last 1 - $stdout = $stdout -split '\n\[stderr\]\n' | Select-Object -First 1 - $stderr = $item.message -split '\n\[stderr\]\n' | Select-Object -Last 1 - - $results += New-Object PSObject -Property @{ - StdOut = $stdout - StdErr = $stderr - } + if ($item.code -like "ComponentStatus/StdOut/*") { + $stdout += $item.message + } + elseif ($item.code -like "ComponentStatus/StdErr/*") { + $stderr += $item.message + } + } + + # Add a result only if there is actual content + if ($stdout -or $stderr) { + $results += New-Object PSObject -Property @{ + StdOut = $stdout.Trim() + StdErr = $stderr.Trim() } } } } catch { - # Return a custom object indicating an error $results += New-Object PSObject -Property @{ StdOut = "Error: Invalid JSON response" StdErr = "" } } - # Ensure that something is always returned if (-not $results) { $results += New-Object PSObject -Property @{ StdOut = "No data or invalid data received." diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index c158a17c..f6936380 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -1,5 +1,38 @@ -# To set the GP registry value -Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value "Server=http://dc1.lme.local:5985/wsman/SubscriptionManager/WEC,Refresh=60" -Type String +<# +.SYNOPSIS +This script sets and retrieves a Group Policy (GP) registry value for Windows Event Log Event Forwarding. + +.DESCRIPTION +The script is used to configure the Subscription Manager URL for Windows Event Log Event Forwarding in a Group Policy setting. It sets the registry value for the Subscription Manager URL using the specified domain, port, and protocol, and then retrieves the value to confirm the setting. This is useful in environments where centralized event log management is required. + +.PARAMETER domain +The domain for the Subscription Manager URL. Default is 'dc1.lme.local'. + +.PARAMETER port +The port number for the Subscription Manager URL. Default is 5985. + +.PARAMETER protocol +The protocol for the Subscription Manager URL. Default is 'http'. + +.EXAMPLE +.\wec_gpo_update_server_name.ps1 +Executes the script with default parameters. + +.EXAMPLE +.\wec_gpo_update_server_name.ps1 -domain "customdomain.local" -port 1234 -protocol "https" +Executes the script with custom domain, port, and protocol. + +#> + +param( + [string]$domain = "dc1.lme.local", + [int]$port = 5985, + [string]$protocol = "http" +) + +# Construct the Subscription Manager URL using the provided parameters +$subscriptionManagerUrl = "Server=$protocol://$domain:$port/wsman/SubscriptionManager/WEC,Refresh=60" +Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value $subscriptionManagerUrl -Type String # To get the GP registry value to confirm it's set $registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" From 246b6fa51cbb66fc0bfb83736784713d1d79df7a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 5 Jan 2024 09:49:53 -0500 Subject: [PATCH 052/103] Fixes hanging on adding ls1 to domain --- testing/SetupTestbed.ps1 | 14 ++++++++++++-- 1 file changed, 12 insertions(+), 2 deletions(-) diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 4c3004b9..c07d75b5 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -242,8 +242,8 @@ Set-NetworkRules -AllowedSourcesList $AllowedSourcesList # Create the VMs # ################## $VMPassword = Get-RandomPassword 12 -Write-Output "`nWriting $VMAdmin password to ${ResourceGroup}.password.txt" -echo $VMPassword > "${ResourceGroup}.password.txt" +Write-Output "`nWriting $VMAdmin password to password.txt" +echo $VMPassword > password.txt Write-Output "`nCreating DC1..." az vm create ` @@ -379,6 +379,15 @@ it is likely that the DNS entry was still successfully added. To verify, log on to DC1 and run 'Resolve-DnsName ls1' in PowerShell. If it returns NXDOMAIN, you'll need to add it manually." Write-Output "The time is $(Get-Date)." +#az vm run-command create ` +# --resource-group $ResourceGroup ` +# --location $Location ` +# --run-as-user $DomainName\$VMAdmin ` +# --run-as-password $VMPassword ` +# --run-command-name "addDNSRecord" ` +# --vm-name DC1 ` +# --script "Add-DnsServerResourceRecordA -Name `"LS1`" -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00" + # Define the PowerShell script with the DomainName variable interpolated $scriptContent = @" @@ -435,6 +444,7 @@ $removeDnsRecordScriptResponse = az vm run-command invoke ` --name DC1 ` --resource-group $ResourceGroup ` --scripts "Remove-Item -Path 'C:\AddDnsRecord.ps1' -Force" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$removeDnsRecordScriptResponse") From f8d23449075d1a02b171081a822e8f3afc2ff9b1 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Mon, 8 Jan 2024 17:18:16 -0500 Subject: [PATCH 053/103] Fix formatting errors on responses --- testing/InstallTestbed.ps1 | 7 ++--- testing/SetupTestbed.ps1 | 14 ++-------- .../azure_scripts/download_in_container.ps1 | 3 +- .../azure_scripts/lib/utilityFunctions.ps1 | 28 +++++++++++++------ .../configure/wec_gpo_update_server_name.ps1 | 2 +- 5 files changed, 27 insertions(+), 27 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 5da87f32..cd565f5b 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -57,6 +57,7 @@ $createDirResponse = az vm run-command invoke ` --resource-group $ResourceGroupName ` --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") # Download the zip file to the VM @@ -66,7 +67,6 @@ $downloadZipFileResponse = .\download_in_container.ps1 ` -ResourceGroupName $ResourceGroupName ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") # Extract the zip file @@ -95,7 +95,7 @@ Write-Host "Waiting for the services to start..." Start-Sleep 20 # See if we can see the forwarding computers in the DC -write-host "Seeing if we can see the forwarding computers in the DC..." +write-host "Checking if we can see the forwarding computers in the DC..." $listForwardingComputersResponse = .\run_script_in_container.ps1 ` -ResourceGroupName $ResourceGroupName ` -VMName $VMName ` @@ -183,7 +183,7 @@ az vm restart ` # Run the lme installer on LS1 Write-Host "Running the lme installer on LS1..." -az vm run-command invoke ` +$installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` @@ -226,7 +226,6 @@ $jsonResponse = az vm run-command invoke ` --name $LinuxVMName ` --resource-group $ResourceGroupName ` --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' - $privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" # Save the private key to a file diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index c07d75b5..4c3004b9 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -242,8 +242,8 @@ Set-NetworkRules -AllowedSourcesList $AllowedSourcesList # Create the VMs # ################## $VMPassword = Get-RandomPassword 12 -Write-Output "`nWriting $VMAdmin password to password.txt" -echo $VMPassword > password.txt +Write-Output "`nWriting $VMAdmin password to ${ResourceGroup}.password.txt" +echo $VMPassword > "${ResourceGroup}.password.txt" Write-Output "`nCreating DC1..." az vm create ` @@ -379,15 +379,6 @@ it is likely that the DNS entry was still successfully added. To verify, log on to DC1 and run 'Resolve-DnsName ls1' in PowerShell. If it returns NXDOMAIN, you'll need to add it manually." Write-Output "The time is $(Get-Date)." -#az vm run-command create ` -# --resource-group $ResourceGroup ` -# --location $Location ` -# --run-as-user $DomainName\$VMAdmin ` -# --run-as-password $VMPassword ` -# --run-command-name "addDNSRecord" ` -# --vm-name DC1 ` -# --script "Add-DnsServerResourceRecordA -Name `"LS1`" -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00" - # Define the PowerShell script with the DomainName variable interpolated $scriptContent = @" @@ -444,7 +435,6 @@ $removeDnsRecordScriptResponse = az vm run-command invoke ` --name DC1 ` --resource-group $ResourceGroup ` --scripts "Remove-Item -Path 'C:\AddDnsRecord.ps1' -Force" - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$removeDnsRecordScriptResponse") diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index 8225d7d7..250204bf 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -72,7 +72,8 @@ if ($os -eq "linux") { $DestinationPath = "/home/$username/lme/$DestinationFileName" # Create the lme directory if it doesn't exist $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" - az vm run-command invoke ` + # We don't want to output this until we fix it so we can put all of the output from thw whole script into one json object + $CreateDirectoryResponse = az vm run-command invoke ` --command-id RunShellScript ` --resource-group $ResourceGroupName ` --name $VMName ` diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 111b54ea..ce12e20a 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -8,32 +8,41 @@ function Format-AzVmRunCommandOutput { try { $responseObj = $JsonResponse | ConvertFrom-Json +# Write-Host "Converted JSON object: $responseObj" if ($responseObj -and $responseObj.value) { $stdout = "" $stderr = "" foreach ($item in $responseObj.value) { +# Write-Host "Processing item: $($item.code)" + + # Check for StdOut and StdErr if ($item.code -like "ComponentStatus/StdOut/*") { - $stdout += $item.message + $stdout += $item.message + "`n" + } elseif ($item.code -like "ComponentStatus/StdErr/*") { + $stderr += $item.message + "`n" } - elseif ($item.code -like "ComponentStatus/StdErr/*") { - $stderr += $item.message + + # Additional case to handle other types of 'code' + # This ensures that all messages are captured + else { + $stdout += $item.message + "`n" } } - # Add a result only if there is actual content if ($stdout -or $stderr) { $results += New-Object PSObject -Property @{ - StdOut = $stdout.Trim() - StdErr = $stderr.Trim() + StdOut = $stdout + StdErr = $stderr } } } - } - catch { + } catch { + $errorMessage = $_.Exception.Message + Write-Host "Error: $errorMessage" $results += New-Object PSObject -Property @{ - StdOut = "Error: Invalid JSON response" + StdOut = "Error: $errorMessage" StdErr = "" } } @@ -48,6 +57,7 @@ function Format-AzVmRunCommandOutput { return $results } + function Show-FormattedOutput { param ( [Parameter(Mandatory = $true)] diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index f6936380..49006b1f 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -31,7 +31,7 @@ param( ) # Construct the Subscription Manager URL using the provided parameters -$subscriptionManagerUrl = "Server=$protocol://$domain:$port/wsman/SubscriptionManager/WEC,Refresh=60" +$subscriptionManagerUrl = "Server=${protocol}://${domain}:${port}/wsman/SubscriptionManager/WEC,Refresh=60" Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value $subscriptionManagerUrl -Type String # To get the GP registry value to confirm it's set From 82cc7b47ec61f49e3a87a0d5cabe751abc0ffef0 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 9 Jan 2024 09:46:49 -0500 Subject: [PATCH 054/103] Update linux expect script for different prompts. --- testing/configure/linux_install_lme.exp | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 3a6051cd..57aba5aa 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -2,6 +2,8 @@ # Change to the LME directory containing files for the Linux server cd /opt/lme/Chapter\ 3\ Files/ +pwd + # Adjust the timeout if necessary set timeout 60 @@ -10,12 +12,20 @@ set expect_out(buffer_size) 100000 log_file -a output.log spawn ./deploy.sh install +sleep 1 +expect { + -re {OK.*} { + send "\r" + } + -re {Proceed.*} { + send "y\r" + } +} + -expect "Proceed? \\\[Y/n\\\] " -send "y\r" expect { - -re "Enter the IP of this Linux server.*10.1.0.5" { + -re "Enter the IP of this Linux server.*" { sleep 1 send "\r" } From f7d696595d4e6198652d12a32e1ec388f9dd1bae Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 10 Jan 2024 06:28:23 -0500 Subject: [PATCH 055/103] Handle the reboot message for linux expect script --- Chapter 3 Files/deploy.sh | 6 +++--- testing/InstallTestbed.ps1 | 7 +++++++ testing/SetupTestbed.ps1 | 1 + testing/TestbedOnlyLinux.ps1 | 6 +++--- .../azure_scripts/lib/utilityFunctions.ps1 | 13 ++++++++----- testing/configure/linux_install_lme.exp | 13 +++++++------ testing/configure/linux_install_lme.sh | 10 ++++++---- testing/configure/linux_update_system.sh | 2 +- 8 files changed, 36 insertions(+), 22 deletions(-) diff --git a/Chapter 3 Files/deploy.sh b/Chapter 3 Files/deploy.sh index a1d0ef9f..f5be70a7 100755 --- a/Chapter 3 Files/deploy.sh +++ b/Chapter 3 Files/deploy.sh @@ -748,10 +748,10 @@ function install() { fi echo -e "\e[32m[X]\e[0m Updating OS software" - apt update && apt upgrade -y + apt-get update && apt-get upgrade -y echo -e "\e[32m[X]\e[0m Installing prerequisites" - apt install ${REQUIRED_PACKS[*]} -y -q + DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install ${REQUIRED_PACKS[*]} -y -q if [ -f /var/run/reboot-required ]; then echo -e "\e[31m[!]\e[0m A reboot is required in order to proceed with the install." @@ -1169,7 +1169,7 @@ then ready "Will install the following packages: ${missing_pkgs[*]}. These are required for LME." sudo apt-get update #confirm install - sudo apt-get --yes install ${missing_pkgs[*]} + sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get --yes install ${missing_pkgs[*]} fi #Change current working directory so relative filepaths work diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index cd565f5b..ecbf24cc 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -32,6 +32,13 @@ Write-Host "Creating a container to keep files for the VM..." Write-Host "Sourcing the variables from the file..." . ./configure/azure_scripts/config.ps1 +# Remove old code if it exists +if (Test-Path ./configure.zip) { + Remove-Item ./configure.zip -Force -Confirm:$false -ErrorAction SilentlyContinue +} else { + Write-Host "File not found." +} + # Zip up the installer scripts for the VM Write-Host "Zipping up the installer scripts for the VM..." ./configure/azure_scripts/zip_my_parents_parent.ps1 diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 4c3004b9..adf3812e 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -367,6 +367,7 @@ for ($i = 1; $i -le $NumClients; $i++) { } Write-Output "`nVM login info:" +Write-Output "ResourceGroup: $($ResourceGroup)" Write-Output "Username: $($VMAdmin)" Write-Output "Password: $($VMPassword)" Write-Output "SAVE THE ABOVE INFO`n" diff --git a/testing/TestbedOnlyLinux.ps1 b/testing/TestbedOnlyLinux.ps1 index bdbbe06b..d62e0001 100644 --- a/testing/TestbedOnlyLinux.ps1 +++ b/testing/TestbedOnlyLinux.ps1 @@ -208,9 +208,8 @@ Set-NetworkRules -AllowedSourcesList $AllowedSourcesList # Create the VMs # ################## $VMPassword = Get-RandomPassword 12 -Write-Output "`nWriting $VMAdmin password to password.txt" -$VMPassword | Out-File -FilePath password.txt -Encoding UTF8 - +Write-Output "`nWriting $VMAdmin password to ${ResourceGroup}.password.txt" +$VMPassword | Out-File -FilePath "${ResourceGroup}.password.txt" -Encoding UTF8 Write-Output "`nCreating LS1..." @@ -238,6 +237,7 @@ if ($null -ne $AutoShutdownTime) { } Write-Output "`nVM login info:" +Write-Output "ResourceGroup: $($ResourceGroup)" Write-Output "Username: $( $VMAdmin )" Write-Output "Password: $( $VMPassword )" Write-Output "SAVE THE ABOVE INFO`n" diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index ce12e20a..837e391f 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -57,7 +57,6 @@ function Format-AzVmRunCommandOutput { return $results } - function Show-FormattedOutput { param ( [Parameter(Mandatory = $true)] @@ -71,10 +70,14 @@ function Show-FormattedOutput { } elseif ($item -is [PSCustomObject]) { # Handle custom objects with StdOut and StdErr - Write-Host "Output (stdout):" - Write-Host $item.StdOut - Write-Host "Error (stderr):" - Write-Host $item.StdErr + if (![string]::IsNullOrWhiteSpace($item.StdOut)) { + Write-Host "Output (stdout):" + Write-Host $item.StdOut + } + if (![string]::IsNullOrWhiteSpace($item.StdErr)) { + Write-Host "Error (stderr):" + Write-Host $item.StdErr + } } } } diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 57aba5aa..9b9c66ad 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -2,8 +2,6 @@ # Change to the LME directory containing files for the Linux server cd /opt/lme/Chapter\ 3\ Files/ -pwd - # Adjust the timeout if necessary set timeout 60 @@ -14,17 +12,20 @@ log_file -a output.log spawn ./deploy.sh install sleep 1 expect { - -re {OK.*} { + -re {.*OK.*} { send "\r" } - -re {Proceed.*} { + -re {.*Proceed.*} { send "y\r" } } - expect { + -re {.*Please reboot and re-run this script to finish the install.*} { + send_user "Reboot required. Exiting...\n" + exit + } -re "Enter the IP of this Linux server.*" { sleep 1 send "\r" @@ -37,7 +38,7 @@ sleep 1 send "ls1.lme.local\r" sleep 1 -# Use braces for regular expressions and ensure correct escaping + expect -re {continue with self signed certificates.*: y} sleep 1 send "\r" diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 575657e5..dbe42353 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -1,7 +1,10 @@ #!/bin/bash # Change to the directory where the script is located -cd "$(dirname "$0")" || exit 1 +script_dir=$(dirname "$0") +cd $script_dir || exit 1 +# We need to get the full path of the script dir for below +script_dir=$(pwd) # Default username username="admin.ackbar" @@ -16,13 +19,12 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ - # Execute script with root privileges -sudo ./linux_install_lme.exp +sudo "$script_dir/linux_install_lme.exp" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip else - echo "Warn: files_for_windows.zip does not exist. Probably because the LME install requires a reboot." + echo "files_for_windows.zip does not exist. Probably because the LME install requires a reboot." fi diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh index 8dabc52f..6e666be0 100644 --- a/testing/configure/linux_update_system.sh +++ b/testing/configure/linux_update_system.sh @@ -1,3 +1,3 @@ # Install Git client to be able to clone the LME repository sudo apt update -sudo apt install git curl zip net-tools jq expect -y \ No newline at end of file +sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq expect -y \ No newline at end of file From 6888fc0be33f2661f3fd6d45286c5f1d27a5f46b Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 07:01:54 -0500 Subject: [PATCH 056/103] Adds InstallTestbed instructions to Readme.md --- testing/InstallTestbed.ps1 | 66 ++++++++++--------- testing/Readme.md | 48 +++++++++----- .../azure_scripts/create_blob_container.ps1 | 10 +-- .../azure_scripts/download_in_container.ps1 | 10 +-- .../azure_scripts/extract_archive.ps1 | 8 +-- .../azure_scripts/lib/utilityFunctions.ps1 | 4 +- .../azure_scripts/run_script_in_container.ps1 | 6 +- 7 files changed, 87 insertions(+), 65 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index ecbf24cc..250ab654 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -1,11 +1,11 @@ param ( [Parameter(Mandatory = $true)] - [string]$ResourceGroupName, + [string]$ResourceGroup, [string]$VMUsername = "admin.ackbar", [string]$VMName = "DC1", [string]$LinuxVMName = "LS1", - [int]$numberOfClients = 2 + [int]$NumberOfClients = 2 ) # If you were to need the password from the SetupTestbed.ps1 script, you could use this: @@ -26,7 +26,7 @@ else { # Create a container to keep files for the VM Write-Host "Creating a container to keep files for the VM..." ./configure/azure_scripts/create_blob_container.ps1 ` - -ResourceGroupName $ResourceGroupName + -ResourceGroup $ResourceGroup # Source the variables from the file Write-Host "Sourcing the variables from the file..." @@ -61,7 +61,7 @@ Write-Host "Making our directory on the VM..." $createDirResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name $VMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" @@ -71,7 +71,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Host "Downloading the zip file to the VM..." $downloadZipFileResponse = .\download_in_container.ps1 ` -VMName $VmName ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") @@ -80,14 +80,14 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Host "Extracting the zip file..." $extractArchiveResponse = .\extract_archive.ps1 ` -VMName $VMName ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -FileName "configure.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") # Run the install script for chapter 1 Write-Host "Running the install script for chapter 1..." $installChapter1Response = .\run_script_in_container.ps1 ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\install_chapter_1.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter1Response") @@ -95,7 +95,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Todo: Loop these for number of vms # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients +Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients # Wait for the services to start Write-Host "Waiting for the services to start..." @@ -104,7 +104,7 @@ Start-Sleep 20 # See if we can see the forwarding computers in the DC write-host "Checking if we can see the forwarding computers in the DC..." $listForwardingComputersResponse = .\run_script_in_container.ps1 ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\list_computers_forwarding_events.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$listForwardingComputersResponse") @@ -112,14 +112,14 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Install the sysmon service on DC1 from chapter 2 Write-Host "Installing the sysmon service on DC1 from chapter 2..." $installChapter2Response = .\run_script_in_container.ps1 ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\install_chapter_2.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter2Response") # Update the group policy on the remote machines Write-Host "Updating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroupName $ResourceGroupName -numberOfClients $numberOfClients +Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients # Wait for the services to start Write-Host "Waiting for the services to start..." @@ -130,7 +130,7 @@ Write-Host "Seeing if you can see sysmon running on a machine..." $showSysmonResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name "C1" ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") @@ -138,7 +138,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Host "Downloading the installers on LS1..." $downloadLinuxZipFileResponse = .\download_in_container.ps1 ` -VMName $LinuxVMName ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" ` -os "linux" @@ -149,7 +149,7 @@ Write-Host "Installing unzip on LS1..." $installUnzipResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts 'apt-get install unzip -y' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installUnzipResponse") @@ -157,7 +157,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Host "Unzipping the file on LS1..." $extractLinuxArchiveResponse = .\extract_archive.ps1 ` -VMName $LinuxVMName ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -FileName "configure.zip" ` -os "linux" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractLinuxArchiveResponse") @@ -167,7 +167,7 @@ Write-Host "Making the installer files executable and updating the system packag $updateLinuxResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts 'chmod +x /home/admin.ackbar/lme/configure/* && /home/admin.ackbar/lme/configure/linux_update_system.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$updateLinuxResponse") @@ -178,14 +178,14 @@ Write-Host "Running the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") # Have to check for the reboot thing here Write-Host "Rebooting ${LinuxVMName}..." az vm restart ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $LinuxVMName # Run the lme installer on LS1 @@ -193,7 +193,7 @@ Write-Host "Running the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") @@ -202,7 +202,7 @@ Write-Host "Capturing the output of the install script for ES passwords..." $getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' # Todo: Extract the output and write this to a file for later use @@ -213,7 +213,7 @@ Write-Host "Generating key using expect on linux..." $generateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") @@ -222,7 +222,7 @@ Write-Host "Adding the public key to the authorized_keys file on LS1..." $authorizePrivateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_authorize_private_key.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$authorizePrivateKeyResponse") @@ -231,7 +231,7 @@ Write-Host "Cat the private key and capture that to the azure shell..." $jsonResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' $privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" @@ -252,7 +252,7 @@ $KeyDownloadUrl = ./copy_file_to_container.ps1 ` Write-Host "Downloading the private key to DC1..." $downloadPrivateKeyResponse = .\download_in_container.ps1 ` -VMName $VmName ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$KeyDownloadUrl" ` -DestinationFilePath "id_rsa" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") @@ -260,7 +260,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Change the ownership of the private key file on DC1 Write-Host "Changing the ownership of the private key file on DC1..." $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") @@ -268,7 +268,7 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse # Trust the key from ls1 so we can scp interactively # Todo: It seems we don't need this but leaving it here for now #.\run_script_in_container.ps1 ` -# -ResourceGroupName $ResourceGroupName ` +# -ResourceGroup $ResourceGroup ` # -VMName $VMName ` # -ScriptPathOnVM "C:\lme\configure\trust_ls1_ssh_key.ps1" @@ -277,7 +277,7 @@ Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 t $scpResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name $VMName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1.lme.local:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") @@ -285,14 +285,14 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Host "Extracting the files on DC1..." $extractFilesForWindowsResponse = .\extract_archive.ps1 ` -VMName $VMName ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -FileName "files_for_windows.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") # Install winlogbeat on DC1 Write-Host "Installing winlogbeat on DC1..." $installWinlogbeatResponse = .\run_script_in_container.ps1 ` - -ResourceGroupName $ResourceGroupName ` + -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\winlogbeat_install.ps1" @@ -300,4 +300,10 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Host "Install completed." -(Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut \ No newline at end of file +$EsPasswords = (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut +# Output the passwords +$EsPasswords + +# Write the passwords to a file +$PasswordPath = "..\..\${ResourceGroup}.password.txt" +$EsPasswords | Out-File -Append -FilePath $PasswordPath \ No newline at end of file diff --git a/testing/Readme.md b/testing/Readme.md index 45301981..4602e257 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -13,14 +13,15 @@ Using the Azure CLI, it creates the following: This script does not install LME; it simply creates a fresh environment that's ready to have LME installed. ## Usage -| **Parameter** | **Alias** | **Description** | **Required** | -|------------------------|-----------|----------------------------------------------------------------------------------------|---------------------------------------| -| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | -| $NumClients | -n | The number of Windows clients to create; maximum 16; defaults to 1 | No | -| $AutoShutdownTime | | The auto-shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900); auto-shutdown not configured if not provided | No | -| $AutoShutdownEmail | | An email to be notified if a VM is auto-shutdown. | No | -| $AllowedSources | -s | Comma-Separated list of CIDR prefixes or IP ranges, e.g. XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc..., that are allowed to connect to the VMs via RDP and ssh. | Yes | -| $NoPrompt | -y | Switch, run the script with no prompt (useful for automated runs). By default, the script will prompt the user to review paramters and confirm before continuing. | No | +| **Parameter** | **Alias** | **Description** | **Required** | +|--------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| +| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | +| $NumClients | -n | The number of Windows clients to create; maximum 16; defaults to 1 | No | +| $AutoShutdownTime | | The auto-shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900); auto-shutdown not configured if not provided | No | +| $AutoShutdownEmail | | An email to be notified if a VM is auto-shutdown. | No | +| $AllowedSources | -s | Comma-Separated list of CIDR prefixes or IP ranges, e.g. XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc..., that are allowed to connect to the VMs via RDP and ssh. | Yes | +| $Location | -l | The region you would like to build the assets in. Defaults to westus | No | +| $NoPrompt | -y | Switch, run the script with no prompt (useful for automated runs). By default, the script will prompt the user to review paramters and confirm before continuing. | No | Example: ``` @@ -28,14 +29,14 @@ Example: ``` ## Running Using Azure Shell -| **#** | **Step** | **Screenshot** | -|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| -| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | -| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | -| 3 | Upload `SetupTestbed.ps1` by clicking the "Upload/Download files" icon | ![image](/docs/imgs/testing-screenshots/shell3.png) | -| 4 | Run the script, providing values for the parameters when promoted (see [Usage](#usage)). The script will take ~20 minutes to run to completion. | ![image](/docs/imgs/testing-screenshots/shell4.png) | -| 5 | Save the login credentials printed to the terminal at the end. At this point you can login to each VM using RDP (for the Windows servers) or SSH (for the Linux server). | ![image](/docs/imgs/testing-screenshots/shell5.png) | -| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | ![image](/docs/imgs/testing-screenshots/delete.png) | +| **#** | **Step** | **Screenshot** | +|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| +| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | +| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | +| 3 | Upload `SetupTestbed.ps1` by clicking the "Upload/Download files" icon *Note: if you want to use the InstallTestbed script, you should probably clone the repo as described in that section, and run SetupTestbed.ps1 from the cloned repo in the testing directory* | ![image](/docs/imgs/testing-screenshots/shell3.png) | +| 4 | Run the script, providing values for the parameters when promoted (see [Usage](#usage)). The script will take ~20 minutes to run to completion. | ![image](/docs/imgs/testing-screenshots/shell4.png) | +| 5 | Save the login credentials printed to the terminal at the end (They will also be in a file called `<$ResourceGroup>.password.txt`). At this point you can login to each VM using RDP (for the Windows servers) or SSH (for the Linux server). | ![image](/docs/imgs/testing-screenshots/shell5.png) | +| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | ![image](/docs/imgs/testing-screenshots/delete.png) | # Extra Functionality: @@ -55,3 +56,18 @@ Flags: - enable: deletes the DENYINTERNET/DENYLOADBALANCER rules - NSG: sets NSG to a custom NSG if desired [NSG1 default] +## Install LME on the cluster: +| **#** | **Step** | **Screenshot** | +|-------|-------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| +| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | +| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | +| 3 | If you have already cloned the LME repo then `cd LME` and run git pull before changing to the testing directory | | +| 3 | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | +| 4 | Now you can run `.\InstallTestbed.ps1 --ResourceGroup YourResourceGroup` | | +| 5 | Save the login credentials printed to the terminal at the end. *See notes* | | +| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | + +Note: When the script finishes you will be in the azure_scripts directory, and you should see the elasticsearch credentials printed to the terminal. +You will need to `cd ../../` to get back to the LME directory. All the passwords should be in the `<$ResourceGroup>.password.txt` file. + + diff --git a/testing/configure/azure_scripts/create_blob_container.ps1 b/testing/configure/azure_scripts/create_blob_container.ps1 index 1c6ac4a9..f3bab04d 100644 --- a/testing/configure/azure_scripts/create_blob_container.ps1 +++ b/testing/configure/azure_scripts/create_blob_container.ps1 @@ -12,7 +12,7 @@ creates a blob container, and saves the configuration to a 'config.ps1' file in The name of the Azure Resource Group for the storage account and blob container. .EXAMPLE -.\create_blob_container.ps1 -ResourceGroupName "YourResourceGroupName" +.\create_blob_container.ps1 -ResourceGroup "YourResourceGroupName" Replace "YourResourceGroupName" with the name of your Azure Resource Group. @@ -26,7 +26,7 @@ Replace "YourResourceGroupName" with the name of your Azure Resource Group. param( [Parameter(Mandatory=$true)] - [string]$ResourceGroupName + [string]$ResourceGroup ) function New-AzureName { @@ -45,7 +45,7 @@ function New-AzureName { } # Get the location of the resource group -$Location = (az group show --name $ResourceGroupName --query location --output tsv) +$Location = (az group show --name $ResourceGroup --query location --output tsv) # Generate a unique storage account name $StorageAccountName = New-AzureName -Prefix "st" @@ -56,7 +56,7 @@ $ContainerName = New-AzureName -Prefix "container" # Create a new storage account az storage account create ` --name $StorageAccountName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --location $Location ` --sku Standard_LRS @@ -65,7 +65,7 @@ Start-Sleep -Seconds 10 # Get the storage account key $StorageAccountKey = (az storage account keys list ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --account-name $StorageAccountName ` --query '[0].value' ` --output tsv) diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index 250204bf..c4984030 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -26,7 +26,7 @@ The operating system type of the VM. Accepts 'Windows', 'Linux', or 'linux'. Def .EXAMPLE .\download_in_container.ps1 ` -VMName "MyVM" ` - -ResourceGroupName "MyResourceGroup" ` + -ResourceGroup "MyResourceGroup" ` -FileDownloadUrl "http://example.com/file.zip" ` -DestinationFilePath "C:\path\to\file.zip" @@ -45,7 +45,7 @@ param( [string]$VMName, [Parameter(Mandatory=$true)] - [string]$ResourceGroupName, + [string]$ResourceGroup, [Parameter(Mandatory=$true)] [string]$FileDownloadUrl, @@ -75,7 +75,7 @@ if ($os -eq "linux") { # We don't want to output this until we fix it so we can put all of the output from thw whole script into one json object $CreateDirectoryResponse = az vm run-command invoke ` --command-id RunShellScript ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $VMName ` --scripts $DirectoryCreationScript } else { @@ -93,13 +93,13 @@ $DownloadScript = if ($os -eq "linux") { if ($os -eq "linux") { az vm run-command invoke ` --command-id RunShellScript ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $VMName ` --scripts $DownloadScript } else { az vm run-command invoke ` --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $VMName ` --scripts $DownloadScript } diff --git a/testing/configure/azure_scripts/extract_archive.ps1 b/testing/configure/azure_scripts/extract_archive.ps1 index bfcbd591..b4e7bce0 100644 --- a/testing/configure/azure_scripts/extract_archive.ps1 +++ b/testing/configure/azure_scripts/extract_archive.ps1 @@ -17,7 +17,7 @@ The name of the Azure Resource Group that contains the VM. The name (and optional path) of the zip file to be unzipped. .EXAMPLE -.\extract_archive.ps1 -VMName "DC1" -ResourceGroupName "YourResourceGroupName" -Filename "filename.zip" +.\extract_archive.ps1 -VMName "DC1" -ResourceGroup "YourResourceGroupName" -Filename "filename.zip" This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. @@ -31,7 +31,7 @@ param( [string]$VMName, [Parameter(Mandatory=$true)] - [string]$ResourceGroupName, + [string]$ResourceGroup, [Parameter(Mandatory=$true)] [string]$Filename, @@ -73,13 +73,13 @@ if ($os -eq "linux") { if ($os -eq "linux") { az vm run-command invoke ` --command-id RunShellScript ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $VMName ` --scripts $UnzipScript } else { az vm run-command invoke ` --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $VMName ` --scripts $UnzipScript } diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index 837e391f..b83e72b2 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -123,7 +123,7 @@ function ExtractPrivateKeyFromJson { function Invoke-GPUpdateOnVMs { param( [Parameter(Mandatory = $true)] - [string]$ResourceGroupName, + [string]$ResourceGroup, [int]$numberOfClients = 2 ) @@ -134,7 +134,7 @@ function Invoke-GPUpdateOnVMs { $gpupdateResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name $vmName ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --scripts "gpupdate /force" # Call the existing Show-FormattedOutput function diff --git a/testing/configure/azure_scripts/run_script_in_container.ps1 b/testing/configure/azure_scripts/run_script_in_container.ps1 index 17a031c5..b247dbeb 100644 --- a/testing/configure/azure_scripts/run_script_in_container.ps1 +++ b/testing/configure/azure_scripts/run_script_in_container.ps1 @@ -21,7 +21,7 @@ The full path of the PowerShell script on the Azure VM that needs to be executed A string of arguments that will be passed to the script. .EXAMPLE -.\run_script_in_container.ps1 -ResourceGroupName "YourResourceGroupName" -VMName "VMName" -ScriptPathOnVM "C:\path\to\your\script.ps1" -ScriptArguments "-Arg1 value1 -Arg2 value2" +.\run_script_in_container.ps1 -ResourceGroup "YourResourceGroupName" -VMName "VMName" -ScriptPathOnVM "C:\path\to\your\script.ps1" -ScriptArguments "-Arg1 value1 -Arg2 value2" This example executes a script located at 'C:\path\to\your\script.ps1' on the VM named "VMName" in the resource group "YourResourceGroupName", passing it the arguments "-Arg1 value1 -Arg2 value2". @@ -32,7 +32,7 @@ This example executes a script located at 'C:\path\to\your\script.ps1' on the VM param( [Parameter(Mandatory=$true)] - [string]$ResourceGroupName, + [string]$ResourceGroup, [Parameter(Mandatory=$true)] [string]$VMName, @@ -49,6 +49,6 @@ $InvokeScriptCommand = @" az vm run-command invoke ` --command-id RunPowerShellScript ` - --resource-group $ResourceGroupName ` + --resource-group $ResourceGroup ` --name $VMName ` --scripts $InvokeScriptCommand From acf6cc9d8070d68f3f27df7a19d96cc01ac391ff Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 09:42:52 -0500 Subject: [PATCH 057/103] Adds InstallTestbed instructions to Readme.md --- testing/InstallTestbed.ps1 | 12 ++++-------- 1 file changed, 4 insertions(+), 8 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 250ab654..e11fd9c8 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -237,8 +237,8 @@ $privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" # Save the private key to a file Write-Host "Saving the private key to a file..." -$filePath = ".\id_rsa" -Set-Content -Path $filePath -Value $privateKey +$privateKeyPath = ".\id_rsa" +Set-Content -Path $privateKeyPath -Value $privateKey # Upload the private key to the container and get a key to download it Write-Host "Uploading the private key to the container and getting a key to download it..." @@ -265,12 +265,8 @@ $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") -# Trust the key from ls1 so we can scp interactively -# Todo: It seems we don't need this but leaving it here for now -#.\run_script_in_container.ps1 ` -# -ResourceGroup $ResourceGroup ` -# -VMName $VMName ` -# -ScriptPathOnVM "C:\lme\configure\trust_ls1_ssh_key.ps1" +# Remove the private key from the local machine +Remove-Item -Path $privateKeyPath # Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." From 71c448cb18d5a5fdb4795821156021fba3ad265a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 09:49:27 -0500 Subject: [PATCH 058/103] Adds InstallTestbed instructions to Readme.md --- testing/configure/linux_install_lme.sh | 3 +++ 1 file changed, 3 insertions(+) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index dbe42353..bab87a07 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -19,6 +19,9 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ + +export DEBIAN_FRONTEND=noninteractive +export NEEDRESTART_MODE=a # Execute script with root privileges sudo "$script_dir/linux_install_lme.exp" From b6ff43630e7c608ae511c708eaa9b79f400b8b8a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 10:50:58 -0500 Subject: [PATCH 059/103] Adds InstallTestbed instructions to Readme.md --- testing/configure/linux_install_lme.sh | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index bab87a07..e6fc9765 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -22,6 +22,11 @@ sudo git clone https://github.com/cisagov/lme.git /opt/lme/ export DEBIAN_FRONTEND=noninteractive export NEEDRESTART_MODE=a + +# Set the noninteractive modes for root +echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc +echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc + # Execute script with root privileges sudo "$script_dir/linux_install_lme.exp" From 0a494806f23c5ccf2b8ee39f804de90dfdfefcad Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 15:22:09 -0500 Subject: [PATCH 060/103] Adds InstallTestbed instructions to Readme.md --- testing/configure/linux_install_lme.sh | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index e6fc9765..a44313a7 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -20,8 +20,9 @@ done # Download a copy of the LME files sudo git clone https://github.com/cisagov/lme.git /opt/lme/ -export DEBIAN_FRONTEND=noninteractive -export NEEDRESTART_MODE=a +echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc +echo 'export NEEDRESTART_MODE=a' >> ~/.bashrc +. ~/.bashrc # Set the noninteractive modes for root echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc From 5f09bfbf28f7e3814d6a011081ba5c3ae07b06e8 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 20:11:44 -0500 Subject: [PATCH 061/103] Adds InstallTestbed instructions to Readme.md --- testing/configure/linux_install_lme.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index a44313a7..eaa60333 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -18,7 +18,10 @@ while getopts "u:" opt; do done # Download a copy of the LME files -sudo git clone https://github.com/cisagov/lme.git /opt/lme/ +#sudo git clone https://github.com/cisagov/lme.git /opt/lme/ +sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lme.git /opt/lme/ +# curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.assets[0].browser_download_url' | xargs -I {} sh -c 'curl -L -O {} && unzip -d /opt/lme/ "$(basename {})"' + echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc echo 'export NEEDRESTART_MODE=a' >> ~/.bashrc From afe7589ce8d31ff101c5affe17cdf147c974a679 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 20:21:22 -0500 Subject: [PATCH 062/103] Adds InstallTestbed instructions to Readme.md --- testing/configure/linux_install_lme.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index eaa60333..3df11d40 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -26,13 +26,14 @@ sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lm echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc echo 'export NEEDRESTART_MODE=a' >> ~/.bashrc . ~/.bashrc +export PS1="" # Set the noninteractive modes for root echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Execute script with root privileges -sudo "$script_dir/linux_install_lme.exp" +sudo "PS1="" $script_dir/linux_install_lme.exp" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ From 2a3484215715fac23fb21f5680b5918c13ed3ea9 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 20:55:04 -0500 Subject: [PATCH 063/103] Adds InstallTestbed instructions to Readme.md --- testing/configure/linux_install_lme.sh | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 3df11d40..06282354 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -26,14 +26,13 @@ sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lm echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc echo 'export NEEDRESTART_MODE=a' >> ~/.bashrc . ~/.bashrc -export PS1="" # Set the noninteractive modes for root echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Execute script with root privileges -sudo "PS1="" $script_dir/linux_install_lme.exp" +sudo -E bash -c "$script_dir/linux_install_lme.exp" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ From a92125a88491f194ffe2b4c72aa988ce76a4e54d Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 21:10:53 -0500 Subject: [PATCH 064/103] Adds InstallTestbed instructions to Readme.md --- Chapter 3 Files/deploy.sh | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Chapter 3 Files/deploy.sh b/Chapter 3 Files/deploy.sh index f5be70a7..4a1a0101 100755 --- a/Chapter 3 Files/deploy.sh +++ b/Chapter 3 Files/deploy.sh @@ -748,10 +748,10 @@ function install() { fi echo -e "\e[32m[X]\e[0m Updating OS software" - apt-get update && apt-get upgrade -y + apt-get update && apt-get DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a upgrade -yq echo -e "\e[32m[X]\e[0m Installing prerequisites" - DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install ${REQUIRED_PACKS[*]} -y -q + DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install ${REQUIRED_PACKS[*]} -yq if [ -f /var/run/reboot-required ]; then echo -e "\e[31m[!]\e[0m A reboot is required in order to proceed with the install." @@ -1169,7 +1169,7 @@ then ready "Will install the following packages: ${missing_pkgs[*]}. These are required for LME." sudo apt-get update #confirm install - sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get --yes install ${missing_pkgs[*]} + sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get -yq install ${missing_pkgs[*]} fi #Change current working directory so relative filepaths work From a7e03f63913f2a4962ce41c650ff475c48a9e04d Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 12 Jan 2024 21:14:49 -0500 Subject: [PATCH 065/103] Adds InstallTestbed instructions to Readme.md --- Chapter 3 Files/deploy.sh | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/Chapter 3 Files/deploy.sh b/Chapter 3 Files/deploy.sh index 4a1a0101..b113b252 100755 --- a/Chapter 3 Files/deploy.sh +++ b/Chapter 3 Files/deploy.sh @@ -748,7 +748,8 @@ function install() { fi echo -e "\e[32m[X]\e[0m Updating OS software" - apt-get update && apt-get DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a upgrade -yq + apt-get update + DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get upgrade -yq echo -e "\e[32m[X]\e[0m Installing prerequisites" DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt-get install ${REQUIRED_PACKS[*]} -yq From e0520526bcb06d8f4e65b3fc34900fa5735ac740 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Sun, 14 Jan 2024 07:05:12 -0500 Subject: [PATCH 066/103] Adds InstallTestbed instructions to Readme.md d --- testing/InstallTestbed.ps1 | 36 ++++++++++++++----------- testing/Readme.md | 19 ++++++------- testing/configure/install_chapter_1.ps1 | 1 + 3 files changed, 31 insertions(+), 25 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index e11fd9c8..a068dca0 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -122,8 +122,8 @@ Write-Host "Updating the group policy on the remote machines..." Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients # Wait for the services to start -Write-Host "Waiting for the services to start..." -Start-Sleep 20 +Write-Host "Waiting for the services to start. Generally they don't show..." +Start-Sleep 10 # See if you can see sysmon running on the machine Write-Host "Seeing if you can see sysmon running on a machine..." @@ -182,20 +182,24 @@ $installLmeResponse = az vm run-command invoke ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") -# Have to check for the reboot thing here -Write-Host "Rebooting ${LinuxVMName}..." -az vm restart ` - --resource-group $ResourceGroup ` - --name $LinuxVMName - -# Run the lme installer on LS1 -Write-Host "Running the lme installer on LS1..." -$installLmeResponse = az vm run-command invoke ` - --command-id RunShellScript ` - --name $LinuxVMName ` - --resource-group $ResourceGroup ` - --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") +# Check if the response contains the need to reboot +$rebootCheckstring = $installLmeResponse | Out-String +if ($rebootCheckstring -match "A reboot is required in order to proceed with the install") { + # Have to check for the reboot thing here + Write-Host "Rebooting ${LinuxVMName}..." + az vm restart ` + --resource-group $ResourceGroup ` + --name $LinuxVMName + + # Run the lme installer on LS1 + Write-Host "Running the lme installer on LS1..." + $installLmeResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVMName ` + --resource-group $ResourceGroup ` + --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") +} # Capture the output of the install script Write-Host "Capturing the output of the install script for ES passwords..." diff --git a/testing/Readme.md b/testing/Readme.md index 4602e257..49630c4a 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -57,15 +57,16 @@ Flags: - NSG: sets NSG to a custom NSG if desired [NSG1 default] ## Install LME on the cluster: -| **#** | **Step** | **Screenshot** | -|-------|-------------------------------------------------------------------------------------------------------------------------------------------------|------------------------------------------------------| -| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | -| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | -| 3 | If you have already cloned the LME repo then `cd LME` and run git pull before changing to the testing directory | | -| 3 | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | -| 4 | Now you can run `.\InstallTestbed.ps1 --ResourceGroup YourResourceGroup` | | -| 5 | Save the login credentials printed to the terminal at the end. *See notes* | | -| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | +| **#** | **Step** | **Screenshot** | +|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| +| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | +| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | +| 3 | If you have already cloned the LME repo then `cd LME` and run git pull before changing to the testing directory | | +| 3 | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | +| 4 | Now you can run `./InstallTestbed.ps1 --ResourceGroup YourResourceGroup` | | +| 4.a | You can also run the command this way if you want to log to a file. `./InstallTestbed.ps1 -ResourceGroup LME-cbaxley-T2 \| Tee-Object -FilePath "./output.log"` | | +| 5 | Save the login credentials printed to the terminal at the end. *See notes* | | +| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | Note: When the script finishes you will be in the azure_scripts directory, and you should see the elasticsearch credentials printed to the terminal. You will need to `cd ../../` to get back to the LME directory. All the passwords should be in the `<$ResourceGroup>.password.txt` file. diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 74b77f02..76661530 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -22,6 +22,7 @@ Start-Sleep 10 .\wec_service_provisioner.ps1 # Run the wevtutil and wecutil commands +Write-Host "Running wevtutil and wecutil commands to start the wec service manually..." wevtutil set-log ForwardedEvents /q:true /e:true wecutil rs lme wecutil gr lme From 52edaa65d9a1fdfa0063ab9deb1d0835029e87d9 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 16 Jan 2024 06:15:00 -0500 Subject: [PATCH 067/103] Modifies parameters to be pascal case --- testing/InstallTestbed.ps1 | 130 +++++++++++------- testing/Readme.md | 20 +-- .../azure_scripts/create_blob_container.ps1 | 6 +- .../azure_scripts/download_in_container.ps1 | 29 ++-- .../azure_scripts/extract_archive.ps1 | 21 +-- .../azure_scripts/lib/utilityFunctions.ps1 | 16 +-- .../azure_scripts/run_script_in_container.ps1 | 11 +- testing/configure/chown_dc1_private_key.ps1 | 16 +-- testing/configure/create_lme_directory.ps1 | 12 +- testing/configure/create_ou.ps1 | 8 +- testing/configure/download_files.ps1 | 14 +- testing/configure/install_chapter_1.ps1 | 46 ++++++- testing/configure/install_chapter_2.ps1 | 18 ++- .../list_computers_forwarding_events.ps1 | 4 +- testing/configure/move_computers_to_ou.ps1 | 8 +- testing/configure/sysmon_gpo_update_vars.ps1 | 14 +- testing/configure/sysmon_import_gpo.ps1 | 14 +- testing/configure/sysmon_link_gpo.ps1 | 4 +- testing/configure/trust_ls1_ssh_key.ps1 | 22 +-- testing/configure/wec_firewall.ps1 | 22 +-- .../configure/wec_gpo_update_server_name.ps1 | 12 +- testing/configure/wec_import_gpo.ps1 | 20 +-- testing/configure/wec_link_gpo.ps1 | 8 +- testing/configure/wec_service_provisioner.ps1 | 14 +- testing/configure/wec_start_service.ps1 | 8 +- testing/configure/winlogbeat_install.ps1 | 63 +++++---- 26 files changed, 324 insertions(+), 236 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index a068dca0..defa33fd 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -2,140 +2,155 @@ param ( [Parameter(Mandatory = $true)] [string]$ResourceGroup, - [string]$VMUsername = "admin.ackbar", [string]$VMName = "DC1", [string]$LinuxVMName = "LS1", [int]$NumberOfClients = 2 ) # If you were to need the password from the SetupTestbed.ps1 script, you could use this: -# $Password = Get-Content "password.txt" +# $Password = Get-Content "${ResourceGroup}.password.txt" + +$ProcessSeparator = "`n----------------------------------------`n" # Define our library path -$libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" +$LibraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" # Check if the library file exists -if (Test-Path -Path $libraryPath) { +if (Test-Path -Path $LibraryPath) { # Dot-source the library script - . $libraryPath + . $LibraryPath } else { - Write-Error "Library script not found at path: $libraryPath" + Write-Error "Library script not found at path: $LibraryPath" } # Create a container to keep files for the VM -Write-Host "Creating a container to keep files for the VM..." -./configure/azure_scripts/create_blob_container.ps1 ` +Write-Output "Creating a container to keep files for the VM..." +$createBlobResponse = ./configure/azure_scripts/create_blob_container.ps1 ` -ResourceGroup $ResourceGroup +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createBlobResponse") +Write-Output $ProcessSeparator # Source the variables from the file -Write-Host "Sourcing the variables from the file..." +Write-Output "`nSourcing the variables from the file..." . ./configure/azure_scripts/config.ps1 # Remove old code if it exists if (Test-Path ./configure.zip) { Remove-Item ./configure.zip -Force -Confirm:$false -ErrorAction SilentlyContinue } else { - Write-Host "File not found." + Write-Output "File not found." } +Write-Output $ProcessSeparator # Zip up the installer scripts for the VM -Write-Host "Zipping up the installer scripts for the VM..." +Write-Output "`nZipping up the installer scripts for the VM..." ./configure/azure_scripts/zip_my_parents_parent.ps1 +Write-Output $ProcessSeparator # Upload the zip file to the container and get a key to download it -Write-Host "Uploading the zip file to the container and getting a key to download it..." +Write-Output "`nUploading the zip file to the container and getting a key to download it..." $FileDownloadUrl = ./configure/azure_scripts/copy_file_to_container.ps1 ` -LocalFilePath "configure.zip" ` -ContainerName $ContainerName ` -StorageAccountName $StorageAccountName ` -StorageAccountKey $StorageAccountKey -Write-Host "File download URL: $FileDownloadUrl" +Write-Output "File download URL: $FileDownloadUrl" +Write-Output $ProcessSeparator -Write-Host "Changing directory to the azure scripts..." +Write-Output "`nChanging directory to the azure scripts..." Set-Location configure/azure_scripts +Write-Output $ProcessSeparator # Make our directory on the VM -Write-Host "Making our directory on the VM..." +Write-Output "`nMaking our directory on the VM..." $createDirResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name $VMName ` --resource-group $ResourceGroup ` --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" - - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") +Write-Output $ProcessSeparator + # Download the zip file to the VM -Write-Host "Downloading the zip file to the VM..." +Write-Output "`nDownloading the zip file to the VM..." $downloadZipFileResponse = .\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") +Write-Output $ProcessSeparator # Extract the zip file -Write-Host "Extracting the zip file..." +Write-Output "`nExtracting the zip file..." $extractArchiveResponse = .\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroup $ResourceGroup ` -FileName "configure.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") +Write-Output $ProcessSeparator # Run the install script for chapter 1 -Write-Host "Running the install script for chapter 1..." +Write-Output "`nRunning the install script for chapter 1..." $installChapter1Response = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\install_chapter_1.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter1Response") +Write-Output $ProcessSeparator # Todo: Loop these for number of vms # Update the group policy on the remote machines -Write-Host "Updating the group policy on the remote machines..." +Write-Output "`nUpdating the group policy on the remote machines..." Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients +Write-Output $ProcessSeparator # Wait for the services to start -Write-Host "Waiting for the services to start..." -Start-Sleep 20 +Write-Output "`nWaiting for the services to start..." +Start-Sleep 10 # See if we can see the forwarding computers in the DC -write-host "Checking if we can see the forwarding computers in the DC..." +write-host "`nChecking if we can see the forwarding computers in the DC..." $listForwardingComputersResponse = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\list_computers_forwarding_events.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$listForwardingComputersResponse") +Write-Output $ProcessSeparator # Install the sysmon service on DC1 from chapter 2 -Write-Host "Installing the sysmon service on DC1 from chapter 2..." +Write-Output "`nInstalling the sysmon service on DC1 from chapter 2..." $installChapter2Response = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\install_chapter_2.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter2Response") +Write-Output $ProcessSeparator # Update the group policy on the remote machines -Write-Host "Updating the group policy on the remote machines..." +Write-Output "`nUpdating the group policy on the remote machines..." Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients +Write-Output $ProcessSeparator # Wait for the services to start -Write-Host "Waiting for the services to start. Generally they don't show..." +Write-Output "`nWaiting for the services to start. Generally they don't show..." Start-Sleep 10 # See if you can see sysmon running on the machine -Write-Host "Seeing if you can see sysmon running on a machine..." +Write-Output "`nSeeing if you can see sysmon running on a machine..." $showSysmonResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name "C1" ` --resource-group $ResourceGroup ` --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") +Write-Output $ProcessSeparator # Download the installers on LS1 -Write-Host "Downloading the installers on LS1..." +Write-Output "`nDownloading the installers on LS1..." $downloadLinuxZipFileResponse = .\download_in_container.ps1 ` -VMName $LinuxVMName ` -ResourceGroup $ResourceGroup ` @@ -143,66 +158,72 @@ $downloadLinuxZipFileResponse = .\download_in_container.ps1 ` -DestinationFilePath "configure.zip" ` -os "linux" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadLinuxZipFileResponse") +Write-Output $ProcessSeparator # Install unzip on LS1 -Write-Host "Installing unzip on LS1..." +Write-Output "`nInstalling unzip on LS1..." $installUnzipResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroup ` --scripts 'apt-get install unzip -y' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installUnzipResponse") +Write-Output $ProcessSeparator # Unzip the file on LS1 -Write-Host "Unzipping the file on LS1..." +Write-Output "`nUnzipping the file on LS1..." $extractLinuxArchiveResponse = .\extract_archive.ps1 ` -VMName $LinuxVMName ` -ResourceGroup $ResourceGroup ` -FileName "configure.zip" ` - -os "linux" + -Os "Linux" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractLinuxArchiveResponse") +Write-Output $ProcessSeparator # Make the installer files executable and update the system packages on LS1 -Write-Host "Making the installer files executable and updating the system packages on LS1..." +Write-Output "`nMaking the installer files executable and updating the system packages on LS1..." $updateLinuxResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroup ` --scripts 'chmod +x /home/admin.ackbar/lme/configure/* && /home/admin.ackbar/lme/configure/linux_update_system.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$updateLinuxResponse") +Write-Output $ProcessSeparator # Run the lme installer on LS1 -Write-Host "Running the lme installer on LS1..." -# Todo: We need to check the output from this and see if we need to reboot -# It should include this line "## logstash_system:" if it completed successfully +Write-Output "`nRunning the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") +Write-Output $ProcessSeparator # Check if the response contains the need to reboot $rebootCheckstring = $installLmeResponse | Out-String if ($rebootCheckstring -match "A reboot is required in order to proceed with the install") { # Have to check for the reboot thing here - Write-Host "Rebooting ${LinuxVMName}..." + Write-Output "`nRebooting ${LinuxVMName}..." az vm restart ` --resource-group $ResourceGroup ` --name $LinuxVMName # Run the lme installer on LS1 - Write-Host "Running the lme installer on LS1..." + Write-Output "`nRunning the lme installer on LS1..." + Write-Output $ProcessSeparator + $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") + Write-Output $ProcessSeparator } # Capture the output of the install script -Write-Host "Capturing the output of the install script for ES passwords..." +Write-Output "`nCapturing the output of the install script for ES passwords..." $getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` @@ -211,27 +232,30 @@ $getElasticsearchPasswordsResponse = az vm run-command invoke ` # Todo: Extract the output and write this to a file for later use Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") +Write-Output $ProcessSeparator # Generate key using expect on linux -Write-Host "Generating key using expect on linux..." +Write-Output "`nGenerating key using expect on linux..." $generateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") +Write-Output $ProcessSeparator # Add the public key to the authorized_keys file on LS1 -Write-Host "Adding the public key to the authorized_keys file on LS1..." +Write-Output "`nAdding the public key to the authorized_keys file on LS1..." $authorizePrivateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_authorize_private_key.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$authorizePrivateKeyResponse") +Write-Output $ProcessSeparator # Cat the private key and capture that to the azure shell -Write-Host "Cat the private key and capture that to the azure shell..." +Write-Output "`nCat the private key and capture that to the azure shell..." $jsonResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` @@ -240,12 +264,13 @@ $jsonResponse = az vm run-command invoke ` $privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" # Save the private key to a file -Write-Host "Saving the private key to a file..." +Write-Output "`nSaving the private key to a file..." $privateKeyPath = ".\id_rsa" Set-Content -Path $privateKeyPath -Value $privateKey +Write-Output $ProcessSeparator # Upload the private key to the container and get a key to download it -Write-Host "Uploading the private key to the container and getting a key to download it..." +Write-Output "`nUploading the private key to the container and getting a key to download it..." $KeyDownloadUrl = ./copy_file_to_container.ps1 ` -LocalFilePath "id_rsa" ` -ContainerName $ContainerName ` @@ -253,52 +278,57 @@ $KeyDownloadUrl = ./copy_file_to_container.ps1 ` -StorageAccountKey $StorageAccountKey # Download the private key to DC1 -Write-Host "Downloading the private key to DC1..." +Write-Output "`nDownloading the private key to DC1..." $downloadPrivateKeyResponse = .\download_in_container.ps1 ` -VMName $VmName ` -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$KeyDownloadUrl" ` -DestinationFilePath "id_rsa" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") +Write-Output $ProcessSeparator # Change the ownership of the private key file on DC1 -Write-Host "Changing the ownership of the private key file on DC1..." +Write-Output "`nChanging the ownership of the private key file on DC1..." $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") +Write-Output $ProcessSeparator # Remove the private key from the local machine Remove-Item -Path $privateKeyPath # Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 -Write-Host "Using the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." +Write-Output "`nUsing the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." $scpResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name $VMName ` --resource-group $ResourceGroup ` --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1.lme.local:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") +Write-Output $ProcessSeparator # Extract the files on DC1 -Write-Host "Extracting the files on DC1..." +Write-Output "`nExtracting the files on DC1..." $extractFilesForWindowsResponse = .\extract_archive.ps1 ` -VMName $VMName ` -ResourceGroup $ResourceGroup ` -FileName "files_for_windows.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") +Write-Output $ProcessSeparator # Install winlogbeat on DC1 -Write-Host "Installing winlogbeat on DC1..." +Write-Output "`nInstalling winlogbeat on DC1..." $installWinlogbeatResponse = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` -VMName $VMName ` -ScriptPathOnVM "C:\lme\configure\winlogbeat_install.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") +Write-Output $ProcessSeparator -Write-Host "Install completed." +Write-Output "`nInstall completed." $EsPasswords = (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut # Output the passwords diff --git a/testing/Readme.md b/testing/Readme.md index 49630c4a..06f3cc83 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -57,16 +57,16 @@ Flags: - NSG: sets NSG to a custom NSG if desired [NSG1 default] ## Install LME on the cluster: -| **#** | **Step** | **Screenshot** | -|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| -| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | -| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | -| 3 | If you have already cloned the LME repo then `cd LME` and run git pull before changing to the testing directory | | -| 3 | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | -| 4 | Now you can run `./InstallTestbed.ps1 --ResourceGroup YourResourceGroup` | | -| 4.a | You can also run the command this way if you want to log to a file. `./InstallTestbed.ps1 -ResourceGroup LME-cbaxley-T2 \| Tee-Object -FilePath "./output.log"` | | -| 5 | Save the login credentials printed to the terminal at the end. *See notes* | | -| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | +| **#** | **Step** | **Screenshot** | +|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| +| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | +| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | +| 3 | If you have already cloned the LME repo then `cd LME` and run git pull before changing to the testing directory | | +| 3 | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | +| 4 | Now you can run `./InstallTestbed.ps1 --ResourceGroup YourResourceGroup` | | +| 4.a | You can also run the command this way if you want to log to a file. `./InstallTestbed.ps1 -ResourceGroup YourResourceGroup \| Tee-Object -FilePath "./output.log"` | | +| 5 | Save the login credentials printed to the terminal at the end. *See notes* | | +| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | Note: When the script finishes you will be in the azure_scripts directory, and you should see the elasticsearch credentials printed to the terminal. You will need to `cd ../../` to get back to the LME directory. All the passwords should be in the `<$ResourceGroup>.password.txt` file. diff --git a/testing/configure/azure_scripts/create_blob_container.ps1 b/testing/configure/azure_scripts/create_blob_container.ps1 index f3bab04d..32eaf9ff 100644 --- a/testing/configure/azure_scripts/create_blob_container.ps1 +++ b/testing/configure/azure_scripts/create_blob_container.ps1 @@ -77,9 +77,9 @@ az storage container create ` --account-key $StorageAccountKey # Output the created resources' details -Write-Host "Created Storage Account: $StorageAccountName" -Write-Host "StorageAccountKey: $StorageAccountKey" -Write-Host "Created Container: $ContainerName" +Write-Output "Created Storage Account: $StorageAccountName" +Write-Output "StorageAccountKey: $StorageAccountKey" +Write-Output "Created Container: $ContainerName" # Define the file path in the same directory as the running script $filePath = Join-Path -Path $PSScriptRoot -ChildPath "config.ps1" diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index c4984030..ada6d5b5 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -17,10 +17,10 @@ The URL of the file to be downloaded. .PARAMETER DestinationFilePath The complete path where the file should be downloaded on the VM. This path is processed to extract just the filename. -.PARAMETER username +.PARAMETER UserName The username for the VM, used in constructing the file path for Linux systems. Default is 'admin.ackbar'. -.PARAMETER os +.PARAMETER Os The operating system type of the VM. Accepts 'Windows', 'Linux', or 'linux'. Default is 'Windows'. .EXAMPLE @@ -28,7 +28,9 @@ The operating system type of the VM. Accepts 'Windows', 'Linux', or 'linux'. Def -VMName "MyVM" ` -ResourceGroup "MyResourceGroup" ` -FileDownloadUrl "http://example.com/file.zip" ` - -DestinationFilePath "C:\path\to\file.zip" + -DestinationFilePath "C:\path\to\file.zip" ` + -UserName "admin.ackbar" ` + -Os "Windows" ` This example downloads a file from 'http://example.com/file.zip' to 'C:\path\to\file.zip' on the VM named 'MyVM' in the 'MyResourceGroup'. @@ -36,8 +38,6 @@ This example downloads a file from 'http://example.com/file.zip' to 'C:\path\to\ .NOTES - Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. - The specified script must exist on the VM and the VM should have the necessary permissions to execute it. - - #> #> param( @@ -54,25 +54,26 @@ param( [string]$DestinationFilePath, # This will be stripped to only the filename [Parameter()] - [string]$username = "admin.ackbar", + [string]$UserName = "admin.ackbar", [Parameter()] [ValidateSet("Windows","Linux","linux")] - [string]$os = "Windows" + [string]$Os = "Windows" ) # Convert the OS parameter to lowercase for consistent comparison -$os = $os.ToLower() +$Os = $Os.ToLower() # Extract just the filename from the destination file path $DestinationFileName = Split-Path -Leaf $DestinationFilePath # Set the destination path depending on the OS -if ($os -eq "linux") { - $DestinationPath = "/home/$username/lme/$DestinationFileName" +if ($Os -eq "linux") { + $DestinationPath = "/home/$UserName/lme/$DestinationFileName" # Create the lme directory if it doesn't exist - $DirectoryCreationScript = "mkdir -p '/home/$username/lme'" - # We don't want to output this until we fix it so we can put all of the output from thw whole script into one json object + $DirectoryCreationScript = "mkdir -p '/home/$UserName/lme'" + # TODO: We don't want to output this until we fix it so we can put all of the output from thw whole script into one json object + # We are just ignoring the output for now $CreateDirectoryResponse = az vm run-command invoke ` --command-id RunShellScript ` --resource-group $ResourceGroup ` @@ -83,14 +84,14 @@ if ($os -eq "linux") { } # The download script -$DownloadScript = if ($os -eq "linux") { +$DownloadScript = if ($Os -eq "linux") { "curl -o '$DestinationPath' '$FileDownloadUrl'" } else { "Invoke-WebRequest -Uri '$FileDownloadUrl' -OutFile '$DestinationPath'" } # Execute the download script with the appropriate command based on OS -if ($os -eq "linux") { +if ($Os -eq "linux") { az vm run-command invoke ` --command-id RunShellScript ` --resource-group $ResourceGroup ` diff --git a/testing/configure/azure_scripts/extract_archive.ps1 b/testing/configure/azure_scripts/extract_archive.ps1 index b4e7bce0..a5aa13d0 100644 --- a/testing/configure/azure_scripts/extract_archive.ps1 +++ b/testing/configure/azure_scripts/extract_archive.ps1 @@ -17,7 +17,12 @@ The name of the Azure Resource Group that contains the VM. The name (and optional path) of the zip file to be unzipped. .EXAMPLE -.\extract_archive.ps1 -VMName "DC1" -ResourceGroup "YourResourceGroupName" -Filename "filename.zip" +.\extract_archive.ps1 ` + -VMName "DC1" ` + -ResourceGroup "YourResourceGroupName" ` + -Filename "filename.zip" ` + -UserName "admin.ackbar" ` + -Os "Windows" This example unzips 'filename.zip' from the 'Downloads' directory of the user 'username' on the VM "DC1" in the resource group "YourResourceGroupName", and extracts it to a subdirectory named 'filename'. @@ -37,24 +42,24 @@ param( [string]$Filename, [Parameter()] - [string]$username = "admin.ackbar", + [string]$UserName = "admin.ackbar", [Parameter()] [ValidateSet("Windows","Linux","linux")] - [string]$os = "Windows" + [string]$Os = "Windows" ) # Convert the OS parameter to lowercase for consistent comparison -$os = $os.ToLower() +$Os = $Os.ToLower() # Extract just the filename (ignoring any provided path) $JustFilename = Split-Path -Leaf $Filename # Set paths depending on the OS -if ($os -eq "linux") { - $ZipFilePath = "/home/$username/lme/$JustFilename" +if ($Os -eq "linux") { + $ZipFilePath = "/home/$UserName/lme/$JustFilename" $FileBaseName = [System.IO.Path]::GetFileNameWithoutExtension($JustFilename) - $ExtractToPath = "/home/$username/lme/$FileBaseName" # Extract to a subdirectory + $ExtractToPath = "/home/$UserName/lme/$FileBaseName" # Extract to a subdirectory $UnzipScript = @" unzip '$ZipFilePath' -d '$ExtractToPath' @@ -70,7 +75,7 @@ if ($os -eq "linux") { } # Execute the unzip script with the appropriate command based on OS -if ($os -eq "linux") { +if ($Os -eq "linux") { az vm run-command invoke ` --command-id RunShellScript ` --resource-group $ResourceGroup ` diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index b83e72b2..af835503 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -8,14 +8,14 @@ function Format-AzVmRunCommandOutput { try { $responseObj = $JsonResponse | ConvertFrom-Json -# Write-Host "Converted JSON object: $responseObj" +# Write-Output "Converted JSON object: $responseObj" if ($responseObj -and $responseObj.value) { $stdout = "" $stderr = "" foreach ($item in $responseObj.value) { -# Write-Host "Processing item: $($item.code)" +# Write-Output "Processing item: $($item.code)" # Check for StdOut and StdErr if ($item.code -like "ComponentStatus/StdOut/*") { @@ -40,7 +40,7 @@ function Format-AzVmRunCommandOutput { } } catch { $errorMessage = $_.Exception.Message - Write-Host "Error: $errorMessage" + Write-Output "Error: $errorMessage" $results += New-Object PSObject -Property @{ StdOut = "Error: $errorMessage" StdErr = "" @@ -66,17 +66,17 @@ function Show-FormattedOutput { foreach ($item in $FormattedOutput) { if ($item -is [string]) { # Handle string messages (like error or informational messages) - Write-Host $item + Write-Output $item } elseif ($item -is [PSCustomObject]) { # Handle custom objects with StdOut and StdErr if (![string]::IsNullOrWhiteSpace($item.StdOut)) { - Write-Host "Output (stdout):" - Write-Host $item.StdOut + Write-Output "Output (stdout):" + Write-Output $item.StdOut } if (![string]::IsNullOrWhiteSpace($item.StdErr)) { - Write-Host "Error (stderr):" - Write-Host $item.StdErr + Write-Output "Error (stderr):" + Write-Output $item.StdErr } } } diff --git a/testing/configure/azure_scripts/run_script_in_container.ps1 b/testing/configure/azure_scripts/run_script_in_container.ps1 index b247dbeb..1819c8ad 100644 --- a/testing/configure/azure_scripts/run_script_in_container.ps1 +++ b/testing/configure/azure_scripts/run_script_in_container.ps1 @@ -21,9 +21,14 @@ The full path of the PowerShell script on the Azure VM that needs to be executed A string of arguments that will be passed to the script. .EXAMPLE -.\run_script_in_container.ps1 -ResourceGroup "YourResourceGroupName" -VMName "VMName" -ScriptPathOnVM "C:\path\to\your\script.ps1" -ScriptArguments "-Arg1 value1 -Arg2 value2" - -This example executes a script located at 'C:\path\to\your\script.ps1' on the VM named "VMName" in the resource group "YourResourceGroupName", passing it the arguments "-Arg1 value1 -Arg2 value2". +.\run_script_in_container.ps1 ` + -ResourceGroup "YourResourceGroupName" ` + -VMName "VMName" ` + -ScriptPathOnVM "C:\path\to\your\script.ps1" ` + -ScriptArguments "-Arg1 value1 -Arg2 value2" + +This example executes a script located at 'C:\path\to\your\script.ps1' on the VM named "VMName" + in the resource group "YourResourceGroup", passing it the arguments "-Arg1 value1 -Arg2 value2". .NOTES - Ensure that the Azure CLI is installed and configured with the necessary permissions to access and run commands on the specified Azure VM. diff --git a/testing/configure/chown_dc1_private_key.ps1 b/testing/configure/chown_dc1_private_key.ps1 index e8a8fece..77aa76f3 100644 --- a/testing/configure/chown_dc1_private_key.ps1 +++ b/testing/configure/chown_dc1_private_key.ps1 @@ -1,21 +1,21 @@ # Path to the private key -$privateKeyPath = "C:\lme\id_rsa" +$PrivateKeyPath = "C:\lme\id_rsa" # Define the SYSTEM account -$systemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM") +$SystemAccount = New-Object System.Security.Principal.NTAccount("NT AUTHORITY", "SYSTEM") # Get the current ACL of the file -$acl = Get-Acl -Path $privateKeyPath +$Acl = Get-Acl -Path $PrivateKeyPath # Clear any existing Access Rules -$acl.SetAccessRuleProtection($true, $false) -$acl.Access | ForEach-Object { $acl.RemoveAccessRule($_) | Out-Null } +$Acl.SetAccessRuleProtection($true, $false) +$Acl.Access | ForEach-Object { $Acl.RemoveAccessRule($_) | Out-Null } # Create a new Access Rule granting FullControl to SYSTEM -$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($systemAccount, "FullControl", "Allow") +$accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($SystemAccount, "FullControl", "Allow") # Add the Access Rule to the ACL -$acl.AddAccessRule($accessRule) +$Acl.AddAccessRule($accessRule) # Set the updated ACL back to the file -Set-Acl -Path $privateKeyPath -AclObject $acl +Set-Acl -Path $PrivateKeyPath -AclObject $Acl diff --git a/testing/configure/create_lme_directory.ps1 b/testing/configure/create_lme_directory.ps1 index 8bef9b66..3a4bf5ed 100644 --- a/testing/configure/create_lme_directory.ps1 +++ b/testing/configure/create_lme_directory.ps1 @@ -1,16 +1,18 @@ # Define the directory path -$directoryPath = "C:\lme" +param( + [string]$DirectoryPath = "C:\lme" +) # Create the directory if it doesn't already exist -if (-not (Test-Path -Path $directoryPath)) { - New-Item -Path $directoryPath -ItemType Directory +if (-not (Test-Path -Path $DirectoryPath)) { + New-Item -Path $DirectoryPath -ItemType Directory } # Define the security principal for 'All Users' $allUsers = New-Object System.Security.Principal.SecurityIdentifier("S-1-1-0") # Get the current ACL of the directory -$acl = Get-Acl -Path $directoryPath +$acl = Get-Acl -Path $DirectoryPath # Define the rights (read and execute) $rights = [System.Security.AccessControl.FileSystemRights]::ReadAndExecute @@ -22,4 +24,4 @@ $accessRule = New-Object System.Security.AccessControl.FileSystemAccessRule($all $acl.AddAccessRule($accessRule) # Set the ACL back to the directory -Set-Acl -Path $directoryPath -AclObject $acl +Set-Acl -Path $DirectoryPath -AclObject $acl diff --git a/testing/configure/create_ou.ps1 b/testing/configure/create_ou.ps1 index 2407cd46..5b546f3c 100644 --- a/testing/configure/create_ou.ps1 +++ b/testing/configure/create_ou.ps1 @@ -6,8 +6,8 @@ param( Import-Module ActiveDirectory # Split the domain into parts and construct the ParentContainerDN -$domainParts = $Domain -split "\." -$ParentContainerDN = ($domainParts | ForEach-Object { "DC=$_" }) -join "," +$DomainParts = $Domain -split "\." +$ParentContainerDN = ($DomainParts | ForEach-Object { "DC=$_" }) -join "," # Define the distinguished name (DN) for the new OU @@ -17,7 +17,7 @@ $NewOUDN = "OU=$ClientOUCustomName,$ParentContainerDN" if (-not (Get-ADOrganizationalUnit -Filter "DistinguishedName -eq '$NewOUDN'" -ErrorAction SilentlyContinue)) { # Create the new OU New-ADOrganizationalUnit -Name $ClientOUCustomName -Path $ParentContainerDN - Write-Host "Organizational Unit '$ClientOUCustomName' created successfully under $ParentContainerDN." + Write-Output "Organizational Unit '$ClientOUCustomName' created successfully under $ParentContainerDN." } else { - Write-Host "Organizational Unit '$ClientOUCustomName' already exists under $ParentContainerDN." + Write-Output "Organizational Unit '$ClientOUCustomName' already exists under $ParentContainerDN." } diff --git a/testing/configure/download_files.ps1 b/testing/configure/download_files.ps1 index 84cd8626..1bc6588e 100644 --- a/testing/configure/download_files.ps1 +++ b/testing/configure/download_files.ps1 @@ -1,20 +1,20 @@ param( - [string]$directory = $env:USERPROFILE + [string]$Directory = $env:USERPROFILE ) # Base directory path - use provided username or default to USERPROFILE -$baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { - "C:\$directory" +$BaseDirectoryPath = if ($Directory -and ($Directory -ne $env:USERPROFILE)) { + "C:\$Directory" } else { "$env:USERPROFILE\Downloads\" } # Todo: Allow for downloading a version by adding a parameter for the version number -$apiUrl = "https://api.github.com/repos/cisagov/LME/releases/latest" -$latestRelease = Invoke-RestMethod -Uri $apiUrl +$ApiUrl = "https://api.github.com/repos/cisagov/LME/releases/latest" +$latestRelease = Invoke-RestMethod -Uri $ApiUrl $zipFileUrl = $latestRelease.assets | Where-Object { $_.content_type -eq 'application/zip' } | Select-Object -ExpandProperty browser_download_url -$downloadPath = "$baseDirectoryPath\" + $latestRelease.name + ".zip" -$extractPath = "$baseDirectoryPath\LME" +$downloadPath = "$BaseDirectoryPath\" + $latestRelease.name + ".zip" +$extractPath = "$BaseDirectoryPath\LME" Invoke-WebRequest -Uri $zipFileUrl -OutFile $downloadPath if (-not (Test-Path -Path $extractPath)) { diff --git a/testing/configure/install_chapter_1.ps1 b/testing/configure/install_chapter_1.ps1 index 76661530..ee16a0a4 100644 --- a/testing/configure/install_chapter_1.ps1 +++ b/testing/configure/install_chapter_1.ps1 @@ -2,30 +2,64 @@ param ( [Parameter( HelpMessage="Path to the configuration directory. Default is 'C:\lme\configure'." )] - [string]$configurePath = "C:\lme\configure" + [string]$ConfigurePath = "C:\lme\configure", + [Parameter( + HelpMessage="Path to the root install directory. Default is 'C:\lme'." + )] + [string]$RootInstallDir = "C:\lme" + ) # Exit the script on any error $ErrorActionPreference = 'Stop' +$ProcessSeparator = "`n----------------------------------------`n" # Change directory to the configure directory -Set-Location -Path $configurePath +Set-Location -Path $ConfigurePath # Run the scripts and check for failure -.\create_lme_directory.ps1 -.\download_files.ps1 -directory lme -.\wec_import_gpo.ps1 -directory lme +Write-Output "Creating the configurePath directory..." +.\create_lme_directory.ps1 -DirectoryPath $RootInstallDir +Write-Output $ProcessSeparator + +Write-Output "Downloading the files..." +.\download_files.ps1 -Directory lme +Write-Output $ProcessSeparator + +Write-Output "Importing the GPOs..." +.\wec_import_gpo.ps1 -Directory lme +Write-Output $ProcessSeparator + Start-Sleep 10 +Write-Output "Updating the GPO server name..." .\wec_gpo_update_server_name.ps1 +Write-Output $ProcessSeparator + +Write-Output "Creating the OU..." .\create_ou.ps1 +Write-Output $ProcessSeparator + +Write-Output "Linking the GPOs..." .\wec_link_gpo.ps1 +Write-Output $ProcessSeparator + +Write-Output "Provisioning the WEC service..." .\wec_service_provisioner.ps1 +Write-Output $ProcessSeparator # Run the wevtutil and wecutil commands -Write-Host "Running wevtutil and wecutil commands to start the wec service manually..." +Write-Output "Running wevtutil and wecutil commands to start the wec service manually..." wevtutil set-log ForwardedEvents /q:true /e:true +Write-Output $ProcessSeparator + +Write-Output "Running wecutil restart command..." wecutil rs lme +Write-Output $ProcessSeparator + +Write-Output "Running wecutil gr command..." wecutil gr lme +Write-Output $ProcessSeparator # Run the move_computers_to_ou script +Write-Output "Moving the computers to the OU..." .\move_computers_to_ou.ps1 diff --git a/testing/configure/install_chapter_2.ps1 b/testing/configure/install_chapter_2.ps1 index 9d5fa89a..d85a9d6b 100644 --- a/testing/configure/install_chapter_2.ps1 +++ b/testing/configure/install_chapter_2.ps1 @@ -2,17 +2,27 @@ param ( [Parameter( HelpMessage="Path to the configuration directory. Default is 'C:\lme\configure'." )] - [string]$configurePath = "C:\lme\configure" + [string]$ConfigurePath = "C:\lme\configure" ) # Exit the script on any error $ErrorActionPreference = 'Stop' +$ProcessSeparator = "`n----------------------------------------`n" # Change directory to the configure directory -Set-Location -Path $configurePath +Set-Location -Path $ConfigurePath -# Run the sysmon install scripts +Write-Output "Installing Sysmon..." .\sysmon_install_in_sysvol.ps1 -.\sysmon_import_gpo.ps1 -directory lme +Write-Output $ProcessSeparator + +Write-Output "Importing the gpo..." +.\sysmon_import_gpo.ps1 -Directory lme +Write-Output $ProcessSeparator + +Write-Output "Updating the gpo variables.." .\sysmon_gpo_update_vars.ps1 +Write-Output $ProcessSeparator + +Write-Output "Linking the gpo..." .\sysmon_link_gpo.ps1 diff --git a/testing/configure/list_computers_forwarding_events.ps1 b/testing/configure/list_computers_forwarding_events.ps1 index 4233270d..ecf8ff3a 100644 --- a/testing/configure/list_computers_forwarding_events.ps1 +++ b/testing/configure/list_computers_forwarding_events.ps1 @@ -23,5 +23,5 @@ foreach ($line in $lines) { } # Display the active computer names -Write-Host "Active Computers Forwarding Events:" -$activeComputers | ForEach-Object { Write-Host $_ } +Write-Output "Active Computers Forwarding Events:" +$activeComputers | ForEach-Object { Write-Output $_ } diff --git a/testing/configure/move_computers_to_ou.ps1 b/testing/configure/move_computers_to_ou.ps1 index d65322ac..4ef36c49 100644 --- a/testing/configure/move_computers_to_ou.ps1 +++ b/testing/configure/move_computers_to_ou.ps1 @@ -20,8 +20,8 @@ $computersContainerDN = "CN=$CurrentCN,$domainDN" $targetOUDN = "OU=$ClientOUCustomName,$domainDN" # Output the DNs for verification -Write-Host "Current Computers Container DN: $computersContainerDN" -Write-Host "Target OU DN: $targetOUDN" +Write-Output "Current Computers Container DN: $computersContainerDN" +Write-Output "Target OU DN: $targetOUDN" # Get the computer accounts in the Computers container $computers = Get-ADComputer -Filter * -SearchBase $computersContainerDN @@ -31,8 +31,8 @@ foreach ($computer in $computers) { try { # Move the computer to the target OU Move-ADObject -Identity $computer.DistinguishedName -TargetPath $targetOUDN - Write-Host "Moved $($computer.Name) to $targetOUDN" + Write-Output "Moved $($computer.Name) to $targetOUDN" } catch { - Write-Host "Failed to move $($computer.Name): $_" + Write-Output "Failed to move $($computer.Name): $_" } } \ No newline at end of file diff --git a/testing/configure/sysmon_gpo_update_vars.ps1 b/testing/configure/sysmon_gpo_update_vars.ps1 index b76fbeda..9707039a 100644 --- a/testing/configure/sysmon_gpo_update_vars.ps1 +++ b/testing/configure/sysmon_gpo_update_vars.ps1 @@ -1,17 +1,17 @@ param( - [string]$gpoName = "LME-Sysmon-Task", - [string]$domainName = "lme.local" + [string]$GpoName = "LME-Sysmon-Task", + [string]$DomainName = "lme.local" ) # Get the FQDN of the current server $fqdn = [System.Net.Dns]::GetHostByName($env:COMPUTERNAME).HostName # Get the GPO object -$gpo = Get-GPO -Name $gpoName +$gpo = Get-GPO -Name $GpoName # Check if GPO is found if ($null -eq $gpo) { - Write-Host "GPO not found" + Write-Output "GPO not found" exit } @@ -19,7 +19,7 @@ if ($null -eq $gpo) { $gpoGuid = $gpo.Id # Define the path to the XML file -$xmlFilePath = "C:\Windows\SYSVOL\sysvol\$domainName\Policies\{$gpoGuid}\Machine\Preferences\ScheduledTasks\ScheduledTasks.xml" +$xmlFilePath = "C:\Windows\SYSVOL\sysvol\$DomainName\Policies\{$gpoGuid}\Machine\Preferences\ScheduledTasks\ScheduledTasks.xml" # Get current time and add 5 minutes $newStartTime = (Get-Date).AddMinutes(5).ToString("yyyy-MM-ddTHH:mm:ss") @@ -34,10 +34,10 @@ $task = $xml.ScheduledTasks.TaskV2 | Where-Object { $_.Properties.name -eq "LME- $task.Properties.Task.Triggers.CalendarTrigger.StartBoundary = $newStartTime # Update the command path -$task.Properties.Task.Actions.Exec.Command = "\\$fqdn\sysvol\$domainName\LME\Sysmon\update.bat" +$task.Properties.Task.Actions.Exec.Command = "\\$fqdn\sysvol\$DomainName\LME\Sysmon\update.bat" # Save the modified XML back to the file $xml.Save($xmlFilePath) # Output the new start time for verification -Write-Host "New start time set to: $newStartTime" \ No newline at end of file +Write-Output "New start time set to: $newStartTime" \ No newline at end of file diff --git a/testing/configure/sysmon_import_gpo.ps1 b/testing/configure/sysmon_import_gpo.ps1 index e8e95519..2f3eb109 100644 --- a/testing/configure/sysmon_import_gpo.ps1 +++ b/testing/configure/sysmon_import_gpo.ps1 @@ -1,10 +1,10 @@ param( - [string]$directory = $env:USERPROFILE + [string]$Directory = $env:USERPROFILE ) # Determine the base directory path based on the provided username -$baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { - "C:\$directory" +$baseDirectoryPath = if ($Directory -and ($Directory -ne $env:USERPROFILE)) { + "C:\$Directory" } else { "$env:USERPROFILE\Downloads" } @@ -17,18 +17,18 @@ foreach ($gpoName in $gpoNames) { $gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue if (-not $gpo) { New-GPO -Name $gpoName | Out-Null - Write-Host "Created GPO: $gpoName" + Write-Output "Created GPO: $gpoName" } else { - Write-Host "GPO $gpoName already exists." + Write-Output "GPO $gpoName already exists." } try { Import-GPO -BackupGpoName $gpoName -TargetName $gpoName -Path $GPOBackupPath -CreateIfNeeded -ErrorAction Stop - Write-Host "Imported settings into GPO: $gpoName" + Write-Output "Imported settings into GPO: $gpoName" } catch { Throw "Failed to import GPO: $gpoName. The GPODisplayName in bkupinfo.xml may not match or other import error occurred." } } -Write-Host "LME Sysmon GPOs have been created and imported successfully." +Write-Output "LME Sysmon GPOs have been created and imported successfully." diff --git a/testing/configure/sysmon_link_gpo.ps1 b/testing/configure/sysmon_link_gpo.ps1 index 1cbb0450..a29aa9eb 100644 --- a/testing/configure/sysmon_link_gpo.ps1 +++ b/testing/configure/sysmon_link_gpo.ps1 @@ -12,7 +12,7 @@ $GPOName = "LME-Sysmon-Task" try { New-GPLink -Name $GPOName -Target $OUDistinguishedName - Write-Host "GPO '$GPOName' linked to OU '$ClientOUCustomName'." + Write-Output "GPO '$GPOName' linked to OU '$ClientOUCustomName'." } catch { - Write-Host "Error linking GPO '$GPOName' to OU '$ClientOUCustomName': $_" + Write-Output "Error linking GPO '$GPOName' to OU '$ClientOUCustomName': $_" } diff --git a/testing/configure/trust_ls1_ssh_key.ps1 b/testing/configure/trust_ls1_ssh_key.ps1 index 3bfaa327..0f3d0a41 100644 --- a/testing/configure/trust_ls1_ssh_key.ps1 +++ b/testing/configure/trust_ls1_ssh_key.ps1 @@ -1,13 +1,13 @@ param ( - [string]$sshHost = "ls1" + [string]$SshHost = "ls1" ) -$sshDirectory = "C:\Windows\System32\config\systemprofile\.ssh" -$knownHostsFile = Join-Path -Path $sshDirectory -ChildPath "known_hosts" +$SshDirectory = "C:\Windows\System32\config\systemprofile\.ssh" +$KnownHostsFile = Join-Path -Path $SshDirectory -ChildPath "known_hosts" # Ensure the .ssh directory exists -if (-not (Test-Path -Path $sshDirectory)) { - New-Item -ItemType Directory -Path $sshDirectory +if (-not (Test-Path -Path $SshDirectory)) { + New-Item -ItemType Directory -Path $SshDirectory } # Function to set ACL for the directory, granting FullControl to SYSTEM and applying inheritance @@ -49,18 +49,18 @@ function Set-SystemOnlyAclForFile { } # Set ACL for the .ssh directory with inheritance -Set-SystemOnlyAclForDirectory -path $sshDirectory +Set-SystemOnlyAclForDirectory -path $SshDirectory # Ensure the known_hosts file exists -if (-not (Test-Path -Path $knownHostsFile)) { - New-Item -ItemType File -Path $knownHostsFile +if (-not (Test-Path -Path $KnownHostsFile)) { + New-Item -ItemType File -Path $KnownHostsFile } # Set ACL for the known_hosts file without inheritance -Set-SystemOnlyAclForFile -path $knownHostsFile +Set-SystemOnlyAclForFile -path $KnownHostsFile # Run ssh-keyscan and append output to known_hosts -ssh-keyscan $sshHost | Out-File -FilePath $knownHostsFile -Append -Encoding UTF8 +ssh-keyscan $SshHost | Out-File -FilePath $KnownHostsFile -Append -Encoding UTF8 # Output the contents of the known_hosts file -Get-Content -Path $knownHostsFile +Get-Content -Path $KnownHostsFile diff --git a/testing/configure/wec_firewall.ps1 b/testing/configure/wec_firewall.ps1 index a148fa89..3e3bb129 100644 --- a/testing/configure/wec_firewall.ps1 +++ b/testing/configure/wec_firewall.ps1 @@ -1,16 +1,18 @@ # Asks user to provide subnet - then creates a inbound allow firewall rule for 5985. Run on WEC server. +param ( + [string]$InboundRuleName = "WinRM TCP In 5985", + [string]$ClientSubnet = "10.1.0.0/24", + [string]$LocalPort = "5985" +) -$inboundRuleName = "WinRM TCP In 5985" -$clientSubnet = Read-Host "Enter your subnet (e.g., 10.1.0.0/24)" - -if (-not (Get-NetFirewallRule -Name $inboundRuleName -ErrorAction SilentlyContinue)) { - New-NetFirewallRule -DisplayName $inboundRuleName ` +if (-not (Get-NetFirewallRule -Name $InboundRuleName -ErrorAction SilentlyContinue)) { + New-NetFirewallRule -DisplayName $InboundRuleName ` -Direction Inbound -Protocol TCP ` - -LocalPort 5985 -Action Allow ` - -RemoteAddress $clientSubnet ` - -Description "Allow inbound TCP 5985 for WinRM from clients subnet" + -LocalPort $LocalPort -Action Allow ` + -RemoteAddress $ClientSubnet ` + -Description "Allow inbound TCP ${LocalPort} for WinRM from clients subnet" } else { - Write-Host "Inbound rule '$inboundRuleName' already exists." + Write-Output "Inbound rule '$InboundRuleName' already exists." } -Write-Host "Inbound WinRM rule has been configured." +Write-Output "Inbound WinRM rule has been configured." diff --git a/testing/configure/wec_gpo_update_server_name.ps1 b/testing/configure/wec_gpo_update_server_name.ps1 index 49006b1f..6557042b 100644 --- a/testing/configure/wec_gpo_update_server_name.ps1 +++ b/testing/configure/wec_gpo_update_server_name.ps1 @@ -19,24 +19,24 @@ The protocol for the Subscription Manager URL. Default is 'http'. Executes the script with default parameters. .EXAMPLE -.\wec_gpo_update_server_name.ps1 -domain "customdomain.local" -port 1234 -protocol "https" +.\wec_gpo_update_server_name.ps1 -Domain "customdomain.local" -Port 1234 -Protocol "https" Executes the script with custom domain, port, and protocol. #> param( - [string]$domain = "dc1.lme.local", - [int]$port = 5985, - [string]$protocol = "http" + [string]$Domain = "dc1.lme.local", + [int]$Port = 5985, + [string]$Protocol = "http" ) # Construct the Subscription Manager URL using the provided parameters -$subscriptionManagerUrl = "Server=${protocol}://${domain}:${port}/wsman/SubscriptionManager/WEC,Refresh=60" +$subscriptionManagerUrl = "Server=${Protocol}://${Domain}:${Port}/wsman/SubscriptionManager/WEC,Refresh=60" Set-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" -Value $subscriptionManagerUrl -Type String # To get the GP registry value to confirm it's set $registryValue = Get-GPRegistryValue -Name "LME-WEC-Client" -Key "HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\EventLog\EventForwarding\SubscriptionManager" # Output the retrieved registry value -Write-Host "Set the subscription manager url value to: " +Write-Output "Set the subscription manager url value to: " $registryValue diff --git a/testing/configure/wec_import_gpo.ps1 b/testing/configure/wec_import_gpo.ps1 index 2830ecda..8906ce2d 100644 --- a/testing/configure/wec_import_gpo.ps1 +++ b/testing/configure/wec_import_gpo.ps1 @@ -1,34 +1,34 @@ param( - [string]$directory = $env:USERPROFILE + [string]$Directory = $env:USERPROFILE ) # Determine the base directory path based on the provided username -$baseDirectoryPath = if ($directory -and ($directory -ne $env:USERPROFILE)) { - "C:\$directory" +$BaseDirectoryPath = if ($Directory -and ($Directory -ne $env:USERPROFILE)) { + "C:\$Directory" } else { "$env:USERPROFILE\Downloads" } -$GPOBackupPath = "$baseDirectoryPath\LME\Chapter 1 Files\Group Policy Objects" +$GPOBackupPath = "$BaseDirectoryPath\LME\Chapter 1 Files\Group Policy Objects" -$gpoNames = @("LME-WEC-Client", "LME-WEC-Server") +$GpoNames = @("LME-WEC-Client", "LME-WEC-Server") -foreach ($gpoName in $gpoNames) { +foreach ($gpoName in $GpoNames) { $gpo = Get-GPO -Name $gpoName -ErrorAction SilentlyContinue if (-not $gpo) { New-GPO -Name $gpoName | Out-Null - Write-Host "Created GPO: $gpoName" + Write-Output "Created GPO: $gpoName" } else { - Write-Host "GPO $gpoName already exists." + Write-Output "GPO $gpoName already exists." } try { Import-GPO -BackupGpoName $gpoName -TargetName $gpoName -Path $GPOBackupPath -CreateIfNeeded -ErrorAction Stop - Write-Host "Imported settings into GPO: $gpoName" + Write-Output "Imported settings into GPO: $gpoName" } catch { Throw "Failed to import GPO: $gpoName. The GPODisplayName in bkupinfo.xml may not match or other import error occurred." } } -Write-Host "LME GPOs have been created and imported successfully." +Write-Output "LME GPOs have been created and imported successfully." diff --git a/testing/configure/wec_link_gpo.ps1 b/testing/configure/wec_link_gpo.ps1 index f78e4584..3c8c4921 100644 --- a/testing/configure/wec_link_gpo.ps1 +++ b/testing/configure/wec_link_gpo.ps1 @@ -14,14 +14,14 @@ $ServerOUDistinguishedName = "OU=Domain Controllers,$DomainDN" try { New-GPLink -Name $GPONameClient -Target $ClientOUDistinguishedName - Write-Host "GPO '$GPONameClient' linked to OU '$ClientOUCustomName'." + Write-Output "GPO '$GPONameClient' linked to OU '$ClientOUCustomName'." } catch { - Write-Host "Error linking GPO '$GPONameClient' to OU '$ClientOUCustomName': $_" + Write-Output "Error linking GPO '$GPONameClient' to OU '$ClientOUCustomName': $_" } try { New-GPLink -Name $GPONameServer -Target $ServerOUDistinguishedName - Write-Host "GPO '$GPONameServer' linked to OU 'Domain Controllers'." + Write-Output "GPO '$GPONameServer' linked to OU 'Domain Controllers'." } catch { - Write-Host "Error linking GPO '$GPONameServer' to OU 'Domain Controllers': $_" + Write-Output "Error linking GPO '$GPONameServer' to OU 'Domain Controllers': $_" } diff --git a/testing/configure/wec_service_provisioner.ps1 b/testing/configure/wec_service_provisioner.ps1 index 81fd348b..4c0d1302 100644 --- a/testing/configure/wec_service_provisioner.ps1 +++ b/testing/configure/wec_service_provisioner.ps1 @@ -1,24 +1,24 @@ # PowerShell script to configure Windows Event Collector param( - [string]$xmlFilePath = "C:\lme\LME\Chapter 1 Files\lme_wec_config.xml" + [string]$XmlFilePath = "C:\lme\LME\Chapter 1 Files\lme_wec_config.xml" ) # Check if Windows Event Collector Service is running and start it if not $wecService = Get-Service -Name "Wecsvc" if ($wecService.Status -ne 'Running') { Start-Service -Name "Wecsvc" - Write-Host "Windows Event Collector Service started." + Write-Output "Windows Event Collector Service started." } else { - Write-Host "Windows Event Collector Service is already running." + Write-Output "Windows Event Collector Service is already running." } # Check if the XML configuration file exists -if (Test-Path -Path $xmlFilePath) { +if (Test-Path -Path $XmlFilePath) { # Run the wecutil command to configure the collector - wecutil cs $xmlFilePath - Write-Host "wecutil command executed successfully with config file: $xmlFilePath" + wecutil cs $XmlFilePath + Write-Output "wecutil command executed successfully with config file: $XmlFilePath" } else { - Write-Host "Configuration file not found at $xmlFilePath" + Write-Output "Configuration file not found at $XmlFilePath" } diff --git a/testing/configure/wec_start_service.ps1 b/testing/configure/wec_start_service.ps1 index 9ed7815e..7677185c 100644 --- a/testing/configure/wec_start_service.ps1 +++ b/testing/configure/wec_start_service.ps1 @@ -2,18 +2,18 @@ try { Start-Service -Name "Wecsvc" - Write-Host "WEC service started successfully." + Write-Output "WEC service started successfully." } catch { - Write-Host "Failed to start WEC service: $_" + Write-Output "Failed to start WEC service: $_" } $ConfigFilePath = "$env:USERPROFILE\Downloads\LME\Chapter 1 Files\lme_wec_config.xml" try { Start-Process -FilePath "wecutil.exe" -ArgumentList "cs `"$ConfigFilePath`"" -Verb RunAs - Write-Host "wecutil command executed successfully." + Write-Output "wecutil command executed successfully." } catch { - Write-Host "Failed to execute wecutil command: $_" + Write-Output "Failed to execute wecutil command: $_" } diff --git a/testing/configure/winlogbeat_install.ps1 b/testing/configure/winlogbeat_install.ps1 index fbf3a198..7e78566c 100644 --- a/testing/configure/winlogbeat_install.ps1 +++ b/testing/configure/winlogbeat_install.ps1 @@ -1,67 +1,66 @@ param ( [Parameter()] - [string]$baseDirectory = "C:\lme", + [string]$BaseDirectory = "C:\lme", [Parameter()] - [string]$winlogbeatVersion = "winlogbeat-8.5.0-windows-x86_64" + [string]$WinlogbeatVersion = "winlogbeat-8.5.0-windows-x86_64" ) # Source and destination directories -$sourceDir = "$baseDirectory\files_for_windows\tmp" -$destinationDir = "C:\Program Files" +$SourceDir = "$BaseDirectory\files_for_windows\tmp" +$DestinationDir = "C:\Program Files" # Copying files from source to destination -Copy-Item -Path "$sourceDir\*" -Destination $destinationDir -Recurse -Force +Copy-Item -Path "$SourceDir\*" -Destination $DestinationDir -Recurse -Force # Winlogbeat url -$url = "https://artifacts.elastic.co/downloads/beats/winlogbeat/$winlogbeatVersion.zip" +$Url = "https://artifacts.elastic.co/downloads/beats/winlogbeat/$WinlogbeatVersion.zip" # Destination path where the file will be saved -$winlogbeatDestination = "$baseDirectory\$winlogbeatVersion.zip" +$WinlogbeatDestination = "$BaseDirectory\$WinlogbeatVersion.zip" + +# Unzip destination +$UnzipDestination = "C:\Program Files\lme\$WinlogbeatVersion" + +# Define the path of the winlogbeat.yml file in C:\Program Files\lme +$WinlogbeatYmlSource = "C:\Program Files\lme\winlogbeat.yml" + +# Define the destination path of the winlogbeat.yml file +$WinlogbeatYmlDestination = Join-Path -Path $UnzipDestination -ChildPath "winlogbeat.yml" + +# Define the full path of the install script +$InstallScriptPath = Join-Path -Path $UnzipDestination -ChildPath "install-service-winlogbeat.ps1" # Create the base directory if it does not exist -if (-not (Test-Path $baseDirectory)) { - New-Item -ItemType Directory -Path $baseDirectory +if (-not (Test-Path $BaseDirectory)) { + New-Item -ItemType Directory -Path $BaseDirectory } # Download the file -Invoke-WebRequest -Uri $url -OutFile $winlogbeatDestination - -# Unzip destination -$unzipDestination = "C:\Program Files\lme\$winlogbeatVersion" +Invoke-WebRequest -Uri $Url -OutFile $WinlogbeatDestination # Unzip the file -Expand-Archive -LiteralPath $winlogbeatDestination -DestinationPath $unzipDestination +Expand-Archive -LiteralPath $WinlogbeatDestination -DestinationPath $UnzipDestination # Define the nested directory path -$nestedDir = Join-Path -Path $unzipDestination -ChildPath $winlogbeatVersion +$nestedDir = Join-Path -Path $UnzipDestination -ChildPath $WinlogbeatVersion # Move the contents of the nested directory up one level and remove the nested directory if (Test-Path $nestedDir) { - Get-ChildItem -Path $nestedDir -Recurse | Move-Item -Destination $unzipDestination + Get-ChildItem -Path $nestedDir -Recurse | Move-Item -Destination $UnzipDestination Remove-Item -Path $nestedDir -Force -Recurse } - -# Define the path of the winlogbeat.yml file in C:\Program Files\lme -$winlogbeatYmlSource = "C:\Program Files\lme\winlogbeat.yml" - -# Define the destination path of the winlogbeat.yml file -$winlogbeatYmlDestination = Join-Path -Path $unzipDestination -ChildPath "winlogbeat.yml" - # Move the winlogbeat.yml file to the destination directory, overwriting if it exists -Move-Item -Path $winlogbeatYmlSource -Destination $winlogbeatYmlDestination -Force +Move-Item -Path $WinlogbeatYmlSource -Destination $WinlogbeatYmlDestination -Force # Set execution policy to Unrestricted for this process Set-ExecutionPolicy Unrestricted -Scope Process -# Define the full path of the install script -$installScriptPath = Join-Path -Path $unzipDestination -ChildPath "install-service-winlogbeat.ps1" - # Check if the install script exists -if (Test-Path $installScriptPath) { +if (Test-Path $InstallScriptPath) { # Change directory to the unzip destination - Push-Location -Path $unzipDestination + Push-Location -Path $UnzipDestination # Run the install script .\install-service-winlogbeat.ps1 @@ -70,7 +69,7 @@ if (Test-Path $installScriptPath) { Pop-Location } else { - Write-Host "The installation script was not found at $installScriptPath" + Write-Output "The installation script was not found at $InstallScriptPath" } Start-Sleep -Seconds 5 @@ -78,8 +77,8 @@ Start-Sleep -Seconds 5 # Start the winlogbeat service try { Start-Service -Name "winlogbeat" - Write-Host "Winlogbeat service started successfully." + Write-Output "Winlogbeat service started successfully." } catch { - Write-Host "Failed to start Winlogbeat service: $_" + Write-Output "Failed to start Winlogbeat service: $_" } From 9c8648910b3a35d9f9e4d3f2e1b0206a09dfa086 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 16 Jan 2024 07:45:19 -0500 Subject: [PATCH 068/103] ls1 not being set on DC1 --- testing/InstallTestbed.ps1 | 5 ++--- testing/SetupTestbed.ps1 | 6 +++--- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index defa33fd..88cff6ae 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -208,11 +208,10 @@ if ($rebootCheckstring -match "A reboot is required in order to proceed with the az vm restart ` --resource-group $ResourceGroup ` --name $LinuxVMName + Write-Output $ProcessSeparator # Run the lme installer on LS1 Write-Output "`nRunning the lme installer on LS1..." - Write-Output $ProcessSeparator - $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVMName ` @@ -305,7 +304,7 @@ $scpResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --name $VMName ` --resource-group $ResourceGroup ` - --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1.lme.local:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' + --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") Write-Output $ProcessSeparator diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index adf3812e..2e27c2c7 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -384,10 +384,10 @@ Write-Output "The time is $(Get-Date)." # Define the PowerShell script with the DomainName variable interpolated $scriptContent = @" `$scriptBlock = { - Add-DnsServerResourceRecordA -Name LS1 -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00 + Add-DnsServerResourceRecordA -Name LS1 -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00 -AsJob } `$job = Start-Job -ScriptBlock `$scriptBlock -`$timeout = 30 +`$timeout = 60 if (Wait-Job -Job `$job -Timeout `$timeout) { Receive-Job -Job `$job Write-Host 'The script completed within the timeout period.' @@ -422,7 +422,7 @@ $addDnsRecordResponse = az vm run-command invoke ` --scripts "C:\AddDnsRecord.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDnsRecordResponse") -Write-Host "Checking if ls1 resolves..." +Write-Host "Checking if ls1 resolves. This should resolve to ls1.lme.local, not another domain..." $resolveLs1Response = az vm run-command invoke ` --command-id RunPowerShellScript ` --resource-group $ResourceGroup ` From 84241f0e4b930152feb131701961183d4c42fd81 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 18 Jan 2024 07:37:02 -0500 Subject: [PATCH 069/103] Adds Linux Only install to SetupTestbed --- testing/InstallTestbed.ps1 | 65 +-- testing/Readme.md | 52 ++- testing/SetupTestbed.ps1 | 439 ++++++++++-------- .../azure_scripts/lib/utilityFunctions.ps1 | 2 +- testing/configure/linux_install_lme.sh | 3 +- 5 files changed, 306 insertions(+), 255 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 88cff6ae..7217fb88 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -1,10 +1,16 @@ param ( + [Alias("g")] [Parameter(Mandatory = $true)] [string]$ResourceGroup, - [string]$VMName = "DC1", - [string]$LinuxVMName = "LS1", - [int]$NumberOfClients = 2 + [Alias("w")] + [string]$DomainController = "DC1", + + [Alias("l")] + [string]$LinuxVM = "LS1", + + [Alias("n")] + [int]$NumClients = 2 ) # If you were to need the password from the SetupTestbed.ps1 script, you could use this: @@ -67,7 +73,7 @@ Write-Output $ProcessSeparator Write-Output "`nMaking our directory on the VM..." $createDirResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` - --name $VMName ` + --name $DomainController ` --resource-group $ResourceGroup ` --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") @@ -77,7 +83,7 @@ Write-Output $ProcessSeparator # Download the zip file to the VM Write-Output "`nDownloading the zip file to the VM..." $downloadZipFileResponse = .\download_in_container.ps1 ` - -VMName $VmName ` + -VMName $DomainController ` -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" @@ -87,7 +93,7 @@ Write-Output $ProcessSeparator # Extract the zip file Write-Output "`nExtracting the zip file..." $extractArchiveResponse = .\extract_archive.ps1 ` - -VMName $VMName ` + -VMName $DomainController ` -ResourceGroup $ResourceGroup ` -FileName "configure.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") @@ -97,15 +103,14 @@ Write-Output $ProcessSeparator Write-Output "`nRunning the install script for chapter 1..." $installChapter1Response = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` - -VMName $VMName ` + -VMName $DomainController ` -ScriptPathOnVM "C:\lme\configure\install_chapter_1.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter1Response") Write-Output $ProcessSeparator -# Todo: Loop these for number of vms # Update the group policy on the remote machines Write-Output "`nUpdating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients +Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumClients Write-Output $ProcessSeparator # Wait for the services to start @@ -116,7 +121,7 @@ Start-Sleep 10 write-host "`nChecking if we can see the forwarding computers in the DC..." $listForwardingComputersResponse = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` - -VMName $VMName ` + -VMName $DomainController ` -ScriptPathOnVM "C:\lme\configure\list_computers_forwarding_events.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$listForwardingComputersResponse") Write-Output $ProcessSeparator @@ -125,14 +130,14 @@ Write-Output $ProcessSeparator Write-Output "`nInstalling the sysmon service on DC1 from chapter 2..." $installChapter2Response = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` - -VMName $VMName ` + -VMName $DomainController ` -ScriptPathOnVM "C:\lme\configure\install_chapter_2.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter2Response") Write-Output $ProcessSeparator # Update the group policy on the remote machines Write-Output "`nUpdating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumberOfClients +Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumClients Write-Output $ProcessSeparator # Wait for the services to start @@ -152,7 +157,7 @@ Write-Output $ProcessSeparator # Download the installers on LS1 Write-Output "`nDownloading the installers on LS1..." $downloadLinuxZipFileResponse = .\download_in_container.ps1 ` - -VMName $LinuxVMName ` + -VMName $LinuxVM ` -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$FileDownloadUrl" ` -DestinationFilePath "configure.zip" ` @@ -164,7 +169,7 @@ Write-Output $ProcessSeparator Write-Output "`nInstalling unzip on LS1..." $installUnzipResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts 'apt-get install unzip -y' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installUnzipResponse") @@ -173,7 +178,7 @@ Write-Output $ProcessSeparator # Unzip the file on LS1 Write-Output "`nUnzipping the file on LS1..." $extractLinuxArchiveResponse = .\extract_archive.ps1 ` - -VMName $LinuxVMName ` + -VMName $LinuxVM ` -ResourceGroup $ResourceGroup ` -FileName "configure.zip" ` -Os "Linux" @@ -184,7 +189,7 @@ Write-Output $ProcessSeparator Write-Output "`nMaking the installer files executable and updating the system packages on LS1..." $updateLinuxResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts 'chmod +x /home/admin.ackbar/lme/configure/* && /home/admin.ackbar/lme/configure/linux_update_system.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$updateLinuxResponse") @@ -194,7 +199,7 @@ Write-Output $ProcessSeparator Write-Output "`nRunning the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") @@ -204,17 +209,17 @@ Write-Output $ProcessSeparator $rebootCheckstring = $installLmeResponse | Out-String if ($rebootCheckstring -match "A reboot is required in order to proceed with the install") { # Have to check for the reboot thing here - Write-Output "`nRebooting ${LinuxVMName}..." + Write-Output "`nRebooting ${LinuxVM}..." az vm restart ` --resource-group $ResourceGroup ` - --name $LinuxVMName + --name $LinuxVM Write-Output $ProcessSeparator # Run the lme installer on LS1 Write-Output "`nRunning the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") @@ -225,7 +230,7 @@ if ($rebootCheckstring -match "A reboot is required in order to proceed with the Write-Output "`nCapturing the output of the install script for ES passwords..." $getElasticsearchPasswordsResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' @@ -237,7 +242,7 @@ Write-Output $ProcessSeparator Write-Output "`nGenerating key using expect on linux..." $generateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") @@ -247,7 +252,7 @@ Write-Output $ProcessSeparator Write-Output "`nAdding the public key to the authorized_keys file on LS1..." $authorizePrivateKeyResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_authorize_private_key.sh' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$authorizePrivateKeyResponse") @@ -257,10 +262,10 @@ Write-Output $ProcessSeparator Write-Output "`nCat the private key and capture that to the azure shell..." $jsonResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name $LinuxVMName ` + --name $LinuxVM ` --resource-group $ResourceGroup ` --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' -$privateKey = ExtractPrivateKeyFromJson -jsonResponse "$jsonResponse" +$privateKey = Get-PrivateKeyFromJson -jsonResponse "$jsonResponse" # Save the private key to a file Write-Output "`nSaving the private key to a file..." @@ -279,7 +284,7 @@ $KeyDownloadUrl = ./copy_file_to_container.ps1 ` # Download the private key to DC1 Write-Output "`nDownloading the private key to DC1..." $downloadPrivateKeyResponse = .\download_in_container.ps1 ` - -VMName $VmName ` + -VMName $DomainController ` -ResourceGroup $ResourceGroup ` -FileDownloadUrl "$KeyDownloadUrl" ` -DestinationFilePath "id_rsa" @@ -290,7 +295,7 @@ Write-Output $ProcessSeparator Write-Output "`nChanging the ownership of the private key file on DC1..." $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` - -VMName $VMName ` + -VMName $DomainController ` -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") Write-Output $ProcessSeparator @@ -302,7 +307,7 @@ Remove-Item -Path $privateKeyPath Write-Output "`nUsing the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." $scpResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` - --name $VMName ` + --name $DomainController ` --resource-group $ResourceGroup ` --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") @@ -311,7 +316,7 @@ Write-Output $ProcessSeparator # Extract the files on DC1 Write-Output "`nExtracting the files on DC1..." $extractFilesForWindowsResponse = .\extract_archive.ps1 ` - -VMName $VMName ` + -VMName $DomainController ` -ResourceGroup $ResourceGroup ` -FileName "files_for_windows.zip" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") @@ -321,7 +326,7 @@ Write-Output $ProcessSeparator Write-Output "`nInstalling winlogbeat on DC1..." $installWinlogbeatResponse = .\run_script_in_container.ps1 ` -ResourceGroup $ResourceGroup ` - -VMName $VMName ` + -VMName $DomainController ` -ScriptPathOnVM "C:\lme\configure\winlogbeat_install.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") diff --git a/testing/Readme.md b/testing/Readme.md index 06f3cc83..aa7117da 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -29,14 +29,14 @@ Example: ``` ## Running Using Azure Shell -| **#** | **Step** | **Screenshot** | -|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| -| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | -| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | -| 3 | Upload `SetupTestbed.ps1` by clicking the "Upload/Download files" icon *Note: if you want to use the InstallTestbed script, you should probably clone the repo as described in that section, and run SetupTestbed.ps1 from the cloned repo in the testing directory* | ![image](/docs/imgs/testing-screenshots/shell3.png) | -| 4 | Run the script, providing values for the parameters when promoted (see [Usage](#usage)). The script will take ~20 minutes to run to completion. | ![image](/docs/imgs/testing-screenshots/shell4.png) | -| 5 | Save the login credentials printed to the terminal at the end (They will also be in a file called `<$ResourceGroup>.password.txt`). At this point you can login to each VM using RDP (for the Windows servers) or SSH (for the Linux server). | ![image](/docs/imgs/testing-screenshots/shell5.png) | -| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | ![image](/docs/imgs/testing-screenshots/delete.png) | +| **#** | **Step** | **Screenshot** | +|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| +| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | +| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | +| 3 | Clone the repo `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | ![image](/docs/imgs/testing-screenshots/shell3.png) | +| 4 | Run the script, providing values for the parameters when promoted (see [Usage](#usage)). The script will take ~20 minutes to run to completion. | ![image](/docs/imgs/testing-screenshots/shell4.png) | +| 5 | Save the login credentials printed to the terminal at the end (They will also be in a file called `<$ResourceGroup>.password.txt`). At this point you can login to each VM using RDP (for the Windows servers) or SSH (for the Linux server). | ![image](/docs/imgs/testing-screenshots/shell5.png) | +| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | ![image](/docs/imgs/testing-screenshots/delete.png) | # Extra Functionality: @@ -57,18 +57,32 @@ Flags: - NSG: sets NSG to a custom NSG if desired [NSG1 default] ## Install LME on the cluster: -| **#** | **Step** | **Screenshot** | -|-------|--------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| -| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | -| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | -| 3 | If you have already cloned the LME repo then `cd LME` and run git pull before changing to the testing directory | | -| 3 | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | -| 4 | Now you can run `./InstallTestbed.ps1 --ResourceGroup YourResourceGroup` | | -| 4.a | You can also run the command this way if you want to log to a file. `./InstallTestbed.ps1 -ResourceGroup YourResourceGroup \| Tee-Object -FilePath "./output.log"` | | -| 5 | Save the login credentials printed to the terminal at the end. *See notes* | | -| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | +### InstallTestbed.ps1 +## Usage +| **Parameter** | **Alias** | **Description** | **Required** | +|-------------------|-----------|----------------------------------------------------------------------------------------|--------------| +| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | +| $NumClients | -n | The number of Windows clients to create; maximum 16; defaults to 1 | No | +| $DomainController | -w | The name of the domain controller in the cluster; defaults to "DC1" | No | +| $LinuxVm | -l | The name of the linux server in the cluster; defaults to "LS1" | No | + +Example: +``` +./InstallTestbed.ps1 --ResourceGroup YourResourceGroup +# Or if you want to save the output to a file +./InstallTestbed.ps1 -ResourceGroup YourResourceGroup | Tee-Object -FilePath "./YourResourceGroup.output.log" +``` +| **#** | **Step** | **Screenshot** | +|-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------| +| 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | +| 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | +| 3.a | If you have already cloned the LME repo then make sure you are in the `LME\testing` directory and run git pull before changing to the testing directory. | | +| 3.b | If you haven't cloned it, clone the github repo in the home directory. `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing`. | | +| 4 | Now you can run one of the commands from the Examples above. | | +| 5 | Save the login credentials printed to the terminal at the end. *See note* | | +| 6 | When you're done testing, simply delete the resource group to clean up all resources created. | | Note: When the script finishes you will be in the azure_scripts directory, and you should see the elasticsearch credentials printed to the terminal. -You will need to `cd ../../` to get back to the LME directory. All the passwords should be in the `<$ResourceGroup>.password.txt` file. +You will need to `cd ../../` to get back to the LME directory. All the passwords should also be in the `<$ResourceGroup>.password.txt` file. diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 2e27c2c7..6b22ac59 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -4,7 +4,7 @@ Creates the following: - A resource group - A virtual network, subnet, and network security group - - 2 VMs: "DC1," a Windows server, and "LS1," a Linux server + - 2 VMs: "DC1," a Windows server, and "LS1," a Linux server. You can use -m for only the linux server - Client VMs: Windows clients "C1", "C2", etc. up to 16 based on user input - Promotes DC1 to a domain controller - Adds "C" clients to the managed domain @@ -18,45 +18,53 @@ #> param ( - [Parameter( - HelpMessage="Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900). Convert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" - )] - $AutoShutdownTime=$null, - - [Parameter( - HelpMessage="Auto-shutdown notification email" - )] - $AutoShutdownEmail=$null, - - [Alias("l")] - [Parameter( - HelpMessage="Location where the cluster will be built. Default westus" - )] - [string]$Location="westus", - - [Alias("g")] - [Parameter(Mandatory=$true)] - [string]$ResourceGroup, - - [Alias("n")] - [Parameter( - HelpMessage="Number of clients to create (Max: 16)" - )] - [int]$NumClients=1, - - [Alias("s")] - [Parameter(Mandatory=$true, - HelpMessage="XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc... Comma-Separated list of CIDR prefixes or IP ranges" - )] - [string]$AllowedSources, - - [Alias("y")] - [Parameter( - HelpMessage="Run the script with no prompt (useful for automated runs)" - )] - [switch]$NoPrompt + [Parameter( + HelpMessage = "Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900). Convert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" + )] + $AutoShutdownTime = $null, + + [Parameter( + HelpMessage = "Auto-shutdown notification email" + )] + $AutoShutdownEmail = $null, + + [Alias("l")] + [Parameter( + HelpMessage = "Location where the cluster will be built. Default westus" + )] + [string]$Location = "westus", + + [Alias("g")] + [Parameter(Mandatory = $true)] + [string]$ResourceGroup, + + [Alias("n")] + [Parameter( + HelpMessage = "Number of clients to create (Max: 16)" + )] + [int]$NumClients = 2, + + [Alias("s")] + [Parameter(Mandatory = $true, + HelpMessage = "XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc... Comma-Separated list of CIDR prefixes or IP ranges" + )] + [string]$AllowedSources, + + [Alias("y")] + [Parameter( + HelpMessage = "Run the script with no prompt (useful for automated runs)" + )] + [switch]$NoPrompt, + + [Alias("m")] + [Parameter( + HelpMessage = "(minimal) Only install the linux server. Useful for testing the linux server without the windows clients" + )] + [switch]$LinuxOnly ) +$ProcessSeparator = "`n----------------------------------------`n" + # Define our library path $libraryPath = Join-Path -Path $PSScriptRoot -ChildPath "configure\azure_scripts\lib\utilityFunctions.ps1" @@ -85,9 +93,9 @@ $VMAdmin = "admin.ackbar" $DomainName = "lme.local" #Port options: https://learn.microsoft.com/en-us/cli/azure/network/nsg/rule?view=azure-cli-latest#az-network-nsg-rule-create -$Ports = 22,3389 -$Priorities = 1001,1002 -$Protocols = "Tcp","Tcp" +$Ports = 22, 3389 +$Priorities = 1001, 1002 +$Protocols = "Tcp", "Tcp" function Get-RandomPassword { @@ -118,42 +126,44 @@ function Set-AutoShutdown { Write-Output "`nCreating Auto-Shutdown Rule for $VMName at time $AutoShutdownTime..." if ($null -ne $AutoShutdownEmail) { - az vm auto-shutdown ` + $autoShutdownResponse = az vm auto-shutdown ` -g $ResourceGroup ` -n $VMName ` --time $AutoShutdownTime ` --email $AutoShutdownEmail + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$autoShutdownResponse") } else { - az vm auto-shutdown ` + $autoShutdownResponse = az vm auto-shutdown ` -g $ResourceGroup ` -n $VMName ` --time $AutoShutdownTime + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$autoShutdownResponse") } } function Set-NetworkRules { - param ( - [Parameter(Mandatory)] - $AllowedSourcesList - ) - - if ($Ports.length -ne $Priorities.length){ - Write-Output "Priorities and Ports length should be equal!" - exit -1 - } - if ($Ports.length -ne $Protocols.length){ - Write-Output "Protocols and Ports length should be equal!" - exit -1 - } - - for ($i = 0; $i -le $Ports.length - 1 ; $i++) { - $port=$Ports[$i] - $priority=$Priorities[$i] - $protocol=$Protocols[$i] - Write-Output "`nCreating Network Port $port rule..." - - az network nsg rule create --name Network_Port_Rule_$port ` + param ( + [Parameter(Mandatory)] + $AllowedSourcesList + ) + + if ($Ports.length -ne $Priorities.length) { + Write-Output "Priorities and Ports length should be equal!" + Exit 1 + } + if ($Ports.length -ne $Protocols.length) { + Write-Output "Protocols and Ports length should be equal!" + Exit 1 + } + + for ($i = 0; $i -le $Ports.length - 1; $i++) { + $port = $Ports[$i] + $priority = $Priorities[$i] + $protocol = $Protocols[$i] + Write-Output "`nCreating Network Port $port rule..." + + $networkRuleResponse = az network nsg rule create --name Network_Port_Rule_$port ` --resource-group $ResourceGroup ` --nsg-name NSG1 ` --priority $priority ` @@ -164,7 +174,8 @@ function Set-NetworkRules { --destination-address-prefixes '*' ` --destination-port-ranges $port ` --description "Allow inbound from $sources on $port via $protocol connections." - } + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$networkRuleResponse") + } } @@ -172,23 +183,23 @@ function Set-NetworkRules { # Validation of Globals # ######################## $AllowedSourcesList = $AllowedSources -Split "," -if ($AllowedSourcesList.length -lt 1){ - Write-Output "**ERROR**: Variable AllowedSources must be set (set with -AllowedSources or -s)" - exit -1 +if ($AllowedSourcesList.length -lt 1) { + Write-Output "**ERROR**: Variable AllowedSources must be set (set with -AllowedSources or -s)" + Exit 1 } if ($null -ne $AutoShutdownTime) { - if ( -not ( $AutoShutdownTime -match '^([01][0-9]|2[0-3])[0-5][0-9]$' ) ){ + if (-not ( $AutoShutdownTime -match '^([01][0-9]|2[0-3])[0-5][0-9]$')) { Write-Output "**ERROR** Invalid time" Write-Output "Enter the Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900), `n`tConvert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" - exit -1 - } + Exit 1 + } } -if ($NumClients -lt 1 -or $NumClients -gt 16) { - Write-Output "The number of clients must be at least 1 and no more than 16." +if (($NumClients -lt 1 -or $NumClients -gt 16) -and -Not $LinuxOnly) { + Write-Output "The number of clients must be at least 1 and no more than 16." $NumClients = $NumClients -as [int] - exit -1 + Exit 1 } ################ @@ -202,39 +213,45 @@ Write-Output "Number of clients: $NumClients" Write-Output "Allowed sources (IP's): $AllowedSourcesList" Write-Output "Auto-shutdown time: $AutoShutdownTime" Write-Output "Auto-shutdown e-mail: $AutoShutdownEmail" +if ($LinuxOnly) { + Write-Output "Running a minimal install on linux" +} if (-Not $NoPrompt) { - do { - $Proceed = Read-Host "`nProceed? (Y/n)" - } until ($Proceed -eq "y" -or $Proceed -eq "Y" -or $Proceed -eq "n" -or $Proceed -eq "N") - - if ($Proceed -eq "n" -or $Proceed -eq "N") { - Write-Output "Setup canceled" - exit - } + do { + $Proceed = Read-Host "`nProceed? (Y/n)" + } until ($Proceed -eq "y" -or $Proceed -eq "Y" -or $Proceed -eq "n" -or $Proceed -eq "N") + + if ($Proceed -eq "n" -or $Proceed -eq "N") { + Write-Output "Setup canceled" + Exit + } } ######################## # Setup resource group # ######################## Write-Output "`nCreating resource group..." -az group create --name $ResourceGroup --location $Location +$createResourceGroupResponse = az group create --name $ResourceGroup --location $Location +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createResourceGroupResponse") ################# # Setup network # ################# Write-Output "`nCreating virtual network..." -az network vnet create --resource-group $ResourceGroup ` +$createVirtualNetworkResponse = az network vnet create --resource-group $ResourceGroup ` --name VNet1 ` --address-prefix $VNetPrefix ` --subnet-name SNet1 ` --subnet-prefix $SubnetPrefix +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createVirtualNetworkResponse") Write-Output "`nCreating nsg..." -az network nsg create --name NSG1 ` +$createNsgResponse = az network nsg create --name NSG1 ` --resource-group $ResourceGroup ` --location $Location +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createNsgResponse") Set-NetworkRules -AllowedSourcesList $AllowedSourcesList @@ -243,23 +260,11 @@ Set-NetworkRules -AllowedSourcesList $AllowedSourcesList ################## $VMPassword = Get-RandomPassword 12 Write-Output "`nWriting $VMAdmin password to ${ResourceGroup}.password.txt" -echo $VMPassword > "${ResourceGroup}.password.txt" +$VMPassword | Out-File -FilePath "${ResourceGroup}.password.txt" -Encoding UTF8 -Write-Output "`nCreating DC1..." -az vm create ` - --name DC1 ` - --resource-group $ResourceGroup ` - --nsg NSG1 ` - --image Win2019Datacenter ` - --admin-username $VMAdmin ` - --admin-password $VMPassword ` - --vnet-name VNet1 ` - --subnet SNet1 ` - --public-ip-sku Standard ` - --private-ip-address $DcIP Write-Output "`nCreating LS1..." -az vm create ` +$createLs1Response = az vm create ` --name LS1 ` --resource-group $ResourceGroup ` --nsg NSG1 ` @@ -272,10 +277,25 @@ az vm create ` --size Standard_E2d_v4 ` --os-disk-size-gb 128 ` --private-ip-address $LsIP +Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createLs1Response") -for ($i = 1; $i -le $NumClients; $i++) { - Write-Output "`nCreating C$i..." - az vm create ` +if (-Not $LinuxOnly){ + Write-Output "`nCreating DC1..." + $createDc1Response = az vm create ` + --name DC1 ` + --resource-group $ResourceGroup ` + --nsg NSG1 ` + --image Win2019Datacenter ` + --admin-username $VMAdmin ` + --admin-password $VMPassword ` + --vnet-name VNet1 ` + --subnet SNet1 ` + --public-ip-sku Standard ` + --private-ip-address $DcIP + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDc1Response") + for ($i = 1; $i -le $NumClients; $i++) { + Write-Output "`nCreating C$i..." + $createClientResponse = az vm create ` --name C$i ` --resource-group $ResourceGroup ` --nsg NSG1 ` @@ -285,6 +305,8 @@ for ($i = 1; $i -le $NumClients; $i++) { --vnet-name VNet1 ` --subnet SNet1 ` --public-ip-sku Standard + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createClientResponse") + } } ########################### @@ -292,99 +314,107 @@ for ($i = 1; $i -le $NumClients; $i++) { ########################### if ($null -ne $AutoShutdownTime) { - Set-AutoShutdown "DC1" Set-AutoShutdown "LS1" - for ($i = 1; $i -le $NumClients; $i++) { - Set-AutoShutdown "C$i" + if (-Not $LinuxOnly){ + Set-AutoShutdown "DC1" + for ($i = 1; $i -le $NumClients; $i++) { + Set-AutoShutdown "C$i" + } } } #################### # Setup the domain # #################### -Write-Output "`nInstalling AD Domain services on DC1..." -az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroup ` - --name DC1 ` - --scripts "Add-WindowsFeature AD-Domain-Services -IncludeManagementTools" - -Write-Output "`nRestarting DC1..." -az vm restart ` - --resource-group $ResourceGroup ` - --name DC1 ` - -Write-Output "`nCreating the ADDS forest..." -az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroup ` - --name DC1 ` - --scripts "`$Password = ConvertTo-SecureString `"$VMPassword`" -AsPlainText -Force; ` -Install-ADDSForest -DomainName $DomainName -Force -SafeModeAdministratorPassword `$Password" - -Write-Output "`nRestarting DC1..." -az vm restart ` - --resource-group $ResourceGroup ` - --name DC1 ` - -for ($i = 1; $i -le $NumClients; $i++) { - Write-Output "`nAdding DC IP address to C$i host file..." - az vm run-command invoke ` +if (-Not $LinuxOnly){ + Write-Output "`nInstalling AD Domain services on DC1..." + $addDomainServicesResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --resource-group $ResourceGroup ` - --name C$i ` - --scripts "Add-Content -Path `$env:windir\System32\drivers\etc\hosts -Value `"`n$DcIP`t$DomainName`" -Force" + --name DC1 ` + --scripts "Add-WindowsFeature AD-Domain-Services -IncludeManagementTools" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDomainServicesResponse") - Write-Output "`nSetting C$i DNS server to DC1..." - az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroup ` - --name C$i ` - --scripts "Get-Netadapter | Set-DnsClientServerAddress -ServerAddresses $DcIP" - - Write-Output "`nRestarting C$i..." + Write-Output "`nRestarting DC1..." az vm restart ` --resource-group $ResourceGroup ` - --name C$i ` + --name DC1 ` - Write-Output "`nAdding C$i to the domain..." - az vm run-command invoke ` + Write-Output "`nCreating the ADDS forest..." + $installAddsForestResponse = az vm run-command invoke ` --command-id RunPowerShellScript ` --resource-group $ResourceGroup ` - --name C$i ` + --name DC1 ` --scripts "`$Password = ConvertTo-SecureString `"$VMPassword`" -AsPlainText -Force; ` - `$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DomainName\$VMAdmin, `$Password; ` - Add-Computer -DomainName $DomainName -Credential `$Credential -Restart" + Install-ADDSForest -DomainName $DomainName -Force -SafeModeAdministratorPassword `$Password" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installAddsForestResponse") - # The following command fixes this issue: - # https://serverfault.com/questions/754012/windows-10-unable-to-access-sysvol-and-netlogon - Write-Output "`nModifying C$i register to allow access to sysvol..." - az vm run-command invoke ` - --command-id RunPowerShellScript ` + Write-Output "`nRestarting DC1..." + az vm restart ` + --resource-group $ResourceGroup ` + --name DC1 ` + + for ($i = 1; $i -le $NumClients; $i++) { + Write-Output "`nAdding DC IP address to C$i host file..." + $addIpResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroup ` + --name C$i ` + --scripts "Add-Content -Path `$env:windir\System32\drivers\etc\hosts -Value `"`n$DcIP`t$DomainName`" -Force" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addIpResponse") + + Write-Output "`nSetting C$i DNS server to DC1..." + $setDnsResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroup ` + --name C$i ` + --scripts "Get-Netadapter | Set-DnsClientServerAddress -ServerAddresses $DcIP" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$setDnsResponse") + + Write-Output "`nRestarting C$i..." + az vm restart ` --resource-group $ResourceGroup ` --name C$i ` - --scripts "cmd.exe /c `"%COMSPEC% /C reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\NetworkProvider\HardenedPaths /v \\*\SYSVOL /d RequireMutualAuthentication=0 /t REG_SZ`"" + + Write-Output "`nAdding C$i to the domain..." + $addToDomainResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroup ` + --name C$i ` + --scripts "`$Password = ConvertTo-SecureString `"$VMPassword`" -AsPlainText -Force; ` + `$Credential = New-Object -TypeName System.Management.Automation.PSCredential -ArgumentList $DomainName\$VMAdmin, `$Password; ` + Add-Computer -DomainName $DomainName -Credential `$Credential -Restart" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addToDomainResponse") + + # The following command fixes this issue: + # https://serverfault.com/questions/754012/windows-10-unable-to-access-sysvol-and-netlogon + Write-Output "`nModifying C$i register to allow access to sysvol..." + $addToSysvolResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroup ` + --name C$i ` + --scripts "cmd.exe /c `"%COMSPEC% /C reg add HKEY_LOCAL_MACHINE\SOFTWARE\Policies\Microsoft\Windows\NetworkProvider\HardenedPaths /v \\*\SYSVOL /d RequireMutualAuthentication=0 /t REG_SZ`"" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addToSysvolResponse") + } } +Write-Output $ProcessSeparator Write-Output "`nVM login info:" -Write-Output "ResourceGroup: $($ResourceGroup)" -Write-Output "Username: $($VMAdmin)" -Write-Output "Password: $($VMPassword)" +Write-Output "ResourceGroup: $( $ResourceGroup )" +Write-Output "Username: $( $VMAdmin )" +Write-Output "Password: $( $VMPassword )" Write-Output "SAVE THE ABOVE INFO`n" - -Write-Output "`nAdding DNS entry for Linux server..." -Write-Warning "NOTE: Sometimes this final call hangs indefinitely. -Haven't figured out why. If it doesn't finish after a few minutes, -hit ctrl+c to kill the process. Even if it didn't exit normally, -it is likely that the DNS entry was still successfully added. To -verify, log on to DC1 and run 'Resolve-DnsName ls1' in PowerShell. -If it returns NXDOMAIN, you'll need to add it manually." -Write-Output "The time is $(Get-Date)." - -# Define the PowerShell script with the DomainName variable interpolated -$scriptContent = @" +Write-Output $ProcessSeparator + +if (-Not $LinuxOnly){ + Write-Output "`nAdding DNS entry for Linux server..." + Write-Warning "NOTE: To verify, log on to DC1 and run 'Resolve-DnsName ls1' in PowerShell. + If it returns NXDOMAIN, you'll need to add it manually." + Write-Output "The time is $( Get-Date )." + # Define the PowerShell script with the DomainName variable interpolated + $scriptContent = @" `$scriptBlock = { - Add-DnsServerResourceRecordA -Name LS1 -ZoneName $DomainName -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00 -AsJob + Add-DnsServerResourceRecordA -Name LS1 -ZoneName $DomainName. -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00 -AsJob } `$job = Start-Job -ScriptBlock `$scriptBlock `$timeout = 60 @@ -398,45 +428,46 @@ if (Wait-Job -Job `$job -Timeout `$timeout) { } "@ -# Convert the script to a Base64-encoded string -$bytes = [System.Text.Encoding]::Unicode.GetBytes($scriptContent) -$encodedScript = [Convert]::ToBase64String($bytes) + # Convert the script to a Base64-encoded string + $bytes = [System.Text.Encoding]::Unicode.GetBytes($scriptContent) + $encodedScript = [Convert]::ToBase64String($bytes) -# Run the encoded script on the Azure VM -Write-Output "`nAdding script to add DNS entry for Linux server. No output expected..." -$createDnsScriptResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name DC1 ` - --resource-group $ResourceGroup ` - --scripts "Set-Content -Path 'C:\AddDnsRecord.ps1' -Value ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('$encodedScript')))" + # Run the encoded script on the Azure VM + Write-Output "`nAdding script to add DNS entry for Linux server. No output expected..." + $createDnsScriptResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name DC1 ` + --resource-group $ResourceGroup ` + --scripts "Set-Content -Path 'C:\AddDnsRecord.ps1' -Value ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('$encodedScript')))" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDnsScriptResponse") + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDnsScriptResponse") -Write-Output "`nRunning script to add DNS entry for Linux server. It could time out or not. Check output of the next command..." -$addDnsRecordResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name DC1 ` - --resource-group $ResourceGroup ` - --scripts "C:\AddDnsRecord.ps1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDnsRecordResponse") + Write-Output "`nRunning script to add DNS entry for Linux server. It could time out or not. Check output of the next command..." + $addDnsRecordResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name DC1 ` + --resource-group $ResourceGroup ` + --scripts "C:\AddDnsRecord.ps1" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDnsRecordResponse") -Write-Host "Checking if ls1 resolves. This should resolve to ls1.lme.local, not another domain..." -$resolveLs1Response = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --resource-group $ResourceGroup ` - --name DC1 ` - --scripts "Resolve-DnsName ls1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$resolveLs1Response") - -Write-Host "Removing the Dns script. No output expected..." -$removeDnsRecordScriptResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name DC1 ` - --resource-group $ResourceGroup ` - --scripts "Remove-Item -Path 'C:\AddDnsRecord.ps1' -Force" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$removeDnsRecordScriptResponse") + Write-Host "Checking if ls1 resolves. This should resolve to ls1.lme.local->${$LsIP}, not another domain..." + $resolveLs1Response = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --resource-group $ResourceGroup ` + --name DC1 ` + --scripts "Resolve-DnsName ls1" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$resolveLs1Response") + Write-Host "Removing the Dns script. No output expected..." + $removeDnsRecordScriptResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name DC1 ` + --resource-group $ResourceGroup ` + --scripts "Remove-Item -Path 'C:\AddDnsRecord.ps1' -Force" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$removeDnsRecordScriptResponse") + +} Write-Output "Done." diff --git a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 index af835503..838d157c 100644 --- a/testing/configure/azure_scripts/lib/utilityFunctions.ps1 +++ b/testing/configure/azure_scripts/lib/utilityFunctions.ps1 @@ -82,7 +82,7 @@ function Show-FormattedOutput { } } -function ExtractPrivateKeyFromJson { +function Get-PrivateKeyFromJson { param ( [Parameter(Mandatory = $true)] [string]$jsonResponse diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 06282354..387259b5 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -20,7 +20,8 @@ done # Download a copy of the LME files #sudo git clone https://github.com/cisagov/lme.git /opt/lme/ sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lme.git /opt/lme/ -# curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.assets[0].browser_download_url' | xargs -I {} sh -c 'curl -L -O {} && unzip -d /opt/lme/ "$(basename {})"' +# curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.assets[0].browser_download_url' | xargs -I {} sh -c 'curl -L -O {}' && unzip -d /opt/lme/ "$(basename {})"' +# https://github.com/cisagov/LME/archive/refs/tags/v1.3.1.zip echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc From 4788351625657bea05d3236fdb6c325e30aef24f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 18 Jan 2024 08:33:52 -0500 Subject: [PATCH 070/103] Remove separate linux only script --- testing/SetupTestbed.ps1 | 73 +++++------ testing/TestbedOnlyLinux.ps1 | 246 ----------------------------------- 2 files changed, 36 insertions(+), 283 deletions(-) delete mode 100644 testing/TestbedOnlyLinux.ps1 diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 6b22ac59..5dc83f27 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -127,18 +127,18 @@ function Set-AutoShutdown { Write-Output "`nCreating Auto-Shutdown Rule for $VMName at time $AutoShutdownTime..." if ($null -ne $AutoShutdownEmail) { $autoShutdownResponse = az vm auto-shutdown ` - -g $ResourceGroup ` - -n $VMName ` - --time $AutoShutdownTime ` - --email $AutoShutdownEmail - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$autoShutdownResponse") + -g $ResourceGroup ` + -n $VMName ` + --time $AutoShutdownTime ` + --email $AutoShutdownEmail + Write-Output $autoShutdownResponse } else { $autoShutdownResponse = az vm auto-shutdown ` - -g $ResourceGroup ` - -n $VMName ` - --time $AutoShutdownTime - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$autoShutdownResponse") + -g $ResourceGroup ` + -n $VMName ` + --time $AutoShutdownTime + Write-Output $autoShutdownResponse } } @@ -164,17 +164,17 @@ function Set-NetworkRules { Write-Output "`nCreating Network Port $port rule..." $networkRuleResponse = az network nsg rule create --name Network_Port_Rule_$port ` - --resource-group $ResourceGroup ` - --nsg-name NSG1 ` - --priority $priority ` - --direction Inbound ` - --access Allow ` - --protocol $protocol ` - --source-address-prefixes $AllowedSourcesList ` - --destination-address-prefixes '*' ` - --destination-port-ranges $port ` - --description "Allow inbound from $sources on $port via $protocol connections." - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$networkRuleResponse") + --resource-group $ResourceGroup ` + --nsg-name NSG1 ` + --priority $priority ` + --direction Inbound ` + --access Allow ` + --protocol $protocol ` + --source-address-prefixes $AllowedSourcesList ` + --destination-address-prefixes '*' ` + --destination-port-ranges $port ` + --description "Allow inbound from $sources on $port via $protocol connections." + Write-Output $networkRuleResponse } } @@ -214,7 +214,7 @@ Write-Output "Allowed sources (IP's): $AllowedSourcesList" Write-Output "Auto-shutdown time: $AutoShutdownTime" Write-Output "Auto-shutdown e-mail: $AutoShutdownEmail" if ($LinuxOnly) { - Write-Output "Running a minimal install on linux" + Write-Output "Creating a linux server only" } if (-Not $NoPrompt) { @@ -233,7 +233,7 @@ if (-Not $NoPrompt) { ######################## Write-Output "`nCreating resource group..." $createResourceGroupResponse = az group create --name $ResourceGroup --location $Location -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createResourceGroupResponse") +Write-Output $createResourceGroupResponse ################# # Setup network # @@ -245,13 +245,13 @@ $createVirtualNetworkResponse = az network vnet create --resource-group $Resourc --address-prefix $VNetPrefix ` --subnet-name SNet1 ` --subnet-prefix $SubnetPrefix -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createVirtualNetworkResponse") +Write-Output $createVirtualNetworkResponse Write-Output "`nCreating nsg..." $createNsgResponse = az network nsg create --name NSG1 ` --resource-group $ResourceGroup ` --location $Location -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createNsgResponse") +Write-Output $createNsgResponse Set-NetworkRules -AllowedSourcesList $AllowedSourcesList @@ -277,7 +277,7 @@ $createLs1Response = az vm create ` --size Standard_E2d_v4 ` --os-disk-size-gb 128 ` --private-ip-address $LsIP -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createLs1Response") +Write-Output $createLs1Response if (-Not $LinuxOnly){ Write-Output "`nCreating DC1..." @@ -292,20 +292,20 @@ if (-Not $LinuxOnly){ --subnet SNet1 ` --public-ip-sku Standard ` --private-ip-address $DcIP - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDc1Response") + Write-Output $createDc1Response for ($i = 1; $i -le $NumClients; $i++) { Write-Output "`nCreating C$i..." $createClientResponse = az vm create ` - --name C$i ` - --resource-group $ResourceGroup ` - --nsg NSG1 ` - --image Win2019Datacenter ` - --admin-username $VMAdmin ` - --admin-password $VMPassword ` - --vnet-name VNet1 ` - --subnet SNet1 ` - --public-ip-sku Standard - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createClientResponse") + --name C$i ` + --resource-group $ResourceGroup ` + --nsg NSG1 ` + --image Win2019Datacenter ` + --admin-username $VMAdmin ` + --admin-password $VMPassword ` + --vnet-name VNet1 ` + --subnet SNet1 ` + --public-ip-sku Standard + Write-Output $createClientResponse } } @@ -440,7 +440,6 @@ if (Wait-Job -Job `$job -Timeout `$timeout) { --name DC1 ` --resource-group $ResourceGroup ` --scripts "Set-Content -Path 'C:\AddDnsRecord.ps1' -Value ([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('$encodedScript')))" - Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDnsScriptResponse") diff --git a/testing/TestbedOnlyLinux.ps1 b/testing/TestbedOnlyLinux.ps1 deleted file mode 100644 index d62e0001..00000000 --- a/testing/TestbedOnlyLinux.ps1 +++ /dev/null @@ -1,246 +0,0 @@ -<# - Creates a "blank slate" for testing/configuring LME. - - Creates the following: - - A resource group - - A virtual network, subnet, and network security group - - "LS1," a Linux server - - This script should do all the work for you, simply specify a new resource group, - and optionally Auto-shutdown configuration each time you run it. - Be sure to copy the username/password it outputs at the end. - After completion, login to the VMs using ssh to configure/test LME. - - Example: ./TestbedOnlyLinux.ps1 -Location centralus -ResourceGroup YourResourceGroup -AutoShutdownTime 0000 -AllowedSources "x.x.x.x/32" -y -#> - -param ( - [Parameter( - HelpMessage = "Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900). Convert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" - )] - $AutoShutdownTime = $null, - - [Parameter( - HelpMessage = "Auto-shutdown notification email" - )] - $AutoShutdownEmail = $null, - - [Alias("l")] - [Parameter( - HelpMessage = "Location where the cluster will be built. Default westus" - )] - [string]$Location = "westus", - - [Alias("g")] - [Parameter(Mandatory = $true)] - [string]$ResourceGroup, - - [Alias("s")] - [Parameter(Mandatory = $true, - HelpMessage = "XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc... Comma-Separated list of CIDR prefixes or IP ranges to whitelist" - )] - [string]$AllowedSources, - - [Alias("y")] - [Parameter( - HelpMessage = "Run the script with no prompt (useful for automated runs)" - )] - [switch]$NoPrompt -) - -#DEFAULTS: -#Desired Netowrk Mapping: -$VNetPrefix = "10.1.0.0/16" -$SubnetPrefix = "10.1.0.0/24" -$LsIP = "10.1.0.5" - -#Domain information: -$VMAdmin = "admin.ackbar" - -#Port options: https://learn.microsoft.com/en-us/cli/azure/network/nsg/rule?view=azure-cli-latest#az-network-nsg-rule-create -$Ports = 22, 3389 -$Priorities = 1001, 1002 -$Protocols = "Tcp", "Tcp" - - -function Get-RandomPassword { - param ( - [Parameter(Mandatory)] - [int]$Length - ) - $TokenSet = @{ - L = [Char[]]'abcdefghijkmnopqrstuvwxyz' - U = [Char[]]'ABCDEFGHIJKMNPQRSTUVWXYZ' - N = [Char[]]'23456789' - } - - $Lower = Get-Random -Count 5 -InputObject $TokenSet.L - $Upper = Get-Random -Count 5 -InputObject $TokenSet.U - $Number = Get-Random -Count 5 -InputObject $TokenSet.N - - $StringSet = $Lower + $Number + $Upper - - (Get-Random -Count $Length -InputObject $StringSet) -join '' -} - -function Set-AutoShutdown { - param ( - [Parameter(Mandatory)] - [string]$VMName - ) - - Write-Output "`nCreating Auto-Shutdown Rule for $VMName at time $AutoShutdownTime..." - if ($null -ne $AutoShutdownEmail) { - az vm auto-shutdown ` - -g $ResourceGroup ` - -n $VMName ` - --time $AutoShutdownTime ` - --email $AutoShutdownEmail - } - else { - az vm auto-shutdown ` - -g $ResourceGroup ` - -n $VMName ` - --time $AutoShutdownTime - } -} - -function Set-NetworkRules { - param ( - [Parameter(Mandatory)] - $AllowedSourcesList - ) - - if ($Ports.length -ne $Priorities.length) { - Write-Output "Priorities and Ports length should be equal!" - exit -1 - } - if ($Ports.length -ne $Protocols.length) { - Write-Output "Protocols and Ports length should be equal!" - exit -1 - } - - for ($i = 0; $i -le $Ports.length - 1; $i++) { - $port = $Ports[$i] - $priority = $Priorities[$i] - $protocol = $Protocols[$i] - Write-Output "`nCreating Network Port $port rule..." - - az network nsg rule create --name Network_Port_Rule_$port ` - --resource-group $ResourceGroup ` - --nsg-name NSG1 ` - --priority $priority ` - --direction Inbound ` - --access Allow ` - --protocol $protocol ` - --source-address-prefixes $AllowedSourcesList ` - --destination-address-prefixes '*' ` - --destination-port-ranges $port ` - --description "Allow inbound from $sources on $port via $protocol connections." - } -} - - -######################## -# Validation of Globals # -######################## -$AllowedSourcesList = $AllowedSources -Split "," -if ($AllowedSourcesList.length -lt 1) { - Write-Output "**ERROR**: Variable AllowedSources must be set (set with -AllowedSources or -s)" - exit -1 -} - -if ($null -ne $AutoShutdownTime) { - if (-not( $AutoShutdownTime -match '^([01][0-9]|2[0-3])[0-5][0-9]$')) { - Write-Output "**ERROR** Invalid time" - Write-Output "Enter the Auto-Shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900), `n`tConvert timezone as necesary: (e.g. 05:30 pm ET -> 9:30 pm UTC -> 21:30 -> 2130)" - exit -1 - } -} - -################ -# Confirmation # -################ -Write-Output "Supplied configuration:`n" - -Write-Output "Location: $Location" -Write-Output "Resource group: $ResourceGroup" -Write-Output "Allowed sources (IP's): $AllowedSourcesList" -Write-Output "Auto-shutdown time: $AutoShutdownTime" -Write-Output "Auto-shutdown e-mail: $AutoShutdownEmail" - -if (-Not$NoPrompt) { - do { - $Proceed = Read-Host "`nProceed? (Y/n)" - } until ($Proceed -eq "y" -or $Proceed -eq "Y" -or $Proceed -eq "n" -or $Proceed -eq "N") - - if ($Proceed -eq "n" -or $Proceed -eq "N") { - Write-Output "Setup canceled" - exit - } -} - -######################## -# Setup resource group # -######################## -Write-Output "`nCreating resource group..." -az group create --name $ResourceGroup --location $Location - -################# -# Setup network # -################# - -Write-Output "`nCreating virtual network..." -az network vnet create --resource-group $ResourceGroup ` - --name VNet1 ` - --address-prefix $VNetPrefix ` - --subnet-name SNet1 ` - --subnet-prefix $SubnetPrefix - -Write-Output "`nCreating nsg..." -az network nsg create --name NSG1 ` - --resource-group $ResourceGroup ` - --location $Location - -Set-NetworkRules -AllowedSourcesList $AllowedSourcesList - -################## -# Create the VMs # -################## -$VMPassword = Get-RandomPassword 12 -Write-Output "`nWriting $VMAdmin password to ${ResourceGroup}.password.txt" -$VMPassword | Out-File -FilePath "${ResourceGroup}.password.txt" -Encoding UTF8 - - -Write-Output "`nCreating LS1..." -az vm create ` - --name LS1 ` - --resource-group $ResourceGroup ` - --nsg NSG1 ` - --image Ubuntu2204 ` - --admin-username $VMAdmin ` - --admin-password $VMPassword ` - --vnet-name VNet1 ` - --subnet SNet1 ` - --public-ip-sku Standard ` - --size Standard_E2d_v4 ` - --os-disk-size-gb 128 ` - --private-ip-address $LsIP - - -########################### -# Configure Auto-Shutdown # -########################### - -if ($null -ne $AutoShutdownTime) { - Set-AutoShutdown "LS1" -} - -Write-Output "`nVM login info:" -Write-Output "ResourceGroup: $($ResourceGroup)" -Write-Output "Username: $( $VMAdmin )" -Write-Output "Password: $( $VMPassword )" -Write-Output "SAVE THE ABOVE INFO`n" - -Write-Output "The time is $( Get-Date )." -Write-Output "Done." From 1a1aa979711d9df85b6bef7d012caa4aebe7a090 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 18 Jan 2024 15:49:21 -0500 Subject: [PATCH 071/103] Update testing/Readme.md Co-authored-by: Alden Hilton <106177711+adhilto@users.noreply.github.com> --- testing/Readme.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/Readme.md b/testing/Readme.md index aa7117da..102926ab 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -16,7 +16,7 @@ This script does not install LME; it simply creates a fresh environment that's r | **Parameter** | **Alias** | **Description** | **Required** | |--------------------|-----------|-------------------------------------------------------------------------------------------------------------------------------------------------------------------|--------------| | $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | -| $NumClients | -n | The number of Windows clients to create; maximum 16; defaults to 1 | No | +| $NumClients | -n | The number of Windows clients to create; maximum 16; defaults to 2 | No | | $AutoShutdownTime | | The auto-shutdown time in UTC (HHMM, e.g. 2230, 0000, 1900); auto-shutdown not configured if not provided | No | | $AutoShutdownEmail | | An email to be notified if a VM is auto-shutdown. | No | | $AllowedSources | -s | Comma-Separated list of CIDR prefixes or IP ranges, e.g. XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc..., that are allowed to connect to the VMs via RDP and ssh. | Yes | @@ -33,7 +33,7 @@ Example: |-------|-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|---------------------------------------------------------| | 1 | Open a cloud shell by navigating to portal.azure.com and clicking the shell icon. | ![image](/docs/imgs/testing-screenshots/shell.png) | | 2 | Select PowerShell. | ![image](/docs/imgs/testing-secreenshots/shell2.png) | -| 3 | Clone the repo `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | ![image](/docs/imgs/testing-screenshots/shell3.png) | +| 3 | Clone the repo `git clone https://github.com/cisagov/LME.git` and then `cd LME\testing` | | | 4 | Run the script, providing values for the parameters when promoted (see [Usage](#usage)). The script will take ~20 minutes to run to completion. | ![image](/docs/imgs/testing-screenshots/shell4.png) | | 5 | Save the login credentials printed to the terminal at the end (They will also be in a file called `<$ResourceGroup>.password.txt`). At this point you can login to each VM using RDP (for the Windows servers) or SSH (for the Linux server). | ![image](/docs/imgs/testing-screenshots/shell5.png) | | 6 | When you're done testing, simply delete the resource group to clean up all resources created. | ![image](/docs/imgs/testing-screenshots/delete.png) | From 6986f696bbc99a94cd5e6b57fefd157cd0888df8 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 18 Jan 2024 15:53:37 -0500 Subject: [PATCH 072/103] Make number of clients consisten between scripts --- testing/Readme.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/Readme.md b/testing/Readme.md index 102926ab..77b3cd40 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -62,7 +62,7 @@ Flags: | **Parameter** | **Alias** | **Description** | **Required** | |-------------------|-----------|----------------------------------------------------------------------------------------|--------------| | $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | -| $NumClients | -n | The number of Windows clients to create; maximum 16; defaults to 1 | No | +| $NumClients | -n | The number of Windows clients you have created; defaults to 2 | No | | $DomainController | -w | The name of the domain controller in the cluster; defaults to "DC1" | No | | $LinuxVm | -l | The name of the linux server in the cluster; defaults to "LS1" | No | From 84eb65b40140b92222423793bcaee651926b6526 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 19 Jan 2024 04:51:50 -0500 Subject: [PATCH 073/103] Add ports for elk stack for testing --- testing/SetupTestbed.ps1 | 22 +++++++++++----------- testing/configure/linux_install_lme.sh | 2 +- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 5dc83f27..be4355ae 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -93,9 +93,9 @@ $VMAdmin = "admin.ackbar" $DomainName = "lme.local" #Port options: https://learn.microsoft.com/en-us/cli/azure/network/nsg/rule?view=azure-cli-latest#az-network-nsg-rule-create -$Ports = 22, 3389 -$Priorities = 1001, 1002 -$Protocols = "Tcp", "Tcp" +$Ports = 22, 3389, 443, 9200, 5044 +$Priorities = 1001, 1002, 1003, 1004, 1005 +$Protocols = "Tcp", "Tcp", "Tcp", "Tcp", "Tcp" function Get-RandomPassword { @@ -335,10 +335,10 @@ if (-Not $LinuxOnly){ --scripts "Add-WindowsFeature AD-Domain-Services -IncludeManagementTools" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDomainServicesResponse") - Write-Output "`nRestarting DC1..." - az vm restart ` - --resource-group $ResourceGroup ` - --name DC1 ` +# Write-Output "`nRestarting DC1..." +# az vm restart ` +# --resource-group $ResourceGroup ` +# --name DC1 ` Write-Output "`nCreating the ADDS forest..." $installAddsForestResponse = az vm run-command invoke ` @@ -349,10 +349,10 @@ if (-Not $LinuxOnly){ Install-ADDSForest -DomainName $DomainName -Force -SafeModeAdministratorPassword `$Password" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installAddsForestResponse") - Write-Output "`nRestarting DC1..." - az vm restart ` - --resource-group $ResourceGroup ` - --name DC1 ` +# Write-Output "`nRestarting DC1..." +# az vm restart ` +# --resource-group $ResourceGroup ` +# --name DC1 ` for ($i = 1; $i -le $NumClients; $i++) { Write-Output "`nAdding DC IP address to C$i host file..." diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 387259b5..db761910 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -33,7 +33,7 @@ echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Execute script with root privileges -sudo -E bash -c "$script_dir/linux_install_lme.exp" +sudo -E bash -c ". /root.bashrc && $script_dir/linux_install_lme.exp" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ From 5295599f89c3c6c5f04d7e1ebbb68e9b3f3026d3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Mon, 22 Jan 2024 06:02:31 -0500 Subject: [PATCH 074/103] Update readmes to change ResourceGroupName to ResourceGroup --- testing/configure/azure_scripts/create_blob_container.ps1 | 2 +- testing/configure/azure_scripts/download_in_container.ps1 | 2 +- testing/configure/azure_scripts/extract_archive.ps1 | 2 +- testing/configure/azure_scripts/run_script_in_container.ps1 | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/configure/azure_scripts/create_blob_container.ps1 b/testing/configure/azure_scripts/create_blob_container.ps1 index 32eaf9ff..8aeb7907 100644 --- a/testing/configure/azure_scripts/create_blob_container.ps1 +++ b/testing/configure/azure_scripts/create_blob_container.ps1 @@ -8,7 +8,7 @@ Requires the Azure Resource Group name as a mandatory argument. Generates unique names for the storage account and container, creates the storage account, retrieves the storage account key, creates a blob container, and saves the configuration to a 'config.ps1' file in the script's directory. -.PARAMETER ResourceGroupName +.PARAMETER ResourceGroup The name of the Azure Resource Group for the storage account and blob container. .EXAMPLE diff --git a/testing/configure/azure_scripts/download_in_container.ps1 b/testing/configure/azure_scripts/download_in_container.ps1 index ada6d5b5..33926357 100644 --- a/testing/configure/azure_scripts/download_in_container.ps1 +++ b/testing/configure/azure_scripts/download_in_container.ps1 @@ -8,7 +8,7 @@ The script takes parameters for VM name, resource group, file URL, destination f .PARAMETER VMName The name of the Virtual Machine where the file will be downloaded. -.PARAMETER ResourceGroupName +.PARAMETER ResourceGroup The name of the Azure resource group where the VM is located. .PARAMETER FileDownloadUrl diff --git a/testing/configure/azure_scripts/extract_archive.ps1 b/testing/configure/azure_scripts/extract_archive.ps1 index a5aa13d0..4deabcb0 100644 --- a/testing/configure/azure_scripts/extract_archive.ps1 +++ b/testing/configure/azure_scripts/extract_archive.ps1 @@ -10,7 +10,7 @@ and unzips the file. The script requires the VM name, resource group name, usern .PARAMETER VMName The name of the Azure Virtual Machine where the file will be unzipped. -.PARAMETER ResourceGroupName +.PARAMETER ResourceGroup The name of the Azure Resource Group that contains the VM. .PARAMETER Filename diff --git a/testing/configure/azure_scripts/run_script_in_container.ps1 b/testing/configure/azure_scripts/run_script_in_container.ps1 index 1819c8ad..67d15c5f 100644 --- a/testing/configure/azure_scripts/run_script_in_container.ps1 +++ b/testing/configure/azure_scripts/run_script_in_container.ps1 @@ -8,7 +8,7 @@ passing specified arguments to it. It uses Azure's 'az vm run-command invoke' to located on the VM. The script requires the VM name, resource group name, the full path of the script on the VM, and a string of arguments to pass to the script. -.PARAMETER ResourceGroupName +.PARAMETER ResourceGroup The name of the Azure Resource Group that contains the VM. .PARAMETER VMName From e64ab4cb0ff0edf7c774db6c051efb1a55620afe Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Mon, 22 Jan 2024 06:09:19 -0500 Subject: [PATCH 075/103] Adds a switch to install linux only --- Chapter 3 Files/dashboard_update.sh | 2 +- Chapter 3 Files/deploy.sh | 1 + testing/InstallTestbed.ps1 | 338 +++++++++++++------------ testing/SetupTestbed.ps1 | 2 +- testing/configure/linux_install_lme.sh | 2 +- 5 files changed, 178 insertions(+), 167 deletions(-) diff --git a/Chapter 3 Files/dashboard_update.sh b/Chapter 3 Files/dashboard_update.sh index 95462440..25b4322a 100644 --- a/Chapter 3 Files/dashboard_update.sh +++ b/Chapter 3 Files/dashboard_update.sh @@ -9,7 +9,7 @@ if [ -r /opt/lme/lme.conf ]; then #reference this file as a source . /opt/lme/lme.conf #check if the version number is equal to the one we want - if [ "$version" == "1.3.0" ]; then + if [ "$version" == "1.3.0" ] || [ "$FRESH_INSTALL" = "true" ]; then echo -e "\e[32m[X]\e[0m Updating from git repo" git -C /opt/lme/ pull #make sure the hostname variable is present diff --git a/Chapter 3 Files/deploy.sh b/Chapter 3 Files/deploy.sh index 2f895de2..0a25377e 100755 --- a/Chapter 3 Files/deploy.sh +++ b/Chapter 3 Files/deploy.sh @@ -740,6 +740,7 @@ function fixreadability() { function install() { + export FRESH_INSTALL="true" echo -e "Will execute the following intrusive actions:\n\t- apt update & upgrade\n\t- install docker (please uninstall before proceeding, or indicate skipping the install)\n\t- initialize docker swarm (execute \`sudo docker swarm leave --force\` before proceeding if you are part of a swarm\n\t- automatic os updates via unattened-upgrades\n\t- checkout lme directory to latest version, and throw away local changes)" prompt "Proceed?" diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 7217fb88..f0c36759 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -10,7 +10,13 @@ param ( [string]$LinuxVM = "LS1", [Alias("n")] - [int]$NumClients = 2 + [int]$NumClients = 2, + + [Alias("m")] + [Parameter( + HelpMessage = "(minimal) Only install the linux server. Useful for testing the linux server without the windows clients" + )] + [switch]$LinuxOnly ) # If you were to need the password from the SetupTestbed.ps1 script, you could use this: @@ -34,7 +40,7 @@ else { Write-Output "Creating a container to keep files for the VM..." $createBlobResponse = ./configure/azure_scripts/create_blob_container.ps1 ` -ResourceGroup $ResourceGroup -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createBlobResponse") +Write-Output $createBlobResponse Write-Output $ProcessSeparator # Source the variables from the file @@ -50,7 +56,7 @@ if (Test-Path ./configure.zip) { Write-Output $ProcessSeparator # Zip up the installer scripts for the VM -Write-Output "`nZipping up the installer scripts for the VM..." +Write-Output "`nZipping up the installer scripts for the VMs..." ./configure/azure_scripts/zip_my_parents_parent.ps1 Write-Output $ProcessSeparator @@ -69,91 +75,94 @@ Write-Output "`nChanging directory to the azure scripts..." Set-Location configure/azure_scripts Write-Output $ProcessSeparator -# Make our directory on the VM -Write-Output "`nMaking our directory on the VM..." -$createDirResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name $DomainController ` - --resource-group $ResourceGroup ` - --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") -Write-Output $ProcessSeparator - - -# Download the zip file to the VM -Write-Output "`nDownloading the zip file to the VM..." -$downloadZipFileResponse = .\download_in_container.ps1 ` - -VMName $DomainController ` - -ResourceGroup $ResourceGroup ` - -FileDownloadUrl "$FileDownloadUrl" ` - -DestinationFilePath "configure.zip" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") -Write-Output $ProcessSeparator - -# Extract the zip file -Write-Output "`nExtracting the zip file..." -$extractArchiveResponse = .\extract_archive.ps1 ` - -VMName $DomainController ` - -ResourceGroup $ResourceGroup ` - -FileName "configure.zip" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") -Write-Output $ProcessSeparator +if (-Not $LinuxOnly) { + Write-Output "`nInstalling on the windows clients..." + # Make our directory on the VM + Write-Output "`nMaking our directory on the VM..." + $createDirResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name $DomainController ` + --resource-group $ResourceGroup ` + --scripts "if (-not (Test-Path -Path 'C:\lme')) { New-Item -Path 'C:\lme' -ItemType Directory }" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$createDirResponse") + Write-Output $ProcessSeparator -# Run the install script for chapter 1 -Write-Output "`nRunning the install script for chapter 1..." -$installChapter1Response = .\run_script_in_container.ps1 ` - -ResourceGroup $ResourceGroup ` - -VMName $DomainController ` - -ScriptPathOnVM "C:\lme\configure\install_chapter_1.ps1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter1Response") -Write-Output $ProcessSeparator + # Download the zip file to the VM + Write-Output "`nDownloading the zip file to the VM..." + $downloadZipFileResponse = .\download_in_container.ps1 ` + -VMName $DomainController ` + -ResourceGroup $ResourceGroup ` + -FileDownloadUrl "$FileDownloadUrl" ` + -DestinationFilePath "configure.zip" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadZipFileResponse") + Write-Output $ProcessSeparator -# Update the group policy on the remote machines -Write-Output "`nUpdating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumClients -Write-Output $ProcessSeparator + # Extract the zip file + Write-Output "`nExtracting the zip file..." + $extractArchiveResponse = .\extract_archive.ps1 ` + -VMName $DomainController ` + -ResourceGroup $ResourceGroup ` + -FileName "configure.zip" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractArchiveResponse") + Write-Output $ProcessSeparator -# Wait for the services to start -Write-Output "`nWaiting for the services to start..." -Start-Sleep 10 + # Run the install script for chapter 1 + Write-Output "`nRunning the install script for chapter 1..." + $installChapter1Response = .\run_script_in_container.ps1 ` + -ResourceGroup $ResourceGroup ` + -VMName $DomainController ` + -ScriptPathOnVM "C:\lme\configure\install_chapter_1.ps1" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter1Response") + Write-Output $ProcessSeparator -# See if we can see the forwarding computers in the DC -write-host "`nChecking if we can see the forwarding computers in the DC..." -$listForwardingComputersResponse = .\run_script_in_container.ps1 ` - -ResourceGroup $ResourceGroup ` - -VMName $DomainController ` - -ScriptPathOnVM "C:\lme\configure\list_computers_forwarding_events.ps1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$listForwardingComputersResponse") -Write-Output $ProcessSeparator + # Update the group policy on the remote machines + Write-Output "`nUpdating the group policy on the remote machines..." + Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumClients + Write-Output $ProcessSeparator -# Install the sysmon service on DC1 from chapter 2 -Write-Output "`nInstalling the sysmon service on DC1 from chapter 2..." -$installChapter2Response = .\run_script_in_container.ps1 ` - -ResourceGroup $ResourceGroup ` - -VMName $DomainController ` - -ScriptPathOnVM "C:\lme\configure\install_chapter_2.ps1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter2Response") -Write-Output $ProcessSeparator + # Wait for the services to start + Write-Output "`nWaiting for the services to start..." + Start-Sleep 10 + + # See if we can see the forwarding computers in the DC + write-host "`nChecking if we can see the forwarding computers in the DC..." + $listForwardingComputersResponse = .\run_script_in_container.ps1 ` + -ResourceGroup $ResourceGroup ` + -VMName $DomainController ` + -ScriptPathOnVM "C:\lme\configure\list_computers_forwarding_events.ps1" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$listForwardingComputersResponse") + Write-Output $ProcessSeparator -# Update the group policy on the remote machines -Write-Output "`nUpdating the group policy on the remote machines..." -Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumClients -Write-Output $ProcessSeparator + # Install the sysmon service on DC1 from chapter 2 + Write-Output "`nInstalling the sysmon service on DC1 from chapter 2..." + $installChapter2Response = .\run_script_in_container.ps1 ` + -ResourceGroup $ResourceGroup ` + -VMName $DomainController ` + -ScriptPathOnVM "C:\lme\configure\install_chapter_2.ps1" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installChapter2Response") + Write-Output $ProcessSeparator -# Wait for the services to start -Write-Output "`nWaiting for the services to start. Generally they don't show..." -Start-Sleep 10 + # Update the group policy on the remote machines + Write-Output "`nUpdating the group policy on the remote machines..." + Invoke-GPUpdateOnVMs -ResourceGroup $ResourceGroup -numberOfClients $NumClients + Write-Output $ProcessSeparator -# See if you can see sysmon running on the machine -Write-Output "`nSeeing if you can see sysmon running on a machine..." -$showSysmonResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name "C1" ` - --resource-group $ResourceGroup ` - --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") -Write-Output $ProcessSeparator + # Wait for the services to start + Write-Output "`nWaiting for the services to start. Generally they don't show..." + Start-Sleep 10 + + # See if you can see sysmon running on the machine + Write-Output "`nSeeing if you can see sysmon running on a machine..." + $showSysmonResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name "C1" ` + --resource-group $ResourceGroup ` + --scripts 'Get-Service | Where-Object { $_.DisplayName -like "*Sysmon*" }' + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$showSysmonResponse") + Write-Output $ProcessSeparator +} +Write-Output "`nInstalling on the linux server..." # Download the installers on LS1 Write-Output "`nDownloading the installers on LS1..." $downloadLinuxZipFileResponse = .\download_in_container.ps1 ` @@ -234,103 +243,104 @@ $getElasticsearchPasswordsResponse = az vm run-command invoke ` --resource-group $ResourceGroup ` --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' -# Todo: Extract the output and write this to a file for later use Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") Write-Output $ProcessSeparator -# Generate key using expect on linux -Write-Output "`nGenerating key using expect on linux..." -$generateKeyResponse = az vm run-command invoke ` - --command-id RunShellScript ` - --name $LinuxVM ` - --resource-group $ResourceGroup ` - --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") -Write-Output $ProcessSeparator - -# Add the public key to the authorized_keys file on LS1 -Write-Output "`nAdding the public key to the authorized_keys file on LS1..." -$authorizePrivateKeyResponse = az vm run-command invoke ` - --command-id RunShellScript ` - --name $LinuxVM ` - --resource-group $ResourceGroup ` - --scripts '/home/admin.ackbar/lme/configure/linux_authorize_private_key.sh' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$authorizePrivateKeyResponse") -Write-Output $ProcessSeparator +if (-Not $LinuxOnly){ + # Generate key using expect on linux + Write-Output "`nGenerating key using expect on linux..." + $generateKeyResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVM ` + --resource-group $ResourceGroup ` + --scripts '/home/admin.ackbar/lme/configure/linux_make_private_key.exp' + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$generateKeyResponse") + Write-Output $ProcessSeparator -# Cat the private key and capture that to the azure shell -Write-Output "`nCat the private key and capture that to the azure shell..." -$jsonResponse = az vm run-command invoke ` - --command-id RunShellScript ` - --name $LinuxVM ` - --resource-group $ResourceGroup ` - --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' -$privateKey = Get-PrivateKeyFromJson -jsonResponse "$jsonResponse" + # Add the public key to the authorized_keys file on LS1 + Write-Output "`nAdding the public key to the authorized_keys file on LS1..." + $authorizePrivateKeyResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVM ` + --resource-group $ResourceGroup ` + --scripts '/home/admin.ackbar/lme/configure/linux_authorize_private_key.sh' + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$authorizePrivateKeyResponse") + Write-Output $ProcessSeparator -# Save the private key to a file -Write-Output "`nSaving the private key to a file..." -$privateKeyPath = ".\id_rsa" -Set-Content -Path $privateKeyPath -Value $privateKey -Write-Output $ProcessSeparator + # Cat the private key and capture that to the azure shell + Write-Output "`nCat the private key and capture that to the azure shell..." + $jsonResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name $LinuxVM ` + --resource-group $ResourceGroup ` + --scripts 'cat /home/admin.ackbar/.ssh/id_rsa' + $privateKey = Get-PrivateKeyFromJson -jsonResponse "$jsonResponse" + + # Save the private key to a file + Write-Output "`nSaving the private key to a file..." + $privateKeyPath = ".\id_rsa" + Set-Content -Path $privateKeyPath -Value $privateKey + Write-Output $ProcessSeparator -# Upload the private key to the container and get a key to download it -Write-Output "`nUploading the private key to the container and getting a key to download it..." -$KeyDownloadUrl = ./copy_file_to_container.ps1 ` - -LocalFilePath "id_rsa" ` - -ContainerName $ContainerName ` - -StorageAccountName $StorageAccountName ` - -StorageAccountKey $StorageAccountKey + # Upload the private key to the container and get a key to download it + Write-Output "`nUploading the private key to the container and getting a key to download it..." + $KeyDownloadUrl = ./copy_file_to_container.ps1 ` + -LocalFilePath "id_rsa" ` + -ContainerName $ContainerName ` + -StorageAccountName $StorageAccountName ` + -StorageAccountKey $StorageAccountKey + + # Download the private key to DC1 + Write-Output "`nDownloading the private key to DC1..." + $downloadPrivateKeyResponse = .\download_in_container.ps1 ` + -VMName $DomainController ` + -ResourceGroup $ResourceGroup ` + -FileDownloadUrl "$KeyDownloadUrl" ` + -DestinationFilePath "id_rsa" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") + Write-Output $ProcessSeparator -# Download the private key to DC1 -Write-Output "`nDownloading the private key to DC1..." -$downloadPrivateKeyResponse = .\download_in_container.ps1 ` - -VMName $DomainController ` - -ResourceGroup $ResourceGroup ` - -FileDownloadUrl "$KeyDownloadUrl" ` - -DestinationFilePath "id_rsa" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$downloadPrivateKeyResponse") -Write-Output $ProcessSeparator + # Change the ownership of the private key file on DC1 + Write-Output "`nChanging the ownership of the private key file on DC1..." + $chownPrivateKeyResponse = .\run_script_in_container.ps1 ` + -ResourceGroup $ResourceGroup ` + -VMName $DomainController ` + -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") + Write-Output $ProcessSeparator -# Change the ownership of the private key file on DC1 -Write-Output "`nChanging the ownership of the private key file on DC1..." -$chownPrivateKeyResponse = .\run_script_in_container.ps1 ` - -ResourceGroup $ResourceGroup ` - -VMName $DomainController ` - -ScriptPathOnVM "C:\lme\configure\chown_dc1_private_key.ps1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$chownPrivateKeyResponse") -Write-Output $ProcessSeparator + # Remove the private key from the local machine + Remove-Item -Path $privateKeyPath -# Remove the private key from the local machine -Remove-Item -Path $privateKeyPath - -# Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 -Write-Output "`nUsing the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." -$scpResponse = az vm run-command invoke ` - --command-id RunPowerShellScript ` - --name $DomainController ` - --resource-group $ResourceGroup ` - --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") -Write-Output $ProcessSeparator + # Use the azure shell to run scp on DC1 to copy the files from LS1 to DC1 + Write-Output "`nUsing the azure shell to run scp on DC1 to copy the files from LS1 to DC1..." + $scpResponse = az vm run-command invoke ` + --command-id RunPowerShellScript ` + --name $DomainController ` + --resource-group $ResourceGroup ` + --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") + Write-Output $ProcessSeparator -# Extract the files on DC1 -Write-Output "`nExtracting the files on DC1..." -$extractFilesForWindowsResponse = .\extract_archive.ps1 ` - -VMName $DomainController ` - -ResourceGroup $ResourceGroup ` - -FileName "files_for_windows.zip" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") -Write-Output $ProcessSeparator + # Extract the files on DC1 + Write-Output "`nExtracting the files on DC1..." + $extractFilesForWindowsResponse = .\extract_archive.ps1 ` + -VMName $DomainController ` + -ResourceGroup $ResourceGroup ` + -FileName "files_for_windows.zip" + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractFilesForWindowsResponse") + Write-Output $ProcessSeparator -# Install winlogbeat on DC1 -Write-Output "`nInstalling winlogbeat on DC1..." -$installWinlogbeatResponse = .\run_script_in_container.ps1 ` - -ResourceGroup $ResourceGroup ` - -VMName $DomainController ` - -ScriptPathOnVM "C:\lme\configure\winlogbeat_install.ps1" + # Install winlogbeat on DC1 + Write-Output "`nInstalling winlogbeat on DC1..." + $installWinlogbeatResponse = .\run_script_in_container.ps1 ` + -ResourceGroup $ResourceGroup ` + -VMName $DomainController ` + -ScriptPathOnVM "C:\lme\configure\winlogbeat_install.ps1" -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") -Write-Output $ProcessSeparator + Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installWinlogbeatResponse") + Write-Output $ProcessSeparator +} Write-Output "`nInstall completed." diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index be4355ae..f82c94fe 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -451,7 +451,7 @@ if (Wait-Job -Job `$job -Timeout `$timeout) { --scripts "C:\AddDnsRecord.ps1" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$addDnsRecordResponse") - Write-Host "Checking if ls1 resolves. This should resolve to ls1.lme.local->${$LsIP}, not another domain..." + Write-Host "Checking if ls1 resolves. This should resolve to ls1.lme.local->${LsIP}, not another domain..." $resolveLs1Response = az vm run-command invoke ` --command-id RunPowerShellScript ` --resource-group $ResourceGroup ` diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index db761910..b16732f5 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -33,7 +33,7 @@ echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Execute script with root privileges -sudo -E bash -c ". /root.bashrc && $script_dir/linux_install_lme.exp" +sudo -E bash -c ". /root/.bashrc && $script_dir/linux_install_lme.exp" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ From 437648c995ed3f1dec8c6fc868973da7ab7804c4 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 23 Jan 2024 05:34:28 -0500 Subject: [PATCH 076/103] Adds simple tests to check install --- testing/configure/linux_test_install.sh | 142 ++++++++++++++++++++++++ 1 file changed, 142 insertions(+) create mode 100644 testing/configure/linux_test_install.sh diff --git a/testing/configure/linux_test_install.sh b/testing/configure/linux_test_install.sh new file mode 100644 index 00000000..64fd7cc4 --- /dev/null +++ b/testing/configure/linux_test_install.sh @@ -0,0 +1,142 @@ +#!/usr/bin/env bash +set -e +file_path='/opt/lme/Chapter 3 Files/output.log' + +# Check if the file exists +if [ ! -f "$file_path" ]; then + echo "File not found!" + exit 1 +fi + +# Read and extract credentials from the last 18 lines +while IFS= read -r line; do + # Remove leading '## ' and trim whitespaces from the line + line=$(echo "$line" | sed 's/^## //g' | xargs) + + # Split the line into key and value + key=$(echo "$line" | awk -F ':' '{print $1}') + value=$(echo "$line" | awk -F ':' '{print $2}' | xargs) # xargs to trim whitespaces from value + + # Remove non-word characters (keep only word characters) + value=$(echo "$value" | sed 's/[^[:alnum:]_]//g') + + case $key in + "elastic") elastic=$value ;; + "kibana") kibana=$value ;; + "logstash_system") logstash_system=$value ;; + "logstash_writer") logstash_writer=$value ;; + "dashboard_update") dashboard_update=$value ;; + esac +done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") + + +check_variable() { + local var_name="$1" + local var_value="$2" + + if [ -z "$var_value" ]; then + echo "Error: '$var_name' is not set or is empty" + return 1 # Return a non-zero status to indicate failure + fi +} + +# Perform the checks +check_variable "elastic" "$elastic" || exit 1 +check_variable "kibana" "$kibana" || exit 1 +check_variable "logstash_system" "$logstash_system" || exit 1 +check_variable "logstash_writer" "$logstash_writer" || exit 1 +check_variable "dashboard_update" "$dashboard_update" || exit 1 + +echo "All variables are set correctly." + +# Get the list of containers and their health status +container_statuses=$(docker ps --format "{{.Names}}: {{.Status}}" | grep -v "CONTAINER ID") + +# Check each container's status +unhealthy=false +while read -r line; do + container_name=$(echo "$line" | awk -F': ' '{print $1}') + health_status=$(echo "$line" | awk -F': ' '{print $2}') + + if [[ $health_status != *"(healthy)"* ]]; then + echo "Container $container_name is not healthy: $health_status" + unhealthy=true + exit 1 + fi +done <<< "$container_statuses" + +# Final check +if [ "$unhealthy" = false ]; then + echo "All containers are healthy." +fi + +ELASTICSEARCH_HOST="localhost" +ELASTICSEARCH_PORT="9200" + +# Get list of all indexes +indexes=$(curl -sk -u "elastic:$elastic" "https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}/_cat/indices?v" | awk '{print $3}') + +# Check if winlogbeat index exists +if echo "$indexes" | grep -q "winlogbeat"; then + echo "Index 'winlogbeat' exists." +else + echo "Index 'winlogbeat' does not exist." >&2 + exit 1 +fi + +# Check if we can query the winlogbeat index +response=$(curl -sk -u "elastic:$elastic" "https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}/winlogbeat-*/_search" -H "Content-Type: application/json" -d '{ + "size": 1, + "query": { + "match_all": {} + } +}') + +# Check if the curl command was successful +if [ $? -eq 0 ]; then + echo "Querying winlogbeat executed successfully." +else + echo "Error executing the query of winlogbeat." >&2 + exit 1 +fi + +# Check the kibana saved objects. +# response=$(curl -sk -u "elastic:$elastic" "https://${ELASTICSEARCH_HOST}:${ELASTICSEARCH_PORT}/.kibana/_search" -H "Content-Type: application/json" -d '{ +# "size": 1000, +# "query": { +# "term": { +# "type": "dashboard" +# } +# } +# }') +# echo $response + + +response=$(curl -sk -u "elastic:$elastic" "https://${ELASTICSEARCH_HOST}/api/kibana/management/saved_objects/_find?perPage=500&page=1&type=dashboard&sortField=updated_at&sortOrder=desc") + +#!/bin/bash + +# List of dashboard names to check +declare -a names_to_check=( + "User Security" + "User HR" + "Sysmon Summary" + "Security Dashboard - Security Log" + "Process Explorer" + "Computer Software Overview" + "Alerting Dashboard" + "HealthCheck Dashboard - Overview" +) + +# Extract dashboard names from the JSON response stored in the variable +dashboard_names=$(echo "$response" | jq -r '.saved_objects[] | select(.type == "dashboard") | .meta.title') + +# Check each name +for name in "${names_to_check[@]}"; do + if grep -qF "$name" <<< "$dashboard_names"; then + echo "Dashboard found: $name" + else + echo "Dashboard NOT found: $name" >&2 + exit 1 + fi +done From 066166e7b826f572a0f0e7067e86816f841d6358 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 23 Jan 2024 07:33:21 -0500 Subject: [PATCH 077/103] Adds simple tests to check install --- testing/InstallTestbed.ps1 | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index f0c36759..d72e3c30 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -348,6 +348,25 @@ $EsPasswords = (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPass # Output the passwords $EsPasswords +Write-Output "`nRunning the tests for lme on LS1..." +$runTestResponse = az vm run-command invoke ` + --command-id RunShellScript ` + --name LS1 ` + --resource-group LME-cbaxley-L3 ` + --scripts '/home/admin.ackbar/lme/configure/linux_test_install.sh' | ConvertFrom-Json + +$message = $runTestResponse.value[0].message +Write-Host "$message`n" +Write-Host "--------------------------------------------" + +# Check if there is stderr content in the message field +if ($message -match '\[stderr\]\n(.+)$') { + Write-Host "Tests failed" + exit 1 +} else { + Write-Host "Tests succeeded" +} + # Write the passwords to a file $PasswordPath = "..\..\${ResourceGroup}.password.txt" $EsPasswords | Out-File -Append -FilePath $PasswordPath \ No newline at end of file From 7b874c21c08fd7e94219fd315f3b0e4af083a9cf Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 23 Jan 2024 07:51:57 -0500 Subject: [PATCH 078/103] Removes the error if the old configure zip is not found. --- testing/InstallTestbed.ps1 | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index d72e3c30..b5c3b40d 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -50,9 +50,8 @@ Write-Output "`nSourcing the variables from the file..." # Remove old code if it exists if (Test-Path ./configure.zip) { Remove-Item ./configure.zip -Force -Confirm:$false -ErrorAction SilentlyContinue -} else { - Write-Output "File not found." } + Write-Output $ProcessSeparator # Zip up the installer scripts for the VM @@ -342,11 +341,6 @@ if (-Not $LinuxOnly){ Write-Output $ProcessSeparator } -Write-Output "`nInstall completed." - -$EsPasswords = (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut -# Output the passwords -$EsPasswords Write-Output "`nRunning the tests for lme on LS1..." $runTestResponse = az vm run-command invoke ` @@ -367,6 +361,12 @@ if ($message -match '\[stderr\]\n(.+)$') { Write-Host "Tests succeeded" } +Write-Output "`nInstall completed." + +$EsPasswords = (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse")[0].StdOut +# Output the passwords +$EsPasswords + # Write the passwords to a file $PasswordPath = "..\..\${ResourceGroup}.password.txt" $EsPasswords | Out-File -Append -FilePath $PasswordPath \ No newline at end of file From 84eda1def425ac54d758ed22363a20a1e2c96ee3 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 24 Jan 2024 06:15:41 -0500 Subject: [PATCH 079/103] Removes the error if the old configure zip is not found. --- testing/InstallTestbed.ps1 | 2 +- testing/configure/linux_test_install.sh | 12 +++++++----- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index b5c3b40d..4ba4e596 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -317,7 +317,7 @@ if (-Not $LinuxOnly){ --command-id RunPowerShellScript ` --name $DomainController ` --resource-group $ResourceGroup ` - --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' + --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1.lme.local:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") Write-Output $ProcessSeparator diff --git a/testing/configure/linux_test_install.sh b/testing/configure/linux_test_install.sh index 64fd7cc4..a82ac0e4 100644 --- a/testing/configure/linux_test_install.sh +++ b/testing/configure/linux_test_install.sh @@ -21,14 +21,16 @@ while IFS= read -r line; do value=$(echo "$value" | sed 's/[^[:alnum:]_]//g') case $key in - "elastic") elastic=$value ;; - "kibana") kibana=$value ;; - "logstash_system") logstash_system=$value ;; - "logstash_writer") logstash_writer=$value ;; - "dashboard_update") dashboard_update=$value ;; + "elastic") export elastic=$value ;; + "kibana") export kibana=$value ;; + "logstash_system") export logstash_system=$value ;; + "logstash_writer") export logstash_writer=$value ;; + "dashboard_update") export dashboard_update=$value ;; esac done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") +process.env.elastic +export elastic=blah node bruno whatever check_variable() { local var_name="$1" From 7727bed1f9340c6d8c58bb392ad1b81fa6e96d95 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 24 Jan 2024 06:37:38 -0500 Subject: [PATCH 080/103] Adds variables to linux tests run command --- testing/InstallTestbed.ps1 | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 4ba4e596..66c4078c 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -345,8 +345,8 @@ if (-Not $LinuxOnly){ Write-Output "`nRunning the tests for lme on LS1..." $runTestResponse = az vm run-command invoke ` --command-id RunShellScript ` - --name LS1 ` - --resource-group LME-cbaxley-L3 ` + --name $LinuxVM ` + --resource-group $ResourceGroup ` --scripts '/home/admin.ackbar/lme/configure/linux_test_install.sh' | ConvertFrom-Json $message = $runTestResponse.value[0].message From 07e17a229ee6702fa5719677d6f5f5fe0b9189fa Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 24 Jan 2024 06:58:59 -0500 Subject: [PATCH 081/103] Move credential extraction to lib for use by other scripts. --- testing/configure/lib/functions.sh | 35 ++++++++++++++ testing/configure/linux_test_install.sh | 64 +++++++++++++------------ 2 files changed, 69 insertions(+), 30 deletions(-) create mode 100644 testing/configure/lib/functions.sh diff --git a/testing/configure/lib/functions.sh b/testing/configure/lib/functions.sh new file mode 100644 index 00000000..d4ac1f17 --- /dev/null +++ b/testing/configure/lib/functions.sh @@ -0,0 +1,35 @@ +# Function to extract credentials from a log file +extract_credentials() { + local file_path=$1 + + # Check if the file exists + if [ ! -f "$file_path" ]; then + echo "File not found!" + return 1 + fi + + # Read and extract credentials from the last 18 lines + while IFS= read -r line; do + # Remove leading '## ' and trim whitespaces from the line + line=$(echo "$line" | sed 's/^## //g' | xargs) + + # Split the line into key and value + key=$(echo "$line" | awk -F ':' '{print $1}') + value=$(echo "$line" | awk -F ':' '{print $2}' | xargs) # xargs to trim whitespaces from value + + # Remove non-word characters (keep only word characters) + value=$(echo "$value" | sed 's/[^[:alnum:]_]//g') + + case $key in + "elastic") export elastic=$value ;; + "kibana") export kibana=$value ;; + "logstash_system") export logstash_system=$value ;; + "logstash_writer") export logstash_writer=$value ;; + "dashboard_update") export dashboard_update=$value ;; + esac + done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") +} + +# Usage in another script +# source /path/to/credential_extractor.sh +# extract_credentials '/opt/lme/Chapter 3 Files/output.log' diff --git a/testing/configure/linux_test_install.sh b/testing/configure/linux_test_install.sh index a82ac0e4..20728a1f 100644 --- a/testing/configure/linux_test_install.sh +++ b/testing/configure/linux_test_install.sh @@ -1,36 +1,40 @@ #!/usr/bin/env bash set -e -file_path='/opt/lme/Chapter 3 Files/output.log' -# Check if the file exists -if [ ! -f "$file_path" ]; then - echo "File not found!" - exit 1 -fi - -# Read and extract credentials from the last 18 lines -while IFS= read -r line; do - # Remove leading '## ' and trim whitespaces from the line - line=$(echo "$line" | sed 's/^## //g' | xargs) - - # Split the line into key and value - key=$(echo "$line" | awk -F ':' '{print $1}') - value=$(echo "$line" | awk -F ':' '{print $2}' | xargs) # xargs to trim whitespaces from value - - # Remove non-word characters (keep only word characters) - value=$(echo "$value" | sed 's/[^[:alnum:]_]//g') - - case $key in - "elastic") export elastic=$value ;; - "kibana") export kibana=$value ;; - "logstash_system") export logstash_system=$value ;; - "logstash_writer") export logstash_writer=$value ;; - "dashboard_update") export dashboard_update=$value ;; - esac -done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") - -process.env.elastic -export elastic=blah node bruno whatever +# Get the full path to the directory containing the current script +script_dir=$(dirname "$(realpath "${BASH_SOURCE[0]}")") + +source "${script_dir}/lib/functions.sh" +extract_credentials '/opt/lme/Chapter 3 Files/output.log' + +#file_path='/opt/lme/Chapter 3 Files/output.log' +# +## Check if the file exists +#if [ ! -f "$file_path" ]; then +# echo "File not found!" +# exit 1 +#fi +# +## Read and extract credentials from the last 18 lines +#while IFS= read -r line; do +# # Remove leading '## ' and trim whitespaces from the line +# line=$(echo "$line" | sed 's/^## //g' | xargs) +# +# # Split the line into key and value +# key=$(echo "$line" | awk -F ':' '{print $1}') +# value=$(echo "$line" | awk -F ':' '{print $2}' | xargs) # xargs to trim whitespaces from value +# +# # Remove non-word characters (keep only word characters) +# value=$(echo "$value" | sed 's/[^[:alnum:]_]//g') +# +# case $key in +# "elastic") export elastic=$value ;; +# "kibana") export kibana=$value ;; +# "logstash_system") export logstash_system=$value ;; +# "logstash_writer") export logstash_writer=$value ;; +# "dashboard_update") export dashboard_update=$value ;; +# esac +#done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") check_variable() { local var_name="$1" From 246a5db8d1090674ac455cc2627394860392ce17 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 24 Jan 2024 07:34:17 -0500 Subject: [PATCH 082/103] Adds npm for other testing --- testing/configure/linux_test_install.sh | 29 ------------------------ testing/configure/linux_update_system.sh | 2 +- 2 files changed, 1 insertion(+), 30 deletions(-) diff --git a/testing/configure/linux_test_install.sh b/testing/configure/linux_test_install.sh index 20728a1f..3dda731d 100644 --- a/testing/configure/linux_test_install.sh +++ b/testing/configure/linux_test_install.sh @@ -7,35 +7,6 @@ script_dir=$(dirname "$(realpath "${BASH_SOURCE[0]}")") source "${script_dir}/lib/functions.sh" extract_credentials '/opt/lme/Chapter 3 Files/output.log' -#file_path='/opt/lme/Chapter 3 Files/output.log' -# -## Check if the file exists -#if [ ! -f "$file_path" ]; then -# echo "File not found!" -# exit 1 -#fi -# -## Read and extract credentials from the last 18 lines -#while IFS= read -r line; do -# # Remove leading '## ' and trim whitespaces from the line -# line=$(echo "$line" | sed 's/^## //g' | xargs) -# -# # Split the line into key and value -# key=$(echo "$line" | awk -F ':' '{print $1}') -# value=$(echo "$line" | awk -F ':' '{print $2}' | xargs) # xargs to trim whitespaces from value -# -# # Remove non-word characters (keep only word characters) -# value=$(echo "$value" | sed 's/[^[:alnum:]_]//g') -# -# case $key in -# "elastic") export elastic=$value ;; -# "kibana") export kibana=$value ;; -# "logstash_system") export logstash_system=$value ;; -# "logstash_writer") export logstash_writer=$value ;; -# "dashboard_update") export dashboard_update=$value ;; -# esac -#done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") - check_variable() { local var_name="$1" local var_value="$2" diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh index 6e666be0..dddac00d 100644 --- a/testing/configure/linux_update_system.sh +++ b/testing/configure/linux_update_system.sh @@ -1,3 +1,3 @@ # Install Git client to be able to clone the LME repository sudo apt update -sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq expect -y \ No newline at end of file +sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq npm expect -y \ No newline at end of file From 5523a1f6c752d7b14bcceb462490f8783ca7c413 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 24 Jan 2024 08:03:14 -0500 Subject: [PATCH 083/103] Adds latest version of nodejs for testing --- testing/configure/linux_update_system.sh | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh index dddac00d..b132f2ab 100644 --- a/testing/configure/linux_update_system.sh +++ b/testing/configure/linux_update_system.sh @@ -1,3 +1,6 @@ # Install Git client to be able to clone the LME repository +curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh +chmod +x nodesource_setup.sh +sudo ./nodesource_setup.sh sudo apt update -sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq npm expect -y \ No newline at end of file +sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq nodejs expect -y \ No newline at end of file From 9435d10264474bbf9549a005fbccdee8f1e10d4d Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 24 Jan 2024 09:32:32 -0500 Subject: [PATCH 084/103] Make output.log readable for tests --- testing/configure/lib/functions.sh | 10 +++------- testing/configure/linux_install_lme.sh | 2 ++ 2 files changed, 5 insertions(+), 7 deletions(-) diff --git a/testing/configure/lib/functions.sh b/testing/configure/lib/functions.sh index d4ac1f17..c9c013cf 100644 --- a/testing/configure/lib/functions.sh +++ b/testing/configure/lib/functions.sh @@ -1,10 +1,10 @@ -# Function to extract credentials from a log file extract_credentials() { - local file_path=$1 + # Set default file path if not provided + local file_path=${1:-'/opt/lme/Chapter 3 Files/output.log'} # Check if the file exists if [ ! -f "$file_path" ]; then - echo "File not found!" + echo "File not found: $file_path" return 1 fi @@ -29,7 +29,3 @@ extract_credentials() { esac done < <(tail -n 18 "$file_path" | grep -E "(elastic|kibana|logstash_system|logstash_writer|dashboard_update):") } - -# Usage in another script -# source /path/to/credential_extractor.sh -# extract_credentials '/opt/lme/Chapter 3 Files/output.log' diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index b16732f5..f86e9ced 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -35,6 +35,8 @@ echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Execute script with root privileges sudo -E bash -c ". /root/.bashrc && $script_dir/linux_install_lme.exp" +chmod ugo+w "/opt/lme/Chapter\ 3\ Files/output.log" + if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip From 71381f15c85df9ccbe3301ab768d21b990963c11 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 25 Jan 2024 06:32:22 -0500 Subject: [PATCH 085/103] Add the -m parameter in the testing readme --- testing/Readme.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/testing/Readme.md b/testing/Readme.md index 77b3cd40..e212f690 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -22,6 +22,7 @@ This script does not install LME; it simply creates a fresh environment that's r | $AllowedSources | -s | Comma-Separated list of CIDR prefixes or IP ranges, e.g. XX.XX.XX.XX/YY,XX.XX.XX.XX/YY,etc..., that are allowed to connect to the VMs via RDP and ssh. | Yes | | $Location | -l | The region you would like to build the assets in. Defaults to westus | No | | $NoPrompt | -y | Switch, run the script with no prompt (useful for automated runs). By default, the script will prompt the user to review paramters and confirm before continuing. | No | +| $LinuxOnly | -m | Run a minimal install of only the linux server | No | Example: ``` @@ -59,16 +60,17 @@ Flags: ## Install LME on the cluster: ### InstallTestbed.ps1 ## Usage -| **Parameter** | **Alias** | **Description** | **Required** | -|-------------------|-----------|----------------------------------------------------------------------------------------|--------------| -| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | -| $NumClients | -n | The number of Windows clients you have created; defaults to 2 | No | -| $DomainController | -w | The name of the domain controller in the cluster; defaults to "DC1" | No | -| $LinuxVm | -l | The name of the linux server in the cluster; defaults to "LS1" | No | +| **Parameter** | **Alias** | **Description** | **Required** | +|---------------------|-----------|----------------------------------------------------------------------------------------|--------------| +| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | +| $NumClients | -n | The number of Windows clients you have created; defaults to 2 | No | +| $DomainController | -w | The name of the domain controller in the cluster; defaults to "DC1" | No | +| $LinuxVm | -l | The name of the linux server in the cluster; defaults to "LS1" | No | +| $LinuxOnly | -m | Run a minimal install of only the linux server | No | Example: ``` -./InstallTestbed.ps1 --ResourceGroup YourResourceGroup +./InstallTestbed.ps1 -ResourceGroup YourResourceGroup # Or if you want to save the output to a file ./InstallTestbed.ps1 -ResourceGroup YourResourceGroup | Tee-Object -FilePath "./YourResourceGroup.output.log" ``` From 6b52688320902609a251093d9748e574803a8af4 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 25 Jan 2024 08:08:49 -0500 Subject: [PATCH 086/103] Download the latest version or a specified version --- testing/InstallTestbed.ps1 | 22 +++++++++---- testing/configure/linux_install_lme.sh | 45 ++++++++++++++++++++++++-- 2 files changed, 57 insertions(+), 10 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 66c4078c..0ad8c8da 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -14,9 +14,12 @@ param ( [Alias("m")] [Parameter( - HelpMessage = "(minimal) Only install the linux server. Useful for testing the linux server without the windows clients" + HelpMessage = "(minimal) Only install the linux server. Useful for testing the linux server without the windows clients" )] - [switch]$LinuxOnly + [switch]$LinuxOnly, + + [Alias("v")] + [string]$Version = $false ) # If you were to need the password from the SetupTestbed.ps1 script, you could use this: @@ -36,6 +39,11 @@ else { Write-Error "Library script not found at path: $LibraryPath" } +if ($Version -and -not ($Version -match '^[0-9]+\.[0-9]+\.[0-9]+$')) { + Write-Host "Invalid version format: $Version. Expected format: X.Y.Z (e.g., 1.3.0)" + exit 1 +} + # Create a container to keep files for the VM Write-Output "Creating a container to keep files for the VM..." $createBlobResponse = ./configure/azure_scripts/create_blob_container.ps1 ` @@ -193,7 +201,6 @@ $extractLinuxArchiveResponse = .\extract_archive.ps1 ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$extractLinuxArchiveResponse") Write-Output $ProcessSeparator -# Make the installer files executable and update the system packages on LS1 Write-Output "`nMaking the installer files executable and updating the system packages on LS1..." $updateLinuxResponse = az vm run-command invoke ` --command-id RunShellScript ` @@ -203,13 +210,15 @@ $updateLinuxResponse = az vm run-command invoke ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$updateLinuxResponse") Write-Output $ProcessSeparator -# Run the lme installer on LS1 +if ($Version) { + $versionArgument = " -v $Version" +} Write-Output "`nRunning the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVM ` --resource-group $ResourceGroup ` - --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' + --scripts "/home/admin.ackbar/lme/configure/linux_install_lme.sh $versionArgument" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") Write-Output $ProcessSeparator @@ -223,13 +232,12 @@ if ($rebootCheckstring -match "A reboot is required in order to proceed with the --name $LinuxVM Write-Output $ProcessSeparator - # Run the lme installer on LS1 Write-Output "`nRunning the lme installer on LS1..." $installLmeResponse = az vm run-command invoke ` --command-id RunShellScript ` --name $LinuxVM ` --resource-group $ResourceGroup ` - --scripts '/home/admin.ackbar/lme/configure/linux_install_lme.sh' + --scripts "/home/admin.ackbar/lme/configure/linux_install_lme.sh $versionArgument" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installLmeResponse") Write-Output $ProcessSeparator } diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index f86e9ced..3fb001a6 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -9,20 +9,59 @@ script_dir=$(pwd) # Default username username="admin.ackbar" -# Parse flag-based arguments -while getopts "u:" opt; do +# Process command line arguments +while getopts "u:v:" opt; do case $opt in u) username=$OPTARG ;; + v) version=$OPTARG ;; \?) echo "Invalid option -$OPTARG" >&2; exit 1 ;; esac done +# Check if version matches the pattern +if [[ -n "$version" && ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then + echo "Invalid version format. Version should match \d+.\d+.\d+" + exit 1 +fi + # Download a copy of the LME files #sudo git clone https://github.com/cisagov/lme.git /opt/lme/ -sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lme.git /opt/lme/ +#sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lme.git /opt/lme/ # curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.assets[0].browser_download_url' | xargs -I {} sh -c 'curl -L -O {}' && unzip -d /opt/lme/ "$(basename {})"' # https://github.com/cisagov/LME/archive/refs/tags/v1.3.1.zip +# Remove any existing LME directories +sudo rm -rf /opt/cisagov-LME-* /opt/lme + +# Get the tarball URL for the specified version +get_tarball_url() { + echo "https://api.github.com/repos/cisagov/LME/tarball/v$1" +} + +# Check if a version is provided +if [ -n "$version" ]; then + tarball_url=$(get_tarball_url "$version") +else + tarball_url=$(curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.tarball_url') +fi + +# Get the version from the tarball URL +v_version=$(basename "$tarball_url") + +echo "Downloading $tarball_url to file: $v_version" +curl -L "$tarball_url" -o "$v_version" + +# extracts it to a folder like cisagov-LME-3412897 +sudo tar -xzpf "$v_version" -C /opt +rm -rf "$v_version" + +extracted_filename=$(sudo ls -ltd /opt/cisagov-LME-* | grep "^d" | head -n 1 | awk '{print $NF}') + +echo "Extracted to $extracted_filename" + +echo "Renaming directory to /opt/lme" +sudo mv "$extracted_filename" /opt/lme + echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc echo 'export NEEDRESTART_MODE=a' >> ~/.bashrc From 03a98f0a82923c12abc3d60221a214dceb75bd77 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 25 Jan 2024 08:26:25 -0500 Subject: [PATCH 087/103] Download the latest version or a specified version --- testing/InstallTestbed.ps1 | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 0ad8c8da..b4db0392 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -39,7 +39,7 @@ else { Write-Error "Library script not found at path: $LibraryPath" } -if ($Version -and -not ($Version -match '^[0-9]+\.[0-9]+\.[0-9]+$')) { +if ($Version -ne $false -and -not ($Version -match '^[0-9]+\.[0-9]+\.[0-9]+$')) { Write-Host "Invalid version format: $Version. Expected format: X.Y.Z (e.g., 1.3.0)" exit 1 } @@ -210,7 +210,8 @@ $updateLinuxResponse = az vm run-command invoke ` Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$updateLinuxResponse") Write-Output $ProcessSeparator -if ($Version) { +$versionArgument = "" +if ($Version -ne $false) { $versionArgument = " -v $Version" } Write-Output "`nRunning the lme installer on LS1..." From 05f548c18a680dea4ea829dd0279017152cfa4e9 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 25 Jan 2024 08:56:43 -0500 Subject: [PATCH 088/103] Download the latest version or a specified version --- testing/configure/linux_install_lme.sh | 6 ------ 1 file changed, 6 deletions(-) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 3fb001a6..07ae7c27 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -24,12 +24,6 @@ if [[ -n "$version" && ! $version =~ ^[0-9]+\.[0-9]+\.[0-9]+$ ]]; then exit 1 fi -# Download a copy of the LME files -#sudo git clone https://github.com/cisagov/lme.git /opt/lme/ -#sudo git clone -b cbaxley-122-testbed_from_scripts https://github.com/cisagov/lme.git /opt/lme/ -# curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.assets[0].browser_download_url' | xargs -I {} sh -c 'curl -L -O {}' && unzip -d /opt/lme/ "$(basename {})"' -# https://github.com/cisagov/LME/archive/refs/tags/v1.3.1.zip - # Remove any existing LME directories sudo rm -rf /opt/cisagov-LME-* /opt/lme From 488e40b92d5ead56b523db9c6a13473a1714476c Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 26 Jan 2024 03:53:18 -0500 Subject: [PATCH 089/103] Reboot for 1.3.0 --- testing/InstallTestbed.ps1 | 2 +- testing/configure/linux_install_lme.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index b4db0392..9d2f6f3d 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -225,7 +225,7 @@ Write-Output $ProcessSeparator # Check if the response contains the need to reboot $rebootCheckstring = $installLmeResponse | Out-String -if ($rebootCheckstring -match "A reboot is required in order to proceed with the install") { +if ($rebootCheckstring -match "reboot is required in order to proceed with the install") { # Have to check for the reboot thing here Write-Output "`nRebooting ${LinuxVM}..." az vm restart ` diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 07ae7c27..e39dfaf3 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -74,5 +74,5 @@ if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ sudo chown "$username":"$username" /home/"$username"/files_for_windows.zip else - echo "files_for_windows.zip does not exist. Probably because the LME install requires a reboot." + echo "files_for_windows.zip does not exist. Probably because a reboot is required in order to proceed with the install" fi From 7818afbeb9a742d49ceb1864e3315901b211a2b0 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 26 Jan 2024 03:54:52 -0500 Subject: [PATCH 090/103] Notes that we could have different expect scripts --- testing/configure/linux_install_lme.sh | 1 + 1 file changed, 1 insertion(+) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index e39dfaf3..2e8ed736 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -66,6 +66,7 @@ echo 'export DEBIAN_FRONTEND=noninteractive' | sudo tee -a /root/.bashrc echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Execute script with root privileges +# Todo: We could put a switch here for different versions and just run different expect scripts sudo -E bash -c ". /root/.bashrc && $script_dir/linux_install_lme.exp" chmod ugo+w "/opt/lme/Chapter\ 3\ Files/output.log" From 9bd97227a2fb84498350e9a3885d2313581ecd99 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 26 Jan 2024 07:01:09 -0500 Subject: [PATCH 091/103] Put back in the restart after all of the domain updates --- testing/SetupTestbed.ps1 | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index f82c94fe..7d0230f4 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -349,10 +349,10 @@ if (-Not $LinuxOnly){ Install-ADDSForest -DomainName $DomainName -Force -SafeModeAdministratorPassword `$Password" Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$installAddsForestResponse") -# Write-Output "`nRestarting DC1..." -# az vm restart ` -# --resource-group $ResourceGroup ` -# --name DC1 ` + Write-Output "`nRestarting DC1..." + az vm restart ` + --resource-group $ResourceGroup ` + --name DC1 ` for ($i = 1; $i -le $NumClients; $i++) { Write-Output "`nAdding DC IP address to C$i host file..." From 52225a7770e73a32e4b75ca12e9248bfb7177fe0 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 26 Jan 2024 08:23:38 -0500 Subject: [PATCH 092/103] Scp uses ls1 instead of ls1.lme.local --- testing/InstallTestbed.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index 9d2f6f3d..c0289133 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -326,7 +326,7 @@ if (-Not $LinuxOnly){ --command-id RunPowerShellScript ` --name $DomainController ` --resource-group $ResourceGroup ` - --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1.lme.local:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' + --scripts 'scp -o StrictHostKeyChecking=no -i "C:\lme\id_rsa" admin.ackbar@ls1:/home/admin.ackbar/files_for_windows.zip "C:\lme\"' Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$scpResponse") Write-Output $ProcessSeparator From 0fabcc35c0841c326210bd2b016736b88ca7128a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 26 Jan 2024 09:03:52 -0500 Subject: [PATCH 093/103] Up the timeout of the adding ls1.lme.local --- testing/SetupTestbed.ps1 | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/SetupTestbed.ps1 b/testing/SetupTestbed.ps1 index 7d0230f4..6e189f99 100644 --- a/testing/SetupTestbed.ps1 +++ b/testing/SetupTestbed.ps1 @@ -417,7 +417,7 @@ if (-Not $LinuxOnly){ Add-DnsServerResourceRecordA -Name LS1 -ZoneName $DomainName. -AllowUpdateAny -IPv4Address $LsIP -TimeToLive 01:00:00 -AsJob } `$job = Start-Job -ScriptBlock `$scriptBlock -`$timeout = 60 +`$timeout = 90 if (Wait-Job -Job `$job -Timeout `$timeout) { Receive-Job -Job `$job Write-Host 'The script completed within the timeout period.' From 9cb4dfcd493a4f2535f06d90f45fdfaa59cad6ce Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Mon, 29 Jan 2024 05:18:17 -0500 Subject: [PATCH 094/103] Up the timeout of the adding ls1.lme.local --- testing/configure/linux_update_system.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh index b132f2ab..20868c50 100644 --- a/testing/configure/linux_update_system.sh +++ b/testing/configure/linux_update_system.sh @@ -3,4 +3,4 @@ curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh chmod +x nodesource_setup.sh sudo ./nodesource_setup.sh sudo apt update -sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq nodejs expect -y \ No newline at end of file +sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq nodejs expect python3-venv -y \ No newline at end of file From df245bc377597907a2b37acceb14e8a047ba736f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 30 Jan 2024 06:02:25 -0500 Subject: [PATCH 095/103] Fixes chmod of the output.log for tests --- testing/configure/linux_install_lme.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 2e8ed736..04f1a264 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -69,7 +69,7 @@ echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Todo: We could put a switch here for different versions and just run different expect scripts sudo -E bash -c ". /root/.bashrc && $script_dir/linux_install_lme.exp" -chmod ugo+w "/opt/lme/Chapter\ 3\ Files/output.log" +chmod ugo+w "/opt/lme/Chapter 3 Files/output.log" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ From cfc8e0eeef04e1357054578ac88e9f8ee7638f8e Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 30 Jan 2024 06:03:25 -0500 Subject: [PATCH 096/103] Adds venv to the gitignore --- .gitignore | 1189 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1189 insertions(+) diff --git a/.gitignore b/.gitignore index 5b650322..a2c14cdd 100644 --- a/.gitignore +++ b/.gitignore @@ -15,3 +15,1192 @@ dashboard_update.sh files_for_windows.zip lme.conf lme_update.sh +/testing/tests/venv/bin/activate +/testing/tests/venv/bin/activate.csh +/testing/tests/venv/bin/activate.fish +/testing/tests/venv/bin/Activate.ps1 +/testing/tests/venv/bin/jsonschema +/testing/tests/venv/bin/normalizer +/testing/tests/venv/bin/pip +/testing/tests/venv/bin/pip3 +/testing/tests/venv/bin/pip3.10 +/testing/tests/venv/bin/pip3.11 +/testing/tests/venv/bin/py.test +/testing/tests/venv/bin/pytest +/testing/tests/venv/bin/python +/testing/tests/venv/bin/python3 +/testing/tests/venv/bin/python3.10 +/testing/tests/venv/lib/python3.10/site-packages/_distutils_hack/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_distutils_hack/override.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_code/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_code/code.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_code/source.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/pprint.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/saferepr.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/terminalwriter.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/wcwidth.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_py/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_py/error.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_py/path.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/rewrite.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/truncate.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/util.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/argparsing.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/compat.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/findpaths.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/mark/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/mark/expression.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/mark/structures.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_argcomplete.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/_version.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/cacheprovider.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/capture.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/compat.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/debugging.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/deprecated.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/doctest.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/faulthandler.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/fixtures.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/freeze_support.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/helpconfig.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/hookspec.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/junitxml.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/legacypath.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/logging.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/main.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/monkeypatch.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/nodes.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/nose.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/outcomes.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/pastebin.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/pathlib.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/py.typed +/testing/tests/venv/lib/python3.10/site-packages/_pytest/pytester.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/pytester_assertions.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/python.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/python_api.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/python_path.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/recwarn.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/reports.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/runner.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/scope.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/setuponly.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/setupplan.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/skipping.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/stash.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/stepwise.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/terminal.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/threadexception.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/timing.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/tmpdir.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/unittest.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/unraisableexception.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/warning_types.py +/testing/tests/venv/lib/python3.10/site-packages/_pytest/warnings.py +/testing/tests/venv/lib/python3.10/site-packages/attr/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/attr/__init__.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/_cmp.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_cmp.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/_compat.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_config.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_funcs.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_make.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_next_gen.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_typing_compat.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/_version_info.py +/testing/tests/venv/lib/python3.10/site-packages/attr/_version_info.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/converters.py +/testing/tests/venv/lib/python3.10/site-packages/attr/converters.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/attr/exceptions.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/filters.py +/testing/tests/venv/lib/python3.10/site-packages/attr/filters.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/py.typed +/testing/tests/venv/lib/python3.10/site-packages/attr/setters.py +/testing/tests/venv/lib/python3.10/site-packages/attr/setters.pyi +/testing/tests/venv/lib/python3.10/site-packages/attr/validators.py +/testing/tests/venv/lib/python3.10/site-packages/attr/validators.pyi +/testing/tests/venv/lib/python3.10/site-packages/attrs/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/attrs/__init__.pyi +/testing/tests/venv/lib/python3.10/site-packages/attrs/converters.py +/testing/tests/venv/lib/python3.10/site-packages/attrs/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/attrs/filters.py +/testing/tests/venv/lib/python3.10/site-packages/attrs/py.typed +/testing/tests/venv/lib/python3.10/site-packages/attrs/setters.py +/testing/tests/venv/lib/python3.10/site-packages/attrs/validators.py +/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/licenses/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/certifi/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/certifi/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/certifi/cacert.pem +/testing/tests/venv/lib/python3.10/site-packages/certifi/core.py +/testing/tests/venv/lib/python3.10/site-packages/certifi/py.typed +/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/cli/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/cli/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/api.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/cd.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/constant.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/legacy.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/md.cpython-310-x86_64-linux-gnu.so +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/md.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/md__mypyc.cpython-310-x86_64-linux-gnu.so +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/models.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/py.typed +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/utils.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/version.py +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_catch.py +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_version.py +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/py.typed +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/idna/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/idna/codec.py +/testing/tests/venv/lib/python3.10/site-packages/idna/compat.py +/testing/tests/venv/lib/python3.10/site-packages/idna/core.py +/testing/tests/venv/lib/python3.10/site-packages/idna/idnadata.py +/testing/tests/venv/lib/python3.10/site-packages/idna/intranges.py +/testing/tests/venv/lib/python3.10/site-packages/idna/package_data.py +/testing/tests/venv/lib/python3.10/site-packages/idna/py.typed +/testing/tests/venv/lib/python3.10/site-packages/idna/uts46data.py +/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/LICENSE.md +/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/iniconfig/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/iniconfig/_parse.py +/testing/tests/venv/lib/python3.10/site-packages/iniconfig/_version.py +/testing/tests/venv/lib/python3.10/site-packages/iniconfig/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/iniconfig/py.typed +/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/licenses/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/issue232/issue.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/contains.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/issue232.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/json_schema_test_suite.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/nested_schemas.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/subcomponents.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/unused_registry.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/validator_creation.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/_suite.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/fuzz_validate.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_cli.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_deprecations.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_format.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_jsonschema_test_suite.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_types.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_utils.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_validators.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_format.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_keywords.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_legacy_keywords.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_types.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_typing.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_utils.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/cli.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/protocols.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema/validators.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/licenses/COPYING +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/entry_points.txt +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/REQUESTED +/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft3/metaschema.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft4/metaschema.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft6/metaschema.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft7/metaschema.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/applicator +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/content +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/core +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/validation +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/metaschema.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/applicator +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/content +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/core +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/validation +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/metaschema.json +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/tests/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/tests/test_jsonschema_specifications.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/_core.py +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/licenses/COPYING +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/packaging/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/_elffile.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/_manylinux.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/_musllinux.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/_parser.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/_structures.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/_tokenizer.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/markers.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/metadata.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/py.typed +/testing/tests/venv/lib/python3.10/site-packages/packaging/requirements.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/specifiers.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/tags.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/utils.py +/testing/tests/venv/lib/python3.10/site-packages/packaging/version.py +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/LICENSE.APACHE +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/LICENSE.BSD +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/autocompletion.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/base_command.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/cmdoptions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/command_context.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/main.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/main_parser.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/parser.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/progress_bars.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/req_command.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/spinners.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/status_codes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/cache.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/check.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/completion.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/configuration.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/debug.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/download.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/freeze.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/hash.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/help.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/index.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/inspect.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/install.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/list.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/search.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/show.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/uninstall.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/base.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/installed.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/sdist.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/collector.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/package_finder.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/sources.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/_distutils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/_sysconfig.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/base.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_compat.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_dists.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_envs.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/_json.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/base.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/pkg_resources.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/candidate.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/direct_url.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/format_control.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/index.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/installation_report.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/link.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/scheme.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/search_scope.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/selection_prefs.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/target_python.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/auth.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/cache.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/download.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/lazy_wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/session.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/utils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/xmlrpc.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/build_tracker.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_editable.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_legacy.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_editable.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_legacy.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/install/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/install/editable_legacy.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/install/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/check.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/freeze.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/prepare.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/constructors.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_file.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_install.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_set.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_uninstall.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/resolver.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/base.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/candidates.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/factory.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/provider.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/reporter.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/requirements.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/resolver.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/base.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/_jaraco_text.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/_log.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/appdirs.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/compat.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/compatibility_tags.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/datetime.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/deprecation.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/direct_url_helpers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/egg_link.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/encoding.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/entrypoints.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/filesystem.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/filetypes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/glibc.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/hashes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/logging.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/misc.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/models.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/packaging.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/setuptools_build.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/subprocess.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/temp_dir.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/unpacking.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/urls.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/virtualenv.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/bazaar.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/git.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/mercurial.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/subversion.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/versioncontrol.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/build_env.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cache.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/configuration.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/main.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/pyproject.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/self_outdated_check.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/wheel_builder.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/_cmd.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/adapter.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/cache.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/controller.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/filewrapper.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/heuristics.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/serialize.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/wrapper.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/cacert.pem +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/core.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/chardetect.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/languages.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/big5freq.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/big5prober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/chardistribution.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetgroupprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachine.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachinedict.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/cp949prober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/enums.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/escprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/escsm.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/eucjpprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrfreq.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwfreq.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312freq.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312prober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/hebrewprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/jisfreq.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/johabfreq.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/johabprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/jpcntx.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langbulgarianmodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langgreekmodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langhebrewmodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langhungarianmodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langrussianmodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langthaimodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langturkishmodel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/latin1prober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/macromanprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcharsetprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcsgroupprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcssm.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/resultdict.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcharsetprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcsgroupprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/sjisprober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/universaldetector.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/utf8prober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/utf1632prober.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/version.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/ansi_test.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/initialise_test.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/isatty_test.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/utils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/winterm_test.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/ansi.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/ansitowin32.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/initialise.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/win32.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/winterm.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/compat.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/database.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/index.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/locators.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/manifest.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/markers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/metadata.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/resources.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/scripts.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/t32.exe +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/t64.exe +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/t64-arm.exe +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/util.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/version.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/w32.exe +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/w64.exe +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/w64-arm.exe +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/distro.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/codec.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/compat.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/core.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/idnadata.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/intranges.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/package_data.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/uts46data.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/ext.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/fallback.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/__about__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/_manylinux.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/_musllinux.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/_structures.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/markers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/requirements.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/specifiers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/tags.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/utils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/version.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/android.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/api.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/macos.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/unix.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/version.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/windows.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/filters/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/_mapping.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/bbcode.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/groff.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/html.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/img.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/irc.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/latex.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/other.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/rtf.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/svg.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/terminal.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/terminal256.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/_mapping.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/python.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/styles/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/cmdline.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/console.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/filter.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatter.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexer.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/modeline.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/plugin.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/regexopt.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/scanner.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/sphinxext.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/style.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/token.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/unistring.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/util.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/diagram/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/actions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/common.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/core.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/helpers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/results.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/testing.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/unicode.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/util.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_compat.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_impl.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/__version__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/_internal_utils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/adapters.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/api.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/auth.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/certs.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/compat.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/cookies.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/help.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/hooks.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/models.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/packages.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/sessions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/status_codes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/structures.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/utils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/providers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/reporters.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/resolvers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/structs.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_cell_widths.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_emoji_codes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_emoji_replace.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_export_format.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_extension.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_fileno.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_inspect.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_log_render.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_loop.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_null_file.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_palettes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_pick.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_ratio.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_spinners.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_stack.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_timer.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_win32_console.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_windows.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_windows_renderer.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_wrap.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/abc.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/align.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/ansi.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/bar.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/box.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/cells.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/color.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/color_triplet.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/columns.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/console.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/constrain.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/containers.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/control.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/default_styles.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/diagnose.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/emoji.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/errors.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/file_proxy.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/filesize.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/highlighter.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/json.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/jupyter.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/layout.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/live.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/live_render.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/logging.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/markup.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/measure.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/padding.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/pager.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/palette.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/panel.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/pretty.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/progress.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/progress_bar.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/prompt.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/protocol.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/region.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/repr.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/rule.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/scope.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/screen.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/segment.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/spinner.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/status.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/style.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/styled.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/syntax.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/table.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/terminal_theme.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/text.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/theme.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/themes.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/traceback.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/tree.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/_asyncio.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/_utils.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/after.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/before.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/before_sleep.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/nap.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/retry.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/stop.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/tornadoweb.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/wait.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/_parser.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/_re.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/_types.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_api.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_macos.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_openssl.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_ssl_constants.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_windows.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/appengine.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/securetransport.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/socks.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/six.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/connection.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/proxy.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/queue.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/request.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/response.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/retry.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssltransport.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/timeout.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/url.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/wait.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/_collections.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/_version.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/connection.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/connectionpool.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/fields.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/filepost.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/poolmanager.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/request.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/response.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/labels.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/mklabels.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/tests.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/x_user_defined.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/six.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/typing_extensions.py +/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/vendor.txt +/testing/tests/venv/lib/python3.10/site-packages/pip/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/__pip-runner__.py +/testing/tests/venv/lib/python3.10/site-packages/pip/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/AUTHORS.txt +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/entry_points.txt +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/LICENSE.txt +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/REQUESTED +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_adapters.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_common.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_compat.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_itertools.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_legacy.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/abc.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/readers.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/simple.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/text/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/context.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/functools.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__init__.pyi +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/more.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/more.pyi +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/recipes.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/recipes.pyi +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_elffile.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_manylinux.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_musllinux.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_parser.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_structures.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_tokenizer.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/markers.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/metadata.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/specifiers.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/tags.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/utils.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/version.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/android.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/api.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/macos.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/unix.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/version.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/windows.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/typing_extensions.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/zipp.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/extern/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_callers.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_hooks.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_manager.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_result.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_tracing.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_version.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/_warnings.py +/testing/tests/venv/lib/python3.10/site-packages/pluggy/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/pytest/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/pytest/__main__.py +/testing/tests/venv/lib/python3.10/site-packages/pytest/py.typed +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/entry_points.txt +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/REQUESTED +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_core.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_jsonschema.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_referencing_suite.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_retrieval.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/_attrs.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/_attrs.pyi +/testing/tests/venv/lib/python3.10/site-packages/referencing/_core.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/jsonschema.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/py.typed +/testing/tests/venv/lib/python3.10/site-packages/referencing/retrieval.py +/testing/tests/venv/lib/python3.10/site-packages/referencing/typing.py +/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/licenses/COPYING +/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/requests/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/requests/__version__.py +/testing/tests/venv/lib/python3.10/site-packages/requests/_internal_utils.py +/testing/tests/venv/lib/python3.10/site-packages/requests/adapters.py +/testing/tests/venv/lib/python3.10/site-packages/requests/api.py +/testing/tests/venv/lib/python3.10/site-packages/requests/auth.py +/testing/tests/venv/lib/python3.10/site-packages/requests/certs.py +/testing/tests/venv/lib/python3.10/site-packages/requests/compat.py +/testing/tests/venv/lib/python3.10/site-packages/requests/cookies.py +/testing/tests/venv/lib/python3.10/site-packages/requests/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/requests/help.py +/testing/tests/venv/lib/python3.10/site-packages/requests/hooks.py +/testing/tests/venv/lib/python3.10/site-packages/requests/models.py +/testing/tests/venv/lib/python3.10/site-packages/requests/packages.py +/testing/tests/venv/lib/python3.10/site-packages/requests/sessions.py +/testing/tests/venv/lib/python3.10/site-packages/requests/status_codes.py +/testing/tests/venv/lib/python3.10/site-packages/requests/structures.py +/testing/tests/venv/lib/python3.10/site-packages/requests/utils.py +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/REQUESTED +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/rpds/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/rpds/__init__.pyi +/testing/tests/venv/lib/python3.10/site-packages/rpds/py.typed +/testing/tests/venv/lib/python3.10/site-packages/rpds/rpds.cpython-310-x86_64-linux-gnu.so +/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/license_files/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/_framework_compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_dumb.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_rpm.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_clib.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_ext.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_py.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_scripts.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/check.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/clean.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/config.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_data.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_egg_info.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_headers.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_lib.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_scripts.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/py37compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/register.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/sdist.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/upload.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_collections.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_functools.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_log.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_macos_compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_modified.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_msvccompiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/archive_util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/bcppcompiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/ccompiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/cmd.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/config.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/core.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/cygwinccompiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/debug.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/dep_util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/dir_util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/dist.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/errors.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/extension.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/fancy_getopt.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/file_util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/filelist.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/log.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/msvc9compiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/msvccompiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/py38compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/py39compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/spawn.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/sysconfig.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/text_file.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/unixccompiler.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/version.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/versionpredicate.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_adapters.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_collections.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_functools.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_itertools.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_meta.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_py39compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_text.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/py.typed +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_adapters.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_common.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_itertools.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_legacy.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/abc.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/py.typed +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/readers.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/simple.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/text/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/context.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/functools.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__init__.pyi +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/more.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/more.pyi +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/py.typed +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/recipes.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/recipes.pyi +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_elffile.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_manylinux.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_musllinux.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_parser.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_structures.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_tokenizer.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/markers.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/metadata.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/py.typed +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/requirements.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/specifiers.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/tags.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/utils.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/version.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_parser.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_re.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_types.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/py.typed +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/ordered_set.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/typing_extensions.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/zipp.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/_requirestxt.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/alias.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/bdist_egg.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/bdist_rpm.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build_clib.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build_ext.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build_py.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/develop.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/dist_info.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/easy_install.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/editable_wheel.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/egg_info.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install_egg_info.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install_lib.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install_scripts.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/launcher manifest.xml +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/register.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/rotate.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/saveopts.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/sdist.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/setopt.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/test.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/upload.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/upload_docs.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/error_reporting.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/extra_validations.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/formats.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_apply_pyprojecttoml.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/expand.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/pyprojecttoml.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/extern/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_core_metadata.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_entry_points.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_imp.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_importlib.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_itertools.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_normalization.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_path.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/_reqs.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/archive_util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/build_meta.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli-32.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli-64.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli-arm64.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/dep_util.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/depends.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/discovery.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/dist.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/errors.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/extension.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/glob.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui-32.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui-64.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui-arm64.exe +/testing/tests/venv/lib/python3.10/site-packages/setuptools/installer.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/launch.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/logging.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/modified.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/monkey.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/msvc.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/namespaces.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/package_index.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/py312compat.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/sandbox.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/script.tmpl +/testing/tests/venv/lib/python3.10/site-packages/setuptools/script (dev).tmpl +/testing/tests/venv/lib/python3.10/site-packages/setuptools/unicode_utils.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/version.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/warnings.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/wheel.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools/windows_support.py +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/entry_points.txt +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/REQUESTED +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/top_level.txt +/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/tomli/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/tomli/_parser.py +/testing/tests/venv/lib/python3.10/site-packages/tomli/_re.py +/testing/tests/venv/lib/python3.10/site-packages/tomli/_types.py +/testing/tests/venv/lib/python3.10/site-packages/tomli/py.typed +/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/LICENSE +/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/urllib3/contrib/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/contrib/pyopenssl.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/contrib/socks.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/connection.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/proxy.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/request.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/response.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/retry.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/ssl_.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/ssl_match_hostname.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/ssltransport.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/timeout.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/url.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/util.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/wait.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/__init__.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/_base_connection.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/_collections.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/_request_methods.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/_version.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/connection.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/connectionpool.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/exceptions.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/fields.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/filepost.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/poolmanager.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3/py.typed +/testing/tests/venv/lib/python3.10/site-packages/urllib3/response.py +/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/licenses/LICENSE.txt +/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/INSTALLER +/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/METADATA +/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/RECORD +/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/WHEEL +/testing/tests/venv/lib/python3.10/site-packages/distutils-precedence.pth +/testing/tests/venv/lib/python3.10/site-packages/py.py +/testing/tests/venv/pyvenv.cfg +/testing/tests/.env From ed148c3ecdcef5408d5012921b21f84526d3f07a Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Tue, 30 Jan 2024 06:05:52 -0500 Subject: [PATCH 097/103] Adds venv to the gitignore --- .gitignore | 1189 +--------------------------------------------------- 1 file changed, 1 insertion(+), 1188 deletions(-) diff --git a/.gitignore b/.gitignore index a2c14cdd..a3dc61a8 100644 --- a/.gitignore +++ b/.gitignore @@ -15,1192 +15,5 @@ dashboard_update.sh files_for_windows.zip lme.conf lme_update.sh -/testing/tests/venv/bin/activate -/testing/tests/venv/bin/activate.csh -/testing/tests/venv/bin/activate.fish -/testing/tests/venv/bin/Activate.ps1 -/testing/tests/venv/bin/jsonschema -/testing/tests/venv/bin/normalizer -/testing/tests/venv/bin/pip -/testing/tests/venv/bin/pip3 -/testing/tests/venv/bin/pip3.10 -/testing/tests/venv/bin/pip3.11 -/testing/tests/venv/bin/py.test -/testing/tests/venv/bin/pytest -/testing/tests/venv/bin/python -/testing/tests/venv/bin/python3 -/testing/tests/venv/bin/python3.10 -/testing/tests/venv/lib/python3.10/site-packages/_distutils_hack/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_distutils_hack/override.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_code/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_code/code.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_code/source.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/pprint.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/saferepr.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/terminalwriter.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_io/wcwidth.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_py/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_py/error.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_py/path.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/rewrite.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/truncate.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/assertion/util.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/argparsing.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/compat.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/config/findpaths.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/mark/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/mark/expression.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/mark/structures.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_argcomplete.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/_version.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/cacheprovider.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/capture.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/compat.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/debugging.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/deprecated.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/doctest.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/faulthandler.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/fixtures.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/freeze_support.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/helpconfig.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/hookspec.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/junitxml.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/legacypath.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/logging.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/main.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/monkeypatch.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/nodes.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/nose.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/outcomes.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/pastebin.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/pathlib.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/py.typed -/testing/tests/venv/lib/python3.10/site-packages/_pytest/pytester.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/pytester_assertions.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/python.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/python_api.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/python_path.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/recwarn.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/reports.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/runner.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/scope.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/setuponly.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/setupplan.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/skipping.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/stash.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/stepwise.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/terminal.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/threadexception.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/timing.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/tmpdir.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/unittest.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/unraisableexception.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/warning_types.py -/testing/tests/venv/lib/python3.10/site-packages/_pytest/warnings.py -/testing/tests/venv/lib/python3.10/site-packages/attr/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/attr/__init__.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/_cmp.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_cmp.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/_compat.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_config.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_funcs.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_make.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_next_gen.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_typing_compat.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/_version_info.py -/testing/tests/venv/lib/python3.10/site-packages/attr/_version_info.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/converters.py -/testing/tests/venv/lib/python3.10/site-packages/attr/converters.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/attr/exceptions.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/filters.py -/testing/tests/venv/lib/python3.10/site-packages/attr/filters.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/py.typed -/testing/tests/venv/lib/python3.10/site-packages/attr/setters.py -/testing/tests/venv/lib/python3.10/site-packages/attr/setters.pyi -/testing/tests/venv/lib/python3.10/site-packages/attr/validators.py -/testing/tests/venv/lib/python3.10/site-packages/attr/validators.pyi -/testing/tests/venv/lib/python3.10/site-packages/attrs/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/attrs/__init__.pyi -/testing/tests/venv/lib/python3.10/site-packages/attrs/converters.py -/testing/tests/venv/lib/python3.10/site-packages/attrs/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/attrs/filters.py -/testing/tests/venv/lib/python3.10/site-packages/attrs/py.typed -/testing/tests/venv/lib/python3.10/site-packages/attrs/setters.py -/testing/tests/venv/lib/python3.10/site-packages/attrs/validators.py -/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/licenses/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/attrs-23.2.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/certifi/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/certifi/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/certifi/cacert.pem -/testing/tests/venv/lib/python3.10/site-packages/certifi/core.py -/testing/tests/venv/lib/python3.10/site-packages/certifi/py.typed -/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/certifi-2023.11.17.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/cli/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/cli/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/api.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/cd.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/constant.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/legacy.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/md.cpython-310-x86_64-linux-gnu.so -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/md.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/md__mypyc.cpython-310-x86_64-linux-gnu.so -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/models.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/py.typed -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/utils.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer/version.py -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/entry_points.txt -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/charset_normalizer-3.3.2.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_catch.py -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_formatting.py -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_suppress.py -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/_version.py -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup/py.typed -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/exceptiongroup-1.2.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/idna/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/idna/codec.py -/testing/tests/venv/lib/python3.10/site-packages/idna/compat.py -/testing/tests/venv/lib/python3.10/site-packages/idna/core.py -/testing/tests/venv/lib/python3.10/site-packages/idna/idnadata.py -/testing/tests/venv/lib/python3.10/site-packages/idna/intranges.py -/testing/tests/venv/lib/python3.10/site-packages/idna/package_data.py -/testing/tests/venv/lib/python3.10/site-packages/idna/py.typed -/testing/tests/venv/lib/python3.10/site-packages/idna/uts46data.py -/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/LICENSE.md -/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/idna-3.6.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/iniconfig/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/iniconfig/_parse.py -/testing/tests/venv/lib/python3.10/site-packages/iniconfig/_version.py -/testing/tests/venv/lib/python3.10/site-packages/iniconfig/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/iniconfig/py.typed -/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/licenses/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/iniconfig-2.0.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/issue232/issue.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/contains.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/issue232.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/json_schema_test_suite.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/nested_schemas.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/subcomponents.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/unused_registry.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/benchmarks/validator_creation.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/_suite.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/fuzz_validate.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_cli.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_deprecations.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_format.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_jsonschema_test_suite.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_types.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_utils.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/tests/test_validators.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_format.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_keywords.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_legacy_keywords.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_types.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_typing.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/_utils.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/cli.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/protocols.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema/validators.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/licenses/COPYING -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/entry_points.txt -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/REQUESTED -/testing/tests/venv/lib/python3.10/site-packages/jsonschema-4.21.1.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft3/metaschema.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft4/metaschema.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft6/metaschema.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft7/metaschema.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/applicator -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/content -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/core -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/meta-data -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/vocabularies/validation -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft201909/metaschema.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/applicator -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/content -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/core -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-annotation -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/format-assertion -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/meta-data -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/unevaluated -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/vocabularies/validation -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/schemas/draft202012/metaschema.json -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/tests/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/tests/test_jsonschema_specifications.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications/_core.py -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/licenses/COPYING -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/jsonschema_specifications-2023.12.1.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/packaging/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/_elffile.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/_manylinux.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/_musllinux.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/_parser.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/_structures.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/_tokenizer.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/markers.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/metadata.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/py.typed -/testing/tests/venv/lib/python3.10/site-packages/packaging/requirements.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/specifiers.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/tags.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/utils.py -/testing/tests/venv/lib/python3.10/site-packages/packaging/version.py -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/LICENSE.APACHE -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/LICENSE.BSD -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/packaging-23.2.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/autocompletion.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/base_command.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/cmdoptions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/command_context.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/main.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/main_parser.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/parser.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/progress_bars.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/req_command.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/spinners.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cli/status_codes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/cache.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/check.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/completion.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/configuration.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/debug.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/download.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/freeze.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/hash.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/help.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/index.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/inspect.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/install.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/list.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/search.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/show.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/uninstall.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/commands/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/base.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/installed.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/sdist.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/distributions/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/collector.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/package_finder.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/index/sources.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/_distutils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/_sysconfig.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/locations/base.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_compat.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_dists.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/importlib/_envs.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/_json.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/base.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/metadata/pkg_resources.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/candidate.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/direct_url.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/format_control.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/index.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/installation_report.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/link.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/scheme.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/search_scope.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/selection_prefs.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/target_python.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/models/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/auth.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/cache.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/download.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/lazy_wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/session.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/utils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/network/xmlrpc.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/build_tracker.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_editable.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/metadata_legacy.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_editable.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/build/wheel_legacy.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/install/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/install/editable_legacy.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/install/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/check.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/freeze.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/operations/prepare.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/constructors.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_file.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_install.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_set.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/req/req_uninstall.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/legacy/resolver.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/base.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/candidates.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/factory.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/found_candidates.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/provider.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/reporter.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/requirements.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/resolvelib/resolver.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/resolution/base.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/_jaraco_text.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/_log.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/appdirs.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/compat.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/compatibility_tags.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/datetime.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/deprecation.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/direct_url_helpers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/egg_link.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/encoding.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/entrypoints.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/filesystem.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/filetypes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/glibc.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/hashes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/logging.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/misc.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/models.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/packaging.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/setuptools_build.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/subprocess.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/temp_dir.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/unpacking.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/urls.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/virtualenv.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/utils/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/bazaar.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/git.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/mercurial.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/subversion.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/vcs/versioncontrol.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/build_env.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/cache.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/configuration.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/main.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/pyproject.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/self_outdated_check.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_internal/wheel_builder.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/file_cache.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/caches/redis_cache.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/_cmd.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/adapter.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/cache.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/controller.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/filewrapper.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/heuristics.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/serialize.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/cachecontrol/wrapper.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/cacert.pem -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/core.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/certifi/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/cli/chardetect.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/metadata/languages.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/big5freq.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/big5prober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/chardistribution.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetgroupprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/charsetprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachine.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/codingstatemachinedict.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/cp949prober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/enums.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/escprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/escsm.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/eucjpprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrfreq.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euckrprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwfreq.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/euctwprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312freq.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/gb2312prober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/hebrewprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/jisfreq.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/johabfreq.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/johabprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/jpcntx.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langbulgarianmodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langgreekmodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langhebrewmodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langhungarianmodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langrussianmodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langthaimodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/langturkishmodel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/latin1prober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/macromanprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcharsetprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcsgroupprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/mbcssm.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/resultdict.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcharsetprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/sbcsgroupprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/sjisprober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/universaldetector.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/utf8prober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/utf1632prober.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/chardet/version.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/ansi_test.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/ansitowin32_test.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/initialise_test.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/isatty_test.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/utils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/tests/winterm_test.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/ansi.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/ansitowin32.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/initialise.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/win32.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/colorama/winterm.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/compat.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/database.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/index.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/locators.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/manifest.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/markers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/metadata.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/resources.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/scripts.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/t32.exe -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/t64.exe -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/t64-arm.exe -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/util.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/version.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/w32.exe -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/w64.exe -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/w64-arm.exe -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distlib/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/distro.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/distro/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/codec.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/compat.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/core.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/idnadata.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/intranges.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/package_data.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/idna/uts46data.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/ext.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/msgpack/fallback.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/__about__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/_manylinux.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/_musllinux.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/_structures.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/markers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/requirements.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/specifiers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/tags.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/utils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/packaging/version.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pkg_resources/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/android.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/api.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/macos.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/unix.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/version.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/platformdirs/windows.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/filters/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/_mapping.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/bbcode.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/groff.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/html.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/img.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/irc.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/latex.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/other.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/pangomarkup.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/rtf.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/svg.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/terminal.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatters/terminal256.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/_mapping.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexers/python.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/styles/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/cmdline.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/console.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/filter.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/formatter.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/lexer.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/modeline.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/plugin.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/regexopt.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/scanner.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/sphinxext.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/style.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/token.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/unistring.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pygments/util.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/diagram/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/actions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/common.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/core.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/helpers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/results.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/testing.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/unicode.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyparsing/util.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_in_process/_in_process.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_compat.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/pyproject_hooks/_impl.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/__version__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/_internal_utils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/adapters.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/api.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/auth.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/certs.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/compat.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/cookies.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/help.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/hooks.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/models.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/packages.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/sessions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/status_codes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/structures.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/requests/utils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/compat/collections_abc.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/providers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/reporters.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/resolvers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/resolvelib/structs.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_cell_widths.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_emoji_codes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_emoji_replace.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_export_format.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_extension.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_fileno.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_inspect.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_log_render.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_loop.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_null_file.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_palettes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_pick.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_ratio.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_spinners.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_stack.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_timer.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_win32_console.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_windows.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_windows_renderer.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/_wrap.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/abc.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/align.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/ansi.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/bar.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/box.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/cells.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/color.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/color_triplet.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/columns.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/console.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/constrain.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/containers.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/control.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/default_styles.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/diagnose.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/emoji.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/errors.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/file_proxy.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/filesize.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/highlighter.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/json.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/jupyter.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/layout.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/live.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/live_render.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/logging.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/markup.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/measure.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/padding.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/pager.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/palette.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/panel.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/pretty.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/progress.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/progress_bar.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/prompt.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/protocol.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/region.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/repr.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/rule.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/scope.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/screen.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/segment.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/spinner.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/status.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/style.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/styled.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/syntax.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/table.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/terminal_theme.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/text.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/theme.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/themes.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/traceback.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/rich/tree.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/_asyncio.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/_utils.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/after.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/before.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/before_sleep.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/nap.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/retry.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/stop.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/tornadoweb.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tenacity/wait.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/_parser.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/_re.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/_types.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/tomli/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_api.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_macos.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_openssl.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_ssl_constants.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/_windows.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/truststore/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/bindings.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_securetransport/low_level.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/_appengine_environ.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/appengine.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/ntlmpool.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/pyopenssl.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/securetransport.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/contrib/socks.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/makefile.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/backports/weakref_finalize.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/packages/six.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/connection.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/proxy.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/queue.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/request.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/response.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/retry.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssl_match_hostname.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/ssltransport.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/timeout.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/url.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/util/wait.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/_collections.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/_version.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/connection.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/connectionpool.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/fields.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/filepost.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/poolmanager.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/request.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/urllib3/response.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/labels.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/mklabels.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/tests.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/webencodings/x_user_defined.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/six.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/typing_extensions.py -/testing/tests/venv/lib/python3.10/site-packages/pip/_vendor/vendor.txt -/testing/tests/venv/lib/python3.10/site-packages/pip/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/__pip-runner__.py -/testing/tests/venv/lib/python3.10/site-packages/pip/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/AUTHORS.txt -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/entry_points.txt -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/LICENSE.txt -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/REQUESTED -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/pip-23.3.2.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_adapters.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_common.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_compat.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_itertools.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/_legacy.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/abc.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/readers.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/importlib_resources/simple.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/text/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/context.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/jaraco/functools.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/__init__.pyi -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/more.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/more.pyi -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/recipes.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/more_itertools/recipes.pyi -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_elffile.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_manylinux.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_musllinux.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_parser.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_structures.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/_tokenizer.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/markers.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/metadata.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/requirements.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/specifiers.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/tags.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/utils.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/packaging/version.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/android.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/api.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/macos.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/unix.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/version.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/platformdirs/windows.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/typing_extensions.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/_vendor/zipp.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/extern/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pkg_resources/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_callers.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_hooks.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_manager.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_result.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_tracing.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_version.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/_warnings.py -/testing/tests/venv/lib/python3.10/site-packages/pluggy/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/pluggy-1.4.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/pytest/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/pytest/__main__.py -/testing/tests/venv/lib/python3.10/site-packages/pytest/py.typed -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/entry_points.txt -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/REQUESTED -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/pytest-8.0.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_core.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_jsonschema.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_referencing_suite.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/tests/test_retrieval.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/_attrs.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/_attrs.pyi -/testing/tests/venv/lib/python3.10/site-packages/referencing/_core.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/jsonschema.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/py.typed -/testing/tests/venv/lib/python3.10/site-packages/referencing/retrieval.py -/testing/tests/venv/lib/python3.10/site-packages/referencing/typing.py -/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/licenses/COPYING -/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/referencing-0.33.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/requests/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/requests/__version__.py -/testing/tests/venv/lib/python3.10/site-packages/requests/_internal_utils.py -/testing/tests/venv/lib/python3.10/site-packages/requests/adapters.py -/testing/tests/venv/lib/python3.10/site-packages/requests/api.py -/testing/tests/venv/lib/python3.10/site-packages/requests/auth.py -/testing/tests/venv/lib/python3.10/site-packages/requests/certs.py -/testing/tests/venv/lib/python3.10/site-packages/requests/compat.py -/testing/tests/venv/lib/python3.10/site-packages/requests/cookies.py -/testing/tests/venv/lib/python3.10/site-packages/requests/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/requests/help.py -/testing/tests/venv/lib/python3.10/site-packages/requests/hooks.py -/testing/tests/venv/lib/python3.10/site-packages/requests/models.py -/testing/tests/venv/lib/python3.10/site-packages/requests/packages.py -/testing/tests/venv/lib/python3.10/site-packages/requests/sessions.py -/testing/tests/venv/lib/python3.10/site-packages/requests/status_codes.py -/testing/tests/venv/lib/python3.10/site-packages/requests/structures.py -/testing/tests/venv/lib/python3.10/site-packages/requests/utils.py -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/REQUESTED -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/requests-2.31.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/rpds/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/rpds/__init__.pyi -/testing/tests/venv/lib/python3.10/site-packages/rpds/py.typed -/testing/tests/venv/lib/python3.10/site-packages/rpds/rpds.cpython-310-x86_64-linux-gnu.so -/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/license_files/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/rpds_py-0.17.1.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/_framework_compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_dumb.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/bdist_rpm.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_clib.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_ext.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_py.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/build_scripts.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/check.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/clean.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/config.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_data.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_egg_info.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_headers.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_lib.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/install_scripts.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/py37compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/register.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/sdist.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/command/upload.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_collections.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_functools.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_log.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_macos_compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_modified.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/_msvccompiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/archive_util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/bcppcompiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/ccompiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/cmd.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/config.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/core.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/cygwinccompiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/debug.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/dep_util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/dir_util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/dist.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/errors.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/extension.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/fancy_getopt.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/file_util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/filelist.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/log.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/msvc9compiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/msvccompiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/py38compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/py39compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/spawn.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/sysconfig.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/text_file.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/unixccompiler.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/version.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_distutils/versionpredicate.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_adapters.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_collections.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_functools.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_itertools.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_meta.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_py39compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/_text.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_metadata/py.typed -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_adapters.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_common.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_itertools.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/_legacy.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/abc.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/py.typed -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/readers.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/importlib_resources/simple.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/text/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/context.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/jaraco/functools.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/__init__.pyi -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/more.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/more.pyi -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/py.typed -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/recipes.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/more_itertools/recipes.pyi -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_elffile.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_manylinux.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_musllinux.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_parser.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_structures.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/_tokenizer.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/markers.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/metadata.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/py.typed -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/requirements.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/specifiers.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/tags.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/utils.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/packaging/version.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_parser.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_re.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/_types.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/tomli/py.typed -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/ordered_set.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/typing_extensions.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_vendor/zipp.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/_requirestxt.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/alias.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/bdist_egg.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/bdist_rpm.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build_clib.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build_ext.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/build_py.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/develop.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/dist_info.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/easy_install.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/editable_wheel.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/egg_info.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install_egg_info.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install_lib.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/install_scripts.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/launcher manifest.xml -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/register.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/rotate.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/saveopts.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/sdist.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/setopt.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/test.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/upload.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/command/upload_docs.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/error_reporting.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/extra_validations.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/fastjsonschema_validations.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_validate_pyproject/formats.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/_apply_pyprojecttoml.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/expand.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/pyprojecttoml.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/config/setupcfg.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/extern/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_core_metadata.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_entry_points.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_imp.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_importlib.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_itertools.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_normalization.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_path.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/_reqs.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/archive_util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/build_meta.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli-32.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli-64.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/cli-arm64.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/dep_util.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/depends.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/discovery.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/dist.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/errors.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/extension.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/glob.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui-32.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui-64.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/gui-arm64.exe -/testing/tests/venv/lib/python3.10/site-packages/setuptools/installer.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/launch.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/logging.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/modified.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/monkey.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/msvc.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/namespaces.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/package_index.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/py312compat.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/sandbox.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/script.tmpl -/testing/tests/venv/lib/python3.10/site-packages/setuptools/script (dev).tmpl -/testing/tests/venv/lib/python3.10/site-packages/setuptools/unicode_utils.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/version.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/warnings.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/wheel.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools/windows_support.py -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/entry_points.txt -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/REQUESTED -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/top_level.txt -/testing/tests/venv/lib/python3.10/site-packages/setuptools-69.0.3.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/tomli/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/tomli/_parser.py -/testing/tests/venv/lib/python3.10/site-packages/tomli/_re.py -/testing/tests/venv/lib/python3.10/site-packages/tomli/_types.py -/testing/tests/venv/lib/python3.10/site-packages/tomli/py.typed -/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/LICENSE -/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/tomli-2.0.1.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/urllib3/contrib/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/contrib/pyopenssl.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/contrib/socks.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/connection.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/proxy.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/request.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/response.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/retry.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/ssl_.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/ssl_match_hostname.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/ssltransport.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/timeout.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/url.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/util.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/util/wait.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/__init__.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/_base_connection.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/_collections.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/_request_methods.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/_version.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/connection.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/connectionpool.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/exceptions.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/fields.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/filepost.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/poolmanager.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3/py.typed -/testing/tests/venv/lib/python3.10/site-packages/urllib3/response.py -/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/licenses/LICENSE.txt -/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/INSTALLER -/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/METADATA -/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/RECORD -/testing/tests/venv/lib/python3.10/site-packages/urllib3-2.1.0.dist-info/WHEEL -/testing/tests/venv/lib/python3.10/site-packages/distutils-precedence.pth -/testing/tests/venv/lib/python3.10/site-packages/py.py -/testing/tests/venv/pyvenv.cfg /testing/tests/.env +/testing/tests/venv/ From e9204afe7c5ef6b83d80e60adfd1780a781f7349 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Wed, 31 Jan 2024 06:05:36 -0500 Subject: [PATCH 098/103] Adds the ability to pass a branch to the installer --- testing/InstallTestbed.ps1 | 11 +++++-- testing/Readme.md | 16 +++++----- testing/configure/linux_install_lme.sh | 42 +++++++++++++++----------- 3 files changed, 41 insertions(+), 28 deletions(-) diff --git a/testing/InstallTestbed.ps1 b/testing/InstallTestbed.ps1 index c0289133..9d297be5 100644 --- a/testing/InstallTestbed.ps1 +++ b/testing/InstallTestbed.ps1 @@ -19,7 +19,10 @@ param ( [switch]$LinuxOnly, [Alias("v")] - [string]$Version = $false + [string]$Version = $false, + + [Alias("b")] + [string]$Branch = $false ) # If you were to need the password from the SetupTestbed.ps1 script, you could use this: @@ -211,7 +214,9 @@ Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse Write-Output $ProcessSeparator $versionArgument = "" -if ($Version -ne $false) { +if ($Branch -ne $false) { + $versionArgument = " -b '$($Branch)'" +} elseif ($Version -ne $false) { $versionArgument = " -v $Version" } Write-Output "`nRunning the lme installer on LS1..." @@ -251,7 +256,7 @@ $getElasticsearchPasswordsResponse = az vm run-command invoke ` --resource-group $ResourceGroup ` --scripts 'tail -n14 "/opt/lme/Chapter 3 Files/output.log" | head -n9' -Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") +# Show-FormattedOutput -FormattedOutput (Format-AzVmRunCommandOutput -JsonResponse "$getElasticsearchPasswordsResponse") Write-Output $ProcessSeparator if (-Not $LinuxOnly){ diff --git a/testing/Readme.md b/testing/Readme.md index e212f690..8577bf09 100644 --- a/testing/Readme.md +++ b/testing/Readme.md @@ -60,13 +60,15 @@ Flags: ## Install LME on the cluster: ### InstallTestbed.ps1 ## Usage -| **Parameter** | **Alias** | **Description** | **Required** | -|---------------------|-----------|----------------------------------------------------------------------------------------|--------------| -| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | -| $NumClients | -n | The number of Windows clients you have created; defaults to 2 | No | -| $DomainController | -w | The name of the domain controller in the cluster; defaults to "DC1" | No | -| $LinuxVm | -l | The name of the linux server in the cluster; defaults to "LS1" | No | -| $LinuxOnly | -m | Run a minimal install of only the linux server | No | +| **Parameter** | **Alias** | **Description** | **Required** | +|-------------------|-----------|----------------------------------------------------------------------------------------|--------------| +| $ResourceGroup | -g | The name of the resource group that will be created for storing all testbed resources. | Yes | +| $NumClients | -n | The number of Windows clients you have created; defaults to 2 | No | +| $DomainController | -w | The name of the domain controller in the cluster; defaults to "DC1" | No | +| $LinuxVm | -l | The name of the linux server in the cluster; defaults to "LS1" | No | +| $LinuxOnly | -m | Run a minimal install of only the linux server | No | +| $Version | -v | Optionally provide a version to install if you want a specific one. `-v 1.3.2` | No | +| $Branch | -b | Optionally provide a branch to install if you want a specific one `-b your_branch` | No | Example: ``` diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 04f1a264..1dfb51ed 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -10,10 +10,11 @@ script_dir=$(pwd) username="admin.ackbar" # Process command line arguments -while getopts "u:v:" opt; do +while getopts "u:v:b:" opt; do case $opt in u) username=$OPTARG ;; v) version=$OPTARG ;; + b) branch=$OPTARG ;; \?) echo "Invalid option -$OPTARG" >&2; exit 1 ;; esac done @@ -32,30 +33,35 @@ get_tarball_url() { echo "https://api.github.com/repos/cisagov/LME/tarball/v$1" } -# Check if a version is provided -if [ -n "$version" ]; then - tarball_url=$(get_tarball_url "$version") +if [ -n "$branch" ]; then + # Clone from the specified branch + git clone --branch "$branch" https://github.com/cisagov/LME.git /opt/lme else - tarball_url=$(curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.tarball_url') -fi - -# Get the version from the tarball URL -v_version=$(basename "$tarball_url") + echo "Getting the code from GitHub" + # Check if a version is provided + if [ -n "$version" ]; then + tarball_url=$(get_tarball_url "$version") + else + tarball_url=$(curl -s https://api.github.com/repos/cisagov/LME/releases/latest | jq -r '.tarball_url') + fi -echo "Downloading $tarball_url to file: $v_version" -curl -L "$tarball_url" -o "$v_version" + # Get the version from the tarball URL + v_version=$(basename "$tarball_url") -# extracts it to a folder like cisagov-LME-3412897 -sudo tar -xzpf "$v_version" -C /opt -rm -rf "$v_version" + echo "Downloading $tarball_url to file: $v_version" + curl -L "$tarball_url" -o "$v_version" -extracted_filename=$(sudo ls -ltd /opt/cisagov-LME-* | grep "^d" | head -n 1 | awk '{print $NF}') + # extracts it to a folder like cisagov-LME-3412897 + sudo tar -xzpf "$v_version" -C /opt + rm -rf "$v_version" -echo "Extracted to $extracted_filename" + extracted_filename=$(sudo ls -ltd /opt/cisagov-LME-* | grep "^d" | head -n 1 | awk '{print $NF}') -echo "Renaming directory to /opt/lme" -sudo mv "$extracted_filename" /opt/lme + echo "Extracted to $extracted_filename" + echo "Renaming directory to /opt/lme" + sudo mv "$extracted_filename" /opt/lme +fi echo 'export DEBIAN_FRONTEND=noninteractive' >> ~/.bashrc echo 'export NEEDRESTART_MODE=a' >> ~/.bashrc From 184f6a4881d00580715ed8b0f206491f95292532 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Thu, 1 Feb 2024 05:12:39 -0500 Subject: [PATCH 099/103] Remove node installer --- testing/configure/linux_update_system.sh | 3 --- 1 file changed, 3 deletions(-) diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh index 20868c50..602e185d 100644 --- a/testing/configure/linux_update_system.sh +++ b/testing/configure/linux_update_system.sh @@ -1,6 +1,3 @@ # Install Git client to be able to clone the LME repository -curl -sL https://deb.nodesource.com/setup_20.x -o nodesource_setup.sh -chmod +x nodesource_setup.sh -sudo ./nodesource_setup.sh sudo apt update sudo DEBIAN_FRONTEND=noninteractive NEEDRESTART_MODE=a apt install git curl zip net-tools jq nodejs expect python3-venv -y \ No newline at end of file From 7b2545632026aa34992b021383758e36beed9a6f Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 2 Feb 2024 07:46:53 -0500 Subject: [PATCH 100/103] Change timeout in expect script for slow connections --- testing/configure/linux_install_lme.exp | 2 +- testing/configure/linux_install_lme.sh | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 9b9c66ad..5d2a6be5 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -4,7 +4,7 @@ cd /opt/lme/Chapter\ 3\ Files/ # Adjust the timeout if necessary -set timeout 60 +set timeout 600 set expect_out(buffer_size) 100000 log_file -a output.log diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh index 1dfb51ed..7cd71703 100644 --- a/testing/configure/linux_install_lme.sh +++ b/testing/configure/linux_install_lme.sh @@ -75,7 +75,7 @@ echo 'export NEEDRESTART_MODE=a' | sudo tee -a /root/.bashrc # Todo: We could put a switch here for different versions and just run different expect scripts sudo -E bash -c ". /root/.bashrc && $script_dir/linux_install_lme.exp" -chmod ugo+w "/opt/lme/Chapter 3 Files/output.log" +sudo chmod ugo+w "/opt/lme/Chapter 3 Files/output.log" if [ -f "/opt/lme/files_for_windows.zip" ]; then sudo cp /opt/lme/files_for_windows.zip /home/"$username"/ From 780f5e11dc9234f110c1bdc6ed78f925243384b6 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 2 Feb 2024 08:00:04 -0500 Subject: [PATCH 101/103] Change timeout in expect script for slow connections --- testing/configure/linux_install_lme.exp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 5d2a6be5..2d490591 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -4,8 +4,8 @@ cd /opt/lme/Chapter\ 3\ Files/ # Adjust the timeout if necessary -set timeout 600 -set expect_out(buffer_size) 100000 +set timeout 1600 +set expect_out(buffer_size) 1000000 log_file -a output.log From 29a01693507e8b42172d8a04c38ee21a41163632 Mon Sep 17 00:00:00 2001 From: Clint Baxley Date: Fri, 2 Feb 2024 08:15:55 -0500 Subject: [PATCH 102/103] Change timeout in expect script for slow connections --- testing/configure/linux_install_lme.exp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp index 2d490591..a3f9b98f 100644 --- a/testing/configure/linux_install_lme.exp +++ b/testing/configure/linux_install_lme.exp @@ -4,7 +4,7 @@ cd /opt/lme/Chapter\ 3\ Files/ # Adjust the timeout if necessary -set timeout 1600 +set timeout 60 set expect_out(buffer_size) 1000000 log_file -a output.log @@ -47,7 +47,7 @@ sleep 1 expect -re {Skip Docker Install\? \(\[y\]es/\[n\]o\): n} sleep 1 send "\r" -set timeout 600 +set timeout 2600 expect eof From 934813e089b284b17335a22e87074942a28e0111 Mon Sep 17 00:00:00 2001 From: cbaxley Date: Tue, 6 Feb 2024 05:48:49 -0500 Subject: [PATCH 103/103] Make shell files executable --- testing/configure/linux_authorize_private_key.sh | 0 testing/configure/linux_install_lme.exp | 0 testing/configure/linux_install_lme.sh | 0 testing/configure/linux_make_private_key.exp | 0 testing/configure/linux_test_install.sh | 0 testing/configure/linux_update_system.sh | 0 6 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 testing/configure/linux_authorize_private_key.sh mode change 100644 => 100755 testing/configure/linux_install_lme.exp mode change 100644 => 100755 testing/configure/linux_install_lme.sh mode change 100644 => 100755 testing/configure/linux_make_private_key.exp mode change 100644 => 100755 testing/configure/linux_test_install.sh mode change 100644 => 100755 testing/configure/linux_update_system.sh diff --git a/testing/configure/linux_authorize_private_key.sh b/testing/configure/linux_authorize_private_key.sh old mode 100644 new mode 100755 diff --git a/testing/configure/linux_install_lme.exp b/testing/configure/linux_install_lme.exp old mode 100644 new mode 100755 diff --git a/testing/configure/linux_install_lme.sh b/testing/configure/linux_install_lme.sh old mode 100644 new mode 100755 diff --git a/testing/configure/linux_make_private_key.exp b/testing/configure/linux_make_private_key.exp old mode 100644 new mode 100755 diff --git a/testing/configure/linux_test_install.sh b/testing/configure/linux_test_install.sh old mode 100644 new mode 100755 diff --git a/testing/configure/linux_update_system.sh b/testing/configure/linux_update_system.sh old mode 100644 new mode 100755