User account pictures with roaming profiles

Posted on Updated on

 

Tip: this article only targets Vista/WS08 and higher.

 

If you want to change your user account picture and you log off and log on again, it could be your new user account picture is gone. This happens when you’re using roaming profiles and

  • the cached profiles are deleted at logoff
  • the cached profiles aren’t deleted at logoff, but you have a farm or collection of multiple systems and the next time you logon you get on a different system (in this case you could see the change several logons later)

To know why, you should know a few things.

 

Figure 1

 

 

Why?

First of all, every user gets a default user account picture (see the red circle in figure 1; the circle itself isn’t part of what you see, it’s just meant to highlight a piece of the screenshot). This picture is used for the user tile, which is visible on the Start menu (figure 1), on the logon screen,… A user can change this picture by selecting another picture from a default set of pictures: go to the Start menu and just click the user tile, which brings you to Control Panel\User Accounts\User Accounts, where you can go to directly too of course. You see the picture the user has currently selected. Then click “Change Your Picture”. In the Control Panel applet you see which picture is currently selected and which other pictures you are able to choose. To effectively change the picture, select another picture and click the button “Click Picture”, which brings you to the previous screen again, but shows you your new choice.

 

Figure 2

 

Figure 3

 

Figure 4

 

Figure 5

 

Figure 6

 

The pictures you can choose from reside in %PROGRAMDATA%\Microsoft\User Account Pictures\Default Pictures. When you change your picture, a copy of the selected picture is made and stored in the local part of the user profile (i.e. in %TEMP% (= %TMP%)) under the name of [domain]+[username].bmp (for example, Greatbank+joebee.bmp for user Joe Beeking with user name joebee in domain with FQDN Greatbank.com). Interesting to know is that when you just check your picture settings, such a bmp file is created too (perhaps to “fix” possibly “non-default and non-intended” situations; if you read on, you’ll probably understand what I mean). If there was already a bmp file in %TEMP%, it’s overwritten. And no, there are situations where there wasn’t already a bmp file in %TEMP%. For example, you could have a bmp file in %TEMP% and deleted it manually.

 

Figure 7

 

Figure 8

 


Figure 9

 

Or there could be another cause for not having a bmp file in %TEMP%. When a new profile is created, the default user account picture is assigned. For that no bmp file is created in %TEMP% for domain users (but it is for local users).

At the same time, when the profile is newly created, related settings are stored in the file [domain]+[username].dat in %PROGRAMDATA%\Microsoft\User Account Pictures. For local users the files are just called [username].bmp and [username].dat, for instance Administrator.bmp for the local Administrator account. For local users the settings are stored somewhere else too and it’s not part of the profile.

 

When checking the user account picture settings, nothing is changed to the dat file, as is the case for the bmp file. When changing the user account picture though the dat file is edited for domain users, but not for local users. For local users the settings are changed to the alternative location I was talking about in the previous paragraph.

 

All this means the problem doesn’t occur with local users’ profiles. First of all, those profiles stay where they are. Secondly, even if temporary user folders (%TEMP% = %TMP%) are deleted at logoff time after a Remote Desktop connection (which is an RDS setting you can disable by the way, see figure 10), there is no real problem as the picture configuration is still present in the alternative location. For completeness: an administrative/console session is also a Remote Desktop session. If you are 100% bypassing RDS (really physical or through the “console” for a virtual machine (VM)) temporary folders aren’t deleted at logoff, even if configured so at RDS level. Thanks to my colleague Jo Jacobs to remind me of that! Anyway, I can go even further: the bmp in %TEMP% isn’t even necessary… Try to replace the bmp file by another bmp file and your account picture just stays the same.

 

Figure 10

 

With domain users though the combination of bmp and dat file are really necessary (but don’t forget there is no bmp file in %TEMP% when the default user account picture is used due to profile creation (but not when the settings are checked or the picture is selected explicitly)). When the local part of the profile or even just the content of %TEMP% is lost, you actually loose the bmp file. Well, it’s not that bad, because as we’ve seen for local users, the bmp file in %TEMP% isn’t that important; it’s the configuration itself that’s important. And for domain users that’s the dat file. If you delete the dat file, you actually get the default picture back (no dat file is like having the default dat file you get after profile creation).

 

When a domain user with a roaming profile logs off and (!) the cached profile isn’t deleted (you can configure this behavior through group policy), the dat file is deleted. The dat file is a little bit considered as part of the profile. If there is a local profile, the dat file should obviously stay; if the profile is roaming, there is no need for the dat file to stay. This is logical. The big problem is the dat file gets lost with roaming profiles this way (as it technically doesn’t belong to the profile and doesn’t roam with the roaming part of the profile) and so is the user account picture configuration.

 

