Johdanto

Käyn tässä kirjoituksessa läpi Windows 10 -käyttäjäprofiilin migraation uudelle käyttäjätilille samalla tietokoneella Azure AD -tenanttimuutoksen yhteydessä. Käytän toimenpiteeseen Microsoftin omaa User State Migration Tool -työkalua (USMT). Käyttäjäprofiilin migraatiolla tarkoitan seuraavien tietojen talteenottoa ja siirtoa:

  • Käyttäjän kotihakemiston C:\Users\%username%\ alikansiot ja tiedostot
  • Rekisterin käyttäjäkohtaiset asetukset käyttöjärjestelmästä ja sovelluksista (NTuser.dat-tiedosto, joka ladataan kirjautumisen yhteydessä rekisterin avaimeen HKEY_CURRENT_USER)

Toteutan migraation niin sanottuna hard-link -migraationa. Tämä tarkoittaa sitä, että toimenpiteet tapahtuvat saman laitteen sisällä, eikä migratoitavaa dataa missään vaiheessa poistu laitteen ulkopuolelle. Näin vältetään ylimääräisen tallennustilan tarve ja tiedostojen tarpeeton kopioiminen, kun tiedostoja ei heti siirretä vanhasta tallennussijainnista uuteen. Sen sijaan vanhassa käyttäjäprofiilissa oleville tiedostoille luodaan niin sanottuun hard-link -migraatiovarastoon ylimääräiset tiedostopolut, joihin referoidaan migraation aikana. Migratoitavilla tiedostoilla tulee siis olemaan kaksi tiedostopolkua, jotka molemmat viittaavat samaan kohdetiedostoon. Lopulta hard-link -migraatiovarasto voidaan poistaa vaikuttamatta vanhan tai uuden käyttäjäprofiilin tiedostoihin.

Profiilien migraatioon löytyy myös kolmannen osapuolen työkaluja, joissa tulee mukana graafinen käyttöliittymä (mm. ProWiz ja USMTGUI). USMT on kuitenkin Microsoftin suosittelema ja ylläpitämä ratkaisu, johon pääosin muut kolmannen osapuolen työkalut perustuvat. Aiemmin oli lisäksi Microsoftin oma Windows Easy Transfer, mutta sen tuki on lopetettu ja työkalu kehitettiinkin jo Windows Vistan aikana. USMT on itsessään äärimmäisen kustamoitava, skriptattava ja skaalautuu hyvin laajoihin ympäristöihin ja provisiointiskenaarioihin esimerkiksi SCCM:n kanssa.

Milloin käyttäjäprofiileja sitten jouduttaisiin migratoimaan saman tietokoneen sisällä? Yksi esimerkkitilanne on muutos Microsoft 365 -tenantissa ja Azure AD -liitoksessa. Tällöin Windows 10 luo uuden käyttäjäprofiilin, kun käyttäjä kirjautuu uudella käyttäjätunnuksellaan ensimmäistä kertaa tietokoneelle uuden tenantin Azure AD -liitoksen jälkeen. Vanha profiili säilyy kuitenkin samalla koneella ja on siten migratoitavissa. Vastaavasti, jos koneella on aiemmin ollut pelkkä paikallinen käyttäjä, käyttäjälle luodaan uusi käyttäjäprofiili Azure AD -liitoksen jälkeen ensimmäistä kertaa kirjauduttaessa Azure AD -tunnuksin. Tällöin paikallisen profiilin data halutaan todennäköisesti migratoida suoraan uudelle käyttäjälle.


Huomioitavaa

Artikkelissa esitetyt toimenpiteet ja komennot on testattu kuvailemassani ympäristössä. Lukija on itse vastuussa esimerkin soveltamisesta omaan käyttötarkoitukseensa sopivaksi.


Työkalun asennus ja perustoiminta

USMT on komentorivipohjainen työkalu, joka sisältyy Windows Assessment and Deployment Kit (Windows ADK) -ohjelmapakettiin. Lataus osoitteesta: https://docs.microsoft.com/fi-fi/windows-hardware/get-started/adk-install#winADK. Windows 10:n 1909 versiolle ei tämän kirjoituksen kirjoitushetkellä ole omaa versiota ADK:sta, joten asennetaan 1903-versio.

Suoritetaan ladattu adksetup.exe -tiedosto ja valitaan asennusohjelmassa valinta “Install the Windows Assessment and Deployment Kit – Windows 10 to this computer“.

Seuraavassa vaiheessa Microsoft pyytää kerätä dataa työkalun käytöstä. Itse kiellän tiedonkeruun ja jatkan eteenpäin. Hyväksyin ohjelmiston käyttöehdot, minkä jälkeen pääsin valitsemaan, mitä kaikkea haluan ADK-paketista asennettavan. Itse en tarvitse USMT:n ohella nyt muuta, joten valitsin ainoastaan User State Migration Tool (USMT) -vaihtoehdon.

Viimeistelin asennuksen.

Ennen työkalun käyttöä kannattaa ymmärtää sen perustoiminnot. USMT koostuu kolmesta suoritettavasta ohjelmasta:

  • ScanState = Vastaa tietokoneen käyttäjäprofiilien ja käyttöjärjestelmäympäristön skannauksesta, tiedostojen ja asetusten keruusta sekä migraatiovaraston luomisesta
  • LoadState = Vastaa migratioon sisällytettyjen käyttäjäprofiilien ja muiden tiedostojen siirtämisestä migraatiovarastosta lopulliseen kohteeseen
  • USMTUtils = Vastaa migraation jälkeisistä siivoustoimista, vianselvityksestä ja virheentarkistuksesta

