Last few months I'm responsible for the migration of Office 365 to Office 365. While doing so, we came into a situation where users have their old mailbox as Primary Account and new Mailbox as their secondary account. This is a quite common scenario that people are running into and something that is expected. Usually, my recommendation is: Please create a new profile for user and topic is closed. It's also quite easy to achieve this in an automated way where you delete all profiles and Outlook just goes with autodiscovery adding new account as required. That's how I have always done this till now. My Client has gone thru setting up 1000+ users with their second account in Outlook and deleting a whole profile, recreating would cause lots of downloading of emails from Office 365 that my Client wanted to avoid.
That's fine, let's try to delete the primary email and keep the new one. Easier said than done!
The primary account cannot be removed unless it is the only account in the profile. You must remove all other Exchange accounts before removing the primary account.
I would lie if I didn't expect it. I did expect it, and I knew I've had quite a ride in the next few days finding out what is what in Outlook profile, and finally having a solution that is fully automated.
Before we dive into it please be aware I've done limited testing to this. I will try to update this post after more testing is done. If you have more knowledge on what is what in Outlook I'm more than open for help. Currently, a module like, version of the code is available on GitHub so feel free to jump in on it and help out. Keep in mind that I've only tested this on Office (Outlook) 2016 and Windows 10. Please report if you run this on anything else and it fails or works!
function Backup-RegistryPath { param( [string] $Key, [string] $BackupPath = "$($env:USERPROFILE)\Desktop", [string] $BackupName ) $Date = Get-Date $FileName = "$BackupName-$($Date.Year)-$($Date.Month)-$($Date.Day).$($Date.Hour).$($Date.Minute).$($Date.Second).reg" $BackupPlace = "$BackupPath\$FileName" if (Test-Path -Path $BackupPlace) { return $null } else { try { if (Test-Path Registry::$Key) { $Registry = Start-MyProgram -Program 'reg.exe' -cmdArgList "export", "$Key", "$BackupPlace" return $BackupPlace } } catch { return $null } } } function Convert-BinaryToHex { param( [alias('Bin')][Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)][Byte[]]$Binary ) if ($null -eq $Binary) { return } # assume pipeline input if we don't have an array (surely there must be a better way) if ($Binary.Length -eq 1) { $Binary = @($input) } $Return = -join ($Binary | foreach { "{0:X2}" -f $_ }) Write-Output $Return } function Convert-BinaryToString { param( [alias('Bin')] [Parameter(Position = 0, Mandatory = $false, ValueFromPipeline = $true)] [Byte[]]$Binary ) if ($null -ne $Binary) { return [System.Text.Encoding]::Unicode.GetString($Binary) } } function Find-OutlookKeys { param( $OutlookVersion = '2016', $EmailFind ) $MainKey = [ordered] @{ 'Outlook 2016' = 'HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles' 'Outlook 2013' = 'HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Outlook\Profiles' } $AllData = foreach ($OutlookVersion in $MainKey.Keys) { $OutlookRegistryKey = $MainKey.$OutlookVersion if ($OutlookVersion -eq 'Outlook 2016') { $SearchValue = '001f6641' } elseif ($OutlookVersion -eq 'Outlook 2013') { $SearchValue = '001f662b' } else { Exit } <# Property : {001f300a, 001f3d13, 00033e03, 00033009...} PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles\Nowy\cb755c91ea7e0b4c97fca67db4f0486b PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles\Nowy PSChildName : cb755c91ea7e0b4c97fca67db4f0486b PSDrive : HKCU PSProvider : Microsoft.PowerShell.Core\Registry PSIsContainer : True SubKeyCount : 0 View : Default Handle : Microsoft.Win32.SafeHandles.SafeRegistryHandle ValueCount : 20 Name : HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles\Nowy\cb755c91ea7e0b4c97fca67db4f0486b #> $RegistryKey = Get-ChildItem -Path "Registry::$OutlookRegistryKey" -Recurse $Special = $RegistryKey | Where-Object { $_.Property -eq $SearchValue } #| Select -Last 1 * $Keys = foreach ($S in $Special) { #$Special.PSPath $Path = "$($S.Name)" <# 001f6641 : {83, 0, 77, 0...} PSPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles\Nowy\0666d1f4813a9a4ba2d9462100225710 PSParentPath : Microsoft.PowerShell.Core\Registry::HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles\Nowy PSChildName : 0666d1f4813a9a4ba2d9462100225710 PSProvider : Microsoft.PowerShell.Core\Registry #> $MyValue = Get-ItemProperty -Path Registry::$Path -Name $SearchValue #$Email = [System.Text.Encoding]::Unicode.GetString( ) $Email = Convert-BinaryToString ($MyValue.$SearchValue) $ParentPath = $S.PSParentPath $ChildName = $S.PSChildName #Write-Color "Path ", $ParentPath, " will delete value ", $ChildName, ' email ', $Email -Color White, Yellow, White, Yellow if ($ChildName -ne 'GroupsStore') { [PsCustomObject] @{ OutlookVersion = $OutlookVersion Profile = ($ParentPath -split '\\')[-1] ProfilePath = $ParentPath RegistryKeyName = $ChildName RegistryKey = "$ParentPath\$ChildName" Email = ($Email -replace 'SMTP:', '').ToLower() } } <# if ($Email -like "*$EmailFind*") { $ParentPath = $S.PSParentPath $ChildName = $S.PSChildName #$Path #Write-Color "ParentPath ", $ParentPath, " Path: ", $Path -Color White, Yellow, White, Yellow if ($ChildName -ne 'GroupsStore') { #Write-Color "Path ", $ParentPath, " will delete value ", $ChildName -Color White, Yellow, White, Yellow # Remove-Item -Path "$ParentPath\$ChildName" -Recurse } } #> #break } #Search-Registry -KeyName '001f6641' -Recurse $Path return $Keys } return $AllData } function Start-MyProgram { [CmdletBinding()] param ( [string] $Program, [string[]] $CmdArgList ) return & $Program $CmdArgList } function Start-OutlookProfile { param( [string] $RemoveAccount, [string] $PrimaryAccount, [string] $BackupPath = "$($env:USERPROFILE)\Desktop", [switch] $GUI, [switch] $DisplayProgress, [switch] $NoBackup, [switch] $DebugOutput, [switch] $WhatIf ) $MainKey = [ordered] @{ 'Outlook 2016' = 'HKEY_CURRENT_USER\Software\Microsoft\Office\16.0\Outlook\Profiles' 'Outlook 2013' = 'HKEY_CURRENT_USER\Software\Microsoft\Office\15.0\Outlook\Profiles' } $AllData = foreach ($OutlookVersion in $MainKey.Keys) { $OutlookRegistryKey = $MainKey.$OutlookVersion # Find All Outlook Profiles $OutlookProfiles = Get-ChildItem -path Registry::$OutlookRegistryKey -ErrorAction SilentlyContinue | Select * if ($null -eq $OutlookProfiles) { continue } $i = 1 $Outlooks = foreach ($Outlook in $OutlookProfiles) { [pscustomobject] @{ Number = $i ProfileName = $Outlook.PSChildName ParentPath = $Outlook.PSParentPath Path = $Outlook.pSPath } $i++ } # Loop thru one or more Outlook Profiles foreach ($OutlookProfile in $Outlooks) { $ProfilePath = $OutlookProfile.Path # default section - this is the key storing Default Value $DefaultKey = '0a0d020000000000c000000000000046' $RegKeyDefault = "$ProfilePath\$DefaultKey" $DefaultValue = (Get-ItemProperty -Path $RegKeyDefault -Name '01023d15' -ErrorAction SilentlyContinue).'01023d15' if ($null -ne $DefaultValue) { $DefaultValueHexServiceUID = Convert-BinaryToHex -Bin $DefaultValue if ($DisplayProgress) { Write-Color -Text '[i] ', 'Default Registry Key: ', $RegKeyDefault -Color Blue, White, Green, White Write-Color -Text '[i] ', 'Binary Value ', $DefaultValue -Color Blue, White, Green, White Write-Color -Text '[i] ', 'Hex version ', $DefaultValueHexServiceUID -Color Blue, White, Green, White -LinesAfter 1 } } # Scan each account in Outlook Profile $Array = foreach ($Outlook in $OutlookProfile) { $ProfilePath = $Outlook.Path $SpecialKey = '9375CFF0413111d3B88A00104B2A6676' $SubKeyProfile = "$ProfilePath\$SpecialKey" $OneProfile = Get-ChildItem -Path $SubKeyProfile $RootProfile = Get-ItemProperty -Path $SubKeyProfile $Val1 = $RootProfile.'{ED475418-B0D6-11D2-8C3B-00104B2A6676}' $Val2 = $RootProfile.'{ED475419-B0D6-11D2-8C3B-00104B2A6676}' $Val3 = $RootProfile.'{ED475420-B0D6-11D2-8C3B-00104B2A6676}' #Convert-BinaryTohex -Binary $Val1 #Convert-BinaryTohex -Binary $Val2 #Convert-BinaryTohex -Binary $Val3 if ($DisplayProgress) { Write-Color '[i] ', 'Profile path ', $ProfilePath -Color Blue, White, Yellow } foreach ($One in $OneProfile) { $AccountName = (Get-ItemProperty -Path Registry::$One -Name 'Account Name' -ErrorAction SilentlyContinu).'Account Name' $ServiceUID = (Get-ItemProperty -Path Registry::$One -Name 'Service UID' -ErrorAction SilentlyContinu).'Service UID' $HexServiceUID = Convert-BinaryToHex -Binary $ServiceUID $PreferencesUID = (Get-ItemProperty -Path Registry::$One -Name 'Preferences UID' -ErrorAction SilentlyContinue).'Preferences UID' $HexPreferencesUID = Convert-BinaryToHex -Binary $PreferencesUID $XPProviderUID = (Get-ItemProperty -Path Registry::$One -Name 'XP Provider UID' -ErrorAction SilentlyContinue).'XP Provider UID' $HexXPProviderUID = Convert-BinaryToHex -Binary $XPProviderUID if ($DisplayProgress) { Write-Color '[Account] ', 'Name ', $AccountName, ' Service UID ', $ServiceUID, ' Hex version ', $HexServiceUID -Color Blue, White, Yellow, White, Yellow, WHite, Yellow } $RegKey = "$ProfilePath\$HexServiceUID" # Find Service UID of account that will be used or is already set as Primary Account $MyValue = (Get-ItemProperty -Path $RegKey -Name '01023d15' -ErrorAction SilentlyContinue).'01023d15' $MyValueHexServiceUID = Convert-BinaryToHex -Binary $MyValue if ($DisplayProgress) { Write-Color '[Account Update] ', 'Key: ', $RegKey, ' Primary Service UID ', $MyValue, ' Hex ', $MyValueHexServiceUID -Color Blue, White, Green, White, Green, White, Green } [PsCustomobject] @{ OutlookVersion = $OutlookVersion Profile = $OutlookProfile.ProfileName ProfileNumber = $One.PSChildName AccountName = $AccountName #ServiceUIDBefore = $ServiceUID ServiceUID = $HexServiceUID #PrimaryServiceUIDBefore = $MyValue RequiredServiceUID = $MyValueHexServiceUID #PreferencesUIDBefore = $PreferencesUID PreferencesUID = $HexPreferencesUID XPProviderUID = $HexXPProviderUID ProfilePath = $ProfilePath } } } if ($DisplayProgress) { Write-Color -LinesAfter 1 } $Array } } <# if (-not $GUI) { # Assing all profiles $OutlookProfiles = $Outlooks } else { # Show GUI $Line = '===================================' do { Clear-Host Write-Color $line -LinesBefore 1 Write-Color 'Outlook Profile Fixer' -C Green -StartTab 1 Write-Color $line foreach ($Outlook in $Outlooks) { Write-Color -Text $Outlook.Number, ' - Profile Name: ', $Outlook.ProfileName -Color Yellow, White, Green } Write-Color '0', ' - ', 'Quit' -Color Yellow, White, Green -LinesAfter 1 $Input = Read-Host 'Select' If ($Input -eq 0) { Exit } elseif ($Outlooks.Number -contains $Input) { break } else { Write-Color 'Wrong choice.', ' Press any key to restart!' -Color Red, Yellow -LinesBefore 1 [void][System.Console]::ReadKey($true) } } while ($Input -ne '0') Clear-Host $OutlookProfiles = $Outlooks[$Input - 1] # End Gui } #> if (-not $NoBackup) { # Backup $Backups = foreach ($OutlookVersion in $MainKey.Keys) { $OutlookRegistryKey = $MainKey.$OutlookVersion [string] $BackupName = "$OutlookVersion-RegistryProfile" # Make registry Backup #Write-Color "[i] ", 'Backup of Key ', $OutlookRegistryKey, ' to ', $BackupPath -Color Blue, White, Yellow, White, Yellow $Backup = Backup-RegistryPath -Key $OutlookRegistryKey -BackupPath $BackupPath -BackupName $BackupName if ($null -ne $Backup) { #try { # Write-Color "[i] ", "Backup of Outlook profiles made to ", $Backup -Color Blue, White, Yellow -LinesAfter 1 #} catch { Write-Color "[i] Backup of Outlook profiles made to $Backup" #} } else { } } } foreach ($Mail in $AllData) { if ($Mail.ProfilePath) { if ($Mail.PreferencesUID -and $Mail.XPProviderUID -and $Mail.PreferencesUID -and $Mail.ProfileNumber) { # Check if user wants to remove any account if ($RemoveAccount) { if ($Mail.AccountName -match $RemoveAccount) { $Keys = @( "$($Mail.ProfilePath)\$($Mail.PreferencesUID)" "$($Mail.ProfilePath)\$($Mail.ServiceUID)" "$($Mail.ProfilePath)\$($Mail.XPProviderUID)" "$($Mail.ProfilePath)\9375CFF0413111d3B88A00104B2A6676\$($Mail.ProfileNumber)" ) foreach ($Key in $Keys) { #try { # Write-Color '[i] ', "Removing key ", $Key -Color Blue, White, Yellow #} catch { Write-host "[i] Removing key $Key" #} if (-Not $WhatIf) { Remove-Item -Path $Key -Confirm:$false #-WhatIf } } } } if ($PrimaryAccount) { if ($Mail.AccountName -match $PrimaryAccount) { $Default = "$($Mail.ProfilePath)\0a0d020000000000c000000000000046" if ($Mail.RequiredServiceUID) { #Try { # Write-Color "[i] ", "Setting default profile ", $Default, ' with ', $Mail.RequiredServiceUID -Color Blue, White, Yellow, White, Green #} catch { Write-Host "[i] Setting default profile $Default with $($Mail.RequiredServiceUID)" #} if (-not $WhatIf) { Set-ItemProperty -Path $Default -Name '01023d15' -Value $Mail.MyValue -Type Binary #-WhatIf } } [int] $PrimaryProfile = $Mail.ProfileNumber [byte[]] $ByteArray = @($PrimaryProfile, 0, 0, 0) $SubValue = "$($Mail.ProfilePath)\9375CFF0413111d3B88A00104B2A6676" #Try { # Write-Color "[i] ", "Setting default profile ", $SubValue, ' in ', "{ED475418-B0D6-11D2-8C3B-00104B2A6676}", ' with ', $ByteArray -Color Blue, White, Yellow, White, Green, White, Yellow #} catch { Write-Color "[i] Setting default profile $SubValue in {ED475418-B0D6-11D2-8C3B-00104B2A6676} with $ByteArray" #} if (-not $WhatIf) { Set-ItemProperty -Path $SubValue -Name "{ED475418-B0D6-11D2-8C3B-00104B2A6676}" -Value $ByteArray -Type Binary #-WhatIf } } } } } } # Remove leftovers $LeftOvers = Find-OutlookKeys foreach ($Left in $LeftOvers) { # Check if user wants to remove any account if ($RemoveAccount) { if ($Left.Email -match "$RemoveAccount") { #try { # Write-Color '[i] ', 'Removing leftovers key ', $Left.RegistryKey -Color Blue, White, Yellow #} catch { Write-Host "[i] Removing leftovers key $($Left.RegistryKey)" #} if (-not $WhatIf) { Remove-Item -Path $Left.RegistryKey -Recurse -Confirm:$False } } } } if ($DebugOutput) { $AllData $LeftOvers } }
Following command is your standard function. With or without WhatIf your profiles will be backed up. Please test this first. See if your .reg file was created. If it was, please check it's content. Make sure everything is there. The good thing about this little script is that you can quickly revert its changes and try again by adding back backup to a registry.
Start-OutlookProfile
This one makes sure your account is set as primary. Keep in mind I'm using WhatIf that means it won't be executed until you remove it. I'm also using only domain due to how Office 365 can have multiple accounts belonging to the same domain (shared accounts, groups and so on). While in this case it most likely doesn't matter, in the later case it will.
Start-OutlookProfile -PrimaryAccount 'domain.pl' -WhatIf
Finally, this is your code to check what it found. Keep in mind that it goes thru all profiles.
Start-OutlookProfile -DebugOutput