Setting Locale and Timezone in Bulk

Hi All,

I’ve recently come up with a way to set the Locale and Timezone settings for users in SCSM in bulk via PowerShell and thought I would share it with you all. It’s based on the post by Travis over at the engineering team blog here, and I’ve added some things so it will set the timezone and locale settings for users already in the CMDB.

The script works by first retrieving all users from the CMDB, then running through each user and creating creating a CSV string containing some identifying strings and timezone/locale settings, adding all of these strings into a CSV file, and once the file is complete uses the import CSV cmdlet to create a new localisation preference record for each user in the CMDB. Once the new records have been created it clears out any blank localisation records that have been automatically created for the users during the AD import.

In order to run the script you need to have the SMLets module installed and working ( and it also uses the SMCmdLetSnapin that comes with an SCSM install. The example I am posting here also requires the directory C:\SMAdmin\CSV\ be present on the server, but that can be updated to suit your requirements. There are 3 files involved in this solution: the PowerShell script itself (Set-Locale.ps1), the CSV file that gets updated and imported (Users.csv), and the XML import mapping file that tells SCSM what to do with the CSV file (UserImport.xml).

I’ll start by posting the entire PowerShell script and then go through the salient points.

Import-Module smlets ; 
Add-PSSnapIn SMCmdletSnapIn ;

#Delete any existing data from the CSV
Clear-Content -Path "C:\SMAdmin\CSV\Users.csv"

#retrieve all users from the CMDB and cycle through them
$users = (get-scsmclass Microsoft.AD.User$ | get-scsmobject)
foreach ($user in $users)
        $UserName = $user.UserName               #get the username, used to identify the person
        $Domain = $user.Domain                   #get the domain, this is required for a CSV import
        $ID = $user.ID                           #get the users guid, we will use this to create the ID for the settings object
        $setPref = 'Pref.'                       #used as a prefix for the localsetting object id
        $setID = $setPref,$ID         
        $setID = [string]::join('',$setID)       #combine the users guid and Pref. to make the id for localesettings
        $timezone = 'AUS Eastern Standard Time'  #set timezone
        $locale = '1033'                         #setting the locale, in this case it's English (United States)
        $data = $UserName, $Domain, $setID, $timezone, $locale  #put it all into an array
        [string]::join(',',$data) | ForEach-Object {Add-Content -Value $_ -Path "C:\SMAdmin\CSV\Users.csv"};   #convert the array to a string and append to the csv

#once all users have been added to the csv, import it into the CMDB using the xml mapping file.
Import-SCSMInstance -DataFileName "C:\SMAdmin\CSV\Users.csv" -FormatFileName "C:\SMAdmin\CSV\UserImport.xml"

#Remove any automatically created localization settings, the script has create new ones for everybody
get-scsmclass System.UserPreference.Localization$ | get-scsmobject -filter {DisplayName -notlike "%-%"} | remove-scsmobject -force

Remove-PSSnapIn SMCmdLetSnapIn;
Remove-Module smlets;

In this particular script I am setting all users to the English (United States) language setting, primarily so I don’t need to localise management pack content to get nice enumeration values in notifications. I’m also setting everyone to Australian Eastern Standard time because I’m in Sydney. If, however, I wanted to set the locale and timezone to a different value depending on what country or city a user is in I would be able to do so by retrieving those values for the user from the CMDB and then running through some if statements to set the values accordingly. So where my script currently reads

$timezone = 'AUS Eastern Standard Time'  #set timezone

and I wanted to set timezones for users in different cities, I could change it to read something like

if ($user.City -like "Perth") {$timezone = 'AUS Western Standard Time'}
elseif ($user.City -like "Adelaide") {$timezone = 'AUS Central Standard Time'}
else {$timezone = 'AUS Eastern Standard Time'}

here I have checked to see if the user is in Perth or Adelaide and set their timezones if they are (I made those codes up btw), and if they aren’t in those 2 cities I know they are in Sydney so I default to that timezone.

Alternatively I might be supporting more than one country and so need to set the language for all of my users based on their country, in this case I change the line

$locale = '1033'   #setting the locale

to have some conditional logic that looks at the country and sets the language code (Language Code table here) accordingly

if ($user.Country -like "New Zealand") {$locale = '5129'}
else {$locale = '3081'}

here I’m looking at the users country entry and if it is New Zealand I set the New Zealand Locale ID, and then default to Australia’s (these ones are real codes).

That covers the PowerShell side of things. The other important file is the XML mapping file, if all you are doing is using it for this purpose then you shouldn’t need to change it at all; an important thing to note is that the order of the fields in the CSV and the XML file have to match up so use caution if editing this file. I will post the contents here for reference

	<Projection Type="System.User.Projection">
			<Class Type="System.Domain.User">
				<Property ID="UserName"/>
				<Property ID="Domain"/>
		<Component Alias="Preference">
				<Class Type="System.UserPreference.Localization">
					<Property ID="Id"/>
					<Property ID="Timezone"/>
					<Property ID="LocaleID"/>

So that is basically it, once you have the script running as you want it you can follow Travis’s excellent instructions for scheduling it via a workflow in SCSM.

The solution is available for download here


This is my new blog dedicated to SCSM.


Get every new post delivered to your Inbox.