ShS's Blog

Just another sysadmin's weblog

Скрипт для массового изменения учетных записей электронной почты в Outlook Express и Microsoft Outlook.

Posted by shs на 2010/01/05

Мне несколько раз за свою карьеру системного администратора приходилось выполнять миграцию учетных записей из одного домена в другой при помощи ADMT. Этот процесс хорошо и подробно описан в документах Microsoft, например: в “ADMT v3.1 Guide: Migrating and Restructuring Active Directory Domains”

Но одной миграцией учетных записей AD дело не всегда ограничивается, зачастую требуется перенастройка пользовательского окружения для смигрированных пользовательских учетных записей. Так, однажды, необходимо было решить задачу по массовому изменению настроек учетных записей электронной почты в Outlook Express и Microsoft Outlook: требовалось изменить в учетных записях электронной почты имя SMTP и IMAP серверов. (Вопрос — «почему нельзя было внести изменения в DNS, вместо того, чтобы городить огород с массовым изменением настроек клиентов электронной почты?» — оставим за кадром. ;))

Возможно, что для внесения изменений в учетные записи MS Outlook можно было бы использовать prf-файлы, но совершено точно, что их нельзя было бы использовать для внесения изменений в учетные записи электронной почты Outlook Express. Поэтому я в очередной раз решил обратиться к сриптам и сначала написал простой скрипт для изменения учетных записей Outlook Express, а затем, на его основе, — и чуть более сложный для Microsoft Outlook.

И так, «погуглив» или воспользовавшись Procmon от Русиновича (сейчас уже не помню;)), я выяснил, что параметры реестра, хранящие настройки учетных записей Outlook Express, находятся в разделе HKEY_CURRENT_USER\Software\Microsoft\Internet Account Manager\Accounts

 

Настройки учетных записей, созданных пользователем, расположены в «номерных» подразделах (имеющих название 00000001, 00000002 и т.д.) При создании очередной новой учетной записи Outlook Express в реестре будет создан очередной «последний номерной+1» раздел. При этом не важно, какого типа  («Почты», «Новостей» или «Службы каталогов») учетную запись вы создаете. Так, например, в подразделе реестра HKEY_CURRENT_USER\Software\Microsoft\Internet Account Manager\Accounts0000001 могут храниться параметры учетной записи «Службы каталогов», а  в HKEY_CURRENT_USER\Software\Microsoft\Internet Account Manager\Accounts0000002 – «Почты».

И так, казалось бы, все просто, структура исходных данных понятна, алгоритм — элементарен. Я уже думал, что за пару минут набросаю скрипт на JScript, но тут-то и выяснилось, что «пришла беда, откуда не ждали»: WSH не имеет средств для выполнения перечисления подключей (подразделов) реестра, и для этого придется использовать WMI. И, если на VBScript это не вызывает никаких проблем, так, для того чтобы получить перечень подразделов реестра HKEY_CURRENT_USER\Software\Microsoft\Internet Account Manager\Accounts, можно использовать такой скрипт:

Const HKEY_LOCAL_MACHINE 	= &H80000002
Const HKEY_CURRENT_USER 	= &H80000001

strComputer = "."

Set oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\" & _
    strComputer & "\root\default:StdRegProv")

strKeyPath = "Software\Microsoft\Internet Account Manager\Accounts"
oReg.EnumKey HKEY_CURRENT_USER, strKeyPath, arrSubKeys

For Each subkey In arrSubKeys
    Wscript.Echo subkey
Next

,то на JScript сделать по аналогии не получится, т.к.
«Normally, direct access is adequate to call a WMI provider method. Direct access means executing a method by using object.method syntax. However, in some cases, direct access cannot be used. For example, JScript does not support output parameters so the return value cannot be directly assigned to a variable.» Поэтому, код на Jscript, код будет выглядеть следующим образом:

var WshShell = WScript.CreateObject ("WScript.Shell");
var SubKeys;
var arrSubKeys=new Array ();
var strOutlookAccounts = "Software\\Microsoft\\Internet Account Manager\\Accounts";

var HKEY_LOCAL_MACHINE	= 0x80000002;
var HKEY_CURRENT_USER 	= 0x80000001;

var strComputer = ".";
oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\" + strComputer + "\\root\\default:StdRegProv");

var method = oReg.Methods_.Item("EnumKey");
var inParams = method.InParameters.SpawnInstance_();
inParams.hDefKey = HKEY_CURRENT_USER;
inParams.sSubKeyName = strOutlookAccounts;
var outParams = oReg.ExecMethod_(method.Name, inParams);
arrSubKeys = outParams.sNames.toArray();

