<# ============================================================================== Azure DevOps to GitHub Migration - Automated Setup Script ============================================================================== Author: Swarup Puvvada Description: Automates the entire ADO to GitHub migration process with GUI-based input collection for all required variables. Version: 2.1 Date: January 23, 2026 Features: - GUI popup windows for variable collection - Option to migrate single repo or all repos - Automated gh CLI extension installation - PAT validation and testing - Comprehensive error handling - Detailed logging - Progress tracking Created by: Swarup Puvvada GitHub: https://github.com/ado2gh-swarup ============================================================================== #> # Set error action preference $ErrorActionPreference = "Stop" # Create log file $LogFile = "ADO-GitHub-Migration-$(Get-Date -Format 'yyyyMMdd-HHmmss').log" function Write-Log { param([string]$Message, [string]$Level = "INFO") $timestamp = Get-Date -Format "yyyy-MM-dd HH:mm:ss" $logMessage = "[$timestamp] [$Level] $Message" Write-Host $logMessage Add-Content -Path $LogFile -Value $logMessage } function Show-InputDialog { param( [string]$Title, [string]$Prompt, [bool]$IsPassword = $false ) Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object System.Windows.Forms.Form $form.Text = $Title $form.Size = New-Object System.Drawing.Size(500, 200) $form.StartPosition = 'CenterScreen' $form.FormBorderStyle = 'FixedDialog' $form.MaximizeBox = $false $form.MinimizeBox = $false $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(10, 20) $label.Size = New-Object System.Drawing.Size(460, 40) $label.Text = $Prompt $form.Controls.Add($label) $textBox = New-Object System.Windows.Forms.TextBox $textBox.Location = New-Object System.Drawing.Point(10, 70) $textBox.Size = New-Object System.Drawing.Size(460, 20) if ($IsPassword) { $textBox.UseSystemPasswordChar = $true } $form.Controls.Add($textBox) $okButton = New-Object System.Windows.Forms.Button $okButton.Location = New-Object System.Drawing.Point(300, 110) $okButton.Size = New-Object System.Drawing.Size(75, 30) $okButton.Text = 'OK' $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.AcceptButton = $okButton $form.Controls.Add($okButton) $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Location = New-Object System.Drawing.Point(390, 110) $cancelButton.Size = New-Object System.Drawing.Size(75, 30) $cancelButton.Text = 'Cancel' $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $cancelButton $form.Controls.Add($cancelButton) $result = $form.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { return $textBox.Text } else { return $null } } function Show-MessageBox { param([string]$Message, [string]$Title = "Information") Add-Type -AssemblyName System.Windows.Forms [System.Windows.Forms.MessageBox]::Show($Message, $Title, 'OK', 'Information') } function Show-ChoiceDialog { param( [string]$Title, [string]$Prompt, [string[]]$Choices ) Add-Type -AssemblyName System.Windows.Forms Add-Type -AssemblyName System.Drawing $form = New-Object System.Windows.Forms.Form $form.Text = $Title $form.Size = New-Object System.Drawing.Size(500, 250) $form.StartPosition = 'CenterScreen' $form.FormBorderStyle = 'FixedDialog' $form.MaximizeBox = $false $form.MinimizeBox = $false $label = New-Object System.Windows.Forms.Label $label.Location = New-Object System.Drawing.Point(10, 20) $label.Size = New-Object System.Drawing.Size(460, 40) $label.Text = $Prompt $form.Controls.Add($label) $radioButtons = @() $yPosition = 70 for ($i = 0; $i -lt $Choices.Length; $i++) { $radioButton = New-Object System.Windows.Forms.RadioButton $radioButton.Location = New-Object System.Drawing.Point(20, $yPosition) $radioButton.Size = New-Object System.Drawing.Size(450, 30) $radioButton.Text = $Choices[$i] if ($i -eq 0) { $radioButton.Checked = $true } $form.Controls.Add($radioButton) $radioButtons += $radioButton $yPosition += 35 } $buttonY = $yPosition + 10 $okButton = New-Object System.Windows.Forms.Button $okButton.Location = New-Object System.Drawing.Point(300, $buttonY) $okButton.Size = New-Object System.Drawing.Size(75, 30) $okButton.Text = 'OK' $okButton.DialogResult = [System.Windows.Forms.DialogResult]::OK $form.AcceptButton = $okButton $form.Controls.Add($okButton) $cancelButton = New-Object System.Windows.Forms.Button $cancelButton.Location = New-Object System.Drawing.Point(390, $buttonY) $cancelButton.Size = New-Object System.Drawing.Size(75, 30) $cancelButton.Text = 'Cancel' $cancelButton.DialogResult = [System.Windows.Forms.DialogResult]::Cancel $form.CancelButton = $cancelButton $form.Controls.Add($cancelButton) $result = $form.ShowDialog() if ($result -eq [System.Windows.Forms.DialogResult]::OK) { for ($i = 0; $i -lt $radioButtons.Length; $i++) { if ($radioButtons[$i].Checked) { return $i } } } return -1 } # Main Script Execution Write-Log "========================================" "INFO" Write-Log "ADO to GitHub Migration Script Started" "INFO" Write-Log "Author: Swarup Puvvada" "INFO" Write-Log "========================================" "INFO" # Welcome Message Show-MessageBox -Title "Welcome!" -Message "Welcome to Azure DevOps to GitHub Migration Tool!`n`nThis wizard will guide you through the migration process.`n`nCreated by: Swarup Puvvada`nGitHub: https://github.com/ado2gh-swarup" # Ask migration type Write-Log "Asking user for migration type..." "INFO" $migrationChoice = Show-ChoiceDialog -Title "Migration Type" -Prompt "Choose your migration type:" -Choices @( "Migrate a SINGLE repository", "Migrate ALL repositories from ONE Team Project", "Migrate ALL repositories from ALL Team Projects (entire organization)" ) if ($migrationChoice -eq -1) { Write-Log "User cancelled." "ERROR" exit } $migrateSingle = ($migrationChoice -eq 0) $migrateOneProject = ($migrationChoice -eq 1) $migrateAllProjects = ($migrationChoice -eq 2) if ($migrateSingle) { Write-Log "Migration type selected: SINGLE repository" "INFO" } elseif ($migrateOneProject) { Write-Log "Migration type selected: ALL repositories from ONE Team Project" "INFO" } else { Write-Log "Migration type selected: ALL repositories from ALL Team Projects" "INFO" } # Collect Azure DevOps Information Write-Log "Collecting Azure DevOps information..." "INFO" $AdoOrg = Show-InputDialog -Title "Azure DevOps Organization" -Prompt "Enter your Azure DevOps Organization name:" if (-not $AdoOrg) { Write-Log "User cancelled." "ERROR"; exit } if ($migrateSingle) { # For single repo migration $AdoTeamProject = Show-InputDialog -Title "Azure DevOps Team Project" -Prompt "Enter your Azure DevOps Team Project name:" if (-not $AdoTeamProject) { Write-Log "User cancelled." "ERROR"; exit } $AdoRepo = Show-InputDialog -Title "Azure DevOps Repository" -Prompt "Enter your Azure DevOps Repository name:" if (-not $AdoRepo) { Write-Log "User cancelled." "ERROR"; exit } } elseif ($migrateOneProject) { # For migrating all repos from ONE team project $AdoTeamProject = Show-InputDialog -Title "Azure DevOps Team Project" -Prompt "Enter the Team Project name (all repos from this project will be migrated):" if (-not $AdoTeamProject) { Write-Log "User cancelled." "ERROR"; exit } $AdoRepo = $null } else { # For migrating all repos from ALL team projects $AdoTeamProject = $null $AdoRepo = $null Show-MessageBox -Title "Info" -Message "The script will discover and migrate ALL repositories from ALL Team Projects in your organization: $AdoOrg`n`nThis may take a long time!" } $AdoPat = Show-InputDialog -Title "Azure DevOps PAT" -Prompt "Enter your Azure DevOps Personal Access Token (PAT):" -IsPassword $true if (-not $AdoPat) { Write-Log "User cancelled." "ERROR"; exit } # Collect GitHub Information Write-Log "Collecting GitHub information..." "INFO" $GhOrg = Show-InputDialog -Title "GitHub Organization" -Prompt "Enter your GitHub Organization name:" if (-not $GhOrg) { Write-Log "User cancelled." "ERROR"; exit } if ($migrateSingle) { $GhRepo = Show-InputDialog -Title "GitHub Repository" -Prompt "Enter your GitHub Repository name:" if (-not $GhRepo) { Write-Log "User cancelled." "ERROR"; exit } } else { $GhRepo = $null } $GhPat = Show-InputDialog -Title "GitHub PAT" -Prompt "Enter your GitHub Personal Access Token (PAT):" -IsPassword $true if (-not $GhPat) { Write-Log "User cancelled." "ERROR"; exit } # Log collected information (without sensitive data) Write-Log "Configuration Summary:" "INFO" if ($migrateSingle) { Write-Log "Migration Type: SINGLE repository" "INFO" Write-Log "ADO Repo: $AdoRepo" "INFO" Write-Log "GitHub Repo: $GhRepo" "INFO" } elseif ($migrateOneProject) { Write-Log "Migration Type: ALL repositories from ONE Team Project" "INFO" } else { Write-Log "Migration Type: ALL repositories from ALL Team Projects" "INFO" } Write-Log "ADO Org: $AdoOrg" "INFO" if ($AdoTeamProject) { Write-Log "ADO Team Project: $AdoTeamProject" "INFO" } Write-Log "GitHub Org: $GhOrg" "INFO" # Check if gh CLI is installed Write-Log "Checking for GitHub CLI (gh)..." "INFO" try { $ghVersion = gh --version Write-Log "GitHub CLI is installed: $ghVersion" "INFO" } catch { Write-Log "GitHub CLI not found. Please install it first from https://cli.github.com/" "ERROR" Show-MessageBox -Title "Error" -Message "GitHub CLI (gh) is not installed.`n`nPlease install it from: https://cli.github.com/`n`nThen run this script again." exit } Write-Log "Authenticating with GitHub..." "INFO" try { # Required for gh ado2gh $env:GITHUB_TOKEN = $GhPat # Optional: validate token works $null = gh api user 2>&1 Write-Log "GitHub authentication successful" "INFO" } catch { Write-Log "GitHub authentication failed: $_" "ERROR" Show-MessageBox -Title "Error" -Message @" GitHub authentication failed. This tool requires a CLASSIC GitHub PAT with: - repo - admin:org - workflow "@ exit } # Install gh-ado2gh extension Write-Log "Installing gh-ado2gh extension..." "INFO" try { gh extension install github/gh-ado2gh 2>&1 | Out-Null Write-Log "gh-ado2gh extension installed successfully" "INFO" } catch { Write-Log "Extension installation failed (may already be installed): $_" "WARN" } # Set environment variables $env:ADO_PAT = $AdoPat if ($migrateOneProject) { # Bulk Migration - Generate Script for All Repos in One Project Write-Log "Starting bulk migration process for all repositories in one project..." "INFO" Show-MessageBox -Title "Bulk Migration Starting" -Message "Generating migration script for ALL repositories in project: $AdoTeamProject`n`nThis may take a moment...`n`nPlease wait..." try { $scriptFile = "migration-script-$(Get-Date -Format 'yyyyMMdd-HHmmss').ps1" Write-Log "Generating migration script..." "INFO" $generateCommand = "gh ado2gh generate-script --ado-org ""$AdoOrg"" --ado-team-project ""$AdoTeamProject"" --github-org ""$GhOrg"" --output ""$scriptFile""" Write-Log "Command: $generateCommand" "INFO" Invoke-Expression $generateCommand if (Test-Path $scriptFile) { Write-Log "Migration script generated: $scriptFile" "INFO" $confirmRun = [System.Windows.Forms.MessageBox]::Show( "Migration script generated successfully!`n`nFile: $scriptFile`n`nDo you want to review the script before running it?`n`nClick YES to open in Notepad, NO to run immediately, CANCEL to exit.", "Script Generated", 'YesNoCancel', 'Question' ) if ($confirmRun -eq 'Yes') { notepad $scriptFile $runScript = [System.Windows.Forms.MessageBox]::Show( "Do you want to run the migration script now?", "Run Migration", 'YesNo', 'Question' ) if ($runScript -eq 'Yes') { Write-Log "Executing migration script..." "INFO" & ./$scriptFile Write-Log "Bulk migration completed!" "INFO" Show-MessageBox -Title "Success!" -Message "Bulk migration completed!`n`nCheck GitHub Organization: https://github.com/$GhOrg`n`nLog file: $LogFile`n`nCreated by: Swarup Puvvada" } else { Write-Log "User chose not to run the script" "INFO" Show-MessageBox -Title "Info" -Message "Migration script saved: $scriptFile`n`nYou can run it manually when ready." } } elseif ($confirmRun -eq 'No') { Write-Log "Executing migration script immediately..." "INFO" & ./$scriptFile Write-Log "Bulk migration completed!" "INFO" Show-MessageBox -Title "Success!" -Message "Bulk migration completed!`n`nCheck GitHub Organization: https://github.com/$GhOrg`n`nLog file: $LogFile`n`nCreated by: Swarup Puvvada" } else { Write-Log "User cancelled script execution" "INFO" Show-MessageBox -Title "Info" -Message "Migration script saved: $scriptFile`n`nYou can run it manually when ready." } # Open GitHub org in browser Start-Process "https://github.com/$GhOrg" } else { Write-Log "Failed to generate migration script" "ERROR" Show-MessageBox -Title "Error" -Message "Failed to generate migration script.`n`nCheck the log file for details: $LogFile" } } catch { Write-Log "Bulk migration failed: $_" "ERROR" Show-MessageBox -Title "Error" -Message "Bulk migration failed!`n`nError: $_`n`nCheck the log file for details: $LogFile" exit } } elseif ($migrateAllProjects) { # Bulk Migration - Generate Script for All Repos in All Projects Write-Log "Starting bulk migration process for all repositories in all projects..." "INFO" Show-MessageBox -Title "Bulk Migration Starting" -Message "Generating migration script for ALL repositories in ALL Team Projects in organization: $AdoOrg`n`nThis may take a moment...`n`nPlease wait..." try { $scriptFile = "migration-script-$(Get-Date -Format 'yyyyMMdd-HHmmss').ps1" Write-Log "Generating migration script..." "INFO" $generateCommand = "gh ado2gh generate-script --ado-org ""$AdoOrg"" --github-org ""$GhOrg"" --output ""$scriptFile""" Write-Log "Command: $generateCommand" "INFO" Invoke-Expression $generateCommand if (Test-Path $scriptFile) { Write-Log "Migration script generated: $scriptFile" "INFO" $confirmRun = [System.Windows.Forms.MessageBox]::Show( "Migration script generated successfully!`n`nFile: $scriptFile`n`nDo you want to review the script before running it?`n`nClick YES to open in Notepad, NO to run immediately, CANCEL to exit.", "Script Generated", 'YesNoCancel', 'Question' ) if ($confirmRun -eq 'Yes') { notepad $scriptFile $runScript = [System.Windows.Forms.MessageBox]::Show( "Do you want to run the migration script now?", "Run Migration", 'YesNo', 'Question' ) if ($runScript -eq 'Yes') { Write-Log "Executing migration script..." "INFO" & ./$scriptFile Write-Log "Bulk migration completed!" "INFO" Show-MessageBox -Title "Success!" -Message "Bulk migration completed!`n`nCheck GitHub Organization: https://github.com/$GhOrg`n`nLog file: $LogFile`n`nCreated by: Swarup Puvvada" } else { Write-Log "User chose not to run the script" "INFO" Show-MessageBox -Title "Info" -Message "Migration script saved: $scriptFile`n`nYou can run it manually when ready." } } elseif ($confirmRun -eq 'No') { Write-Log "Executing migration script immediately..." "INFO" & ./$scriptFile Write-Log "Bulk migration completed!" "INFO" Show-MessageBox -Title "Success!" -Message "Bulk migration completed!`n`nCheck GitHub Organization: https://github.com/$GhOrg`n`nLog file: $LogFile`n`nCreated by: Swarup Puvvada" } else { Write-Log "User cancelled script execution" "INFO" Show-MessageBox -Title "Info" -Message "Migration script saved: $scriptFile`n`nYou can run it manually when ready." } # Open GitHub org in browser Start-Process "https://github.com/$GhOrg" } else { Write-Log "Failed to generate migration script" "ERROR" Show-MessageBox -Title "Error" -Message "Failed to generate migration script.`n`nCheck the log file for details: $LogFile" } } catch { Write-Log "Bulk migration failed: $_" "ERROR" Show-MessageBox -Title "Error" -Message "Bulk migration failed!`n`nError: $_`n`nCheck the log file for details: $LogFile" exit } } else { # Single Repository Migration Write-Log "Starting single repository migration process..." "INFO" Show-MessageBox -Title "Migration Starting" -Message "The migration process is about to start.`n`nRepository: $AdoRepo -> $GhRepo`n`nThis may take several minutes depending on repository size.`n`nPlease wait..." try { $migrationCommand = "gh ado2gh migrate-repo --ado-org ""$AdoOrg"" --ado-team-project ""$AdoTeamProject"" --ado-repo ""$AdoRepo"" --github-org ""$GhOrg"" --github-repo ""$GhRepo""" Write-Log "Executing migration command..." "INFO" Write-Log "Command: gh ado2gh migrate-repo --ado-org $AdoOrg --ado-team-project $AdoTeamProject --ado-repo $AdoRepo --github-org $GhOrg --github-repo $GhRepo" "INFO" Invoke-Expression $migrationCommand Write-Log "Migration completed successfully!" "INFO" Show-MessageBox -Title "Success!" -Message "Migration completed successfully!`n`nRepository: https://github.com/$GhOrg/$GhRepo`n`nCheck the log file for details: $LogFile`n`nCreated by: Swarup Puvvada" # Open the migrated repository in browser Start-Process "https://github.com/$GhOrg/$GhRepo" } catch { Write-Log "Migration failed: $_" "ERROR" Show-MessageBox -Title "Error" -Message "Migration failed!`n`nError: $_`n`nCheck the log file for details: $LogFile" exit } } Write-Log "========================================" "INFO" Write-Log "Script execution completed" "INFO" Write-Log "========================================" "INFO" # Cleanup sensitive environment variables Remove-Item Env:\ADO_PAT -ErrorAction SilentlyContinue Remove-Item Env:\GH_TOKEN -ErrorAction SilentlyContinue Write-Host "`nScript completed. Log file: $LogFile" -ForegroundColor Green Read-Host "`nPress Enter to exit"