Noista ohjelmista keskityn tässä artikkelissa kahteen ensimmäiseen. Lisäksi USMT käyttää tyypillisesti seuraavia neljää .xml-päätteistä konfiguraatiotiedostoa:

  • MigApp.xml = Määrittää, mitä sovellusasetuksia migratoidaan ja miten
  • MigUser.xml = Määrittää, mitä tiedostoja ja profiiliasetuksia käyttäjäprofiilista migratoidaan ja miten (pääasiassa käyttäjän kotihakemiston sisältä tai tiedostopäätteen perusteella)
  • MigDocs.xml = Määrittää, mitä tiedostoja ja profiiliasetuksia käyttäjäprofiilista migratoidaan ja miten (käyttäjän kotihakemiston sisä- tai ulkopuolelta tiedostosijainnin perusteella)
  • Config.xml = Kustomoitava tiedosto, jossa määritetään, mitä tulisi jättää migraation ulkopuolelle

Config.xml on noista ainoa, jota on tarkoitus muokata. Se voidaan generoida valinnaisesti ScanState-ohjelmalla. Tiedostossa voidaan määrittää, mitä komponentteja tai järjestelmäasetuksia tulisi jättää pois migraatiosta. Esimerkki config.xml -tiedoston generoimisesta:

scanstate.exe /genconfig:config.xml /i:migapp.xml /i:migdocs.xml /i:ExcludeSystemFolders.xml /i:MigrateBrowserAppData.xml /o /v:5

Itse en tässä esimerkissä käytä config.xml -tiedostoa migratoinnin kustomoimiseen. Käytän sen sijaan kustomoimaani ExcludeSystemFolders.xml -tiedostoa EhlerTechiltä sekä luomaani MigrateBrowserAppdata.xml -tiedostoa. Tarkennan tiedostojen käyttötarkoituksen myöhemmin kirjoitukseni aikana.

Muita kannattaa ajatella valmiina template-tiedostoina, joihin ei kosketa. MigUser.xml ja MigDocs.xml -tiedostoja ei tulisi käyttää samanaikaisesti, vaan ainoastaan toista niistä. Microsoft suosittelee itse mieluummin MigDocs.xml:n käyttöä, sillä se kerää dataa järjestelmästä monipuolisemmin, eikä ole rajoittunut vain tiettyihin tiedostopäätteisiin toisin kuin MigUser.xml. Myös muita konfiguraatiotiedostoja voidaan luoda ja sisällyttää migraatioon halutessa.

Kannattaa kuitenkin pitää mielessä, että käytettävät xml-tiedostot tulee määrittää sekä ScanState että LoadState-vaiheissa. Tämä siksi, että käytettyjä xml-tiedostoja ei sisällytetä migraatiovarastoon (väliaikainen tallennussijainti migratoitaville tiedoille ennen loppusijoituspaikkaa). Molemmat ohjelmat tarvitsevat xml-tiedostot ohjaamaan migraatiotoimia (mitä migratoidaan ja miten) ja siksi ne tulee sisällyttää molempien ohjelmien komentoihin.


Esimerkin migratointitilanne

Otetaan esimerkkitilanne, jossa olen migratoimassa käyttäjäprofiilia Azure AD -käyttäjältä nimeltä azuread\markuspyhäranta. Käyttäjän organisaatio on tekemässä Azure AD-/Microsoft 365 -tenantin migraatiota uuteen tenanttiin. Käyttäjän Windows 10 -tietokone on liitetty vanhaan tenanttiin, jonka Azure AD -liitos tulee katkaista ennen tietokoneen liittämistä uuden tenantin pilvitoimialueeseen.

Mitä sitten tapahtuu käyttäjän vanhalle käyttäjäprofiilille, kun Azure AD -liitos katkaistaan? Sille ei voida enää kirjautua. Azure AD -tiliä ei voida muuntaa paikalliseksi käyttäjätiliksi, ja sen käyttäjäprofiili tulee löytymään Windowsissa tuntemattomana. Profiili ei kuitenkaan poistu, ja sillä on yksilöllinen SID-tunnus, josta se tunnistetaan myös liitoksen katkaisun jälkeen.

Kun Azure AD -liitos on tehty uuteen tenanttiin, käyttäjälle luodaan uusi käyttäjäprofiili ensimmäistä kertaa kirjauduttaessa käyttäjän uuden tenantin Azure AD -tunnuksilla. Windows 10:ssä ei voi olla kahta samannimistä käyttäjätunnusta. Käyttäjän Azure AD -identiteetin etu- ja sukunimi ovat samat myös uudessa tenantissa. Tällöin Windows tyypillisesti ottaa käyttäjän etu- ja sukunimestä 12 ensimmäistä merkkiä, joiden jälkeen tulee alaviiva ja seitsemän satunnaisen merkin muodostama merkkijono (pieniä kirjaimia ja numeroita). Uuden Windows-käyttäjätunnuksen muoto tulee siis todennäköisesti olemaan: azuread\markuspyhära_<merkkijono>.


Migraation toimenpiteet lyhyesti tiivistettynä

Kuvaan tässä tarvittavat toimenpiteet ikään kuin lyhyenä muistilistana. Kuvaan myöhemmin samat toimet yksityiskohtaisemmin.

1) Luodaan paikallinen järjestelmänvalvojatili, jos ei sellaista ei jo ole olemassa.

  • Tietokoneen hallinta > Paikalliset käyttäjät ja ryhmät > Käyttäjät > Uusi käyttäjä… > …
  • Tietokoneen hallinta > Paikalliset käyttäjät ja ryhmät > Ryhmät > Järjestelmänvalvojat > Ominaisuudet > Lisää > …

2) Otetaan migratoitavan tilin käyttäjänimi talteen esimerkiksi komentorivin whoami -komennolla käyttäjälle kirjautuneena. Tätä tarvitaan myöhemmin ainakin LoadStatea ajaessa.

C:\Users\markuspyhäranta>whoami
azuread\markuspyhäranta