Notes:

  • to reflect a manual (!) change to the bmp/dat files you need to restart the current Explorer process (explorer.exe), for example by logging off and on again or by killing the process and starting it again; for instance, if you delete the dat file, you need to restart explorer.exe before you can see your account picture is reset to the default.
  • when you delete a profile from a local user, the profile is created again when that users logs in again, but only the bmp file seems to be created (in %TEMP%), not the dat file anymore. So the dat file for a local users seems to be created only at the initial profile creation (the system seems to see the difference, probably because there is no alternative picture configuration data yet at initial profile creation).
  • You can extend the set of pictures Windows offers for your account picture by adding a bmp file to %PROGRAMDATA%\Microsoft\User Account Pictures\Default Pictures. The default pictures all have the name usertileNUMBER.bmp (for instance, usertile22.bmp), but there is no obligation to follow this name syntax if you add other bmp pictures. Note that by default you don’t have the rights to this folder and TrustedInstaller is the owner; so you should change the owner, add the necessary permissions, add the file(s). Afterwards you should delete the permissions and reset the ownership to NT SERVICE\TrustedInstaller (chosen domain should be the local system when Windows pops up the box to enter the account!), except when you want to keep those custom permissions and the custom ownership. In figure 3 and 7 you can see I’ve added 1 BMP: it’s the first picture from figure 3 and the first file from figure 7 (test32.bmp).
  • If the cached profiles aren’t deleted at logoff, you logon again the next time on the same system, but Remote Desktop Services (RDS) on that system is configured to delete temporary folders at logoff (so they can’t survive a session), there is no problem. Yes, the bmp file is gone, but the dat file is still there.
  • The group policy setting to determine the behavior for cached roaming user profiles, is called “Delete cached copies of roaming profiles” (in Computer Configuration\Policies\Administrative Templates\Windows Components\System\User Profiles). By default those cached copies aren’t deleted, but I recommend to enable this on large farms, because the chance you get the same server again is small, it takes a lot of disk space (although you can limit this) and the chance on a merging error is non-existent when the copies are deleted. On small farms that’s another story of course.
  • The default picture, although shown amongst the other pictures (see figure 3 or 4), isn’t located in the “Default Pictures” folders, but one level higher. Its name is user.bmp. There is a second bmp located one level higher than “Default Pictures” and also named differently (guest.bmp), but this one doesn’t appear in the Control Panel applet. This last BMP is used for the Guest account.
  • By adding pictures to Default Pictures, removing pictures from this folder or replacing pictures in this folder (and even one level higher), you can change the set of pictures users can choose from and even the default pictures can be changed the way you want! J

 

 

The solution…

The only thing that we really need for roaming profiles is the dat file. But if we want to keep everything as clean and supported as possible, we shouldn’t forget about the bmp file in %TEMP% either.

 

