diff --git a/01_essentials/02-history/README.md b/01_essentials/02-history/README.md index 84fdd3e..42d5eca 100644 --- a/01_essentials/02-history/README.md +++ b/01_essentials/02-history/README.md @@ -8,7 +8,6 @@ In this module, you will: - Use `git show` to view specific commit details - Use `git diff` to compare changes between commits - Use `git diff --staged` to view changes ready to be committed -- Use `git blame` to find who made specific changes - Understand commit hashes and references - Discover how `git diff` reveals changes not visible in current files @@ -31,7 +30,6 @@ You'll explore an existing Git repository that contains multiple commits. Your g - Examining changes between specific commits - Understanding staged changes - **Finding a secret code hidden in the commit history!** (Only discoverable by using `git diff`) -- **Tracking down who made a suspicious code change** (Using `git blame`) The setup script will create an `answers.md` file in the challenge directory with questions for you to answer. Fill in your answers directly in that file. @@ -45,8 +43,7 @@ The setup script will create an `answers.md` file in the challenge directory wit 6. Try different log formats: `git log --stat`, `git log --graph` 7. View specific commits: `git show ` 8. Compare specific commits: `git diff ` -9. Use `git blame` to find who wrote specific lines: `git blame -e ` -10. Fill in your answers in `answers.md` +9. Fill in your answers in `answers.md` > **Important Notes:** > - You can use any Git commands you like to explore the repository @@ -207,19 +204,6 @@ git diff HEAD # Show all changes (staged + unstaged) vs last c - `git diff HEAD` - See all your changes since the last commit - `git diff ` - Compare any two points in history -### Finding Who Changed What with git blame - -```bash -git blame # Show who last modified each line -git blame -e # Show with email addresses -git blame -L 10,20 # Blame specific line range (lines 10-20) -``` - -**When to use `git blame`:** -- Find who wrote a specific line of code -- Identify when a bug was introduced -- Understand the context/reason for a change by finding the author - ## Verification Once you've filled in your answers in `answers.md`, verify your solution: diff --git a/01_essentials/02-history/setup.ps1 b/01_essentials/02-history/setup.ps1 index 2dc7b65..ae01b86 100644 --- a/01_essentials/02-history/setup.ps1 +++ b/01_essentials/02-history/setup.ps1 @@ -200,39 +200,6 @@ Set-Content -Path "app.py" -Value $appContent git add . git commit -m "Add user profile feature" | Out-Null -# Commit 6: Add a suspicious change (for git blame challenge) -Write-Host "Adding configuration change..." -ForegroundColor Green -# Temporarily change git user for this commit -git config user.name "Suspicious Developer" -git config user.email "guilty@email.com" - -$appContent = @" -# app.py - Main application file -from auth import login, logout -from database import connect, disconnect -from profile import get_profile - -def main(): - print("Welcome to My App!") - connect() - # Application initialization code here - if login("admin", "admin123"): # TODO: Change default credentials! - profile = get_profile("admin") - print(f"User profile: {profile}") - pass - -if __name__ == "__main__": - main() -"@ -Set-Content -Path "app.py" -Value $appContent - -git add . -git commit -m "Update default login credentials" | Out-Null - -# Reset git config back to original -git config user.name "Workshop Student" -git config user.email "student@example.com" - # Create a staged change scenario Write-Host "Creating staged changes for exploration..." -ForegroundColor Green $configContent = @" @@ -342,29 +309,6 @@ git diff database.py --- -## Question 6: Who changed the login credentials to hardcoded values? 🔍 - -**The Challenge:** -Someone on the team added hardcoded login credentials to `app.py` (username: "admin", password: "admin123"). This is a security issue! Use `git blame` to find out who made this change. - -**Your task:** Find the email address of the person who wrote the line containing `login("admin", "admin123")`. - -**Suggested commands:** -``````bash -# View who changed each line in app.py -git blame app.py - -# For a more readable format -git blame -e app.py # Shows email addresses - -# Look for the line with login("admin", "admin123") -# The format is: commit_hash (Author Name date time line_number) line_content -`````` - -**Your Answer (provide the email address):** - - - --- ## Quick Reference - Useful Commands @@ -394,14 +338,6 @@ git diff # Show unstaged changes git diff HEAD # Show all changes since last commit `````` -**Finding Who Changed What:** -``````bash -git blame # Show who last modified each line -git blame -e # Show with email addresses -git blame -L 10,20 # Blame specific line range -git blame | grep "pattern" # Find who changed lines matching pattern -`````` - **Repository Status:** ``````bash git status # Show working tree status diff --git a/01_essentials/02-history/verify.ps1 b/01_essentials/02-history/verify.ps1 index 0478f84..08b08a6 100644 --- a/01_essentials/02-history/verify.ps1 +++ b/01_essentials/02-history/verify.ps1 @@ -41,8 +41,8 @@ if (-not (Test-Path "answers.md")) { $answers = Get-Content "answers.md" -Raw $answersLower = $answers.ToLower() - # Check 1: Contains "6" or "six" for commit count - if ($answersLower -match "6|six") { + # Check 1: Contains "5" or "five" for commit count + if ($answersLower -match "5|five") { Write-Host "[PASS] Correct commit count found" -ForegroundColor Green } else { Write-Host "[FAIL] Commit count not found or incorrect" -ForegroundColor Red @@ -93,14 +93,6 @@ if (-not (Test-Path "answers.md")) { $allChecksPassed = $false } - # Check 6: Contains "guilty@email.com" for git blame challenge - if ($answersLower -match "guilty@email\.com") { - Write-Host "[PASS] Correct email address found using git blame!" -ForegroundColor Green - } else { - Write-Host "[FAIL] Guilty developer's email not found" -ForegroundColor Red - Write-Host "[HINT] Use 'git blame -e app.py' to see who changed each line with email addresses" -ForegroundColor Yellow - $allChecksPassed = $false - } } Set-Location .. @@ -118,7 +110,6 @@ if ($allChecksPassed) { Write-Host " - See which files changed in commits" -ForegroundColor White Write-Host " - Check staged changes with git diff --staged" -ForegroundColor White Write-Host " - Compare changes between specific commits with git diff" -ForegroundColor White - Write-Host " - Track down who made changes with git blame" -ForegroundColor White Write-Host "`nReady for the next module!" -ForegroundColor Green Write-Host "" } else { diff --git a/03_advanced/05-blame/README.md b/03_advanced/05-blame/README.md new file mode 100644 index 0000000..01de914 --- /dev/null +++ b/03_advanced/05-blame/README.md @@ -0,0 +1,169 @@ +# Module 05: Git Blame - Code Archaeology + +## Learning Objectives + +In this module, you will: +- Use `git blame` to find who made specific changes +- Understand blame output format and information +- Track down problematic code changes +- Learn when and why to use `git blame` +- Investigate code history to understand context + +## Challenge + +### Setup + +Run the setup script to create your challenge environment: + +```powershell +.\setup.ps1 +``` + +This will create a `challenge/` directory with a Git repository that has a security issue - someone committed hardcoded credentials! + +### Your Task + +Your team has discovered a security vulnerability: hardcoded credentials were added to the codebase. Your job is to investigate who made this change and document your findings. + +The setup script will create an `investigation.md` file in the challenge directory with questions for you to answer. Use `git blame` and other Git commands to track down the responsible developer. + +**Scenario:** +- Someone added hardcoded login credentials (`username: "admin"`, `password: "admin123"`) to `app.py` +- This is a critical security issue +- You need to identify who made this change so the team can discuss it with them + +**Suggested Approach:** + +1. Navigate to the challenge directory: `cd challenge` +2. Open `investigation.md` to see the questions +3. Examine `app.py` to find the suspicious line +4. Use `git blame` to find who wrote that line +5. Use `git blame -e` to see email addresses +6. Use `git show` to see the full commit details +7. Document your findings in `investigation.md` + +> **Important Notes:** +> - `git blame` shows who last modified each line +> - Each line shows: commit hash, author, date, line number, and content +> - Use `-e` flag to show email addresses +> - Use `-L` to focus on specific line ranges + +## Key Concepts + +- **Git Blame**: Shows the revision and author who last modified each line of a file +- **Code Archaeology**: Using Git history to understand when and why code changed +- **Author Attribution**: Identifying who wrote specific code for context, not punishment +- **Commit Context**: Understanding the full story behind a change + +## Understanding Git Blame Output + +When you run `git blame app.py`, you'll see output like this: + +``` +a1b2c3d4 (John Doe 2024-01-15 10:30:45 +0000 1) # app.py - Main application +a1b2c3d4 (John Doe 2024-01-15 10:30:45 +0000 2) +e5f6g7h8 (Jane Smith 2024-01-16 14:20:10 +0000 3) from auth import login +e5f6g7h8 (Jane Smith 2024-01-16 14:20:10 +0000 4) +i9j0k1l2 (Bob Wilson 2024-01-17 09:15:30 +0000 5) def main(): +i9j0k1l2 (Bob Wilson 2024-01-17 09:15:30 +0000 6) login("admin", "admin123") +``` + +### Breaking It Down + +Each line shows: +1. **Commit Hash** (`a1b2c3d4`) - The commit that last changed this line +2. **Author Name** (`John Doe`) - Who made the change +3. **Date/Time** (`2024-01-15 10:30:45 +0000`) - When it was changed +4. **Line Number** (`1`) - The line number in the current file +5. **Line Content** (`# app.py - Main application`) - The actual code + +### Useful Git Blame Options + +```bash +git blame # Basic blame output +git blame -e # Show email addresses instead of names +git blame -L 10,20 # Only show lines 10-20 +git blame -L 10,+5 # Show 5 lines starting from line 10 +git blame -w # Ignore whitespace changes +git blame # Blame as of specific commit +``` + +### Following Up After Blame + +Once you find the commit hash: + +```bash +git show # See the full commit details +git log -p # See commit with diff +git show --stat # See which files were changed +``` + +## When to Use Git Blame + +**Good reasons to use `git blame`:** +- 🔍 Understanding why code was written a certain way +- 📚 Finding context for a piece of code +- 🐛 Identifying when a bug was introduced +- 💡 Discovering the thought process behind a decision +- 👥 Finding who to ask about specific code + +**Not for blaming:** +- ❌ Finding someone to blame for mistakes +- ❌ Tracking "productivity" or code ownership +- ❌ Punishing developers for old code + +**Remember:** Code archaeology is about understanding, not blaming! + +## Useful Commands + +### Investigation Commands + +```bash +# Find who changed each line +git blame +git blame -e # With email addresses + +# Focus on specific lines +git blame -L 10,20 # Lines 10-20 +git blame -L :function_name # Specific function (Git 2.20+) + +# See historical blame +git blame ^ # Blame before a specific commit + +# Combine with grep +git blame | grep "pattern" # Find who wrote lines matching pattern +``` + +### Context Commands + +```bash +# See full commit details +git show +git log -1 # Just the commit message + +# See all commits by author +git log --author="name" + +# See what else changed in that commit +git show --stat +``` + +## Verification + +Once you've completed your investigation in `investigation.md`, verify your solution: + +```powershell +.\verify.ps1 +``` + +The verification script will check that you've identified the correct developer. + +## Need to Start Over? + +If you want to reset the challenge and start fresh: + +```powershell +.\reset.ps1 +``` + +This will remove the challenge directory and run the setup script again, giving you a clean slate. diff --git a/03_advanced/05-blame/reset.ps1 b/03_advanced/05-blame/reset.ps1 new file mode 100644 index 0000000..17a7649 --- /dev/null +++ b/03_advanced/05-blame/reset.ps1 @@ -0,0 +1,24 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Resets the Module 05 challenge environment. + +.DESCRIPTION + This script removes the challenge directory and re-runs the setup script + to give you a fresh start. +#> + +Write-Host "`n=== Resetting Module 05 Challenge ===" -ForegroundColor Cyan + +# Remove challenge directory if it exists +if (Test-Path "challenge") { + Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow + Remove-Item -Recurse -Force "challenge" + Write-Host "Challenge directory removed." -ForegroundColor Green +} else { + Write-Host "No challenge directory found to remove." -ForegroundColor Yellow +} + +# Run setup script +Write-Host "`nRunning setup script..." -ForegroundColor Cyan +& "./setup.ps1" diff --git a/03_advanced/05-blame/setup.ps1 b/03_advanced/05-blame/setup.ps1 new file mode 100644 index 0000000..50ead77 --- /dev/null +++ b/03_advanced/05-blame/setup.ps1 @@ -0,0 +1,323 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Sets up the Module 05 challenge environment for git blame investigation. + +.DESCRIPTION + This script creates a challenge directory with a Git repository that + contains a security vulnerability (hardcoded credentials) for students + to investigate using git blame. +#> + +Write-Host "`n=== Setting up Module 05 Challenge ===" -ForegroundColor Cyan + +# Remove existing challenge directory if it exists +if (Test-Path "challenge") { + Write-Host "Removing existing challenge directory..." -ForegroundColor Yellow + Remove-Item -Recurse -Force "challenge" +} + +# Create fresh challenge directory +Write-Host "Creating challenge directory..." -ForegroundColor Green +New-Item -ItemType Directory -Path "challenge" | Out-Null +Set-Location "challenge" + +# Initialize Git repository +Write-Host "Initializing Git repository..." -ForegroundColor Green +git init | Out-Null + +# Commit 1: Initial project structure (by Alice) +Write-Host "Creating initial project structure..." -ForegroundColor Green +git config user.name "Alice Johnson" +git config user.email "alice@example.com" + +$appContent = @" +# app.py - Main application file + +def main(): + print("Welcome to My App!") + # Application initialization code here + pass + +if __name__ == "__main__": + main() +"@ +Set-Content -Path "app.py" -Value $appContent + +git add . +git commit -m "Initial project structure" | Out-Null + +# Commit 2: Add authentication module (by Bob) +Write-Host "Adding authentication module..." -ForegroundColor Green +git config user.name "Bob Chen" +git config user.email "bob@example.com" + +$authContent = @" +# auth.py - Authentication module + +def login(username, password): + # Authenticate user + print(f"Logging in user: {username}") + return True + +def logout(username): + # Log out user + print(f"Logging out user: {username}") + return True +"@ +Set-Content -Path "auth.py" -Value $authContent + +$appContent = @" +# app.py - Main application file +from auth import login, logout + +def main(): + print("Welcome to My App!") + # Application initialization code here + pass + +if __name__ == "__main__": + main() +"@ +Set-Content -Path "app.py" -Value $appContent + +git add . +git commit -m "Add authentication module" | Out-Null + +# Commit 3: Add database connection (by Carol) +Write-Host "Adding database connection..." -ForegroundColor Green +git config user.name "Carol Martinez" +git config user.email "carol@example.com" + +$databaseContent = @" +# database.py - Database connection module + +def connect(): + # Connect to database + print("Connecting to database...") + return True + +def disconnect(): + # Disconnect from database + print("Disconnecting from database...") + return True +"@ +Set-Content -Path "database.py" -Value $databaseContent + +$appContent = @" +# app.py - Main application file +from auth import login, logout +from database import connect, disconnect + +def main(): + print("Welcome to My App!") + connect() + # Application initialization code here + pass + +if __name__ == "__main__": + main() +"@ +Set-Content -Path "app.py" -Value $appContent + +git add . +git commit -m "Add database connection" | Out-Null + +# Commit 4: Add hardcoded credentials (THE SECURITY ISSUE - by Suspicious Developer) +Write-Host "Adding suspicious change..." -ForegroundColor Green +git config user.name "Suspicious Developer" +git config user.email "guilty@email.com" + +$appContent = @" +# app.py - Main application file +from auth import login, logout +from database import connect, disconnect + +def main(): + print("Welcome to My App!") + connect() + # Quick fix for testing - TODO: Remove before production! + if login("admin", "admin123"): + print("Admin logged in successfully") + pass + +if __name__ == "__main__": + main() +"@ +Set-Content -Path "app.py" -Value $appContent + +git add . +git commit -m "Add quick test login for debugging" | Out-Null + +# Commit 5: Add logging (by David - innocent commit after the security issue) +Write-Host "Adding logging module..." -ForegroundColor Green +git config user.name "David Lee" +git config user.email "david@example.com" + +$loggingContent = @" +# logging_config.py - Logging configuration + +import logging + +def setup_logging(): + logging.basicConfig( + level=logging.INFO, + format='%(asctime)s - %(name)s - %(levelname)s - %(message)s' + ) + return logging.getLogger(__name__) +"@ +Set-Content -Path "logging_config.py" -Value $loggingContent + +git add . +git commit -m "Add logging configuration" | Out-Null + +# Reset git config +git config user.name "Workshop Student" +git config user.email "student@example.com" + +# Create investigation.md template +Write-Host "Creating investigation template..." -ForegroundColor Green +$investigationTemplate = @" +# Security Investigation Report + +## Incident Overview + +A security vulnerability has been discovered in the codebase: hardcoded credentials in `app.py`. + +**Your task:** Use git blame and related Git commands to investigate this security issue and document your findings. + +--- + +## Question 1: What line number contains the hardcoded password? + +Look at `app.py` and find the line with `"admin123"`. + +**Your Answer:** + + + +--- + +## Question 2: Who added the hardcoded credentials? + +Use `git blame` to find the email address of the developer who wrote the line with the hardcoded credentials. + +**Suggested commands:** +``````bash +# View blame with email addresses +git blame -e app.py + +# Or focus on specific lines (if you know the line range) +git blame -L 8,10 app.py + +# Look for the line containing login("admin", "admin123") +`````` + +**Your Answer (provide the email address):** + + + +--- + +## Question 3: What was the commit message for the change that introduced the hardcoded credentials? + +Once you've found the commit hash from git blame, use `git show` or `git log` to see the full commit message. + +**Suggested commands:** +``````bash +# After finding the commit hash from git blame +git show +git log -1 +`````` + +**Your Answer:** + + + +--- + +## Question 4: How many files were modified in the commit that added the hardcoded credentials? + +Use `git show` with the `--stat` flag to see which files were changed. + +**Suggested commands:** +``````bash +git show --stat +git show --name-only +`````` + +**Your Answer:** + + + +--- + +## Question 5: When was this security vulnerability introduced? + +Use the timestamp from git blame to determine when the vulnerable code was committed. + +**Your Answer (date and time):** + + + +--- + +## Recommendations + +Based on your investigation, what actions should the team take? + +**Your Recommendations:** + + + +--- + +## Quick Reference - Investigation Commands + +**Finding Who Changed What:** +``````bash +git blame # Show who last modified each line +git blame -e # Show with email addresses +git blame -L 10,20 # Blame specific line range +`````` + +**Getting Commit Details:** +``````bash +git show # See full commit details +git show --stat # See files changed +git log -1 # See commit message only +git log -p # See commit with diff +`````` + +**Searching History:** +``````bash +git log --all --grep="keyword" # Search commit messages +git log --author="name" # See commits by author +git log --since="2 weeks ago" # Recent commits +`````` + +--- + +When you're done with your investigation, run ``..\verify.ps1`` to check your answers! +"@ + +Set-Content -Path "investigation.md" -Value $investigationTemplate + +# Return to module directory +Set-Location .. + +Write-Host "`n=== Setup Complete! ===" -ForegroundColor Green +Write-Host "`nYour investigation environment is ready in the 'challenge/' directory." -ForegroundColor Cyan +Write-Host "`nScenario: Someone committed hardcoded credentials to app.py!" -ForegroundColor Yellow +Write-Host "`nNext steps:" -ForegroundColor Cyan +Write-Host " 1. cd challenge" -ForegroundColor White +Write-Host " 2. Open 'investigation.md' to see the investigation questions" -ForegroundColor White +Write-Host " 3. Use 'git blame -e app.py' to start your investigation" -ForegroundColor White +Write-Host " 4. Fill in your findings in 'investigation.md'" -ForegroundColor White +Write-Host " 5. Run '..\verify.ps1' to check your investigation" -ForegroundColor White +Write-Host "" diff --git a/03_advanced/05-blame/verify.ps1 b/03_advanced/05-blame/verify.ps1 new file mode 100644 index 0000000..8b843ae --- /dev/null +++ b/03_advanced/05-blame/verify.ps1 @@ -0,0 +1,114 @@ +#!/usr/bin/env pwsh +<# +.SYNOPSIS + Verifies the Module 05 challenge solution. + +.DESCRIPTION + This script checks that: + - The challenge directory exists + - A Git repository exists + - investigation.md exists with correct findings about the security issue +#> + +Write-Host "`n=== Verifying Module 05 Solution ===" -ForegroundColor Cyan + +$allChecksPassed = $true + +# Check if challenge directory exists +if (-not (Test-Path "challenge")) { + Write-Host "[FAIL] Challenge directory not found. Did you run setup.ps1?" -ForegroundColor Red + exit 1 +} + +Set-Location "challenge" + +# Check if git repository exists +if (-not (Test-Path ".git")) { + Write-Host "[FAIL] Not a git repository. Did you run setup.ps1?" -ForegroundColor Red + Set-Location .. + exit 1 +} + +# Check if investigation.md exists +if (-not (Test-Path "investigation.md")) { + Write-Host "[FAIL] investigation.md not found. Did you run setup.ps1?" -ForegroundColor Red + Write-Host "[HINT] The setup script should have created investigation.md for you" -ForegroundColor Yellow + $allChecksPassed = $false +} else { + Write-Host "[PASS] investigation.md exists" -ForegroundColor Green + + # Read the investigation file + $investigation = Get-Content "investigation.md" -Raw + $investigationLower = $investigation.ToLower() + + # Check 1: Line number (line 8 contains the hardcoded password) + if ($investigationLower -match "8") { + Write-Host "[PASS] Correct line number identified" -ForegroundColor Green + } else { + Write-Host "[FAIL] Line number not found or incorrect" -ForegroundColor Red + Write-Host "[HINT] Look at app.py to find which line contains 'admin123'" -ForegroundColor Yellow + $allChecksPassed = $false + } + + # Check 2: Email address (guilty@email.com) + if ($investigationLower -match "guilty@email\.com") { + Write-Host "[PASS] Correct email address found using git blame!" -ForegroundColor Green + } else { + Write-Host "[FAIL] Developer's email address not found" -ForegroundColor Red + Write-Host "[HINT] Use 'git blame -e app.py' to see who changed each line with email addresses" -ForegroundColor Yellow + $allChecksPassed = $false + } + + # Check 3: Commit message (contains "test" or "debug" or "quick") + if ($investigationLower -match "test|debug|quick") { + Write-Host "[PASS] Commit message identified" -ForegroundColor Green + } else { + Write-Host "[FAIL] Commit message not found" -ForegroundColor Red + Write-Host "[HINT] Use 'git show ' to see the commit message" -ForegroundColor Yellow + $allChecksPassed = $false + } + + # Check 4: Number of files (1 file - only app.py) + if ($investigationLower -match "1|one|app\.py") { + Write-Host "[PASS] Number of files modified identified" -ForegroundColor Green + } else { + Write-Host "[FAIL] Number of files modified not found" -ForegroundColor Red + Write-Host "[HINT] Use 'git show --stat' to see which files were changed" -ForegroundColor Yellow + $allChecksPassed = $false + } + + # Check 5: Some mention of timestamp/date (flexible check) + # We're just checking they attempted to answer this + if ($investigationLower -match "202|date|time|\d{4}-\d{2}-\d{2}") { + Write-Host "[PASS] Timestamp/date documented" -ForegroundColor Green + } else { + Write-Host "[FAIL] Timestamp/date not documented" -ForegroundColor Red + Write-Host "[HINT] The git blame output shows the date and time of each change" -ForegroundColor Yellow + $allChecksPassed = $false + } +} + +Set-Location .. + +# Final summary +if ($allChecksPassed) { + Write-Host "`n" -NoNewline + Write-Host "=====================================" -ForegroundColor Green + Write-Host " INVESTIGATION COMPLETE!" -ForegroundColor Green + Write-Host "=====================================" -ForegroundColor Green + Write-Host "`nExcellent detective work! You've successfully used git blame to track down the security issue." -ForegroundColor Cyan + Write-Host "`nYou now know how to:" -ForegroundColor Cyan + Write-Host " - Use git blame to find who modified each line" -ForegroundColor White + Write-Host " - Read and interpret git blame output" -ForegroundColor White + Write-Host " - Use git blame with -e flag to show email addresses" -ForegroundColor White + Write-Host " - Find commit details after identifying changes with blame" -ForegroundColor White + Write-Host " - Conduct code archaeology to understand code history" -ForegroundColor White + Write-Host "`nRemember: git blame is for understanding, not blaming!" -ForegroundColor Yellow + Write-Host "`nReady for the next module!" -ForegroundColor Green + Write-Host "" +} else { + Write-Host "`n[SUMMARY] Some checks failed. Review the hints above and try again." -ForegroundColor Red + Write-Host "[INFO] You can run this verification script as many times as needed." -ForegroundColor Yellow + Write-Host "" + exit 1 +}