3) Katkaistaan Azure AD -liitos: Asetukset > Tilit > Käytä työpaikan tai koulun resursseja > Katkaise yhteys. Syötetään pyydettäessä juuri luodun paikallisen järjestelmänvalvojan tunnukset ja käynnistetään tietokone uudelleen.

4) Kirjaudutaan paikallisella järjestelmänvalvojatilillä, joka luotiin kohdassa 1) ja ajetaan ScanState korotetuin oikeuksin:

.\scanstate.exe "C:\Users\USMTStore" /o /hardlink /nocompress /i:migapp.xml /i:migdocs.xml /i:ExcludeSystemFolders.xml /i:MigrateBrowserAppData.xml /localonly /ui:S-1-12-1-1426919175-1304152533-3987183276-4051951554 /ue:*\* /progress:"C:\Users\USMTScanStateProgress.log" /l:"C:\Users\USMTScanState.log" /v:5 /c

5) Pysytään paikallisella järjestelmänvalvojan tilillä kirjautuneena ja tehdään Azure AD -liitos uuteen tenanttiin käyttäjän uuden tenantin tunnuksilla: Asetukset > Tilit > Käytä työpaikan tai koulun resursseja > Liitä tämä laite Azure Active Directoryyn

6) Kirjaudutaan ulos paikalliselta järjestelmänvalvojan tililtä ja kirjaudutaan sisään käyttäjän uuden tenantin Azure AD -tunnuksella, jolloin tilille luodaan oma Windows-käyttäjäprofiili. Ajetaan LoadState korotetuin oikeuksin:

.\loadstate.exe "C:\Users\USMTStore" /hardlink /nocompress /i:migapp.xml /i:migdocs.xml /i:ExcludeSystemFolders.xml /i:MigrateBrowserAppdata.xml /ui:S-1-12-1-1426919175-1304152533-3987183276-4051951554 /ue:*\* /progress:"C:\Users\USMTLoadStateProgress.log" /l:"C:\Users\USMTLoadState.log" /mu:azuread\markuspyhäranta:azuread\markuspyhära_fetjidl /v:5 /c

7) Kun LoadState on valmis, kirjaudutaan kerran ulos ja kirjaudutaan takaisin käyttäjän uuden tenantin Azure AD -tunnuksella. Kaikkien vanhan tenantin käyttäjäprofiilin asetusten, tiedostojen ja muiden määritysten tulisi nyt olla migratoituna uudelle profiilille.

8) Varmistetaan huolellisesti ScanStaten ja LoadStaten progress-lokeista, ettei mitään kriittisiä virheitä tapahtunut toimenpiteiden aikana, eikä mitään oleellista ole jäänyt migratoimatta.

9) Kun ollaan varmoja, että kaikki data on varmasti migratoitu, poistetaan manuaalisesti hard-link-varasto sijainnista C:\Users\USMTStore. Migraatiovaraston poistaminen ei poista dataa itse alkuperäisen käyttäjän profiilista, vaan ainoastaan linkitykset tiedostojen alkuperäiseen sijaintiin. Kun on täysin varmaa, että migraatio on ollut onnistunut, voidaan alkuperäinen käyttäjäprofiili poistaa halutessa tallennustilan säästämiseksi.

Ohjauspaneeli > Järjestelmä ja suojaus > Järjestelmä > Järjestelmän lisäasetukset > Käyttäjäprofiilit – Asetukset… > valitaan poistettava käyttäjäprofiili > Poista


Migraation toimenpiteet laajemmin kuvattuna

Mitä tuossa siis tehtiin ja miksi?

1) Paikallisen järjestelmänvalvojan luominen

Luotiin paikallinen järjestelmävalvojatili, jotta tietokoneelle voidaan kirjautua Azure AD -liitoksen katkaisemisen jälkeen. Kun liitos on katkaistu, tietokoneelle ei enää voida kirjautua millään Azure AD -tunnuksin. Siksi tarvitaan paikallinen järjestelmävalvojatili tietokoneella, jolla toimenpiteitä tehdään. Itse tein esimerkiksi paikallisen järjestelmänvalvojan “markus“:

Tietokoneen hallinta > Paikalliset käyttäjät ja ryhmät > Käyttäjät > Uusi käyttäjä… > …

Lisäsin tunnuksen paikalliseen “Järjestelmänvalvojat“-ryhmään:

Tietokoneen hallinta > Paikalliset käyttäjät ja ryhmät > Ryhmät > Järjestelmänvalvojat > Ominaisuudet > Lisää > …

Minulla on nyt paikallinen järjestelmänvalvojan tili, jolle voin kirjautua, kun Azure AD -liitos on katkaistu, eikä alkuperäiselle Azure AD -käyttäjälle voida enää kirjautua.

Voimmekin siksi tässä vaiheessa kiinnittää huomiota käyttäjän työpöydän taustakuvaan, pikakuvakkeisiin ja tehtäväpalkin väriin. Jos migraatio onnistuu, tulisi työpöytäympäristönkin näyttää samanlaiselta uudella käyttäjäprofiililla.


2) Migratoitavan käyttäjänimen talteenottaminen

Migratoitavan profiilin käyttäjänimeä tarvitaan LoadState-vaiheessa. Koska olemme migratoimassa Azure AD -tilin profiilia toisen Azure AD -tilin profiiliin, tulee meidän tietää alkuperäisen käyttätilin käyttäjänimi. Tämä siksi, että käyttäjän nimi on todennäköisesti sama molemmissa Azure AD -tenanteissa, jolloin Windows ei pysty nimeämään uuden tenantin käyttäjää samalla nimellä.

Tämä ei olisi ongelma paikallisten toimialueiden kohdalla, joissa tunnuksen toimialue vaihtuisi, mutta Azure AD -käyttäjätilien toimialue merkitään Windowsissa tenantista huolimatta aina azuread\<käyttäjänimi>. Tämä johtaa tilanteeseen, jossa uusi käyttäjä saa eri käyttäjänimen, eivätkä nimet täsmää. USMT taas oletuksena etsii samannimistä käyttäjää migraation kohteesta, ja siksi meidän tulee uudelleennimetä migratoitava käyttäjä LoadState-vaiheessa vastaamaan uuden käyttäjän nimeä.

