Jump to content


  • 0
anyweb

Migrate to the cloud - Part 1. Setup

Question

Introduction

This blog series is comprised of 3 parts. In this part  I'll cover how you can migrate your existing configuration manager managed, domain joined devices to Azure AD joined, and Intune managed devices. During that process the app also converts those devices to Windows Autopilot devices, all with minimal downtime for the end user and via an easy to use self-service app.

migrate to the cloud.png

If you'd like to see a video showing the entire migration process then here it is.

Note: In the video,  I refer to a Windows Hello for Business problem pin entry, but that was simply because I was restoring a check-pointed virtual machine and testing it over and over. You shouldn't see that problem on regular computers.

The app itself is comprised of 3 main parts which does the following:

Part #1
1. Create local migration admin account APSweepback, enable Autologin
2. Remove MBAM client
3. Remove SCCM client
4. Change the Windows shell
5. Drop out of the domain
6. Restart computer...

Part #2
1. AutoLogin as APSweepback account
2. Start second script (shell)
3. rename old 'on prem' account to xxxxx.OLD
4. popup AADJ wizard asking for credentials
5. convert the device to Windows Autopilot device
6. create scheduled task for part 3
7. restart computer (to reapply UAC settings and for WHFB)

Part #3
1. Install Company Portal
2. Launch OneDrive for Business
3. Cleanup registry keys and changes
4. add to Autopilot Sweepback completed AAD group (for reporting and remediation scripts)
5. popup notification that all is done and logoff

The app development is mostly done, but it's still evolving based on feedback, if you know of better ways of doing things within the app then do please let me know.

Here's a short overview of the apps main features

  • Created with Powershell
  • Uses Azure Functions (HttpTriggers)
  • Disconnects a device from the domain/ConfigMgr
  • Connects to Azure AD/Intune (uses Auto MDM enrollment)
  • Convert device to Windows Autopilot
  • Users data stored in OneDrive
  • Users data remains on the device after migration
  • Installed apps remain installed on the device
  • UI front end for the end user
  • Status screen indicating progress
  • Detailed Logs
  • Email ability (via Azure/Sendgrid)

Step 1. Get the scripts

Note: You can only download these files when logged on as a member of https://www.windows-noob.com

autopilot_sweepback.zip

 

Note: Last updated 2022/05/31 (v1.4 logsfolder bug)

Extract the zip to C:\DEV

The extracted ZIP files should look something like this

extract to c dev.png

 

Step 2. Get ServiceUI.exe from MDT

You'll need the ServiceUI.exe executable file to display user interfaces (UI) to end users in SYSTEM context. As our app will be deployed from ConfigMgr in SYSTEM context, we'll utilize ServiceUI.exe. To get the file, download and install MDT somewhere and navigate to C:\Program Files\Microsoft Deployment Toolkit\Templates\Distribution\Tools\x64. To download MDT click here.

Copy the ServiceUI.exe file to your extracted C:\DEV\autopilot_sweepback\Encode files folder so it looks like this.

ServiceUI extracted.png

 

Step 3. create some azure ad groups

In Microsoft Endpoint Manager (MEM), create two Static Azure AD groups with the following names:

  • Autopilot Sweepback Completed
  • Convert devices to Windows Autopilot

After creating the groups, take note of the ObjectId of each aad group.

 

aad group objectid.png

 

Step 4. create a Windows Autopilot deployment profile

In MEM, navigate to Devices, Windows, Windows Enrollment, and select Windows Autopilot Deployment Profiles, select Create to create a new profile and make sure that Convert all targeted devices to Autopilot is set to YES and that the profile is assigned to the Convert devices to Windows Autopilot Azure AD group created in step 3 above.
Convert all targeted devices to Autopilot.png
 

Step 5. create an Azure function

In Azure, I will assume you've already created a functionapp as per Step 4 of this blog post. If not, go ahead and create one and then return to this step. Next create a new httptrigger called add_device_to_aad_group and insert the following code into it.

 

# Niall Brady 2022/05/21 (used by the Check Compliance, Software Updates to devices solutions amongst others...)
# Dynamically ADDS a device to an azure ad group 
#

