Как сохранить файл из 1С на сервер или сетевую папку, если у пользователя сервера нет прав доступа?

Программист 1С v8.3 (Управляемые формы) IT и автоматизация бизнеса
← На главную

В практике разработки на платформе 1С:Предприятие мы часто сталкиваемся с задачами интеграции, когда необходимо выгрузить файл (например, выполнить выгрузку движений документа в XML, сформировать файл Excel или текстовый лог) в определенную папку. Казалось бы, задача тривиальная, особенно если использовать готовые инструменты для копирования файлов и каталогов между клиентом и сервером. Однако, как только мы переходим от файлового варианта работы к клиент-серверному, и особенно когда целевая папка находится на другом сетевом ресурсе, возникают ошибки доступа. В этой статье мы подробно разберем, почему возникают такие проблемы, почему стандартные методы 1С не помогают, и как обойти ограничения, когда системные администраторы отказываются выдавать прямые права.

Понимаем корень проблемы: от чьего имени работает код?

Прежде чем искать решение, давайте разберемся в архитектуре процесса. Когда мы работаем в управляемых формах и выполняем код на сервере (в директивах компиляции &НаСервере, &НаСервереБезКонтекста), этот код выполняется процессом сервера приложений 1С — обычно это rphost.exe. Это критично, когда требуется, например, экспорт документов базы в JSON для интеграции с внешними системами.

Операционная система Windows (или Linux) воспринимает этот процесс не как "пользователя Ивана, запустившего 1С", а как пользователя операционной системы, под которым запущена служба "Агент сервера 1С:Предприятия". Чаще всего это локальный служебный пользователь USR1CV8 или системная учетная запись Local System.

Проблема возникает в двух случаях:

  1. Локальная папка с ограниченным доступом: Служба сервера 1С не имеет прав NTFS на запись в конкретную папку на том же сервере.
  2. Сетевая папка (шара): Служба сервера работает под локальным пользователем (например, SERVER1\USR1CV8). Когда этот пользователь пытается обратиться к сетевому пути \\FILESERVER\Exchange, удаленный сервер его не знает, так как этот пользователь существует только локально. Доступ блокируется.

Миф о Привилегированном режиме

Многие разработчики ошибочно полагают, что использование конструкции УстановитьПривилегированныйРежим(Истина) решит проблему доступа к файлам. Давайте развеем этот миф.

Привилегированный режим в 1С отключает проверку:

Однако этот режим никак не влияет на права операционной системы. Код 1С не может приказать Windows игнорировать настройки безопасности файловой системы. Если у пользователя ОС, под которым запущен rphost.exe, нет прав на запись в папку, 1С получит отказ в доступе ("Access denied"), даже если включен привилегированный режим.

Решение 1: Подключение сетевого ресурса через WScript (Наиболее надежный метод)

Если администраторы отказываются давать права пользователю, под которым работает сервер 1С (или это технически невозможно из-за отсутствия пользователя в домене), нам придется авторизоваться на сетевом ресурсе "на лету" прямо из кода 1С. Это часто необходимо для подготовки данных и последующего импорта данных из форматов XLS, XLSX, TXT или CSV в другие системы.

Для этого мы воспользуемся COM-объектом WScript.Network, который позволяет подключить сетевой диск или просто авторизоваться на ресурсе, используя переданные логин и пароль.

Рассмотрим алгоритм действий:

  1. Создаем COM-объект.
  2. Подключаем сетевой ресурс, передавая имя пользователя и пароль, у которых есть права.
  3. Выполняем запись файла.
  4. Отключаем ресурс (необязательно, но рекомендуется для порядка).

Посмотрим на пример реализации функции записи:


&НаСервере
Процедура ЗаписатьФайлВЗащищеннуюСетевуюПапку()
    
    ПутьКРесурсу = "\\Server\HiddenShare";
    Логин = "Domain\UserWithRights";
    Пароль = "SuperSecretPass123";
    ИмяФайла = "export_data.txt";
    
    // Попытка создать COM-объект для работы с сетью
    Попытка
        WshNetwork = Новый COMОбъект("WScript.Network");
    Исключение
        Сообщить("Не удалось создать WScript.Network: " + ОписаниеОшибки());
        Возврат;
    КонецПопытки;
    
    // Подключаем сетевой ресурс.
    // Параметры MapNetworkDrive:
    // 1. Буква диска (пустая строка "", если не хотим занимать букву, но это работает не всегда стабильно, лучше использовать NET USE)
    // Однако MapNetworkDrive чаще используют для создания буквы диска.
    // Альтернативный и более надежный вариант для простого доступа без буквы - использование команды NET USE через WScript.Shell (см. ниже)
    // Но если мы хотим использовать именно WScript.Network для маппинга:
    
    БукваДиска = "Z:";
    
    // Сначала попробуем отключить диск, если он вдруг завис от прошлой сессии
    Попытка
        WshNetwork.RemoveNetworkDrive(БукваДиска, Истина, Истина);
    Исключение
        // Игнорируем ошибку, если диска не было
    КонецПопытки;
    
    Попытка
        // Подключаем диск с авторизацией
        WshNetwork.MapNetworkDrive(БукваДиска, ПутьКРесурсу, Ложь, Логин, Пароль);
        
        // Теперь мы можем писать в Z:\
        ТекстДок = Новый ТекстовыйДокумент;
        ТекстДок.УстановитьТекст("Важные данные для выгрузки");
        
        ПолныйПуть = БукваДиска + "\" + ИмяФайла;
        ТекстДок.Записать(ПолныйПуть, КодировкаТекста.UTF8);
        
        Сообщить("Файл успешно записан: " + ПолныйПуть);
        
        // Отключаем диск после работы
        WshNetwork.RemoveNetworkDrive(БукваДиска, Истина, Истина);
        
    Исключение
        Сообщить("Ошибка при работе с сетевым ресурсом: " + ОписаниеОшибки());
        // Пытаемся почистить за собой в случае ошибки
        Попытка WshNetwork.RemoveNetworkDrive(БукваДиска, Истина, Истина); Исключение КонецПопытки;
    КонецПопытки;