for (var i=0;i<arrSubKeys.length;i++)
{
    WScript.Echo(arrSubKeys[i]);
}

Подробнее об этом можно прочитать здесь: Writing WMI Scripts in JScript, Constructing InParameters Objects and Parsing OutParameters Objects

Т.к. кусок кода, который выполняет перечисление разделов реестра нам еще пригодится для  скрипта, работающего с Microsoft Outlook, то логично было бы оформить его в виде функции, что и было проделано, см. функцию function EnumSubKeys (эта функция, как некоторые другие, реализующие работу  с реестром, была опубликована на одном из форумов, к сожалению, ссылку на оригинальный пост автора я сейчас найти не смог, поэтому дам ссылку на копию)

И так, вот и результат: скрипт, выполняющий изменение SMTP и IMAP серверов в учетных записях Оutlook Express

//////////////////////////////////////////////////////////////////////////////////
// shs 20071114
// JScript ChangeOEMailServers.js
// Замена текущих значений SMTP и IMAP серверов в учетных записях Outlook Express
//
// Пример вызова (не реализовано! параметры задаются в теле скрипта, а не передаются в командной строке!):
//cscript ChangeOEMailServers.js <old_SMTP_server> <new_SMTP_server> [<old_IMAP_server> <new_IMAP_server>]
//////////////////////////////////////////////////////////////////////////////////
var WshShell = WScript.CreateObject ("WScript.Shell");
//
var arrAccounts; //
var SubKeys;
var strMailAccounts = "HKCU\\Software\\Microsoft\\Internet Account Manager\\Accounts";
var strComputer = ".";
//
if ((WScript.Arguments.Count()!=4|WScript.Arguments.Count()!=6) & false) //false - заглушка
{
  WScript.Echo ("Ошибка! Неправильное количество аргументов. \n"+
  "Пример вызова: cscript ChangeOutlookSMTPIMAPservers.js <old_SMTP_server> <new_SMTP_server> <old_IMAP_server> <new_IMAP_server> [<old_LDAP_server> <new_LDAP_server>]");
}
else
{
  //Заглушка (пока работаем без параметров командной строки)
  var arrTypeOfServer = new Array ("SMTP Server", "IMAP Server") ; //, "LDAP Server");
  var arrOldServer = new Array();
  var arrNewServer = new Array();
  arrOldServer[0] = "oldmailserver";   // WScript.Arguments.Item(0); //старый SMTP-сервер
  arrOldServer[1] = "oldmailserver";  // WScript.Arguments.Item(2);  //старый IMAP-сервер
//  arrOldServer[2]  = "ldap";  // WScript.Arguments.Item(4); //старый LDAP-сервер
  arrNewServer[0] = "newmailserver";   // WScript.Arguments.Item(1); //новый SMTP-сервер
  arrNewServer[1] = "newmailserver";  // WScript.Arguments.Item(3);  //новый IMAP-сервер
//  arrNewServer[2]  = "ldap";   // WScript.Arguments.Item(5); //новый LDAP-сервер

  var strOldLDAPServer, strNewLDAPServer;
  strOldLDAP=strNewLDAP="";

	//Выполняем перечисление учетных записей электронной почты
	arrAccounts = EnumSubKeys(strComputer, strMailAccounts);
	for (var iAccNdx=0;iAccNdx<arrAccounts.length;iAccNdx++)
	{
		for (var iTOSNdx in arrTypeOfServer)
		{
			var strServer=""
			//в каждой учетной записи пытаемся прочитать значение параметра, содержащееся в массиве arrTypeOfServer
			try
			{
				strServer = WshShell.RegRead(strMailAccounts+"\\"+arrAccounts[iAccNdx]+"\\"+arrTypeOfServer[iTOSNdx]);
			}
			catch(e){}
			if (strServer!="")
			{
				if (arrOldServer[iTOSNdx]==strServer)
				{
				  WScript.Echo(strMailAccounts+"\\"+arrAccounts[iAccNdx]+"\\"+arrTypeOfServer[iTOSNdx]);
				  WScript.Echo("Found: " +arrTypeOfServer[iTOSNdx]+" = "+strServer+"...");
					//Заменяем старое название сервера на новое
					WshShell.RegWrite(strMailAccounts+"\\"+arrAccounts[iAccNdx]+"\\"+arrTypeOfServer[iTOSNdx], arrNewServer[iTOSNdx],"REG_SZ");
					WScript.Echo("...and changed to: " +arrTypeOfServer[iTOSNdx]+" = "+arrNewServer[iTOSNdx]+"\n");
				}
			}
		}
	}//end for
}
//------------------------------------------------------------------------------
//Эта функция выполняет перечисление подключей (подразделов) реестра
//(для заданного компьютера и заданного ключа (раздела)  реестра)
//Приходится использовать WMI, т.к. WSH не имеет средств для выполнения данной задачи
function EnumSubKeys (strComputer,RegKey)
{
  var RootKey = new Object()
  RootKey["HKCR"] = RootKey["HKEY_CLASSES_ROOT"]   = 0x80000000;
  RootKey["HKCU"] = RootKey["HKEY_CURRENT_USER"]   = 0x80000001;
  RootKey["HKLM"] = RootKey["HKEY_LOCAL_MACHINE"]  = 0x80000002;
  RootKey["HKUS"] = RootKey["HKEY_USERS"]          = 0x80000003;
  RootKey["HKCC"] = RootKey["HKEY_CURRENT_CONFIG"] = 0x80000005;
  var RootVal = RootKey[RegKey.substr(0, RegKey.indexOf("\\"))]
  if (RootVal != undefined)
  {
  	var oReg=GetObject("winmgmts:{impersonationLevel=impersonate}!\\\\" + strComputer + "\\root\\default:StdRegProv");
  	var method = oReg.Methods_.Item("EnumKey");
  	var inParams = method.InParameters.SpawnInstance_();
	inParams.hDefKey = RootVal;
	inParams.sSubKeyName = RegKey.substr(RegKey.indexOf("\\") + 1);
	var outParams = oReg.ExecMethod_(method.Name, inParams);
	return outParams.sNames.toArray();
  }
}

