{"id":2094,"date":"2014-02-02T00:01:00","date_gmt":"2014-02-02T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2014\/02\/02\/weekend-scripter-use-powershell-to-migrate-to-active-directory-on-premises\/"},"modified":"2014-02-02T00:01:00","modified_gmt":"2014-02-02T00:01:00","slug":"weekend-scripter-use-powershell-to-migrate-to-active-directory-on-premises","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/weekend-scripter-use-powershell-to-migrate-to-active-directory-on-premises\/","title":{"rendered":"Weekend Scripter:  Use PowerShell to Migrate to Active Directory On-Premises"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft PFE, Asia Gandecka, talks about using Windows PowerShell to migrate users from Windows Azure Active Directory to Active Directory on-premises.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Let&rsquo;s welcome a new guest blogger, Asia Gandecka&hellip;<\/p>\n<p style=\"margin-left:30px\"><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/Asia.jpg\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/Asia.jpg\" alt=\"Photo of Asia Gandecka\" title=\"Photo of Asia Gandecka\" \/><\/a><\/p>\n<p style=\"margin-left:30px\">I have been with Microsoft since 2011 working as a a premier field engineer. I&nbsp;support the SharePoint infrastructure, Office 365, and SharePoint Online. SharePoint and Windows PowerShell work closely together, but it wasn&rsquo;t until Office 365 when I decided to take a stab at Windows PowerShell. I have found it very handy at allowing me to manage SharePoint and Office 365 in faster, simpler, and more robust ways. It&rsquo;s my first time here, and I am excited to share with you some of my work. Have fun scripting!<\/p>\n<p>When working with a customer, we got to a point where we wanted to move users from Office 365 in Windows Azure AD to Active Directory on-premises. We wanted to start using Windows Intune, which requires using Active Directory on-premises.<\/p>\n<p>The big questions we had was, &ldquo;How can we avoid duplicate UPNs?&rdquo; in addition to making sure that the users&#039; data in the cloud stayed as-is. In this scenario, users only utilized SharePoint Online, and they did not have Exchange Online set up. That did not allow the SMTP email addresses to match the user&rsquo;s names.<\/p>\n<p>So, is it possible to match the users? The quick answer is, &ldquo;Yes!&rdquo;<\/p>\n<p>Those who have worked with Active Directory and the directory synchronization tool, DirSync, know already that this tool it is one way to sync from Active Directory on-premises to Windows Azure AD. In this scenario, I need the exact opposite. Yes, I still claim it is possible. Let me explain&hellip;<\/p>\n<p>Every user has a unique identifier in Active Directory on-premises called <b>ObjectGUID<\/b>, which in Windows Azure AD is <b>ImmutableId<\/b>. It pretty much is the same thing, but it is coded differently. I look at it as the same word, but a different language.<\/p>\n<p>When DirSync runs, it takes the user&rsquo;s information&mdash;its <b>ObjectGUID<\/b> and their UPNs&mdash;and tries to move it to Windows Azure AD. If a UPN is already taken by an object in Windows Azure AD, you will receive the error message shown in the following image:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4861.wes-2-2-14-1.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4861.wes-2-2-14-1.png\" alt=\"Image of error message\" title=\"Image of error message\" \/><\/a><\/p>\n<p>The <b>Distinguished Name<\/b> is our <b>ImmutableId<\/b> here.<\/p>\n<p>This is the time to make the translation and prove to DirSync that <b>ObjectGUID<\/b> is in fact <b>ImmutableId <\/b>for the UPN that we are trying to synchronize.&nbsp;&nbsp;<\/p>\n<p>In this example, we have user <b>AsiaK@onlineworld.co<\/b><a href=\"mailto:kasia@jogandec.msftonilnerepro.com\"><\/a>, and we will translate the <b>ObjectGUID<\/b> so that it is understood by DirSync.<\/p>\n<p><b>&nbsp; &nbsp; &nbsp;Note<\/b>&nbsp; If you are not running it on an Active Directory server you will need to import the Active Directory module on that <br \/>&nbsp; &nbsp; &nbsp;computer. For instructions, read the following Hey, Scripting Guy! Blog posts:<\/p>\n<ul>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/use-active-directory-cmdlets-with-powershell-to-find-users\/\" target=\"_blank\">Use Active Directory Cmdlets with PowerShell to Find Users<\/a><\/li>\n<li><a href=\"https:\/\/devblogs.microsoft.com\/scripting\/install-active-directory-management-service-for-easy-powershell-access\/\" target=\"_blank\">Install Active Directory Management Service for Easy PowerShell Access<\/a><\/li>\n<\/ul>\n<p>You will also need to set up your computer for access to Windows Azure AD and download the Windows PowerShell module for it. For instructions, read <a href=\"https:\/\/aka.ms\/aadposh\" target=\"_blank\">Manage Windows Azure AD using Windows PowerShell<\/a>.<\/p>\n<p>We can start working with the script in Window PowerShell modules that are installed for Active Directory and Microsoft Online Services (MSOnline):<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; Import-Module ActiveDirectory<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; Import-Module MSOnline<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7384.wes-2-2-14-2.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/7384.wes-2-2-14-2.png\" alt=\"Image of command\" title=\"Image of command\" \/><\/a><\/p>\n<p>Then connect to Office 365:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; Connect-MsolService<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2538.wes-2-2-14-3.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/2538.wes-2-2-14-3.png\" alt=\"Image of menu\" width=\"450\" height=\"248\" title=\"Image of menu\" \/><\/a><\/p>\n<p>Next, I am assigning the user that I would like to fix. (Later I will show you how to automate this for more than one user.)<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; $FixUser = &ldquo;AsiaK@onlineworld.co<a href=\"mailto:kasia@jogandec.msftonilnerepro.com\"><\/a>&rdquo;<\/p>\n<p>Then I am getting the organizational unit (OU) that the user is in, in Active Directory on-premises.<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; $ou = &quot;DC=contoso,DC=com&quot;<\/p>\n<p>Next, we need the Active Directory on-premises user information. We are getting the user based on their UPN and OU.<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; $ADUser = Get-ADUser -SearchBase $ou -Filter {userprincipalname -like $FixUser}<\/p>\n<p>It is good to double-check that we got what we wanted. To verify, run:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; $ADUser<\/p>\n<p>We can see in the following image that our <b>ObjectGUID<\/b> looks different than the&nbsp;<b>ImmutableId <\/b>(<b>Distinguished Name<\/b>) that we found previously:<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4370.wes-2-2-14-4.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/4370.wes-2-2-14-4.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>Let&rsquo;s verify whether the user in the cloud has the <b>ImmutableId<\/b> set (this step is optional). <b>Get-MsolUser<\/b> will return all users from Windows Azure AD. To specifically check on AsiaK, we add <b>&ndash;UserPrincianleName<\/b> <b>$FixUser<\/b>. And I want to present the data in a table (<b>FT<\/b>) with only <b>UserPrincipalName<\/b> and the <b>ImmutableId. <\/b><\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;&nbsp; Get-MsolUser -UserPrincipalName $FixUser | FT UserPrincipalName, ImmutableID&nbsp;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-2-2-14-5.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-2-2-14-5.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>As shown here, we do not have the <b>ImmutableId<\/b> set. Let&rsquo;s fix that.<\/p>\n<p>We take all we have in <b>$ADUser<\/b>, and by using pipe character ( <b>|<\/b> ), we can convert the <b>ObjectGUID<\/b> to <b>ImmutableId<\/b> based on what is stored in <b>$ADUser<\/b>. The <b>[Convert]::ToBase64String($_.ObjectGUID.ToByteArray())<\/b> will do the conversion trick.<\/p>\n<p>After that, we take all of that information and set the Windows Azure AD users <b>ImmutableId<\/b> accordingly. The script to do this is:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;&nbsp; $ADUser | ForEach-Object {<\/p>\n<p style=\"margin-left:30px\">$immutableId = [Convert]::ToBase64String($_.ObjectGUID.ToByteArray());<\/p>\n<p style=\"margin-left:30px\">Set-MsolUser -UserPrincipalName $_.UserPrincipalName -ImmutableId $immutableId;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p>To verify that we correctly got the user set, we can run the <b>Get-MSolUser<\/b> command again:<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt;&nbsp; Get-MsolUser -UserPrincipalName $FixUser | FT UserPrincipalName, ImmutableID&nbsp;<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-2-2-14-6.png\"><img decoding=\"async\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/wes-2-2-14-6.png\" alt=\"Image of command output\" title=\"Image of command output\" \/><\/a><\/p>\n<p>We can now see that the <b>ImmutableId<\/b> matches the <b>Distinguished Name<\/b> from the error message. Now we can re-run DirSync, and the user will sync correctly.<\/p>\n<p>If we would like to automate the process for all users we can make few small changes to the script, as shown here:&nbsp;<\/p>\n<p style=\"margin-left:30px\">#Connect to Office 365<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; Connect-MsolService<\/p>\n<p style=\"margin-left:30px\">\n<p style=\"margin-left:30px\">#specify UPN suffix from AD onprem. Change contoso.com to match your domain this way everyone under that domain will be synchronized.<\/p>\n<p style=\"margin-left:30px\">&nbsp;PS C:\\&gt; $upns = &quot;*contoso.com&quot;<\/p>\n<p style=\"margin-left:30px\">\n<p style=\"margin-left:30px\">#Set OU, change Contoso to match your local AD setup.<\/p>\n<p style=\"margin-left:30px\">&nbsp;PS C:\\&gt; $ou = &quot;DC=contoso,DC=com&quot;<\/p>\n<p style=\"margin-left:30px\">\n<p style=\"margin-left:30px\"># This will get all users under $OU where their UPN contains $upns (anything that matches *contoso.com).<\/p>\n<p style=\"margin-left:30px\">&nbsp;PS C:\\&gt; $Users = Get-ADUser -SearchBase $ou -Filter {userprincipalname -like $upns}<\/p>\n<p style=\"margin-left:30px\">\n<p style=\"margin-left:30px\">#Match all the users&nbsp;<\/p>\n<p style=\"margin-left:30px\">PS C:\\&gt; $Users | ForEach-Object {<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; $immutableId = [Convert]::ToBase64String($_.ObjectGUID.ToByteArray());<\/p>\n<p style=\"margin-left:30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; Set-MsolUser -UserPrincipalName $_.UserPrincipalName -ImmutableId $immutableId;<\/p>\n<p style=\"margin-left:30px\">}<\/p>\n<p style=\"margin-left:30px\">\n<p style=\"margin-left:30px\">#Verify all users have been assigned the <b>ImmutableId<\/b>.<\/p>\n<p style=\"margin-left:30px\">&nbsp;PS C:\\&gt; Get-MsolUser | Format-Table UserPrincipalName, ImmutableID&nbsp;<\/p>\n<p>~Asia&nbsp;<\/p>\n<p>Thank you, Asia, for writing this blog and sharing your knowledge and time.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft PFE, Asia Gandecka, talks about using Windows PowerShell to migrate users from Windows Azure Active Directory to Active Directory on-premises. Microsoft Scripting Guy, Ed Wilson, is here. Let&rsquo;s welcome a new guest blogger, Asia Gandecka&hellip; I have been with Microsoft since 2011 working as a a premier field engineer. I&nbsp;support the SharePoint infrastructure, [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[7,482,476,56,3,61,45],"class_list":["post-2094","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-active-directory","tag-asia-gandecka","tag-azure","tag-guest-blogger","tag-scripting-guy","tag-weekend-scripter","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft PFE, Asia Gandecka, talks about using Windows PowerShell to migrate users from Windows Azure Active Directory to Active Directory on-premises. Microsoft Scripting Guy, Ed Wilson, is here. Let&rsquo;s welcome a new guest blogger, Asia Gandecka&hellip; I have been with Microsoft since 2011 working as a a premier field engineer. I&nbsp;support the SharePoint infrastructure, [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2094","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=2094"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/2094\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=2094"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=2094"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=2094"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}