Otetaan migratoitavan tilin käyttäjänimi talteen esimerkiksi komentorivin whoami -komennolla käyttäjälle kirjautuneena. Tätä tarvitaan myöhemmin LoadStatea ajaessa.

C:\Users\markuspyhäranta>whoami
azuread\markuspyhäranta

Käyttäjänimen saa talteen tässä vaiheessa myös esimerkiksi navigoimalla Ohjauspaneeli > Järjestelmä ja suojaus > Järjestelmä > Järjestelmän lisäasetukset > Käyttäjäprofiilit – Asetukset…


3) Azure AD -liitoksen katkaiseminen

Katkaistiin Azure AD -liitos: Asetukset > Tilit > Käytä työpaikan tai koulun resursseja > Katkaise yhteys, jolloin syötettiin pyydettäessä juuri luodun paikallisen järjestelmävalvojan tunnukset ja käynnistettiin tietokone uudelleen. Azure AD -liitos katkaistaan, sillä konetta ei voida liittää uuden tenantin Azureen ennen vanhan liitoksen poistamista.

Syötin paikallisen tunnuksen muodossa .\markus. Tämä siksi, että tietokone on vielä tässä vaiheessa Azure AD -liitetty ja Windows tulisi siten etsimään käyttäjääni Azure AD:n identiteettivarastosta. Piste viittaa tähän paikalliseen tietokoneeseen, ja näin Windows ymmärtää, että olen syöttämässä paikallista-, enkä pilvitoimialuetunnusta.

Entä mitä nykyiselle käyttäjäprofiilille tapahtuu toimenpiteen yhteydessä?

Ennen Azure AD -liitoksen katkaisemista, käyttäjäprofiili on käyttöjärjestelmässä muodossa azuread\markuspyhäranta. Tämä voidaan todentaa mm. navigoimalla: Ohjauspaneeli > Järjestelmä ja suojaus > Järjestelmä > Järjestelmän lisäasetukset > Käyttäjäprofiilit – Asetukset… Liitoksen katkaisun jälkeen käyttäjäprofiili näkyy kuitenkin tuntemattomana käyttäjätilinä.

Tuntemattomaan profiiliin voidaan viitata sen Secure Identifierilla (SID), joka löytyy Windowsin rekisteriavaimesta:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

Siellä on listattuna kaikki tietokoneen profiilit niiden SID:n perusteella. Tarkastelemalla arvoa “ProfileImagePath” voidaan helposti tunnistaa, onko kyseessä oikea profiili. Eli navigoidaan Rekisterieditori > \HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

Nyt siis tiedämme, että migratoitavan käyttäjäprofiilin SID on:

S-1-12-1-1426919175-1304152533-3987183276-4051951554

Voimme käyttää tuota SID:tä, kun määritämme ScanState-komennolla, mitä käyttäjäprofiilia ollaan migratoimassa. Meidän pitäisi myös pystyä käyttämään käyttäjäprofiilin nimeä azuread\markuspyhäranta, vaikka se näkyykin tällä hetkellä tuntemattomana. Itse käytän tässä esimerkissä SID:tä.


4) ScanState

Kirjauduttiin paikallisella järjestelmävalvojantilillä ja ajettiin ScanState. Avattiin PowerShell korotetuin oikeuksin ja mentiin siihen hakemistoon, jossa scanstate.exe -ohjelma sijaitsee. Itse jätin asennussijainnin oletukselle USMT:n asennusvaiheessa, joten navigoin PowerShellissä:

cd C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\User State Migration Tool\amd64

Ajettiin ScanState seuraavilla valinnoilla:

.\scanstate.exe "C:\Users\USMTStore" /o /hardlink /nocompress /i:migapp.xml /i:migdocs.xml /i:ExcludeSystemFolders.xml /i:MigrateBrowserAppData.xml /localonly /ui:S-1-12-1-1426919175-1304152533-3987183276-4051951554 /ue:*\* /progress:"C:\Users\USMTScanStateProgress.log" /l:"C:\Users\USMTScanState.log" /v:5 /c

Mitä tuo komento siis tekee? Käydään jokainen valinta läpi:

  • scanstate.exe “C:\Users\USMTStore” = Määrittää suorittamani ScanState.exe -ohjelman ja migraatiovaraston, johon migratoitava data normaalisti kopioidaan. Huom! Tässä yhteydessä dataa ei oikeasti kopioida, sillä määrittelen myös /hardlink ja /nocompress -valinnat.
  • /o = Ylikirjoittaa migraatiovarastossa olevan datan ja config.xml -tiedoston, jos ne ovat jo olemassa.
  • /hardlink = Määrittää migraatiovaraston hard-link -varastoksi. Tällöin dataa ei oikeasti kopioida komennossa määritettyyn varastoon, vaan varastoon luodaan hard-linkit alkuperäisiin tiedostoihin. Dataa ei siis kahdenneta tässä vaiheessa ollenkaan.
  • /nocompress = Tämä tarvitaan aina /hardlink -valinnan kanssa. Oletuksena USMT pakkaa datan, mutta hard-link -migraatiossa dataa ei ikinä kompressoida. Käytännössä siksi, että hard-link -migraatiossa luodaan vain linkitys datan alkuperäiseen sijaintiin, jossa se on pakkaamattomassa muodossaan.
  • /i:migapp.xml = Sisällyttää komentoon migapp.xml-tiedoston, joka sisältää sääntöjä siitä, miten sovellusasetuksia tulisi migratoida.
  • /i:migdocs.xml = Sisällyttää komentoon migdocs.xml-tiedoston, joka sisältää sääntöjä siitä, miten tiedostoja ja profiiliasetuksia tulisi migratoida.
  • /i:ExcludeSystemFolders.xml = Sisällytää komentoon ExcludeSystemFolders.xml-tiedoston. Suljen sillä pois kaikki käyttöjärjestelmän tiedostohakemistot, joiden alta en halua mitään migratoitavan. Olin jo valmiiksi siirtänyt tiedoston samaan hakemistoon. Tiedoston sisältö:
<?xml version="1.0" encoding="UTF-8"?>
<migration urlid="http:\\www.usmtgui.com/migration/1.0/migxmlext/ExcludeSystemFolders.xml">

<!-- This is a modified version of ExcludeSystemFolders.xml by EhlerTech: https:\\ehlertech.com/customxmls/. Modified on 21.5.2020 by Markus Pyhäranta. -->

    <_locDefinition>
		<_locDefault _loc="locNone"/>
		<_locTag _loc="locData">displayName</_locTag>
    </_locDefinition>
    <component type="Documents" context="UserAndSystem" id="documents"> 
        <displayName>ExcludeSystemFolders</displayName> 
        <role role="data"> 
            <rules> 
                <Exclude> 
                    <objectSet /> 
                </Exclude> 
                <unconditionalExclude> 
                    <objectSet>
			<pattern type="File">C:\boot\* [*]</pattern>
                        <pattern type="File">C:\_SMSTaskSequence\* [*]</pattern>
                        <pattern type="File">C:\WINDOWS.old\* [*]</pattern>
                        <pattern type="File">C:\WINDOWS.old.*\* [*]</pattern>
                        <pattern type="File">C:\SWSetup\* [*]</pattern>
                        <pattern type="File">C:\MININT\* [*]</pattern>
                        <pattern type="File">C:\ [prot_ins.sys]</pattern>
			<pattern type="File">C:\ProgramData\* [*]</pattern>
			<pattern type="File">C:\Program Files\* [*]</pattern>
			<pattern type="File">C:\Program Files (x86)\* [*]</pattern>
			<pattern type="File">C:\Quarantine\* [*]</pattern>
			<pattern type="File">C:\PerfLogs\* [*]</pattern>
			<pattern type="File">C:\MSOCache\* [*]</pattern>
			<pattern type="File">C:\Dell\* [*]</pattern>
			<pattern type="File">C:\Intel\* [*]</pattern>
			<pattern type="File">C:\Windows\* [*]</pattern>
			<pattern type="File">C:\DRIVERS\* [*]</pattern>
			<pattern type="File">C:\Recovery\* [*]</pattern>
			<pattern type="File">C:\Windows10Upgrade\* [*]</pattern>
			<pattern type="File">C:\$GetCurrent\* [*]</pattern>
			<script>MigXmlHelper.GenerateDrivePatterns ("* [*.tmp]", "Fixed")</script>
                    </objectSet> 
                </unconditionalExclude> 
            </rules> 
        </role> 
    </component>
</migration>
  • /i:MigrateBrowserAppData.xml = Sisällytää komentoon MigrateBrowserAppData.xml-tiedoston. Sisällytän sillä migraatioon kaikki tiedostot ja alikansiot Google Chrome ja Mozilla Firefox -selainten profiilihakemistoista, joiden alta haluan migratoitavan mm. kirjanmerkit, tallennetut salasanat ja niin edelleen. Olin jo valmiiksi siirtänyt tiedoston samaan hakemistoon. Tiedoston sisältö:
<?xml version="1.0" encoding="UTF-8"?>
<migration urlid="https://www.vetonaula.fi/windows-10-kayttajaprofiilin-migraatio-azure-ad-tenanttimuutoksen-yhteydessa-usmt/">
  <component context="UserAndSystem" type="Application">
    <displayName>MigrateBrowserAppData</displayName>
    <role role="Settings">
      <rules context="User">
        <include>
          <objectSet>
            <pattern type="File">%CSIDL_LOCAL_APPDATA%\Google\Chrome\User Data\* [*]</pattern>
	    <pattern type="File">%CSIDL_APPDATA%\Mozilla\Firefox\Profiles\* [*]</pattern>
          </objectSet>
        </include>
      </rules>
    </role>
  </component>
</migration>
  • /localonly = Määrittää, että migraatioon kuuluu vain paikallisia tiedostoja. Mitään tiedostoja ulkoisilta tallennusmedioilta, kuten USB-muistitikuilta tai verkkoasemilta ei migratoida.
  • /ui:S-1-12-1-1426919175-1304152533-3987183276-4051951554 = Määrittää migratoinnin piiriin kuuluvat käyttäjäprofiiit, eli tässä tapauksessa vain käyttäjäprofiilin “S-1-12-1-1426919175-1304152533-3987183276-4051951554”
  • /ue:*\* = Määrittää migratoinnin piiriin kuulumattomat käyttäjäprofiilit, eli tässä tapauksessa aivan kaikki käyttäjäprofiilit huolimatta toimialueesta ja sijainnista. Valinta /ui voittaa aina, jos sen ja /ue -valinnan kanssa tulee ristiriita. Esimerkiksi profiili “S-1-12-1-1426919175-1304152533-3987183276-4051951554” on nyt sekä sisällytetty migraatioon että jätetty sen ulkopuolelle. /ui -valinta ottaa kuitenkin prioriteetin, joten se sisällytetään ja kaikki muut jätetään pois.
  • /progress:”C:\Users\USMTScanStateProgress.log” = Määrittää valinnaisen progress-lokin sijainnin hakemistoon C:\Users\USMTScanStateProgress.log. Sisältää mm. virheilmoitukset.
  • /l:”C:\Users\USMTScanState.log” = Määrittää ScanState-lokin sijainnin hakemistoon C:\Users\USMTScanState.log. ScanState-loki generoidaan aina komennon ajamisen yhteydessä oletuksena, mutta tällä voidaan määrittää sen tallennussijainti.
  • /v:5 = Määrittää lokitettavien tietojen tason, eli mitä halutaan lokitettavan ScanState-ohjelman toimista. Lokituksen eri tasot on kuvattu ScanStaten syntaksin dokumentaatiossa.
  • /c = Määrittää, että ScanState-komento tulee ajaa loppuun, vaikka virheilmoituksia tulisikin. Virheiden merkityksellisyys on jälkeenpäin arvioitavissa lokitiedoista.