КонецПроцедуры

Решение 2: Использование команды NET USE через WScript.Shell

Иногда метод MapNetworkDrive может быть неудобен, так как требует свободной буквы диска, а в многопоточной серверной среде это может вызвать коллизии (если разные фоновые задания попытаются занять букву Z:). Более гибкий способ — использовать команду CMD net use для авторизации на ресурсе без назначения буквы диска.

Разберем, как это сделать с помощью объекта WScript.Shell.


&НаСервере
Процедура ЗаписатьЧерезNetUse()

    ПутьКШаре = "\\192.168.1.50\Exchange";
    Логин = "MyDomain\UserWrite";
    Пароль = "Pa$$word";
    
    Шелл = Новый COMОбъект("WScript.Shell");
    
    // Формируем команду подключения.
    // /delete нужен, чтобы разорвать старые подключения к этому ресурсу, если они "зависли"
    // >nul 2>&1 скрывает вывод команды, чтобы не засорять логи, но для отладки можно убрать
    КомандаУдаления = "net use """ + ПутьКШаре + """ /delete /y";
    Шелл.Run(КомандаУдаления, 0, Истина);
    
    // Команда подключения
    КомандаПодключения = "net use """ + ПутьКШаре + """ """ + Пароль + """ /user:""" + Логин + """";
    
    КодВозврата = Шелл.Run(КомандаПодключения, 0, Истина);
    
    Если КодВозврата <> 0 Тогда
        Сообщить("Ошибка подключения к сетевой папке. Код ошибки: " + КодВозврата);
        Возврат;
    КонецЕсли;
    
    // Теперь, когда соединение установлено, процесс сервера 1С имеет доступ к пути
    Попытка
        Текст = Новый ТекстовыйДокумент;
        Текст.ДобавитьСтроку("Проверка записи");
        Текст.Записать(ПутьКШаре + "\test_file.txt");
        Сообщить("Запись прошла успешно!");
    Исключение
        Сообщить("Ошибка записи: " + ОписаниеОшибки());
    КонецПопытки;
    
    // Отключаемся (хороший тон)
    Шелл.Run(КомандаУдаления, 0, Истина);

КонецПроцедуры

Важные нюансы метода:

Решение 3: Архитектурные обходные пути (Без паролей в коде)

Если служба безопасности запрещает хранить пароли в коде 1С, нам придется изменить подход к передаче файлов. Рассмотрим варианты, когда мы не пробиваемся через права, а обходим их.

Вариант А: Использование FTP

Если целевой сервер поддерживает FTP, это идеальный вариант. Права на доступ к файловой системе сервера регулируются самой службой FTP, и пользователь 1С (как процесс ОС) здесь не участвует. Мы используем встроенный объект FTPСоединение.


// Пример записи через FTP
Соединение = Новый FTPСоединение("server_address", 21, "ftp_user", "ftp_pass");
Соединение.УстановитьТекущийКаталог("/upload/");
Соединение.Записать(ЛокальныйПутьКВременномуФайлу, "remote_file.txt");

Вариант Б: "Папка обмена" и скрипт-перекладчик

Это классический паттерн интеграции в закрытых контурах безопасности. Вместо того чтобы мучиться с сетевыми путями, можно использовать O-Bridges для простого обмена данными между базами 1С и сторонними приложениями. Если же вы настраиваете процесс вручную, схема выглядит так:

  1. Создается локальная папка на сервере 1С, куда у пользователя USR1CV8 есть полные права (например, C:\Exchange1C\).
  2. 1С просто сохраняет файлы туда. Это никогда не вызывает ошибок доступа. Так может быть реализована даже массовая выгрузка картинок номенклатуры в каталог.
  3. Системный администратор настраивает Планировщик задач (Task Scheduler).
  4. Задача запускает скрипт (PowerShell или .bat) от имени привилегированного доменного пользователя.
  5. Скрипт забирает файлы из C:\Exchange1C\ и перемещает их в целевую защищенную сетевую папку.

Этот метод полностью снимает головную боль с правами доступа с программиста 1С и перекладывает ответственность за доставку файла на администраторов.

Выводы

Давайте резюмируем. Если вы столкнулись с ошибкой доступа при записи файла на сервере:

  1. Не тратьте время на ПривилегированныйРежим — он не поможет с правами файловой системы.
  2. Если возможно, попросите администраторов дать права пользователю, под которым запущена служба сервера 1С.
  3. Если это невозможно (сетевая шара, недоменный пользователь), используйте WScript.Network или net use для временной авторизации.
  4. Если хранение паролей в коде недопустимо — используйте FTP или промежуточную папку обмена.
← На главную