PS Скрипт немного не доведен до ума (я поленился реализовать передачу параметров из командной строки в скрипт, оставив пару «заглушек» и определив значения входных параметров в теле скрипта), но вполне работоспособный.

Продолжение следует…

Реклама

комментариев 6 to “Скрипт для массового изменения учетных записей электронной почты в Outlook Express и Microsoft Outlook.”

  1. […] WordPress.com « Скрипт для массового изменения учетных записей электр… […]

  2. Дмитрий said

    доброе время суток!

    >Вопрос – «почему нельзя было внести изменения в DNS, вместо того, чтобы городить огород с >массовым изменением настроек клиентов электронной почты?» – оставим за кадром.

    вы имеете ввиду mx-запись в локальной зоне? для меня сейчас очень актуален вопрос автоматической смены адресов pop3, imap, и smtp серверов в настройках outlook express клиентов. Только желательно без применения скриптов. Не могли бы вы немного развить свою мысль про днс?

    • shs said

      Нет, mx запись тут не причем. mx-запись используется почтовыми серверами, а не клиентами. Почтовый клиент испольует тот адрес (или DNS-имя smtp-севрера), который ему было явно указан в конкретной учетной записи электронной почты. Предположим, что у вас в DNS имеется, например, такая запись MyMailServer.mydomain.local A 10.0.0.1, и в учетных записях ваших почтовых клиентов smtp-сервер указан, как MyMailServer.mydomain.local. Вы хотите, что бы ваши клиенты перстали пользоваться сервером 10.0.0.1, а вместо него стали использовать 10.0.0.2. В этом случае все, что вам нужно сделать, это внести изменния в DNS так, чтобы вышеупомянутая A-запись указывала на новый сервер: MyMailServer.mydomain.local A 10.0.0.2. При этом, вам ничего не придется менять на стороне клиента.

      • Дмитрий said

        Спасибо за ответ, действительно все просто )) Можно еще сделать маппинг портов, если первоначально адреса в аутлуках указывали на почтовый сервер на шлюзе.

  3. Владимир said

    Доброе время суток!!!!
    Вопрос — а каким образом можно сменить порты, ни где не могу найти инфу.?

    • shs said

      а вы попробуйте ее (инфу) не найти, но добыть. Используйте procmon от sysinternals, для мониторинга изменений в реестре при смене портов в почтовом клиенте.
      ЗЫ Мой бложек перехал и теперь располагается по адресу http://shserg.ru

Добавить комментарий

Заполните поля или щелкните по значку, чтобы оставить свой комментарий:

Логотип WordPress.com

Для комментария используется ваша учётная запись WordPress.com. Выход / Изменить )

Фотография Twitter

Для комментария используется ваша учётная запись Twitter. Выход / Изменить )

Фотография Facebook

Для комментария используется ваша учётная запись Facebook. Выход / Изменить )

Google+ photo

Для комментария используется ваша учётная запись Google+. Выход / Изменить )

Connecting to %s

 
%d такие блоггеры, как: