#Область ОбластьПараметров
// Параметры процедуры обновления
var now = new Date();
var outFileName = "log" + now.valueOf() + ".txt"; // Путь к log-файлу
var v8exe = [ИмяИсполняемогоФайлаПрограммы]; // Путь к исполняемому файлу 1С:Предприятия 8
var v8exeEnterprise = [ИмяФайлаЗапускаПриложенияВРежимеПредприятия]; // Путь к исполняемому файлу 1С:Предприятия 8 для запуска тонкого или толстоко клиентов
var infoBasePath = [ПараметрПутиКИнформационнойБазе]; 
var BaseFileName = [СтрокаПутиКФайлуИнформационнойБазы]; 
var connectionString = [СтрокаСоединенияИнформационнойБазы] +'UC=РезервноеКопирование'; 
var infoBaseAuthorization = [ПараметрыАутентификацииПользователя]; 
var backupFileName = [КаталогРезервнойКопии]+'.zip';  // Файл резервной копии
var UseRestore = [ВосстанавливатьИнформационнуюБазу];  // Использовать восстановление ИБ в случае падения
var createBackup = [СоздаватьРезервнуюКопию]; // создавать резервную копию
var eventLogID = [СобытиеЖурналаРегистрации];
var adminName = [ИмяАдминистратораОбновления];	// имя администратора, инициировавшего обновление
var doBlockUsers = [БлокироватьСоединенияИБ];  // устанавливать блокировку соединений перед обновлением
var comConnectorName = [ИмяCOMСоединителя];  // имя COM-класса для работы с 1С:Предприятием 8 через COM-соединение
var useComConnector = [ИспользоватьCOMСоединитель];  // флаг использования COM-соединения для работы с 1С:Предприятием 8
var typeReserveCopying = [ТипРезервногоКопирования];  // Тип Резервного копирования: "1" - прямо сейчас, "2" - отложенное, "3" - при завершении работы.
var tempLogFileName = "templog.txt";
#КонецОбласти

#Область ОбластьРезервногоКопирования
var oFileSystemObject = new ActiveXObject("Scripting.FileSystemObject");

var thisFileName;
var thisFileDir;

if (oHTA != null)
{
	thisFileName = eval("oHTA.commandLine");
	thisFileDir = thisFileName.substr(1, thisFileName.lastIndexOf("\\")-1);
}
else
{
	thisFileName = eval("WScript.ScriptFullName");
	thisFileDir = thisFileName.substr(0, thisFileName.lastIndexOf("\\")-1);
}
var oShell = new ActiveXObject("WScript.Shell"); 
var oShellApplication = new ActiveXObject("Shell.Application");
oShell.CurrentDirectory = thisFileDir;

var errorMarker = "{ERR}";
var successMarker = "{OK }";

// Переменные состояния
var backupCreated = false;
var connectionsDenied = false;
var logging1C = false;
var ComConnection = null;

// Переменные состояния функции doDisconnectAndBlockUsersHTA()
var disconnectionStep = 0;
var connection = null;
var disconnectionInterval;
var disconnectionStartDateTime;

// Открыть файл sFilePath.
function runApp(sFilePath, sFileArgs, show, bWaitOnReturn) 
{ 
	if (bWaitOnReturn == undefined)
	    bWaitOnReturn = false;
	if (show == undefined)
	    show = SW_SHOW;
	if (sFileArgs == undefined)
	    sFileArgs = "";
	var ret = 1;
	log(format("Запускается: {0}; параметры: {1}; окно: {2}; ожидание: {3}", 
	    sFilePath, sFileArgs, SWtoString(show), bWaitOnReturn));
	if (oFileSystemObject.FileExists(sFilePath))
	{
        try
        {
	        ret = oShell.Run(format('"{0}" {1}', sFilePath, sFileArgs), show, bWaitOnReturn); 
	    }
        catch(e) 
        { 
            log(format("Исключение в runApp: {0}, {1}.", e.name, e.message), true);
            return 1;
        }
   		log(format("Код возврата: {0}", ret), ret != 0);
   		return ret;
    }
    else
		log(format("Запускаемый файл не существует: {0}", sFilePath), true);
	return ret;
}

function clearLogFile()
{
    var outFile = oFileSystemObject.OpenTextFile(outFileName, ForWriting, true, TristateTrue);
    outFile.Close();
}

// Записать текст в лог
function log(text, failed)
{
	if (failed == undefined)
	    failed = false;
	logFile(text, failed);
}

// Записать текст в лог-файл
function logFile(text, failed)
{
	var now = new Date();
    var f;
    try
    {
        f = oFileSystemObject.OpenTextFile(outFileName, ForAppending, true, TristateTrue);
    }
    catch(e) { return; }    
	try
	{
    	var status = (failed == false ? successMarker : errorMarker);
	    f.WriteLine(format("{0} {1} {2}", now, status, text));
	}
	finally
	{
	    try
	    {
	        f.Close();
	    }
	    catch(e) { return; }
	}
}

// Записать текст из временного лог-файла
function appendLog()
{
	var f;
	var outf;
	var text;
	try
	{
		f = oFileSystemObject.OpenTextFile(tempLogFileName, ForReading, false, TristateFalse);
		outf = oFileSystemObject.OpenTextFile(outFileName, ForAppending, true, TristateTrue);
	}
    catch(e) { return; }    
    try
    {
    	var oldAtEndOfStream = f.AtEndOfStream;
		if (!oldAtEndOfStream)
		{
			text = f.ReadAll();   	
			outf.WriteLine(text);   
		}
	}
	finally
	{
		try
		{
			f.Close();
			outf.Close();
		}
	    catch(e) { return; }
    }
}

// Записать текст в журнал регистрации
function log1C(text, failed)
{
    if (logging1C)
        return;
    var connection = createConnection();
    if (connection == null)
        return;
    try
    {
        log1CInternal(connection, text, failed);
    }
    finally
    {
        connection = null;
    }
}

// Записать текст в журнал регистрации
function log1CInternal(connection, text, failed)
{
    if (logging1C)
        return;
    logging1C = true;
    try
    {
        try
        {
            var eventLogLevel = failed ? connection.EventLogLevel.Error : connection.EventLogLevel.Information;
            connection.WriteLogEvent(eventLogID, eventLogLevel, null, null, text, 
                connection.EventLogEntryTransactionMode.Independent);
        }
        catch(e) 
        { 
            log(format("Исключение в log1CInternal: {0}, {1}.", e.name, e.message), true);
            return;
        }
    }
    finally
    {
        logging1C = false;
    }
}

// Инициализация
function initialize()
{
    clearLogFile();
    log(format("Файл скрипта: {0}", thisFileName));
    log(format("Файл резервной копии: {0}", backupFileName));
     return 0; 
}

// Финализация
function finalize(success)
{
   
   var TestFolder = oShellApplication.NameSpace(backupFileName);

    if (success == undefined)
        success = false;
        
   if (!(oFileSystemObject.FileExists(backupFileName)))
   
  	 	log("Внимание!!! Произошла ошибка при создании резервной копии ИБ. Для диагностики запустите резервное копирование вручную");
  	 
  
  
   if (TestFolder!= null) 
  	    log("Резервная копия успешно создана");
   if (TestFolder== null) 
   		{
  	 	log("Внимание!!! Произошла ошибка при создании резервной копии ИБ. Для диагностики запустите резервное копирование вручную");
  	 	success = false;
  	 	}


    // Запись результата обновления в Event Log
    writeEventLog(success);

    if (!success)
    {
        allowConnections(false); // Разрешение подключений
    }
      	
      	 	 
    write1CEventLog();      // Запись всей информации из log-файла в журнал регистрации
    setResult(success);
        
}
	
function createConnection()
{
    if (!useComConnector)
    	return null;
    
    if (!ComConnection == null)	
    	return ComConnection;
    		
    try
    {
        var ComConnector = new ActiveXObject(comConnectorName);
        ComConnection = ComConnector.Connect(connectionString);
        return ComConnection;
    }
    catch(e)
    {
        log(format("Исключение в createConnection: {0}, {1}", e.name, e.message), true);
        return null;
    }
    
}

// Записать весь log-файл в журнал регистрации
function write1CEventLog()
{
    if (!oFileSystemObject.FileExists(outFileName))
        return;
        
    var connection = createConnection();
    if (connection == null)
        return;
    try
    {
        var f = oFileSystemObject.OpenTextFile(outFileName, ForReading, false, TristateTrue);
        
        var text;
        while (!f.AtEndOfStream)
        {
            text = f.ReadLine();
            while ((text.indexOf(successMarker) < 0) && (text.indexOf(errorMarker) < 0) && !f.AtEndOfStream)
               text += "\n" + f.ReadLine();

            var failed = text.indexOf(errorMarker) > 0;
            log1CInternal(connection, text, failed);
        }
    }
    catch(e) 
    { 
        log(format("Исключение в write1CEventLog: {0}, {1}.", e.name, e.message), true);
        return;
    }
    finally
    {
        connection = null;
    }
}

function doSetResult(success)
{
    var connection = createConnection();
    if (connection == null)
        return (useComConnector ? 1 : 0);
    var res = 0;
    try
    {
        connection.РезервноеКопированиеИБСервер.ЗавершитьРезервноеКопирование(success,backupFileName);
    }
    catch(e)
    {
        log(format("Исключение при вызове РезервноеКопированиеИБСервер.ЗавершитьРезервноеКопирование: {0}, {1}.", e.name, e.message), true);
        res = 2;
    }
    return res;
}


// Передать в приложение результат выполнения 
function setResult(success)
{
    var result = doSetResult(success);
    CollectGarbage();   // освобождает соединения с COM-объектом
    return result;
}

// Записать результат выполнения процедуры обновления в Event Log
function writeEventLog(success)
{
    try
    {
        var eventKind = success ? EVENT_SUCCESS : EVENT_CRITICAL;
        var message;
        if (success)
            message = "Резервное копирование базы провелось успешно.";
        else
            message = "Ошибка при резервном копировании информационной базы.";
        message += format(" Параметры информационной базы: {0}.", infoBasePath);
        if (!success)
            message += " Протокол резервного сохранен в журнал регистрации.";
        oShell.LogEvent(eventKind, message);
    }
    catch(e)
    {
        log(format("Исключение в writeEventLog: {0}, {1}.", e.name, e.message), true);
    }
}

// Cоздание резервной копии информационной базы
function backupDB()
{   
	try
	{
    
	var NewTextFile = oFileSystemObject.CreateTextFile(backupFileName,false);
	
	NewTextFile.Write(String.fromCharCode(80,75,5,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0));
	NewTextFile.Close();
	
	var ZIPFile = oFileSystemObject.GetAbsolutePathName(backupFileName);
	var dFolder = oShellApplication.NameSpace(ZIPFile);
   	var file = oFileSystemObject.GetAbsolutePathName(BaseFileName);
	var FolderNameSpace = oFileSystemObject.GetParentFolderName(file);
	var Folder = oShellApplication.Namespace(FolderNameSpace);
	var FolderItemNameSpace = oFileSystemObject.GetFileName(file);
	var FolderItem = Folder.ParseName(FolderItemNameSpace);
	
	if (!createBackup)
		return 0;
		
	dFolder.CopyHere(file);
	
	ret = 0;
   	log(format("Попытка создания резервной копии", ret), ret != 0);
	}
	catch(e)
	{
		alert(e.message);
		CollectGarbage();   // предотвращает исключение out of memory
		log(format("Исключение при создании резервной копии базы", e.name, e.message), true);
		ret = -1;
	}
	if (ret == 0)
	    backupCreated = true;  
	
	return ret;
}

function WaitUntilFinish()
{
	var connection = createConnection();
    if (connection == null)
	    return (useComConnector ? 1 : 0);
	    
	FileSize = connection.РезервноеКопированиеИБСервер.ОпределитьРазмерФайлаСКопией(backupFileName)    
	
	connection = null;
	
	if (FileSize < 5)
		return -1;
		
    return 0;
}


function doAllowConnections(updateAndFillDB)
{
    if (updateAndFillDB == undefined)
        updateAndFillDB = false;
        
    var connection = createConnection();
    if (connection == null)
        return (useComConnector ? 1 : 0);
    
 
	
	    try
	    {
	        connection.СоединенияИБ.РазрешитьРаботуПользователей();
	        connectionsDenied = false;
	    }
	    catch(e)
	    {
	        CollectGarbage();   // предотвращает исключение out of memory
	        log(format("Исключение при вызове СоединенияИБ.РазрешитьРаботуПользователей: {0}, {1}.", e.name, e.message), true);
	        return 3;
	    }
    return 0;
}

// Первоначальное заполнение информационной базы, разрешение подключений новых соединений, 
// и оповещение о результате обновления
function allowConnections(updateAndFillDB)
{
    var result = doAllowConnections(updateAndFillDB);
    CollectGarbage();   // освобождает соединения с COM-объектом
    return result;
}

function doDisconnectAndBlockUsersHTA(connection)
{
    if (connection == null)
        return 1;
    var result = 0;
    try
    {
    	while (true)
    	{
    	    switch(disconnectionStep)
    	    {
    	        case 0: 
    	        {
    	            connection.СоединенияИБ.УстановитьБлокировкуСоединений("в связи с необходимостью резервного копирования информационной базы.", 
	                               														"РезервноеКопирование");
                    disconnectionInterval = connection.СоединенияИБ.ПараметрыБлокировкиСеансов().ИнтервалОжиданияЗавершенияРаботыПользователей * 1000;
                    disconnectionStartDateTime = connection.СоединенияИБ.ПараметрыБлокировкиСеансов().Начало;
                    if (connection.ЗначениеЗаполнено(disconnectionStartDateTime))
    	                disconnectionStep++;    
                    else
                        disconnectionStep += 2;
    	            break;
                }
                case 1:
                {
                    if (!connection.СоединенияИБ.УстановленаБлокировкаСоединений() || 
                        connection.ПолучитьСеансыИнформационнойБазы().Количество() <= 1)
                    {
                        disconnectionStep++;
                        break;
                    }
                    
                    var now = new Date();
                    if (now - disconnectionInterval <= disconnectionStartDateTime)
                        return -1;
                    disconnectionStep++;
    	            break;
                }
                case 2:
                {
                    if (!connection.СоединенияИБ.УстановленаБлокировкаСоединений())
                    {
                        log("Попытка завершения работы пользователей завершилась безуспешно: отменена блокировка ИБ.", true);
                        return 3;
                    }

	                if (connection.ПолучитьСеансыИнформационнойБазы().Количество() <= 1)
	                    return 0;
	                
	                // после начала блокировки сеансы всех пользователей должны быть отключены	
	                // если этого не произошло пробуем принудительно прервать соединение.
                    doDisconnectConnections(connection);
                    if (connection.ПолучитьСеансыИнформационнойБазы().Количество() > 1)
                    {
		                connection.СоединенияИБ.РазрешитьРаботуПользователей();
		                var message = connection.СоединенияИБ.ПолучитьНазванияСоединенийИБ("Не удалось отключить соединения:");
		                log(message, true);
		                return 3;
                    }   
                    return 0;
                }
            }
        }
    }
    catch(e)
    {
        CollectGarbage();   // предотвращает исключение out of memory
        log(format("Исключение при вызове doDisconnectAndBlockUsersHTA: {0}, {1}.", e.name, e.message), true);
        result = 2;
    }
    return result;
}

// Завершение работы пользователей и запрет на подключение новых соединений 
// Возвращает:
//   -1           - выполнение отложено, необходимо повторить вызов функции через 18 секунд
//   0            - функция выполнена успешно
//   другое число - код ошибки
//  
function disconnectAndBlockUsersHTA()
{
    if (!doBlockUsers)
    {
        connectionsDenied = true;
        return 0;
    }
    if (disconnectionStep == 0)
    {
        connection = createConnection();
        if (connection == null && useComConnector)
            return 1;
    }
    var result = -1;
    if (useComConnector)
	    try
	    {
	        result = doDisconnectAndBlockUsersHTA(connection);
	    }
	    finally
	    {
	        if (result != -1)
	        {
	            connection = null;
	            CollectGarbage();   // освобождает соединения с COM-объектом
	        }
	    }
	else
		result = 0;
    if (result == 0)
        connectionsDenied = true;
    return result;
}

function doDisconnectAndBlockUsers()
{
    var connection = createConnection();
    if (connection == null)
        return (useComConnector ? 1 : 0);
    var result = 0;
    try
    {
    	connection.СоединенияИБ.УстановитьБлокировкуСоединений("в связи с необходимостью резервного копирования информационной базы.", 
	                               								"РезервноеКопированиеИБ");
    	
        var interval = 0;
        var startDateTime = connection.ПолучитьБлокировкуУстановкиСоединений().Начало;
        var now = new Date();
        
        if (connection.ЗначениеЗаполнено(startDateTime))
            while (now - interval <= startDateTime)
            {
                if (!connection.ПолучитьБлокировкуУстановкиСоединений().Установлена)
                    break;
                if (connection.ПолучитьСеансыИнформационнойБазы().Количество() <= 1)
                    break;
                WScript.Sleep(18 * 1000);
                now = new Date(); 
            }
        
        if (!connection.ПолучитьБлокировкуУстановкиСоединений().Установлена)
        {
            log("Попытка завершения работы пользователей завершилась безуспешно: отменена блокировка ИБ.", true);
            return 3;
        }

	    // после начала блокировки сеансы всех пользователей должны быть отключены	
	    // если этого не произошло пробуем принудительно прервать соединения.
        doDisconnectConnections(connection);
        if (connection.ПолучитьСеансыИнформационнойБазы().Количество() > 1)
        {
		    connection.СоединенияИБ.РазрешитьРаботуПользователей();
		    var message = connection.СоединенияИБ.ПолучитьНазванияСоединенийИБ("Не удалось отключить соединения:");
		    log(message, true);
		    return 3;
        }   
            
        if (result != 0)
            log("Попытка завершения работы пользователей завершилась безуспешно.", true);
    }
    catch(e)
    {
        CollectGarbage();   // предотвращает исключение out of memory
        log(format("Исключение при вызове doDisconnectAndBlockUsers: {0}, {1}.", e.name, e.message), true);
        result = 2;
    }
    return result;
}

function doDisconnectConnections(connection)
{
    var adminParams = connection.СоединенияИБ.ПолучитьПараметрыАдминистрированияИБ();
	connection.СоединенияИБ.ОтключитьСоединенияИБ(adminParams);
}

// Завершение работы пользователей и запрет на подключение новых соединений 
function disconnectAndBlockUsers()
{
    var result = 0;
    if (doBlockUsers)
	    result = doDisconnectAndBlockUsers();
    CollectGarbage();   // освобождает соединения с COM-объектом
    if (result == 0 && doBlockUsers)
        connectionsDenied = true;
    return result;
}



// Интерактивный запуск "1С:Предприятие"
function runEnterprise()
{
	if (typeReserveCopying != "3") {
		return runApp(v8exeEnterprise, format('ENTERPRISE {0} {1}', infoBasePath, infoBaseAuthorization ), SW_SHOW, false);
	}
}
#КонецОбласти