The solution for the bmp file could have been to remark the folder as roaming (instead of local), but to do that you actually need to remark the %LOCALAPPDATA% as roaming and mark every subfolder of this path as local (because they were initially local J), except for “Temp”. This is a hell of a job, especially because the subfolders of %LOCALAPPDATA% can change over time, so it’s not an administrator-friendly way. Also, files in the root of %LOCALAPPDATA% will be marked roaming instead of local, which isn’t always something you want… Another reason why this is not a good idea is the fact we’re making %TEMP% roaming! Duh-uh! But even if you would like to do this, you can probably just forget it. We can’t mark variables as roaming, so we have to refer to the real path. But %TEMP% is changing in every session (except when it’s configured temporary folders don’t change with every session), so we can’t predict that. The bottom line is we can’t make our user account picture roaming (or with a lot of work and a possible loss of features (i.e. session specific temporary folders, as those have their benefits), an error-prone system (new folders can become roaming instead of local) and/or markups you actually don’t really want (for example, a file marked as roaming in %LOCALPPDATA%, while you wanted to being it marked as local), so we have to workaround this problem.

 

Side note: the registry named value ExcludeProfileDirs in HKEY_CURRENT_USER\Software\Microsoft\Windows NT\CurrentVersion\Winlogon makes it possible to exclude folders from the roaming part. By default the value is

  • Before Vista: Local Settings;Temporary Internet Files;History;Temp
  • Since Vista: AppData\Local;AppData\LocalLow;$Recycle.Bin

 

For the dat file there is no way to roam it, as it resides under ProgramData. So just as with the bmp file we need some custom way to save and load the configuration data.

 

How? Well, through logon and logoff scripts. If we have a logoff script that saves the bmp and dat file to a certain location at logoff and another script that does the reverse at logon, we’re in! Note that during logon and logoff %TEMP% refers to the Temp folder in the local profile part, while during the session it refers to the “real” %TEMP%, i.e. a subfolder in Temp named differently every time the user logs on. This means the scripts can only be used during logon/logoff, except when you would build in some logic to detect the state and act based on that.

 

For example, I have created a logoff and logon script in PowerShell (PS). The logoff script is called “Save user account picture”, while the logon script has been named “Load user account picture”. The first script is configured as a logoff script for our users through a group policy, while the same has happened for the second script (but then as a logon script). The logoff script checks for the existence of the bmp and dat file and if they both exist, copies them to a folder “User account picture” on the user’s home drive. The logon script checks if both those files exist in that folder on the home drive and if so, copies them to their local location on the system where the user has just logged on.

 

This concept makes it possible to configure a user account picture and not only keeps it saved for the roaming profile/farm, but also makes this configuration cross-farm, as it’s not really profile specific anymore (the picture can even be “shared” across roaming and local profiles this way!). Of course you can change the scripts a little bit and make the setting profile/farm specific. It all depends on what exactly you want.

 

My logoff script only saves the files when both are available. Normally an explicit change to the account pictures always results in the creation or adaptation of the bmp and the dat file. The only “default” situation where both files don’t exist, is when a roaming profile is created. But if there was already some custom account picture existing on the home drive, it was already loaded at logon time! And when this wasn’t the case, well, then we won’t need to save the dat file, as it just represents the default situation. This way we reduce the amount of copies, especially because most users probably never makes changes to their account picture in the enterprise.

There is 1 situation where this could be a problem. Suppose you haven’t implemented my workaround yet and you have 2 systems using roaming profiles. On system 1 you had already customized your account picture, while on system 2 you’ve never changed a thing. If you log on to system 2 and log off again, nothing is saved. If you log on to system 1 later, the default picture settings from system 2 aren’t replicated… So if you consider the first system you logon too after the implementation of the workaround is a fact as the system that should set your account picture choice, that system has a 100% default account picture configuration, you log on to such a system and other systems have custom settings, then you don’t get what you want. In that case you should change my script to copy/delete stuff every time at logoff and logon or at least build in a lot more logic. I didn’t do that, because there could be a lot of other reasons why you don’t want our solution to work that way:

  • After the implementation of the solution you should be very well aware of which system to log off from first; that’s not an easy job for many end users…
  • If another system has already custom account picture settings, you probably want that system as the baseline. With other words, you probably want the settings from system 1 as the baseline and not those of system 2.

Again, it all depends on which behavior you want. My bullets were enough to convince me to only copy when there is an explicit existence of a bmp and dat file, so when a user has ever made some change (well, or just checked its account picture settings, but we can’t tell the difference…).

 

Note: I know users could delete bmp and/or dat files themselves. For example, suppose a user changes his or her account picture. Later the user deletes the bmp file from %TEMP%. As said, this doesn’t change a thing: the custom picture just stays, as it’s the dat file that really counts. But the logoff script won’t copy anything, so the change doesn’t get saved. Now, this is a hole in my script, I’m aware of that. But typically this situation doesn’t occur and if it occurs, it’s no real disaster, as only the latest change isn’t saved. The user should just make the change again et voila! If you really want to avoid this, you can build extra logic into the script by comparing the modified timestamp of the bmp and dat files at logoff time to those of logon time (so at logon you should save this information somewhere).

 

One last thing: another caveat is the fact the last logoff wins (imagine a situation where you’re logged in at different systems simultaneously). Most of the time that’s what you probably want, but in some cases you might prefer a situation where the change only gets saved if it’s newer than what’s on the home drive.

 

My preferences were obviously the simplest ones, so I was lucky J I hope you are too!

 

Ok, so here is the script. Don’t forget to digitally sign the script with a code signing certificate that’s a trusted publisher on the systems the script is supposed to run, if the PowerShell execution policy is set to AllSigned or RemoteSigned. If the policy is set to Restricted, the script will never work. I recommend AllSigned, although RemoteSigned is acceptable too in some environments (but I would (almost) never recommend Unrestricted!). If you don’t know what I’m talking about, it’s a good idea to start learning those things (go ahead, start Binging ;-)); and if you really, really, don’t want to do so, perhaps you can rewrite the script to VBScript…?

 

Load user account picture.ps1

if((Test-Path “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).dat”) -and (Test-Path “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).bmp”))

{

    Copy-Item “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).dat” “$(cat env:\PROGRAMDATA)\Microsoft\User Account Pictures”

    Copy-Item “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).bmp” “$(cat env:TMP)\$((@(Get-ChildItem $(cat env:TMP)))[0])”

}

 

Save user account picture.ps1

if((Test-Path “$(cat env:\PROGRAMDATA)\Microsoft\User Account Pictures\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).dat”) -and (Test-Path “$(cat env:TMP)\$((@(Get-ChildItem $(cat env:TMP)))[0])\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).bmp”))

{

    if(!(Test-Path “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture”))

    {

        New-Item -ItemType directory -Path “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture”

    }

    Copy-Item “$(cat env:\PROGRAMDATA)\Microsoft\User Account Pictures\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).dat” “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture”

    Copy-Item “$(cat env:TMP)\$((@(Get-ChildItem $(cat env:TMP)))[0])\$(cat env:\USERDOMAIN)+$(cat env:\USERNAME).bmp” “\\dg3.be\alp\Users\$(cat env:\USERNAME)\User Account Picture”

}

 

Here you see an example of the script being used as a logon script. Because I have whitespaces in my path I had to embrace the whole path with double quotes.

 

Figure 11

 

Hmm… well, perhaps one last idea to end with. You could skip the logoff script and change the logon script in such a way pictures are loaded from certain sources, like Active Directory (AD) or SharePoint. This way you can enforce the picture used and still make it personalized (but not in the sense that users can change it and keep that change). Oh well, it all depends… indeed, on what you want! J

 

Links:

 

 

Greetings,

Pedro

 

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s