Komennolla siis käytännössä määritettiin, mitä migratoidaan, miltä käyttäjäprofiililta ja mihin migraatiovarastoon. Siinä ei määritellä, mille käyttäjälle tietoja migratoidaan, eikä se oikeasti migratoi uudelle käyttäjälle vielä mitään.

Alla suoritetun komennon tuloste:

SCANSTATE.EXE
(C) 2012 Microsoft Corporation. All rights reserved.

Log messages are being sent to 'C:\Users\USMTScanState.log'

Starting the migration process
Processing the settings store

Examining the system to discover the migration units
 S-1-12-1-1426919175-1304152533-3987183276-4051951554 (MarkusPyhäranta) (1 of 2): 100% done
 This Computer (2 of 2): 100% done

Selecting migration units

Estimating total file size for the progress log
 S-1-12-1-1426919175-1304152533-3987183276-4051951554 - 1105 files
 PF17ZVG3\Markus - 0 files
 This Computer - 1599 files

Gathering data
 S-1-12-1-1426919175-1304152533-3987183276-4051951554 (1 of 2): 100% done
 This Computer (2 of 2): 100% done
 Commit

Success.

ScanState return code: 0

Komento meni läpi. Näen molempien lokien yhteenvedosta, että ScanState-vaihe on mennyt läpi ilman virheitä:

USMTScanState.log:

[0x000000] ----------------------------------- USMT ERROR SUMMARY -----------------------------------
[0x000000] No error in migration process is recorded.

USMTScanStateProgress.log:

22 May 2020, 20:39:30 03:00, 00:00:38, errorCode, 0, numberOfIgnoredErrors, 0, message, "Successful run"

Herää kuitenkin kysymys siitä, miksi USMT skannasi ScanState-vaiheessa myös tiedostoja “This Computer” -profiilista. Tämä on normaalia ja kuuluu USMT:n toimintaperiaatteeseen. Microsoftin dokumentaatiossa ”How USMT Works” sanotaan muun muassa seuraavaa:

The system profile, the “All users” profile in a source computer running Windows XP, or the Public profile in a source computer running Windows Vista, Windows 7, and Windows 8, is always migrated and you cannot exclude these profiles from the migration.

Tuo on siis normaalia. Koska itse sisällytin ScanStateen myös kustomoidun ExcludeSystemFolders.xml -tiedoston, tiedän, ettei mitään tiedostoja tulla migratoimaan C:\Users\ -hakemiston ulkopuolelta. Pystyn tarkistamaan sen navigoimalla ScanState-komennossa määrittämääni hard-link -migraatiovarastoon komennon ajamisen jälkeen:

Migraatiovaraston sisältö käyttäjän kotihakemiston osalta:


5) Azure AD -liitos uuteen tenanttiin

Tehtiin Azure AD -liitos uuteen tenanttiin käyttäjän uuden tenantin tunnuksilla navigoimalla Windowsissa: Asetukset > Tilit > Käytä työpaikan tai koulun resursseja > Liitä tämä laite Azure Active Directoryyn

Syötettiin pyydettäessä käyttäjän Azure AD -tunnukset. Kun liitos oli tehty, kirjauduttiin ulos paikallisen järjestelmänvalvojan käyttäjätililtä. Valittiin Windowsin kirjautumisikkunassa valinta “Toinen käyttäjä” ja kirjauduttiin käyttäjän uuden tenantin Azure AD -tunnuksilla. Tällöin Windows alkoi määrittämään käyttäjäprofiilia, minkä aikana näytöllä esitettiin niitä tyypillisiä viestejä: “Tämä voi kestää useita minuutteja”, “Älä sammuta tietokonetta”, “Tietokonetta valmistellaan käyttöä varten”.

Koska kyseessä oli Azure AD -tili, organisaation käytännöt halusivat heti Windows Hello for Businessin määrittämisen. Tehtiin määritykset, minkä jälkeen päästiin Windowsin työpöydälle.

Tarkistin komentorivin whoami -komennolla, millä nimellä uusi käyttäjätili on luotu, sillä tarvitsen tietoa LoadState-vaiheessa:

C:\Users\MarkusPyhära_fetjidl>whoami
azuread\markuspyhära_fetjidl

Windows 10 oli nimeni 12 ensimmäisen merkin jälkeen lisännyt alaviivan ja satunnaisen seitsemän merkin merkkijonon. Vaikka käyttäjätunnus ei suoranaisesti miellytä silmää, niin ulkoasulla ei lopulta ole mitään väliä. Käyttäjä kirjautuu Windowsiin kuitenkin Azure AD -tunnuksellaan. Jos nimi häiritsee käyttäjän kotihakemistossa, voidaan kotihakemistokansion nimi halutessa uudelleennimetä paikallisen järjestelmänvalvojatilin kautta. Sen jälkeen tulee muistaa päivittää myös käyttäjäprofiilin uusi “ProfileImagePath“-arvo rekisteriavaimeen:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\ProfileList

6) LoadState

Ajettiin LoadState kirjautuneena uuden tenantin käyttäjätilillä. Azure AD -liitoksen tehneelle käyttäjätilille määritetään oletuksena paikallisen järjestelmänvalvojan oikeudet. Avattiin PowerShell korotetuin oikeuksin ja mentiin siihen hakemistoon, jossa loadstate.exe -ohjelma sijaitsee:

cd C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\User State Migration Tool\amd64

LoadStaten toiminnan kannalta tulee ymmärtää se, että missään vaiheessa ScanStaten prosessia ei määritellä, mille käyttäjäprofiilille tietoja ollaan siirtämässä. ScanState vain skannaa profiiliympäristön ja määrittää, minkä käyttäjän tiedot migratoidaan, muttei mille käyttäjälle.

LoadState taas päättelee määrittelemieni valintojen mukaan, mitkä käyttäjäprofiilit tulisi migratoida. Oletuksena se yrittäisi migratoisi muuten kaikki. Samat ScanState-ohjelman kanssa käytetyt /ui ja /ue -valinnat tulee sisällyttää myös LoadStaten komentoon. LoadState ei kuitenkaan migratoi sellaisia käyttäjiä, joita ei löydy kohdelaitteelta jo etukäteen. Se siis pyrkii aina etsimään migratoitavaa käyttäjäprofiilia vastaavan käyttäjän myös kohdelaitteelta. Jos se ei löydä sellaista, mitään ei migratoida.

Tässä esimerkkitilanteessa olen tekemässä migraatiota Azure AD -käyttäjälle nimellä azuread\markuspyhäranta. LoadState tulee siis etsimään samannimistä käyttäjää koneelta, jolla LoadState suoritetaan. Esimerkkitilanteessani tietokone on kuitenkin sama, eli mitä tapahtuisi LoadState vaiheessa nyt? LoadState tekisi migraation käyttäjältä azuread\markuspyhäranta samalle käyttäjälle azuread\markuspyhäranta. Käytännössä olisimme siis lähtöpisteessä. Tätä ongelmaa ei tulisi vastaan, jos tehtäisiin migraatioita kahden tietokoneen välillä. Miten siis saamme LoadStaten ymmärtämään, ettei migraatiovaraston tietoja olla siirtämässä samalle lähdeprofiilille?

LoadStatesta löytyy valinta /mu, jolla voidaan uudelleennimetä käyttäjäprofiili kohdekoneella. Sillä voidaan käytännössä määrittää uusi toimialue ja käyttäjänimi migratoitavalle käyttäjälle. Uudelleennimeäminen tapahtuu periaatteella:

/mu:OldDomain\OldUsername:NewDomain\NewUserName

Koska molemmat käyttäjät ovat AzureAD -käyttäjiä, tulee sekä vanhan että uuden käyttäjän nimessä olemaan toimialueena “AzureAD”. Voimme siis tehdä nimimuutoksen seuraavasti:

/mu:azuread\markuspyhäranta:azuread\markuspyhära_fetjidl

Tuon valinnan sisällyttäminen komentoon saa LoadState-ohjelman ymmärtämään, että käyttäjäprofiilin azuread\markuspyhäranta -tiedot tullaan migratoimaan hard-link -migraatiovarastosta kohdekoneen käyttäjälle azuread\markuspyhära_fetjidl, eikä kohdekoneelta etsitä samannimistä kohdekäyttäjää kuin migraation lähteessä.

Ajettiin LoadState seuraavilla valinnoilla:

.\loadstate.exe "C:\Users\USMTStore" /hardlink /nocompress /i:migapp.xml /i:migdocs.xml /i:ExcludeSystemFolders.xml /i:MigrateBrowserAppData.xml /ui:S-1-12-1-1426919175-1304152533-3987183276-4051951554 /ue:*\* /progress:"C:\Users\USMTLoadStateProgress.log" /l:"C:\Users\USMTLoadState.log" /mu:azuread\markuspyhäranta:azuread\markuspyhära_fetjidl /v:5 /c

Mitä tuo komento siis tekee? Käydään jokainen valinta läpi:

  • loadstate.exe “C:\Users\USMTStore” = Määrittää suorittamani LoadState.exe -ohjelman ja migraatiovaraston, josta migratoitava data kopioidaan. Tässä yhteydessä ko. sijainnissa ei oikeasti sijaitse kopioitavaa dataa, vaan ainoastaan hard-linkit tiedostojen alkuperäiseen sijaintiin vanhan käyttäjän kotihakemistossa, josta tiedostot nyt kopioidaan uudelle profiilille.
  • /hardlink = Määrittää, että data migratoidaan hard-link -varastosta.
  • /nocompress = Tämä tarvitaan aina /hardlink -valinnan kanssa. Määrittää, että migraatiovaraston dataa ei ole pakattu.
  • /i:migapp.xml = Sisällyttää komentoon migapp.xml-tiedoston, joka sisältää sääntöjä siitä, miten sovellusasetuksia tulisi migratoida.
  • /i:migdocs.xml = Sisällyttää komentoon migdocs.xml-tiedoston, joka sisältää sääntöjä siitä, miten tiedostoja ja profiiliasetuksia tulisi migratoida.
  • /i:ExcludeSystemFolders.xml = Sisällytää komentoon ExcludeSystemFolders.xml-tiedoston. Suljen sillä pois kaikki käyttöjärjestelmän tiedostohakemistot, joiden alta en halua mitään migratoitavan. Olin jo valmiiksi siirtänyt tiedoston samaan hakemistoon.
  • /i:MigrateBrowserAppData.xml = Sisällytää komentoon MigrateBrowserAppData.xml-tiedoston. Sisällytän sillä migraatioon kaikki tiedostot ja alikansiot Google Chrome ja Mozilla Firefox -selainten profiilihakemistoista, joiden alta haluan migratoitavan mm. kirjanmerkit, tallennetut salasanat ja niin edelleen. Olin jo valmiiksi siirtänyt tiedoston samaan hakemistoon.
  • /ui:S-1-12-1-1426919175-1304152533-3987183276-4051951554 = Määrittää migratoinnin piiriin kuuluvat käyttäjäprofiiit, eli tässä tapauksessa vain käyttäjäprofiilin “S-1-12-1-1426919175-1304152533-3987183276-4051951554”
  • /ue:*\* = Määrittää migratoinnin piiriin kuulumattomat käyttäjäprofiilit, eli tässä tapauksessa aivan kaikki käyttäjäprofiilit huolimatta toimialueesta ja sijainnista. Valinta /ui voittaa aina, jos sen ja /ue -valinnan kanssa tulee ristiriita. Esimerkiksi profiili “S-1-12-1-1426919175-1304152533-3987183276-4051951554” on nyt sekä sisällytetty migraatioon että jätetty sen ulkopuolelle. /ui -valinta kuitenkin ottaa prioriteetin, joten se sisällytetään ja kaikki muut jätetään pois.
  • /progress:”C:\Users\USMTLoadStateProgress.log” = Määrittää valinnaisen progress-lokin sijainnin hakemistoon C:\Users\USMTLoadStateProgress.log. Sisältää mm. virheilmoitukset.
  • /l:”C:\Users\USMTLoadState.log” = Määrittää LoadState-lokin sijainnin hakemistoon C:\Users\USMTLoadState.log.
  • /mu:azuread\markuspyhäranta:azuread\markuspyhära_fetjidl = Esitetään muutos käyttäjänimessä. Eli migraation kohdetietokoneelta tullaan etsimään käyttäjää “azuread\markuspyhära_fetjidl” migraation kohteeksi. Migraation lähteenä toimii käyttäjän “azuread\markuspyhäranta” käyttäprofiili, joka määritettiin sen SID-tunnuksella valinnassa /ui.
  • /v:5 = Määrittää lokitettavien tietojen tason, eli mitä halutaan lokitettavan LoadState-komennon toimista.
  • Lokituksen eri tasot on kuvattu LoadStaten syntaksin dokumentaatiossa.
  • /c = Määrittää, että LoadState-komento tulee ajaa loppuun, vaikka virheilmoituksia tulisikin. Virheiden merkityksellisyys on jälkeenpäin arvioitavissa lokitiedoista.

Komennolla siis käytännössä määritettiin, mitä migratoidaan, mistä sijainnista, miten ja millä nimellä käyttäjäprofiilin tulisi migraation jälkeen sijaita kohteessa.

Alla suoritetun komennon tuloste:

LOADSTATE.EXE Version 10.0.18362
(C) 2012 Microsoft Corporation. All rights reserved.

Log messages are being sent to 'C:\Users\USMTLoadStateFINAL.log'

Starting the migration process
Processing the settings store

Selecting migration units

Examining the system to discover the migration units
 AzureAD\MarkusPyhära_fetjidl (1 of 2): 100% done
 This Computer (2 of 2): 100% done

Estimating total file size for the progress log
 AzureAD\MarkusPyhära_fetjidl - 0 files
 S-1-12-1-1426919175-1304152533-3987183276-4051951554 - 1105 files
 PF17ZVG3\Markus - 0 files
 This Computer - 34 files

Applying data
 S-1-12-1-1426919175-1304152533-3987183276-4051951554 (1 of 2): 100% done
 This Computer (2 of 2): 100% done

Success.

LoadState return code: 0

Komento meni läpi. Näen myös lokeista, että komento suoritui ilman virheilmoituksia.

USMTLoadState.log:

[0x000000] ----------------------------------- USMT ERROR SUMMARY -----------------------------------
[0x000000] No error in migration process is recorded.

USMTLoadStateProgress.log:

22 May 2020, 20:59:52 03:00, 00:02:46, errorCode, 0, numberOfIgnoredErrors, 0, message, "Successful run"

7-9) Viimeistelevät toimenpiteet

Kun LoadState oli valmis, kirjauduin kerran ulos ja takaisin käyttäjän uuden tenantin Azure AD -tunnuksella. Tietyt asetukset, kuten fontit, taustakuva, pikakuvakkeet ja näytönsäästäjän asetukset eivät muuten tule voimaan.

Uudelleenkirjautumisen jälkeen muutokset olivat suoraan havaittavissa:

Varmistin huolellisesti ScanStaten ja LoadStaten progress-lokeista, ettei mitään kriittisiä virheitä tapahtunut toimenpiteiden aikana, eikä mitään oleellista ollut jäänyt migratoimatta. ScanStaten-lokit arvioin jo tämän artikkelin vaiheessa 4) ja LoadStaten vaiheessa 6). Tiedän, ettei migraation aika esiintynyt mitään virheitä, jotka voisivat aiheuttaa tiedonmenetystä käyttäjän datan osalta.

Tarkistin käyttäjän kotihakemiston, enkä havainnut minkään puuttuvan. Navigoin resurssienhallinnasta manuaalisesti hard-link-varaston sijaintiin C:\Users\USMTStore ja poistin sen lopullisesti. Poistotoimenpide ei poista dataa alkuperäiseltä käyttäjäprofiililta, vaan ainoastaan tiedostoihin luodut hard-linkit.

Huomasin, että ainakaan Mozilla Firefox ei ymmärtänyt käyttää AppData-kansiosta löytyvää migratoitua profiilikansiota uudelle Firefoxin oletusprofiilille. Siksi jouduin uudelleennimeämään migratoidun profiilikansion vastaamaan oletusprofiilikansion kansionimeä, jonka näin syöttämällä osoiteriville about:profiles.

Jos vanhalle käyttäjälle ei ole tarvetta, voidaan koko profiili poistaa esimerkiksi navigoimalla: Ohjauspaneeli > Järjestelmä ja suojaus > Järjestelmä > Järjestelmän lisäasetukset > Käyttäjäprofiilit – Asetukset… > valitaan vanha käyttäjäprofiili > Poista.


Aiheeseen liittyen:


Artikkelin on kirjoittanut Vetonaulan IT-asiantuntija Markus Pyhäranta.