using namespace System.Net
# Input bindings are passed in via param block.
param($Request, $TriggerMetadata)

# Write to the Azure Functions log stream.
Write-Host "PowerShell HTTP trigger function processed a request."
# Interact with query parameters or the body of the request.
$deviceId = $Request.Query.deviceId
$GroupID = $Request.Query.GroupId

if (-not $deviceId) { 
$deviceId = $Request.Body.deviceId
}
if (-not $GroupId) { 
$GroupId = $Request.Body.GroupId
} 

# define the following variables
$ApplicationID =    "" # this is the id of the app you created in app registrations
$TenantDomainName = "" # your tenant name, eg: windowsnoob.com
$AccessSecret =     "" # this is the secret of the app you create in app registrations


# create the body
$Body = @{
Grant_Type = "client_credentials"
Scope = "https://graph.microsoft.com/.default"
client_Id = $ApplicationID
Client_Secret = $AccessSecret
}

# make initial connection to Graph
$ConnectGraph = Invoke-RestMethod -Uri "https://login.microsoftonline.com/$TenantDomainName/oauth2/v2.0/token" -Method POST -Body $Body
# get the token
$token = $ConnectGraph.access_token
$token

# to improve logging...
$triggerName = "add_device_to_aad_group"
$a = Get-Date
$body = " `n"
$body = $body + "$a Starting the '$triggerName' function...`n"
$body = $body + "$a Connected to tenant: $TenantDomainName.`n"

#START $FindDevice
if ($deviceId -and $GroupId) {
	$Group = Invoke-RestMethod -Method Get -uri "https://graph.microsoft.com/v1.0/groups?`$filter=Id eq '$GroupId'" -Headers @{Authorization = "Bearer $token"} | Select-Object -ExpandProperty Value
	$GroupName = $Group.displayName
	$body = $body + "$a You supplied deviceId: '$deviceId'" + ".`n" 
	$body = $body + "$a You supplied groupId: '$GroupId'" + ".`n"    
	$body = $body + "$a Group.displayName: '$GroupName'" + ".`n"
    
	#$GroupMembers =  Invoke-RestMethod -Method Get -uri "https://graph.microsoft.com/v1.0/groups/$GroupID/members?$filter " -Headers @{Authorization = "Bearer $token"} | Select-Object -ExpandProperty Value
	# | Select-Object -ExpandProperty Value
    
    # below fixes the 100 members per returned result in AAD problem
    $GroupMembers2 = Invoke-RestMethod -Method GET -uri "https://graph.microsoft.com/v1.0/groups/$GroupID/members?`$count=true&`$filter=startswith(deviceid,'$deviceId')" -Headers @{Authorization = "Bearer $token";"ConsistencyLevel" = "eventual"}
	
	# if found do this
	if ($GroupMembers2.value.deviceId){
		#$body = $body + "--------------------------------------------------------------------`n"
        #$body = $body + "This device was found in the AAD group so no need to add it again...`n"
		#$body = $body + "deviceId: " + $GroupMembers2.value.deviceId + "`n"
        #$body = $body + "displayName: " + $GroupMembers2.value.displayName + "`n"
		#$body = $body + "--------------------------------------------------------------------`n"
		Write-Host -ForegroundColor Yellow "$GroupMembers2.value.displayName is in the group" 
		$body = $body + "$a Device: " + $GroupMembers2.value.displayName + " is already in the " + $GroupName + " group, nothing to do.`n"
		$body = $body + "$a The computer is already in the group, nothing to do.`n"
		$Status = "Already present in group"
	}
	else	{
        $AddDevice = Invoke-RestMethod -Method Get -uri "https://graph.microsoft.com/v1.0/devices?`$filter=deviceId eq '$deviceId'" -Headers @{Authorization = "Bearer $token"} | Select-Object -ExpandProperty Value | %{ 
        Write-Host -ForegroundColor Green "Adding $($_.DisplayName) ($($_.ID)) to the group"
        $body = $body +  "$a Adding $($_.DisplayName) ($($_.ID)) to the group with ObjectID $GroupID.`n"
        $ComputerName = $($_.DisplayName) 
        $Status = "ADDED"
        $BodyContent = @{
            "@odata.id"="https://graph.microsoft.com/v1.0/devices/$($_.id)"
        } | ConvertTo-Json
            # code to add it here...
            # the $ref variable is explained here... kinda # https://docs.microsoft.com/en-us/graph/api/group-post-members?view=graph-rest-1.0&tabs=http
            try {Invoke-RestMethod -Method POST -uri "https://graph.microsoft.com/v1.0/groups/$GroupID/members/`$ref" -Headers @{Authorization = "Bearer $token"; 'Content-Type' = 'application/json'} -Body $BodyContent
            # pause some seconds to allow time for the object to be populated if recently added...
            sleep 30
            }
            catch { $body = $body + "$a ERROR ADDING THE DEVICE`n"
                    $body = $body + "Here is the error message: '$_.ErrorMessage'"
                    $Status = "ERROR ADDING THE DEVICE"
                    }
	}
    }

}
#END $FindDevice

$a = Get-Date
$body = $body + "$a Exiting Azure function."
# Associate values to output bindings by calling 'Push-OutputBinding'.
Push-OutputBinding -Name Response -Value ([HttpResponseContext]@{
StatusCode = [HttpStatusCode]::OK
Body = $body
})

 

In the code above, fill in the following values that correspond to your environment:

  • ApplicationID
  • TenantDomainName
  • AccessSecret

application id tenant and access secret.png

Don't forget to Save your changes in the Http trigger. Take note of the function URL by clicking on Get Function URL, it'll look something like this

image.png

Step 6. edit the variables

Next, open Powershell ISE and locate the win.ap.sweepback_part1.ps1 powershell script. Fill in or change the missing values for the variables listed below:

Note: DjoinPwd and DjoinAcct must use valid credentials for a user in your domain. The values below are examples from my lab.

image.png

So it looks more like this (the values from my tenant are blurred):

image.png

Note: The APIKey value is for sending emails using sendgrid, if you'd like info about setting that up see this guide (point 4)

Next, open the encode.ps1 script and run it, once completed, browse to the Encoded files folder and locate the

After running the script, locate the encoded_ServiceUI.txt file and open it in notepad.

image.png

Copy the contents of that file using CTRL+A followed by CTRL+C

ecoded_serviceui.png

Paste that code into the following line in between the quotation marks

serviceui code added.png

Save the changes to the win.ap.sweepback_part1.ps1 code.

Step 7. create and deploy the app in ConfigMgr

In my example, I simply created a package/program in ConfigMgr to deploy this app, use whatever application model you wish. To do this simply copy two files to a folder called Autopilot_Sweepback and use that as your package source.

  • ServiceUI.exe
  • win.ap.sweepback_part1.ps1

package source for configmgr.png

the program for the package uses the following line

ServiceUI.exe -process:explorer.exe %SYSTEMROOT%\System32\WindowsPowerShell\v1.0\powershell.exe -NoProfile -WindowStyle Hidden -ExecutionPolicy Bypass -File Win.AP.Sweepback_part1.ps1

as shown here

image.png

Next, deploy the package to a collection containing some devices you want to migrate.

deployed to all windows 10.png

Step 8. Test it

Now the hard work is mostly done and you can start testing it, launch it from Software Center and start migrating to the cloud !

migrate to the cloud in software center.png

That's it, join me in the next parts where we'll go a little further!

cheers

niall

Related reading

Share this post


Link to post
Share on other sites

Recommended Posts

  • 0

i guess you modified the script ? did you look at part 3 the troubleshooting part it gives you some ideas to help with troubleshooting

 

Share this post


Link to post
Share on other sites

  • 0
3 hours ago, anyweb said:

i guess you modified the script ? did you look at part 3 the troubleshooting part it gives you some ideas to help with troubleshooting

 

No, I didn't modify anything.  I did not setup the smtp/email stuff, but otherwise followed step by step.  I'm probably not smart enough to make sense of those troubleshooting steps 😞 Thanks though!

 

EDIT - I did check the logs.  1st is the "part1" and the second is the  "status_part1" last few line of each. 

08/18/2022 10:16:00 Stopping SMS service
08/18/2022 10:16:00 Fixing ODBF
08/18/2022 10:16:15 Exiting the 'migrate my pc' script.
08/18/2022 10:16:18 about to read regpath: 'HKLM:\SOFTWARE\365 Technologies\' regkey: 'atStep'
08/18/2022 10:16:18 Ending the status UI script for AP Migration part 1...
08/18/2022 10:16:18 aborting out of this...

 

Edited by This_guy

Share this post


Link to post
Share on other sites

  • 0

yours is bombing out very early, in the prerequisites check,

you can try remming out the call to  'fixing odbf' function, it's at line 587, it's not needed (for my work environment only)

# fix odbf computer name before continuing
LogWrite "Fixing ODBF"
FixODBF

fix it like so (place # in front of those 2 lines)

# fix odbf computer name before continuing
#LogWrite "Fixing ODBF"
#FixODBF

once done, save the changes and test again please

Share this post


Link to post
Share on other sites

  • 0
On 8/22/2022 at 2:37 AM, anyweb said:

yours is bombing out very early, in the prerequisites check,

you can try remming out the call to  'fixing odbf' function, it's at line 587, it's not needed (for my work environment only)

# fix odbf computer name before continuing
LogWrite "Fixing ODBF"
FixODBF

fix it like so (place # in front of those 2 lines)

# fix odbf computer name before continuing
#LogWrite "Fixing ODBF"
#FixODBF

once done, save the changes and test again please

We get further, but I am realizing that my hope of using your script(s) without SCCM installed probably just won't work.  I now get:

08/26/2022 05:53:44 uninstalling ConfigMgr agent...
08/26/2022 05:53:44 Starting RemoveSCCMClient function
08/26/2022 05:53:44 An error occurred when trying to email the logs, here is the error: This command cannot be run due to the error: The system cannot find the file specified.
08/26/2022 05:53:44 Something failed, aborting Migrate process
08/26/2022 05:53:44 setting HKLM:\HKEY_LOCAL_MACHINE\SOFTWARE\My Company atStep 10 String
08/26/2022 05:53:44 registry value set successfully

 

Share this post


Link to post
Share on other sites

  • 0

if you are not using SCCM, then you need to rem out the RemoveSCCMClient call, I think it's in the takeaction function, just place a # in front of it and that'll help, otherwise it will fail,

start with that, then try again

Share this post


Link to post
Share on other sites

  • 0
1 hour ago, anyweb said:

if you are not using SCCM, then you need to rem out the RemoveSCCMClient call, I think it's in the takeaction function, just place a # in front of it and that'll help, otherwise it will fail,

start with that, then try again

Zipping it all up...to create the following ZIP file: 'C:\MigrateLogs.zip'
08/26/2022 07:15:53 An error occurred when trying to email the logs, here is the error: The remote server returned an error: (401) Unauthorized.
08/26/2022 07:15:53 Something failed, aborting Migrate process

I didn't set up the mail function - is that what would be causing the script to fail here now?

Share this post


Link to post
Share on other sites

  • 0

the mail function is used when a failure occurs to send logs to a shared email inbox, you can search the script and rem it out however you will need it sooner or later, that's why it's there

i think it's in the somethingfailed function (not looking at the scripts right now)

Share this post


Link to post
Share on other sites

  • 0

hi @dipalma

thank you for trying out my solution, this code is 'as is' and it's up to you to make it work in your environment, you can rem out all the scrolling by editing the associated log file, but what you really should have seen is the full screen status screen and not the powershell logging

what that means is something probably failed which is why you are seeing the powershell cmd instead of the status screen,

feel free to post your logs here and i can take a look.

that said, i'm still working on it and will hopefully have a newer version of it to release in the coming month or two with a LOT of bug fixes and improvements

cheers

niall

Share this post


Link to post
Share on other sites

Join the conversation

You can post now and register later. If you have an account, sign in now to post with your account.

Guest
Answer this question...

×   Pasted as rich text.   Paste as plain text instead

  Only 75 emoji are allowed.

×   Your link has been automatically embedded.   Display as a link instead

×   Your previous content has been restored.   Clear editor

×   You cannot paste images directly. Upload or insert images from URL.

Loading...


×
×
  • Create New...