Last active
January 2, 2026 11:27
-
-
Save skarllot/1dfeab6c180cf85dd9250c308712f3c7 to your computer and use it in GitHub Desktop.
Convert Microsoft Edge Work/School Profile to Personal Profile - Allows signing in with personal Microsoft accounts (MSA) instead of requiring corporate Azure AD accounts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <# | |
| .SYNOPSIS | |
| Converts a Microsoft Edge Work/School profile to a Personal profile. | |
| .DESCRIPTION | |
| This script converts an Edge profile that was created as a Work/School profile | |
| (requiring Azure AD/Entra ID corporate accounts) to a Personal profile that | |
| accepts personal Microsoft accounts (MSA). | |
| The script: | |
| - Checks if Edge is running (exits if it is) | |
| - Lists all Edge profiles and their types | |
| - Creates automatic backups in your home directory | |
| - Removes the work profile marker (kodiak.work.profile) | |
| - Changes the profile type from Work/School to Personal | |
| - Provides rollback instructions if needed | |
| .PARAMETER ProfileName | |
| Optional. The name of the profile to convert (e.g., "Profile 1", "Default"). | |
| If not specified, the script will display a list of profiles to choose from. | |
| .EXAMPLE | |
| .\Convert-EdgeWorkProfileToPersonal.ps1 | |
| Runs the script interactively, prompting you to select a profile. | |
| .EXAMPLE | |
| .\Convert-EdgeWorkProfileToPersonal.ps1 -ProfileName "Profile 1" | |
| Converts the specified profile directly. | |
| .NOTES | |
| Version: 1.0 | |
| IMPORTANT: Close Microsoft Edge completely before running this script. | |
| Backups are created automatically in: $env:USERPROFILE\EdgeProfileBackup_[timestamp]\ | |
| #> | |
| [CmdletBinding()] | |
| param( | |
| [Parameter(Mandatory=$false)] | |
| [string]$ProfileName | |
| ) | |
| $ErrorActionPreference = 'Stop' | |
| #region Helper Functions | |
| function Write-ColorMessage { | |
| param( | |
| [string]$Message, | |
| [ValidateSet('Success','Error','Info','Warning')] | |
| [string]$Type = 'Info' | |
| ) | |
| $color = switch ($Type) { | |
| 'Success' { 'Green' } | |
| 'Error' { 'Red' } | |
| 'Warning' { 'Yellow' } | |
| 'Info' { 'Cyan' } | |
| } | |
| Write-Host $Message -ForegroundColor $color | |
| } | |
| function Test-EdgeRunning { | |
| $edgeProcesses = Get-Process -Name 'msedge' -ErrorAction SilentlyContinue | |
| return ($null -ne $edgeProcesses) | |
| } | |
| function Get-EdgeUserDataPath { | |
| return "$env:LOCALAPPDATA\Microsoft\Edge\User Data" | |
| } | |
| function Get-EdgeProfiles { | |
| $userDataPath = Get-EdgeUserDataPath | |
| $localStatePath = Join-Path $userDataPath 'Local State' | |
| if (-not (Test-Path $localStatePath)) { | |
| throw "Edge Local State file not found at: $localStatePath" | |
| } | |
| $localState = Get-Content $localStatePath -Raw | ConvertFrom-Json | |
| $profiles = @() | |
| foreach ($profileKey in $localState.profile.info_cache.PSObject.Properties.Name) { | |
| $profileData = $localState.profile.info_cache.$profileKey | |
| $profileType = switch ($profileData.edge_non_signin_profile_type) { | |
| 1 { 'Personal' } | |
| 2 { 'Work/School' } | |
| default { 'Unknown' } | |
| } | |
| $profiles += [PSCustomObject]@{ | |
| Key = $profileKey | |
| Name = $profileData.name | |
| Type = $profileType | |
| TypeValue = $profileData.edge_non_signin_profile_type | |
| AccountEmail = $profileData.user_name | |
| } | |
| } | |
| return $profiles | |
| } | |
| function Show-ProfileList { | |
| param([array]$Profiles) | |
| Write-ColorMessage "`nAvailable Edge Profiles:" -Type Info | |
| Write-Host ("=" * 80) | |
| for ($i = 0; $i -lt $Profiles.Count; $i++) { | |
| $profile = $Profiles[$i] | |
| $typeColor = if ($profile.Type -eq 'Work/School') { 'Yellow' } else { 'Green' } | |
| Write-Host ("{0,3}. " -f ($i + 1)) -NoNewline | |
| Write-Host ("{0,-20} " -f $profile.Key) -NoNewline -ForegroundColor White | |
| Write-Host ("{0,-25} " -f $profile.Name) -NoNewline | |
| Write-Host ("{0,-15}" -f "[$($profile.Type)]") -ForegroundColor $typeColor | |
| if ($profile.AccountEmail) { | |
| Write-Host (" Account: {0}" -f $profile.AccountEmail) -ForegroundColor Gray | |
| } | |
| } | |
| Write-Host ("=" * 80) | |
| } | |
| function New-BackupDirectory { | |
| $timestamp = Get-Date -Format 'yyyyMMdd_HHmmss' | |
| $backupPath = Join-Path $env:USERPROFILE "EdgeProfileBackup_$timestamp" | |
| if (-not (Test-Path $backupPath)) { | |
| New-Item -ItemType Directory -Path $backupPath -Force | Out-Null | |
| } | |
| return $backupPath | |
| } | |
| function Backup-ProfileFiles { | |
| param( | |
| [string]$ProfileKey, | |
| [string]$BackupPath | |
| ) | |
| $userDataPath = Get-EdgeUserDataPath | |
| # Backup Local State | |
| $localStatePath = Join-Path $userDataPath 'Local State' | |
| $localStateBackup = Join-Path $BackupPath 'Local State' | |
| Copy-Item $localStatePath $localStateBackup -Force | |
| Write-ColorMessage " [✓] Backed up: Local State" -Type Success | |
| # Backup Profile Preferences | |
| $preferencesPath = Join-Path $userDataPath "$ProfileKey\Preferences" | |
| if (Test-Path $preferencesPath) { | |
| $profileBackupDir = Join-Path $BackupPath $ProfileKey | |
| New-Item -ItemType Directory -Path $profileBackupDir -Force | Out-Null | |
| $preferencesBackup = Join-Path $profileBackupDir 'Preferences' | |
| Copy-Item $preferencesPath $preferencesBackup -Force | |
| Write-ColorMessage " [✓] Backed up: $ProfileKey\Preferences" -Type Success | |
| } | |
| return $true | |
| } | |
| function Convert-ProfileToPersonal { | |
| param( | |
| [string]$ProfileKey | |
| ) | |
| $userDataPath = Get-EdgeUserDataPath | |
| $changes = @() | |
| # Change 1: Remove kodiak work profile marker from Preferences | |
| Write-ColorMessage "`nApplying changes..." -Type Info | |
| $preferencesPath = Join-Path $userDataPath "$ProfileKey\Preferences" | |
| if (Test-Path $preferencesPath) { | |
| $preferences = Get-Content $preferencesPath -Raw | ConvertFrom-Json | |
| if ($preferences.PSObject.Properties.Name -contains 'kodiak') { | |
| $preferences.PSObject.Properties.Remove('kodiak') | |
| $preferences | ConvertTo-Json -Depth 100 -Compress | Set-Content $preferencesPath -Encoding UTF8 | |
| $changes += " [✓] Removed work profile marker (kodiak) from Preferences" | |
| Write-ColorMessage $changes[-1] -Type Success | |
| } else { | |
| Write-ColorMessage " [→] No kodiak marker found in Preferences (already personal?)" -Type Warning | |
| } | |
| } | |
| # Change 2: Update profile type in Local State | |
| $localStatePath = Join-Path $userDataPath 'Local State' | |
| $localState = Get-Content $localStatePath -Raw | ConvertFrom-Json | |
| $currentType = $localState.profile.info_cache.$ProfileKey.edge_non_signin_profile_type | |
| if ($currentType -eq 2) { | |
| $localState.profile.info_cache.$ProfileKey.edge_non_signin_profile_type = 1 | |
| $localState | ConvertTo-Json -Depth 100 -Compress | Set-Content $localStatePath -Encoding UTF8 | |
| $changes += " [✓] Changed profile type from Work/School (2) to Personal (1)" | |
| Write-ColorMessage $changes[-1] -Type Success | |
| } elseif ($currentType -eq 1) { | |
| Write-ColorMessage " [→] Profile type already set to Personal (1)" -Type Warning | |
| } else { | |
| Write-ColorMessage " [!] Unknown profile type: $currentType" -Type Warning | |
| } | |
| return $changes | |
| } | |
| function Show-RollbackInstructions { | |
| param([string]$BackupPath) | |
| Write-Host "`n" | |
| Write-ColorMessage "=== ROLLBACK INSTRUCTIONS ===" -Type Warning | |
| Write-Host "If you need to undo these changes, run the following commands in PowerShell:" | |
| Write-Host "" | |
| Write-Host " `$backupPath = '$BackupPath'" -ForegroundColor Gray | |
| Write-Host " `$userDataPath = '$(Get-EdgeUserDataPath)'" -ForegroundColor Gray | |
| Write-Host "" | |
| Write-Host " # Close Edge first, then restore:" -ForegroundColor Gray | |
| Write-Host " Copy-Item (Join-Path `$backupPath 'Local State') `$userDataPath -Force" -ForegroundColor Cyan | |
| Write-Host " Copy-Item (Join-Path `$backupPath 'Profile X\Preferences') `$userDataPath -Recurse -Force" -ForegroundColor Cyan | |
| Write-Host "" | |
| } | |
| #endregion | |
| #region Main Script | |
| try { | |
| Write-Host "`n" | |
| Write-ColorMessage "╔═══════════════════════════════════════════════════════════════╗" -Type Info | |
| Write-ColorMessage "║ Edge Work Profile to Personal Profile Converter ║" -Type Info | |
| Write-ColorMessage "╚═══════════════════════════════════════════════════════════════╝" -Type Info | |
| Write-Host "`n" | |
| # Step 1: Check if Edge is running | |
| Write-ColorMessage "[1/6] Checking if Microsoft Edge is running..." -Type Info | |
| if (Test-EdgeRunning) { | |
| Write-ColorMessage "`n[ERROR] Microsoft Edge is currently running!" -Type Error | |
| Write-Host "`nPlease close all Edge windows and try again." -ForegroundColor Yellow | |
| Write-Host "To close Edge completely:" | |
| Write-Host " 1. Close all Edge windows" | |
| Write-Host " 2. Check system tray for Edge icon and quit it" | |
| Write-Host " 3. Or run: Stop-Process -Name msedge -Force" | |
| exit 1 | |
| } | |
| Write-ColorMessage " [✓] Edge is not running" -Type Success | |
| # Step 2: Get and display profiles | |
| Write-ColorMessage "`n[2/6] Loading Edge profiles..." -Type Info | |
| $profiles = Get-EdgeProfiles | |
| if ($profiles.Count -eq 0) { | |
| Write-ColorMessage "[ERROR] No Edge profiles found!" -Type Error | |
| exit 1 | |
| } | |
| Write-ColorMessage " [✓] Found $($profiles.Count) profile(s)" -Type Success | |
| # Step 3: Select profile | |
| if (-not $ProfileName) { | |
| Show-ProfileList -Profiles $profiles | |
| Write-Host "`nEnter the number of the profile to convert (or 'q' to quit): " -NoNewline -ForegroundColor Yellow | |
| $selection = Read-Host | |
| if ($selection -eq 'q') { | |
| Write-ColorMessage "`nOperation cancelled by user." -Type Warning | |
| exit 0 | |
| } | |
| $index = [int]$selection - 1 | |
| if ($index -lt 0 -or $index -ge $profiles.Count) { | |
| Write-ColorMessage "`n[ERROR] Invalid selection!" -Type Error | |
| exit 1 | |
| } | |
| $selectedProfile = $profiles[$index] | |
| } else { | |
| $selectedProfile = $profiles | Where-Object { $_.Key -eq $ProfileName -or $_.Name -eq $ProfileName } | Select-Object -First 1 | |
| if (-not $selectedProfile) { | |
| Write-ColorMessage "[ERROR] Profile '$ProfileName' not found!" -Type Error | |
| exit 1 | |
| } | |
| } | |
| Write-Host "`n" | |
| Write-ColorMessage "[3/6] Selected Profile:" -Type Info | |
| Write-Host " Name: $($selectedProfile.Name)" -ForegroundColor White | |
| Write-Host " Key: $($selectedProfile.Key)" -ForegroundColor Gray | |
| Write-Host " Current Type: $($selectedProfile.Type)" -ForegroundColor $(if ($selectedProfile.Type -eq 'Work/School') { 'Yellow' } else { 'Green' }) | |
| if ($selectedProfile.Type -ne 'Work/School') { | |
| Write-ColorMessage "`n[!] This profile is not a Work/School profile." -Type Warning | |
| Write-Host "It may already be configured as Personal. Continue anyway? (y/N): " -NoNewline | |
| $confirm = Read-Host | |
| if ($confirm -ne 'y') { | |
| Write-ColorMessage "`nOperation cancelled." -Type Warning | |
| exit 0 | |
| } | |
| } | |
| # Step 4: Confirm | |
| Write-Host "`nThis will convert the profile to allow personal Microsoft account sign-in." | |
| Write-Host "Do you want to continue? (y/N): " -NoNewline -ForegroundColor Yellow | |
| $confirm = Read-Host | |
| if ($confirm -ne 'y') { | |
| Write-ColorMessage "`nOperation cancelled by user." -Type Warning | |
| exit 0 | |
| } | |
| # Step 5: Create backups | |
| Write-ColorMessage "`n[4/6] Creating backups..." -Type Info | |
| $backupPath = New-BackupDirectory | |
| Write-ColorMessage " Backup location: $backupPath" -Type Info | |
| Backup-ProfileFiles -ProfileKey $selectedProfile.Key -BackupPath $backupPath | |
| # Step 6: Convert profile | |
| Write-ColorMessage "`n[5/6] Converting profile..." -Type Info | |
| $changes = Convert-ProfileToPersonal -ProfileKey $selectedProfile.Key | |
| # Step 7: Verification | |
| Write-ColorMessage "`n[6/6] Verifying changes..." -Type Info | |
| $updatedProfiles = Get-EdgeProfiles | |
| $updatedProfile = $updatedProfiles | Where-Object { $_.Key -eq $selectedProfile.Key } | |
| if ($updatedProfile.Type -eq 'Personal') { | |
| Write-ColorMessage " [✓] Profile type successfully changed to Personal" -Type Success | |
| } else { | |
| Write-ColorMessage " [!] Profile type is: $($updatedProfile.Type)" -Type Warning | |
| } | |
| # Success summary | |
| Write-Host "`n" | |
| Write-ColorMessage "╔═══════════════════════════════════════════════════════════════╗" -Type Success | |
| Write-ColorMessage "║ SUCCESS! Profile conversion completed ║" -Type Success | |
| Write-ColorMessage "╚═══════════════════════════════════════════════════════════════╝" -Type Success | |
| Write-Host "`n" | |
| Write-ColorMessage "Changes applied:" -Type Info | |
| foreach ($change in $changes) { | |
| Write-Host $change | |
| } | |
| Write-Host "`n" | |
| Write-ColorMessage "Next steps:" -Type Info | |
| Write-Host " 1. Open Microsoft Edge with the '$($selectedProfile.Name)' profile" | |
| Write-Host " 2. Try signing in with your personal Microsoft account" | |
| Write-Host " 3. Enable sync if desired" | |
| Write-Host "`n" | |
| Write-ColorMessage "Backup location: $backupPath" -Type Info | |
| Show-RollbackInstructions -BackupPath $backupPath | |
| } catch { | |
| Write-Host "`n" | |
| Write-ColorMessage "╔═══════════════════════════════════════════════════════════════╗" -Type Error | |
| Write-ColorMessage "║ ERROR OCCURRED ║" -Type Error | |
| Write-ColorMessage "╚═══════════════════════════════════════════════════════════════╝" -Type Error | |
| Write-Host "`n" | |
| Write-ColorMessage "Error: $($_.Exception.Message)" -Type Error | |
| Write-Host "`nStack Trace:" -ForegroundColor Gray | |
| Write-Host $_.ScriptStackTrace -ForegroundColor Gray | |
| if ($backupPath -and (Test-Path $backupPath)) { | |
| Write-Host "`n" | |
| Write-ColorMessage "Backups were created at: $backupPath" -Type Warning | |
| Write-ColorMessage "You can use these to restore if needed." -Type Warning | |
| } | |
| exit 1 | |
| } | |
| #endregion |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment