Случайны выбор дневника Раскрыть/свернуть полный список возможностей


Найдено 63 сообщений
Cообщения с меткой

vbscript - Самое интересное в блогах

Следующие 30  »
rss_rss_hh_new

Интеграционные возможности easla.com

Понедельник, 16 Мая 2016 г. 14:54 (ссылка)


Ни одна современная система электронного документооборота немыслима без возможности интеграции ее в существующее информационное пространство организации с помощью API или протоколов связи.







Не исключение и easla.com.

Читать дальше →

https://habrahabr.ru/post/300894/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Ревизии и переписка в проектном институте. Интеграция easla.com и TDMS

Четверг, 12 Мая 2016 г. 13:32 (ссылка)

В статье речь пойдет о специфических для проектных предприятий процедурах документооборота, а точнее, об интеграции технического документооборота (у нас – на основе TDMS) и внешней переписки. На предприятиях других типов тоже могут существовать аналогичные потребности, поэтому, если у вас есть вопросы в отношении интеграции или автоматизации с помощью easla.com, статью также имеет смысл прочитать – тут описываются интересные технические детали.



Я собирался выступить на ежегодной конференции в ПАО «Гипротюменнефтегаз», однако из-за сильной текущей загрузки просто не успел подготовиться. Чем не оправдал ожиданий моих знакомых и коллег (ожидалась небольшая публичная дискуссия). Описываемое далее решение не содержит ничего революционного с организационной точки зрения, но, смею надеяться, некоторого внимания оно все же заслуживает.





Несколько начальных пунктов в статье посвящены «Зачем». Далее — «Каким образом» (VBScript, MS SQL + XML). Если больше интересно, каким образом — листайте до 5-го пункта.




1. РЕВИЗИИ. ЧТО ЭТО ТАКОЕ.



Ревизии – это версии документов. Само слово пришло из иностранных стандартов, где ГОСТы 21-й серии распространения не имеют. Там, «у них», на документах в основных надписях есть поле «Rev.», которое, собственно, и расшифровывается как «Revision».

Примечание
Если честно, сами по себе ревизии несколько ущербны. Например, чтобы проектировщику заменить пару листов в документе, нужно выпускать новую ревизию на весь документ. И если в документе 300 страниц… В ГОСТах 21.*, в отличие от ревизий, подробно рассматриваются все возможные ситуации с листами.



С другой стороны, жизнь ведет нас к тому, что передача документов будет выполняться в электронном виде (и, отмечу, это уже так, как минимум, в 60% наших заказов, даже ГлавГосЭкспертиза принимает документацию в электронном виде). А в электронном виде полистно отслеживать изменения, например, в документах Word, мягко говоря, неудобно. В отношении же файлов, например, с 3D-моделями – вообще непонятно, о каких листах может идти речь.



Компании с иностранным участием начали активно внедрять ревизии примерно 3-4 года назад.

Т.е. ревизиям — быть. Больше того, один из наших Заказчиков после получения первых документов с ревизиями (хотя он не предъявлял таких требований) при получении документов без ревизий начал возмущаться. Дальше станет понятно, почему.



В процессе разработки проектной документации проектировщик не просто чертит чертежи. Проектировщик очень активно общается с экспертами Заказчика и с конструкторами заводов-изготовителей. Как в неформальном, так и в формальном виде. Т.е. передает документацию на согласование с сопроводительным письмом, отвечает на замечания, вносит поправки, снова посылает документацию с сопроводительным письмом и т.д.. До победного конца. Пока не согласуют. Каждый разрабатываемый документ.



Правильный способ работы заключается в том, чтобы перед отправкой сдать документ в архив. При сдаче в архив присваивается инвентарный номер и ставится номер изменения на чертеже. Но сдача в архив – процедура длительная, в ней задействовано, как минимум, два других подразделения. Поэтому проектировщики избегают сдачи документации в архив каждый раз при передаче на согласование. И если бы только проектировщики – избегают ГИПы, Главный Инженер, и даже сам Заказчик не заинтересован в том, чтобы задерживать процедуру согласования документации.

Примечание
Зачем же вообще нужна сдача в архив? Дело в том, что есть небольшая, но важная разница между передачей «готовой документации» и передачей «для согласования». Когда передается готовая документация – оформляется накладная. Это накладывает юридические обязательства на Заказчика. И поэтому там точно должно быть все сделано в соответствии с ГОСТ. А вот в части согласования требования, как правило, не такие жесткие – Заказчик прекрасно понимает, что на сдачу в архив уходит время, которое ему так же важно, как и проектному институту.





Т.е. внедрен учет ревизий или нет – обмен «без архива» идет в любом случае. Ставить номер изменения без сдачи в архив тоже нельзя. А в результате возникает путаница. Документация попадает сначала к Заказчику (можно идентифицировать по исходящему номеру письма от Проектировщика), потом – к эксперту (а вот тут уже исходящий номер от Заказчика! Номер письма Проектировщика пропал!). Специалисты Заказчика могут передать (и передают!) разным экспертам (а экспертов у Заказчика немало) документацию разных версий, и понять это невозможно до тех пор, пока не начинается разбор полетов.



Для того, чтобы путаницы не происходило – внедряется учет ревизий. На каждом переданном в электронном или бумажном виде документе написан номер ревизии, дата ее выпуска и комментарий. Т.о., когда проектировщик с экспертом связываются по телефону, по номеру ревизии становится понятно, одинаковые документы они держат в руках, или нет.




2. КАК ОБЫЧНО РАБОТАЮТ С РЕВИЗИЯМИ.



Как ни печально, в большинстве организаций по сию пору обычной ситуацией является «ручная автоматизация». Т.е. функции учета выполняет не машина, а люди. Например, с помощью Excel. В «хорошем» случае есть группа выпуска, которая контролирует процессы передачи документации. В запущенном (что не редкость) – такой группы нет, учет ведут сами проектировщики.



Т.е. для того, чтобы передать документ Заказчику, инженер-проектировщик присваивает номер ревизии, распечатывает документ, идет к начальнику группы, подписывает, потом к главному специалисту, тоже подписывает, потом – к начальнику отдела, потом – к нормоконтролеру, потом, возможно, к согласующим отделам, наконец, к ГИПу, и – может его отсканировать (вручную !!!). После сканирования – нужно составить сопроводительное письмо, подписать его, собрать сканы и передать это все например, помощнику ГИПа или специально выделенному лицу, ответственному за документооборот. Это лицо все проверит, даст Бог – не найдет ошибок (представляете, каково заново все это проходить?). Потом, наконец, письмо с приложениями отправляют (ах да, письмотоже отсканировать, т.к. там подписи!).



Заказчики, нужно сказать, попадаются разные. Одним нужно непременно через почту. Даже если там пара гигабайт. Другим – непременно через ссылку на ресурс Проектировщика. Третьим нужно выложить все в определенном порядке на ресурс Заказчика. В общем, много вариантов. Это тоже, как правило, делается вручную.




3. А ЧТО НУЖНО ОТ РЕВИЗИЙ, КРОМЕ ИХ УЧЕТА?



После передачи документа начинается самое интересное. Документов много, поэтому чуть ли не самое первое, с чего начинают проектирование – это реестр документации (нет, есть, конечно, титульный список,но это вне темы данной статьи). По этому реестру, как правило, потом контролируется готовность работ. Каждый документ может в части готовности находиться в одном из статусов:


  • «В разработке» — еще не передавался Заказчику.

  • «Передан» — нужен номер письма.

  • «Доработка» — есть замечания.

  • «Согласован» — документ согласован.



И еще нужно учитывать, что согласование – процесс многоэтапный, есть внутренняя экспертиза, есть ГлавГосЭкспертиза, есть привязка к конструкторской документации и т.д…



Такой реестр в «запущенном» случае составить реально, но уйдет недели две, и ошибки будут в 20% случаев. В случае «ручной автоматизации» вроде бы легче – т.к. есть специальный человек, который денно и нощно отслеживает (по крайней мере, должен) передачу документации и ее согласование. Какая-никакая, а все же централизация. Что дает результат примерно «через день» и… 10-15% ошибок. Почему? А потому, что согласование – процесс многоэтапный, а «ответственный» — нередко далек от проектирования, нюансов — не понимает. Корректнее всего процесс согласования отслеживает сам проектировщик.



Кроме того, есть вопрос контроля соответствия документации друг другу. В проектных документах часто упоминаются другие проектные документы. Составляется даже специальная «Ведомость ссылочных и прилагаемых документов». По ГОСТу, в примечании обязательно указывается номер изменения документа. Т.о., по реестру документов с номерами изменений можно отследить, корректен ли документ в отношении ссылок, или он составлен на основании устаревших данных. При учете ревизий, как правило, требуют кроме номера изменения указывать и идентификатор ревизии. Для тех же целей.




4. КАК АВТОМАТИЗИРОВАЛИ УЧЕТ РЕВИЗИЙ МЫ.



При внедрении учета ревизий мы исходили из 2-х предпосылок. Во-первых, нужно сократить объем работы проектировщику (все эти распечатывания и сканирования). Во-вторых, нужно дать инструмент для отслеживания процесса согласования. Кому-то. Лучше всего – проектировщику. Ну нет у нас специального лица для отслеживания согласования. Поэтому – проектировщику, и инструмент этот должен быть удобным!



Начнем с 1-го пункта. На момент внедрения учета ревизий у нас уже был налаженный процесс сдачи в архив, в котором создавались PDF с подписями. Проектировщики им вовсю пользовались для того, чтобы обойти печать и сканирование с подписями (правда, при этом здорово напрягался архив). Поэтому были добавлены несколько полей в наши объекты и реализована процедура фиксирования ревизий, в которую было включено автоматическое создание PDF с подписями.



Дальше сначала была реализована просто выгрузка файлов документов (исходные и PDF). А после этого была реализована функция, которая разрешила сразу же половину неразберихи в части отслеживания процессов – в TDMS проектировщик на зафиксированной ревизии нажимает кнопку «Добавить к письму», выбирает письмо, и ревизия сама попадает в письмо в easla.com, а также устанавливается ссылка на объект ревизии в TDMS. Вроде бы мелочь, но зато сколько проблем это решает! Проектировщик экономит время на извлечении из TDMS, сборе материалов, их архивировании и передаче в службу документооборота, а ГИП может за 5 минут получить достоверный список того, что отправлено!



И еще никто не тратит много времени на архивирование материалов и правильную их передачу Заказчику.

Примечание
Карлик, на самом деле, базируется на плечах гигантов. Пока не налажена работа с ревизиями (что, в свою очередь, подразумевает стабильную работу «живого» архива), автоматическая установка подписей в PDF (чтобы избежать сканирования) и т.д. – внедрять такие «мелочи» очень проблематично.







По пункту 2 была реализована следующая функция – в TDMS проектировщик выбирает ревизию документа, нажимает кнопку «Письмо согласования» и выбирает из перечня входящее письмо, в котором есть информация о согласовании документа. Также выбирается, согласован документ, или есть замечания. Все.

Примечание
Можно было автоматизировать процесс согласования более полноценно – проектировщик перечислял бы все замечания, вносил бы ответы, формировал бы письмо. Но было решено ограничиться этими возможностями потому, что большого интереса к составлению подробного отчета со всеми замечаниями нет.



В таком виде реализован процесс согласования конструкторской документации. Там интерес есть, т.к. множество отделов подготавливают один общий документ, что при «ручной автоматизации» невероятно мучительно. В произведении Чуковского (а точнее, Хью Лофтинга) упоминается Тяни-толкай, который, конечно, не являлся аллегорией на наше общество, но символически в смысле способа делать дела очень соответствует. И не только «у нас».



Что имеем в результате? В результате проектировщик:


  • получает способ хранения в системе всех вариантов, которые он разрабатывал для заказчика и для смежных отделов;

  • может указать прямо в системе, каким письмом какой вариант он отправил;

  • занимается отправкой не день-два, как раньше, а только час (нужна проверка вышестоящими специалистами);

  • сам видит, в каком состоянии находится его работа (документов много, всего не запомнишь).

  • не отвлекается еженедельно по нескольку раз на подготовку отчетов по просьбе Заказчика, ГИП сам подготавливает реестр за 5 минут!

  • и т.д.



Пример реестра:







Проектировщику необязательно формировать реестр – для него есть специальная выборка в TDMS, в которой по выбранной позиции показывается информация о передаче и согласовании:





Примечание
Нет, мы пока не автоматизировали контроль ссылочной целостности по ревизиям. Мы можем это сделать, но проектировщики пока к этому морально не готовы.






5. ТЕХНИЧЕСКИЕ АСПЕКТЫ. ИНТЕГРАЦИЯ TDMS С EASLA.COM.



Интеграция реализована в 3-х точках:


  1. Функция «Добавить к письму»

  2. Функция «Письмо согласования»

  3. Функция «Подготовка реестра»



Особенность задачи заключается в том, что при удалении из письма в easla.com какого-нибудь приложения это должно отразиться на реестре. Кроме того, если проектировщик подготавливает письмо, помещает в него документы, а потом в процессе подготовки понимает, что добавил туда что-то не то, то ему нужно удалить из письма это «что-то не то», и на этом — все! Ссылки на объекты в других системах должны «погибнуть» именно для данного конкретного файла, не более!



В каждом файле приложения имеются поля для хранения информации. Более того, в каждом файле приложения easla.com позволяет хранить не просто поле описания длиной, положим, 256 байт (как это чаще всего сделано в других системах), но целый список «Состав файла», в каждом элементе которого может храниться «Имя», «Номер ревизии», «Наименование ревизии» и «Параметры версии»:





Мы, фактически, являлись заказчиками этой особенности easla.com, и она нам очень пригодилась. Разные Заказчики просят по-разному формировать архивы, в одном архиве может находиться по несколько документов.




5.1. ФУНКЦИЯ «ДОБАВИТЬ К ПИСЬМУ» И ФУНКЦИЯ «ПИСЬМО СОГЛАСОВАНИЯ»


Разработка бизнес-логики в TDMS производится на VBS. За что отдельное спасибо разработчикам TDMS. Да, VBS уже морально устарел, и лучше бы это был .Net, но никакого специального языка программирования, по крайней мере, они изобретать не стали. Чем избавили нас от ограничений и глюков машины собственной разработки. Не говоря о том, что на Бейсике учат писать еще в школе.



Кроме того, в системе easla.com есть COM-интерфейс для работы с системой. Он встроен в агент, который устанавливается на каждое рабочее место. В этом интерфейсе реализовано несколько полезных инструментов. В данном случае мы воспользовались инструментом для выбора элементов списка, который выглядит вот так:





Вверху – строка для фильтрации элементов, внизу – перечень объектов (в данном случае – исходящих писем, но могут быть и любые другие элементы).



Далее несколько кусков кода, которые показывают, как реализована интеграция. Некоторые места кода вызывают удивление не очень профессиональным уровнем, можно и покомпактнее, и покрасивее написать, но что поделать – не боги горшки обжигают. Главное – работает.



Получение исходящего письма из easla.com

Function GetOutingLetter()
Set GetOutingLetter = Nothing
Dim ea
On Error Resume Next
Err = 0

Set ea = CreateObject("Easla.Agent")
If Err <> 0 Then
MsgBox "EaslaAgent не установлен. Обратитесь к администратору", VbOKOnly & VbCritical, "Ошибка"
Set ea = Nothing
Exit Function
End If

‘получение определения процесса «управление перепиской»
Set process = ea.getProcessCOM("crs_management")
If process Is Nothing Then
MsgBox "EaslaAgent не смог авторизоваться. Обратитесь к администратору", VbOKOnly & VbCritical, "Ошибка"
Set ea = Nothing
Exit Function
End If

‘получение определения объекта «исходящее»
Set object_def = ea.getObjectdefCOM(process, "crs_management_outgoing", 0)

Dim arr1(2)
arr1(0) = "crs_management_outgoing_regnum"
arr1(1) = "crs_management_outgoing_document"
arr1(2) = "crs_management_outgoing_attachments"

‘формирование условий поиска, в данном случае – по статусу
Set d = ea.CreateKeyValuesPairSoapItemCOM("status", Array("crs_management_outgoing_created"))
‘получение результатов выборки
Set result = ea.getObjectrefsCOM(object_def, arr1, Array(d))

‘задание списка выводимых в диалоге параметров
Set kvps1 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps1.key = "Идентификатор"
kvps1.value = "id"

Set kvps2 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps2.key = "Описание"
kvps2.value = "description"

Set kvps3 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps3.key = "Дата создания"
kvps3.value = "createtime"

Set kvps4 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps4.key = "Статус"
kvps4.value = "status.name"

‘вывод диалога
Err = 0
Set ooo = ea.ShowSelectObjectDialogCOM(result, Array(kvps1, kvps2, kvps3, kvps4))
If Err = 0 Then
Set GetOutingLetter = ooo
End If
Set ea = Nothing
End Function


Загрузка файла в easla.com и установка параметров



‘o – объект письма
‘commonname – название файла приложения
‘revision – идентификатор ревизии для основного описания
‘filename – название файла для основного описания
‘revdata – описание ревизии для основного описания
‘guids – список объектов в TDMS типа TDMSSheet для списка «Состав файла»
Function AddFileToOutingLetter(o, commonname, revision, filename, guids, revdata)
Set AddFileTotOutingLetter = Nothing
Dim ea
On Error Resume Next
Err = 0
Set ea = CreateObject("Easla.Agent")
If Err <> 0 Then
MsgBox "EaslaAgent не установлен. Обратитесь к администратору", VbOKOnly & VbCritical, "Ошибка"
Set ea = Nothing
Exit Function
End If

Set process = ea.getProcessCOM("crs_management")
If process Is Nothing Then
MsgBox "EaslaAgent не смог авторизоваться. Обратитесь к администратору", VbOKOnly & VbCritical, "Ошибка"
Set ea = Nothing
Exit Function
End If

‘сначала – проверка, есть ли такие файлы в письме (прикрепить-то easla.com позволяет, но нам этого не надо)
‘извлекаем атрибуты объекта, файлы приложений – это тоже атрибуты
set attrs = ea.GetAttrsFromObjectCOM(o)
colKeys = attrs.Keys
For Each strKey In colKeys
If attrs.Item(strKey).code = "crs_management_outgoing_attachments" Then
For Each f In attrs.Item(strKey).values
If f.nowname = commonname And f.isdeleted = "0" Then
MsgBox "Ошибка прикрепления: удалите из письма и прикрепите единовременно все файлы этого комплекта " & commonname, VbOKOnly & VbCritical, "Ошибка"
Exit Function
End If
Next
End If
Next

‘загрузка в easla.com
Set orss = CreateObject("EaslaAgent.com.easla.ObjectrefSimpleSoap")
orss.id = o.id
Err = 0
‘собственно загрузка
set uploadfile = ea.uploadFileCOM(orss, code, filename)
If Err <> 0 or uploadfile is Nothing Then
MsgBox "Во время прикрипления документа к письму возникла ошибка. Обратитесь к администратору", VbOKOnly & VbCritical, "Ошибка"
Set ea = Nothing
Exit Function
End If

Set kvps1 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps1.key = "srcname"
kvps1.value = commonname

Set kvps2 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps2.key = "revcode"
kvps2.value = revision

Set kvps4 = CreateObject("EaslaAgent.com.easla.KeyValuePairSoap")
kvps4.key = "revdata"
kvps4.value = revdata

‘обновление основной информации о файле
set ooo = ea.updateFileCOM(uploadfile, Array(kvps1, kvps2,kvps4))
If Err = 0 Then

Dim arrFCSS()
ReDim Preserve arrFCSS(0)

‘обновление списка «Состав файла»
For Each ob in guids.Objects
n = UBound(arrFCSS)
ReDim Preserve arrFCSS(n + 1)
arrFCSS(n) = ob.description ‘описание объекта

n = UBound(arrFCSS)
ReDim Preserve arrFCSS(n + 1)
arrFCSS(n) = ob.guid ‘связь с объектом TDMS

n = UBound(arrFCSS)
ReDim Preserve arrFCSS(n + 1)
arrFCSS(n) = ob.Attributes("REV_LETTER").Classifier.Code & ob.Attributes("REV_NUM") ‘ревизия

n = UBound(arrFCSS)
ReDim Preserve arrFCSS(n + 1)
arrFCSS(n) = ob.Attributes("REV_DESCRIPTION") ‘описание ревизии
Next
‘обновление описания приложения
Set AddFileTotOutingLetter = ea.updateFileConsistCOM2(ooo, arrFCSS)

End If

Set ea = Nothing
End Function





Функции «Добавить к письму» и «Письмо согласования» в части получения номеров писем похожи, как близнецы, поэтому тратить время читателя на получение номера исходящего письма из easla.com я не буду.




5.2. ФУНКЦИЯ «ПОДГОТОВКА РЕЕСТРА»


Данные в системах о связи писем и ревизий есть, теперь стоит озаботиться извлечением этих данных для подготовки отчета. Отчет можно построить на основе выборок TDMS с использованием события «QueryAfterExecute» для связи с информацией, получаемой из easla.com, но по соображениям скорости обработки мы решили сделать это через SQL, благо, что easla.com обладает возможностью получения данных в запросах SQL. Для этого к серверу MS SQL устанавливается расширение, позволяющее извлекать любую информацию из БД easla.com.



Весь код запросов приводить не буду, остановлюсь на ключевых моментах.



Получение перечня писем по перечню идентификаторов документов



CREATE PROCEDURE [dbo].[PR_TDMSReport_GetDocList_SENT]
(
@guid uniqueidentifier –элемент дерева, с которого начинать поиск документов
)
AS
BEGIN

declare @id bigint
select @id = f_objid from tngptdms.dbo.tobject (nolock) where f_guid = @guid;

declare @temp_revs table
([guid_rev] uniqueidentifier --GUID ревизии
,descr varchar(max) --описание ревизии
,letter varchar(10) --1-е поле ид-ра ревизии
,id varchar(10) --2-е поле ид-ра ревизии
,t datetime --время фиксирования ревизии
,objid_rev bigint --системный ид-р ревизии
);

--заполнение таблицы документами, находящимися ниже по дереву
insert into @temp_revs
EXEC [TNGP].[dbo].[PR_TDMSRevision_GetListByObject] @guid = @guid

--формирование перечня GUID-ов для XML-запроса в ESLA
declare @subquery varchar (MAX)
set @subquery = cast ((select '{'+cast([guid_rev] as varchar(50))+'}'
from @temp_revs
for xml path('item'), elements, type) as varchar(MAX))

--здесь заполняется секция условий для XML-запроса
declare @query XML
set @query =
'

crs_management_outgoing_attachments
'
+ @subquery +
'


'

--временная таблица для хранения результатов, получаемых из easla.com
declare @temquerytbl table
(
regnum varchar(32),
regdate varchar(32),
revguids xml,
[SentStatus] varchar(40)
)

--параметры, необходимые для запроса в easla.com
DECLARE @organization_id AS INT;
DECLARE @process_id AS INT;
DECLARE @objectdef_id AS INT;
DECLARE @user_id AS INT;
declare @ret int
declare @logined int
set @logined = 0

if(@subquery is not NULL)
begin
-- пользователь,пароль – можно завести пользователя с правами просмотра всей информации в БД ESLA, чтобы не указывать системного администратора
-- EASLAlogin – функция из расширения для easla.com
select @logined = [master].[dbo].[EASLAlogin](пользователь,пароль)

IF (@logined = 1)
BEGIN
--выборка параметров для запроса в easla.com
SELECT @organization_id = organization.id, @process_id = process.id, @objectdef_id = objectdef.id
FROM [master].[dbo].[EASLAgetOrganization] ('TNGP') AS organization
LEFT JOIN [master].[dbo].[EASLAgetAllProcesses] () AS process ON process.oid = organization.id
LEFT JOIN [master].[dbo].[EASLAgetAllObjectdefs] () AS objectdef ON objectdef.pid = process.id
WHERE process.code = 'crs_management' AND objectdef.code = 'crs_management_outgoing';

-- ид-р пользователя в easla.com
SELECT @user_id = id FROM [master].[dbo].[EASLAgetOrganizationUser] (@organization_id, пользователь)

--запрос в easla.com необходимой информации
insert into @temquerytbl
SELECT attributerefs.value('(ArrayOfAttributerefSimpleSoap[1]/AttributerefSimpleSoap[1]/values/item/node())[1]','varchar(30)') as letternum
,attributerefs.value('(ArrayOfAttributerefSimpleSoap[1]/AttributerefSimpleSoap[2]/values/item/node())[1]','varchar(30)') as regdate
,cast(attributerefs.query('(ArrayOfAttributerefSimpleSoap[1]/AttributerefSimpleSoap[3]/values/item/consist/item/revdata)')as varchar(max)) as revguid
,cast([status].query('(StatusSimpleSoap[1]/name[1]/node())')as varchar(max)) as sentstatus


from master.[dbo].[EASLAgetobjectrefs](
@process_id,
@objectdef_id
--перечень запрашиваемых полей
,CAST('

crs_management_outgoing_regnum
crs_management_outgoing_sentdate
crs_management_outgoing_attachments

' AS XML)
,@query,
@user_id
);

end

declare @temquerytbl1 table
(
revguid varchar(50),
regnum varchar(30),
regdate varchar(30),
sentstatus varchar(40)
)

insert into @temquerytbl1
select cast(t2.loc.query('(./node())') as varchar(50)), regnum,replace(regdate,'/','.'),sentstatus
from @temquerytbl as T
CROSS APPLY revguids.nodes('/revdata') as T2(Loc)

END

IF (@logined = 1)
BEGIN
select @logined = 1 - [master].[dbo].[EASLAlogout]()
end





Также есть похожая процедура PR_TDMSReport_GetDocList_RECEIVED, в которой запрашивается информация по письмам согласования. Атрибуты, в которых указано письмо согласования, хранятся в TDMS, поэтому есть отличия, но в целом для описания принципа работы несущественные.



Есть набор процедур, через операцию JOIN объединяющих все эти данные с данными из TDMS (район проектирования, площадка строительства, позиция по генплану и т.д., около 50 параметров). Процедур несколько, т.к. есть довольно специфические требования некоторых Заказчиков. Они вызываются из макросов в документах MS Excel. Шаблонов документов существует около 10 штук – отчеты различаются, каждому из Заказчиков – свой вариант.




ЗАКЛЮЧЕНИЕ



По моему опыту, внедрение очень небольшого количества видов учета проходит так же гладко, как внедрение учета ревизий. После внедрения архив стал действительно «живым», потому что проектировщики получили возможности, существенно сокращающие им время на, скажем так, не самые основные задачи. За два года (что, отмечу, говорит о некотором уровне стабильности) зарегистрировано уже более 20 тыс. писем (входящих и исходящих), подавляющая часть которых связана с проектной документацией. Я не сомневаюсь, Заказчики нашего предприятия отмечают значительное отличие в части организованности процесса согласования по сравнению с другими предприятиями.



Серьезную роль сыграло и наличие хорошего рабочего контакта с разработчиками easla.com. Оправданные запросы на реализацию возможностей (такие, как «Состав файла»), всегда обсуждались и вполне своевременно реализовывались.



Original source: habrahabr.ru.

https://habrahabr.ru/post/283386/?utm_source=habrahabr&utm_medium=rss&utm_campaign=best

Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

[Из песочницы] Проверка статуса антивируса в корпоративной сети посредством VBScript

Пятница, 11 Марта 2016 г. 13:37 (ссылка)

Предисловие



Все началось с того, что купленное корпоративное решение для аудита систем не предоставляло нужную информацию по используемому антивирусному продукту, да и работала слишком уж долго, а панель управления, используемого компанией антивируса, оставляет желать лучшего. Решено было использовать «костыль» для сбора информации об антивирусах в домене.



Приведенный ниже сценарий обрабатывает статусы состояний только антивирусов, используемых в нашей корпоративной сети.



Что же собственно нужно и как это сделать?



Первым делом было установлено, что же нужно получать от антивируса и как это сделать в короткий промежуток времени со всего домена.



Получать нужно было:



1) Наименование установленного антивируса

2) Активен ли антивирус

3) Обновлены ли на нем базы



Собственно способ был найден моментально — использовать WMI (Windows Management Instrumentation).



Пришлось погрузиться в изучение самой структуры WMI на ПК, в этом мне помог замечательный набор утилит WMI Tools.



После чего нужно было решить как взаимодействовать с WMI, не долго думая решил написать сценарий на VBScript.



Разбор полетов



Сценарий обрабатывает 3500 хостов примерно за 1 час. Собственно сам код сценария:



Код сценария
WScript.Interactive = true

compid = 0

On Error Resume Next

Set objDomain = GetObject("LDAP://DOMAIN/OU=Workstations,DC=DOMAIN")

comps = Array()

for each objDomainItem in objDomain
if objDomainItem.objectClass = "Computer" then
idxLast = UBound (comps)
ReDim Preserve comps(idxLast + 1)
comps(idxLast + 1) = objDomainItem.dNSHostName
end if
next

Set objFS = CreateObject("Scripting.FileSystemObject")
Set objNewFile = objFS.CreateTextFile("C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT")

a = ""


objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.WriteLine "javascript"" src=""TableFilter/tablefilter.js"">"
objNewFile.WriteLine ""
objNewFile.WriteLine a & ""
objNewFile.WriteLine "

AVSI -- Date: " & Now() & "

"

objNewFile.WriteLine "javascript"">"
objNewFile.WriteLine "var tableToExcel = (function() {"
objNewFile.WriteLine " var uri = 'data:application/vnd.ms-excel;base64,'"
objNewFile.WriteLine " , template = '{table}
'"
objNewFile.WriteLine " , base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) }"
objNewFile.WriteLine " , format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) }"
objNewFile.WriteLine "return function(table, name) {"
objNewFile.WriteLine " if (!table.nodeType) table = document.getElementById(table)"
objNewFile.WriteLine " var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML}"
objNewFile.WriteLine " window.location.href = uri + base64(format(template, ctx))"
objNewFile.WriteLine "}"
objNewFile.WriteLine "})()"
objNewFile.WriteLine ""
objNewFile.WriteLine ""

objNewFile.WriteLine ""
objNewFile.WriteLine ""

for each comp in comps
compid = compid + 1

Set WshShell = WScript.CreateObject("WScript.Shell")
Ping = WshShell.Run("ping -n 1 " & comp, 0, True)
Select Case Ping
Case 0
On Error Resume next
Set oWMI = GetObject("winmgmts:\\" & comp & "\root\SecurityCenter2")
On Error Resume next
Set colAVItems = oWMI.ExecQuery("Select * from AntiVirusProduct")
If colAVItems.count = 0 Then
objNewFile.WriteLine ""
ElseIf colAVItems.count = 1 Then
For Each AntiVirus in colAVItems
If (AntiVirus.displayName) <> "Windows Defender" Then
AVStatus = hex(AntiVirus.ProductState)
If (AVStatus = "61000") _
OR (AVStatus = "51000") _
OR (AVStatus = "41000") Then
objNewFile.WriteLine ""
ElseIf (AVStatus = "41010") _
OR (AVStatus = "61010") _
OR (AVStatus = "51010") Then
objNewFile.WriteLine ""
ElseIf (AVStatus = "60000") _
OR (AVStatus = "50000") _
OR (AVStatus = "40000") Then
objNewFile.WriteLine ""
Else
objNewFile.WriteLine ""
End if
End If
Next
End If
Case 1
objNewFile.WriteLine ""
End Select
Next
objNewFile.WriteLine "
idComputerAV NameAV StatusAV BasesHost Status
" & compid & "" & comp & "No AntiViruses foundDisabledNOT Up to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveUp to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveNOT Up to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "On Access scanning disabled!Up to DateOnline
" & compid & "" & comp & "" & AntiVirus.displayName & "UnknownUnknownOnline
" & compid & "" & comp & "UnknownUnknownUnknownOffline
"

objNewFile.WriteLine "javascript"">"
objNewFile.WriteLine "//"
objNewFile.WriteLine ""

objNewFile.WriteLine "

End of scan: " & Now() & "

"

objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.Close
objFS.MoveFile "C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT", "C:\TEMP\AV_Check\Reports\AV_Status_" & Date & "_" & Hour(Now()) & "." & Minute(Now()) & ".htm"




Что же собственно происходит? А происходит именно вот что:



1) Мы подключаемся к домену и заходим в каталог Workstations:



Подключение к домену посредством LDAP
Set objDomain = GetObject("LDAP://DOMAIN/OU=Workstations,DC=DOMAIN")




2) Создаем пустой массив, в который будут добавляться ПК пользователей с соответствующим классом Computer:



Создание и заполнение массива
for each objDomainItem in objDomain
if objDomainItem.objectClass = "Computer" then
idxLast = UBound (comps)
ReDim Preserve comps(idxLast + 1)
comps(idxLast + 1) = objDomainItem.dNSHostName
end if
next




3) Создаем файл отчета. Отчет было решено формировать в .htm формате и соответственно формируем страницу в самом сценарии:



Заголовок спойлера
Set objFS = CreateObject("Scripting.FileSystemObject") 
Set objNewFile = objFS.CreateTextFile("C:\TEMP\AV_Check\Reports\AV_Status_Scan_is_Running.WAIT")

a = ""


objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.WriteLine "javascript"" src=""TableFilter/tablefilter.js"">"
objNewFile.WriteLine ""
objNewFile.WriteLine a & ""
objNewFile.WriteLine "

AVSI -- Date: " & Now() & "

"

objNewFile.WriteLine "javascript"">"
objNewFile.WriteLine "var tableToExcel = (function() {"
objNewFile.WriteLine " var uri = 'data:application/vnd.ms-excel;base64,'"
objNewFile.WriteLine " , template = '{table}
'"
objNewFile.WriteLine " , base64 = function(s) { return window.btoa(unescape(encodeURIComponent(s))) }"
objNewFile.WriteLine " , format = function(s, c) { return s.replace(/{(\w+)}/g, function(m, p) { return c[p]; }) }"
objNewFile.WriteLine "return function(table, name) {"
objNewFile.WriteLine " if (!table.nodeType) table = document.getElementById(table)"
objNewFile.WriteLine " var ctx = {worksheet: name || 'Worksheet', table: table.innerHTML}"
objNewFile.WriteLine " window.location.href = uri + base64(format(template, ctx))"
objNewFile.WriteLine "}"
objNewFile.WriteLine "})()"
objNewFile.WriteLine ""
objNewFile.WriteLine ""

objNewFile.WriteLine ""
objNewFile.WriteLine ""

{ ... }

objNewFile.WriteLine "
idComputerAV NameAV StatusAV BasesHost Status
"

objNewFile.WriteLine "javascript"">"
objNewFile.WriteLine "//"
objNewFile.WriteLine ""

objNewFile.WriteLine "

End of scan: " & Now() & "

"

objNewFile.WriteLine ""
objNewFile.WriteLine ""
objNewFile.Close




Для удобства был использован HTML Table Filter Generator, который формирует фильтры по завершению выполнения сценария по сформированной таблице с полями id, Computer, AV Name, AV Status, AV Bases.



Также добавлена кнопка выгрузки таблицы в Excel, которую я нашел на каком-то форуме (честно сказать с ней я даже не возился и оставил как есть, работает криво и, как показала практика, только под FireFox).



4) Массив у нас сформирован и хранится в памяти, теперь рассмотрим заполнение таблицы отчета. Первым делом мы ставим счетчик для присваивания id каждому хосту из массива. После этого вызываем Shell скрипт для проверки доступности хоста путем отправки на него 1 icmp пакета. Создаем условия на обработку отклика, Case 0 — хост доступен и выполняем сценарий сбора данных для заполнения таблицы, Case 1 — выводим в таблицу данные о том, что хост не доступен:



Проверка доступности хоста
for each comp in comps 
compid = compid + 1

Set WshShell = WScript.CreateObject("WScript.Shell")
Ping = WshShell.Run("ping -n 1 " & comp, 0, True)
Select Case Ping
Case 0
{ ... }
Case 1
objNewFile.WriteLine "" & compid & "" & comp & "UnknownUnknownUnknownOffline"
End Select
Next




5) Проверяем есть ли у нас ошибки, а если есть, то просто переходим к следующему хосту. Информация по Антивирусам, Антишпионам и Межсетевым экранам в WMI хранится в каталоге \root\SecurityCenter2, по-этому подключаемся к нему и создаем WQL запрос, который собственно и вытаскивает нужную нам информацию по продукту. Проверяем есть ли вообще на хосте антивирус, а если есть, то проверяем не Windows Defender ли он, а если даже и он, то просто игнорируем его. Каждый антивирус имеет свой код состояния, об этом я узнал на форуме:



Проверка статуса Антивируса и заполнение таблицы
On Error Resume next 
Set oWMI = GetObject("winmgmts:\\" & comp & "\root\SecurityCenter2")
On Error Resume next
Set colAVItems = oWMI.ExecQuery("Select * from AntiVirusProduct")
If colAVItems.count = 0 Then
objNewFile.WriteLine "" & compid & "" & comp & "No AntiViruses foundDisabledNOT Up to DateOnline"
ElseIf colAVItems.count = 1 Then
For Each AntiVirus in colAVItems
If (AntiVirus.displayName) <> "Windows Defender" Then
AVStatus = hex(AntiVirus.ProductState)
If (AVStatus = "61000") _
OR (AVStatus = "51000") _
OR (AVStatus = "41000") Then
objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveUp to DateOnline"
ElseIf (AVStatus = "41010") _
OR (AVStatus = "61010") _
OR (AVStatus = "51010") Then
objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "ActiveNOT Up to DateOnline"
ElseIf (AVStatus = "60000") _
OR (AVStatus = "50000") _
OR (AVStatus = "40000") Then
objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "On Access scanning disabled!Up to DateOnline"
Else
objNewFile.WriteLine "" & compid & "" & comp & "" & AntiVirus.displayName & "UnknownUnknownOnline"
End if
End If
Next
End If




Бонус



Ну и как бонус код на Python. Он создает текстовый файл, который можно использовать для выгрузки в Excel (в виде разделителя колонок — табуляция). К сожалению посредством LDAP выгружать список хостов у меня не получилось, а так же при использовании большого списка сценарий падает, возможно кто-нибудь доработает его для своих нужд:



Сам код
import wmi
import codecs
import os

with open('Comp_list.txt','r') as list:

file = codecs.open('text.txt', 'w', 'utf-8')

file.write("Computer" + " AV Name" + " Host Status" + " AV Status" + " AV Bases\n")

for comp in list:
response = os.system("ping -n 1 " + comp)
if response == 0:
path = '//%s/root/SecurityCenter2' % comp
c = wmi.WMI(moniker=path)
wql = "Select * from AntiVirusProduct"
wql = c.query(wql)
if wql == []:
file.write(comp + " no AntiVirus found" + " Online" + " Unknown" + " Unknown\n")
else:
for AntiVirus in wql:
ProductState_in_hex = str(hex(AntiVirus.ProductState))
check_install = ProductState_in_hex[0:3]
check_state = ProductState_in_hex[3:5]
check_updates = ProductState_in_hex[5:7]
if check_state == "10" and check_updates == "00":
file.write(comp + " " + AntiVirus.displayName + " Online" + " Active" + " Up to Date\n")
elif check_state == "10" and check_updates == "10":
file.write(comp + " " + AntiVirus.displayName + " Online" + " Active" + " NOT Up to Date\n")
elif check_state == "00" and check_updates == "00":
file.write(comp + " " + AntiVirus.displayName + " Online" + " On Access scanning disabled!" + " Up to Date\n")
elif check_state == "00" and check_updates == "00":
file.write(comp + " " + AntiVirus.displayName + " Online" + " On Access scanning disabled!" + " NOT Up to Date\n")
else:
file.write(comp + " " + AntiVirus.displayName + " Online" + " Unknown state\n" + " " + check_install)
else:
file.write(comp + " Unknown" + " Offline" + " Unknown" + " Unknown\n")
file.close()





Original source: habrahabr.ru (comments, light).

https://habrahabr.ru/post/279049/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Можно ли полагаться на данные, извлекаемые WMI классами?

Четверг, 13 Августа 2015 г. 21:51 (ссылка)

На примере нескольких WMI-классов Win32_xxxx, показано, что как минимум некоторые из свойств объектов, возвращаемые указанными классами, совершенно не соответствуют реальным значениям этих свойств.



Ниже рассматриваются примеры выдач WMI-классами Win32_CDROMDrive, Win32_DiskDrive, Win32_DiskPartition, Win32_LogicalDisk, Win32_Volume и демонстрируется, что выдаваемая информация, мягко говоря, не соответствует действительности или выдается в очень неудобном формате или просто опускается. В качестве стенда для выполнения WQL-запросов к WMI-классам используется программа ScriptomaticV2.hta, разработанная группой разработчиков “Scripting Guy” фирмы Microsoft. ScriptomaticV2.hta поддерживает VBS, JS, Perl, Python. В силу отсутствия двух последних, использовались лишь выдачи JS и VBS. Поэтому заранее приношу извинения разработчикам упомянутых WMI-классов, если Perl и / или Python выдают корректную информацию. Кроме того, надеюсь, что использование тех же самых WMI-классов в программах на C#, C++ обеспечивает корректную выдачу результатов.



1. Неверная или опускаемая дата создания или монтирования объекта



Все перечисленные выше классы в списке свойств содержат свойство, именуемое “InstallDate”. Этому свойству в Windows Registry соответствует REG_QWORD. В среде Windows 8.1+ (8.1 и всех сборок Windows 10) CDROMDrive, DiskDrive, это значение хранится в InitialTimeStamp, адресуемом



HKLM\SYSTEM\CurrentControlSet\Enum\SCSI\\Device Parameters\StorPort



Значение InitialTimeStamp МОЖЕТ принимать значение NULL, но в большинстве случаев оно содержит вполне реальную дату в формате, прекрасно описанном в документации Microsoft:



“Unique value that indicates the time when an event is generated.

This is a 64-bit FILETIME value that represents the number of 100-nanosecond intervals after January 1, 1601. The information is in the Coordinated Universal Time (UTC) format. This property is inherited from __Event. To convert this value to other time formats, use the SWbemDateTime methods SetFileTime and GetFileTime.”




Видимо разработчики Win32-WMI-классов не захотели привлекать еще и методы SWbemDateTime и потому выдача JS-кода в поле InstallDate всегда подставляет null date, выдача VBS-кода — это поле скромно опускает. Но ведь никакие методы не нужны, для того, чтобы 64-битное QWORD число, описанного выше формата, преобразовать в число, представляющее дату в миллисекундах, на основе которого можно создать объект Date. Для этого потребуется элементарная арифметика.



2. Противоречивые данные, ошибка в поле InterfaceType, Win32_DiskDrive



Index: 0

InstallDate: null date должно быть Sun Jul 19 08:12:08 UTC+0300 2015

InterfaceType: IDE



Model: ST9320423AS

Name: \\.\PHYSICALDRIVE0



PNPDeviceID: SCSI\DISK&VEN_&PROD_ST9320423AS\4&3516B3B5&0&000000



Кто-нибудь может дать разумное объяснение значению поля InterfaceType, прямо противоречащее как указанному ниже PNPDeviceID так и тому факту, что начиная с Windows 8.1 в HKLM\SYSTEM\CurrentControlSet\Enum\ интерфейс IDE вообще отсутствует и последний раз он присутствовал лишь в среде Windows 7?



3. Отрицательные значения в полях SerialNumber, Signature классами Win32_DiskDrive, Win32_Volume



SerialNumber: Hitachi HT100219FCC400NEJTBU5G

Signature: -1498719820



Purpose: null

QuotasEnabled: false

QuotasIncomplete: false

QuotasRebuilding: false

SerialNumber: -1408044882



Это вообще любимая “фишка”, выдача очень важной информации в совершенно неудобоваримом формате. И SerialNumber и Signature все привыкли читать в 16-ном виде.



4. Неверная индексация разделов для Gpt-форматированных дисков, класс Win32_DiskPartition



Caption: Disk #3, Partition #0



Description: GPT: Basic Data



Ну как, объясните мне, Gpt-форматированный раздел типа “Basic Data” приобрел индекс 0, который по праву принадлежит MSR-разделу? Естественно, что MSR-раздел Win32_DiskPartition в списке разделов вообще холодно игнорирует.



5. Наличие полей, содержащих NULL для JS или пусто для VBS для всех объектов в WQL-запросе



В качестве примера могу привести значения свойств Access и Description для класса Win32_Volume. У меня на 9 смонтированных устройствах, включающих два внутренних диска, пару виртуальных DVD-ROM, несколько VHD с Gpt-форматированными разделами, USB-диском, SD-картой и флэшкой, расположены 16 томов и все они в указанных полях содержат или NULL для JS-выдачи или пусто для VBS-выдачи. Спрашивается каким же должен быть том, на каком устройстве располагаться для того, чтобы для него хоть одно из указанных свойств оказалось значимым? А если такого быть не может, то зачем вообще включать эти свойства в выдачи?

Решил проверить с помощью PS и “gwmi win32_volume” для всех томов выдала пустые значения свойств Access, Description.



Заключение



Основной смысл этой короткой, возможно излишне эмоциональной публикации состоит в том, чтобы привлечь внимание всех, кто использует WMI-классы в своем коде, критически оценивать извлекаемые данные, перепроверять их из других источников. Сразу же добавлю, что MSFT-классы, аналогичные описанным выше Win32-классам, выдают всегда корректную информацию, хотя и они грешат выдачей отрицательных чисел в полях Signature.

Original source: habrahabr.ru (comments, light).

http://habrahabr.ru/post/264717/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

SMS-чат на коленках

Четверг, 29 Мая 2015 г. 03:49 (ссылка)

image



Понадобился нам как-то смс-чат для небольшой группы пользователей. Основными требованиями были надежность и простота реализации. В наличии был средненький офисный компьютер с Windows ХР на борту, USB-модем Huawei E1550, сим-карта с положительным балансом и среднестатистический эникейщик.



Хотелось нам следующего: инженеры из числа оперативного персонала, заступая на дежурство, подключаются к группе чата и могут обмениваться между собой короткими текстовыми сообщениями. Это полезно при решении проблем, касающихся нескольких отделов (релейщиков и энергетиков, например). Когда присутствие в группе не требуется – можно выйти и сообщения не получать.



Теоретически все было просто. Берем GSM-модем, пишем программу, которая проверяет на нем входящие сообщения, выдергивает из них нужную информацию, производит обработку и передает по списку подключенных абонентов.



На практике все оказалось иначе. Активное гугление привело нас на несколько проектов, в том числе и на Хабр. Но все оказались довольно сложными. Ибо Delphi из нас никто особо не понимает, а проекты для Линукса мы не рассматривали в принципе – у нас все машины виндовые.



Последней находкой стала программа от питерской компании Headwind Solutions. Называется она «Персональный СМС Сервер». Программа платная, но есть 30 дней демо-режима. Мы начали ковырять ее.



Программа оказалась очень удобной и надежной. Основная фишка ее в том, что она избавляет от необходимости работать с модемом напрямую. Она сама работает с GSM-модемом, проверяет входящие сообщения и отправляет исходящие. Если поступает новое вызывает скрипт и передает ему два параметра: номер отправителя и текст сообщения. Все остальное решается скриптом. Уже из скрипта можно вызывать процедуру отправки сообщения в программу. Сообщений может быть много, программа сама поставит их в очередь на отправку и грамотно передаст. Скрипт написан на VBS.



Программа, кстати, может работать как служба Windows. Мы сначала проигнорировали эту возможность и совершенно напрасно служба работает стабильнее.



На самой программе подробно останавливаться не будем. Она имеет много настраиваемых параметров, несложна и хорошо описана в документации на сайте разработчика.



Подробнее остановимся на скрипте чата. Помимо самого скрипта, в том же каталоге понадобится создать три файла: hlr.txt, vlr.txt и vlr_back.txt.

Первый файл заполняем номерами абонентов, имеющих доступ к чату. Формат такой: мобильный номер без плюса <пробел> идентификатор абонента.



79111234567 Иванов (энергетик)

79111234568 Петров (WDM)

79111234569 Сидоров (RRL)



Второй и третий файлы оставляем пустыми. Во втором хранятся записи о вошедших в группу абонентах, а третий файл используется скриптом для добавления/удаления абонента из группы.



Скрипт поддерживает три команды. Начинаются они со знака # (решетка). Чтобы войти в группу чата нужно отправить смс на номер сим-карты модема с текстом #1, чтобы выйти #0. Для запроса текущего списка пользователей нужно отправить #?

Запросы от абонентов, не вошедших в группу, игнорируются.



Входящие сообщения обрабатываются следующим образом. В начало исходного сообщения ставится идентификатор абонента (у нас это фамилия сотрудника и его отдел), а затем это сообщение передается всем абонентам из файла vlr.txt. Отправитель получает квитанцию об отправке сообщения. В ней дублируется его сообщение и количество абонентов, которому оно отправлено. Передача квитанции была добавлена в качестве контрольной меры. Если квитанция получена, значит, чат исправен, деньги на сим-карте есть и всем участникам чата сообщение улетело.



Привожу наши настройки программы. Параметры подбирались несколько лет методом проб и ошибок:



image



И собственно скрипт:



Код чата на VBS
' Получаем значения переменных, которые передаются скрипту при его вызове
Number = WScript.Arguments(0)
Message = WScript.Arguments(1)
Message = Trim(Message)


' Обнуляем флаги, устанавливаем значение переменных
FlagVlr = 0
FlagHlr = 0
FlagSymbol=0
Users = ""
Count = 0


' Устанавливаем соответствие между переменными и именами файлов
vlr = "vlr.txt"
hlr = "hlr.txt"
vlr_back = "vlr_back.txt"


' Ищем номер абонента в списке HLR
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set filehlr = objFSO.OpenTextFile(hlr, 1)

Do Until filehlr.AtEndOfStream
sLine = filehlr.ReadLine()
nSpace = InStr(sLine, " ")

If nSpace > 0 Then
Number_hlr = Left(sLine, nSpace - 1)
Name_hlr = Trim(Right(sLine, Len(sLine) - nSpace))
End If

If (Number_hlr = Number) Then
FlagHlr = 1
Name = Name_hlr
End If

If (Len(Users) = 2) Then
Users = ""
End If
Loop
filehlr.Close


' Ищем номер абонента в списке VLR
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set filevlr = objFSO.OpenTextFile(vlr, 1)

Do Until filevlr.AtEndOfStream
sLine = filevlr.ReadLine()
nSpace = InStr(sLine, " ")

If nSpace > 0 Then
Users = Users & ", "
Number_vlr = Left(sLine, nSpace - 1)
Name_vlr = Trim(Right(sLine, Len(sLine) - nSpace))
End If

Count = Count + 1

If (Number_vlr = Number) Then
FlagVlr = 1
Name = Name_vlr
End If


If (Len(Users) = 2) Then
Users = ""
End If

Users = Users & Name_vlr
Loop
filevlr.Close


' Устанавливаем флаги в зависимости от наличия записи номера в файлах HLR и VLR

If (FlagHlr = 0) Then
Flaguser = 0
End If


If (FlagHlr = 1) And (FlagVlr = 0) Then
Flaguser = 1
End If


If (FlagHlr = 1) And (FlagVlr = 1) Then
Flaguser = 2
End If


' Устанавливаем значение текстовых сообщений

MessageAlreadyEnter = "Вы уже вошли в чат. Сейчас в группе: " & Users & "."
MessageNowInGroup = "Сейчас в группе: " & Users & "."
MessageEmpty = "Вы отправили пустое сообщение."


' Устанавливаем значение текстовых сообщений при пустой группе

If (Count = 0) Then
MessageNowInGroup = "В группе нет собеседников."
End If

If (Count = 1) Then
MessageAlreadyEnter = "Вы уже вошли в чат. В группе нет собеседников."
End If


' Обработка специальных сообщений

dlina = Len(Message)
symbol = Trim(Message)
symbol = Left(symbol, 1)
If (symbol = "#") Then
FlagSymbol = 1
End If


' Обработка запроса на вход в группу

If (Message = "#1") And (Flaguser = 1) Then
FlagVlr = 0
FlagSymbol = 0

Set filevlr = objFSO.OpenTextFile(vlr, 1)
Set filevlrback = objFSO.OpenTextFile(vlr_back, 2)
rec = Number + " " + Name
filevlrback.WriteLine(rec)

Do Until filevlr.AtEndOfStream
sw = filevlr.ReadLine()
filevlrback.WriteLine(sw)
Loop

filevlr.Close
filevlrback.Close

Set filevlr = objFSO.OpenTextFile(vlr, 2)
Set filevlrback = objFSO.OpenTextFile(vlr_back, 1)
Do Until filevlrback.AtEndOfStream
sw = filevlrback.ReadLine()
filevlr.WriteLine(sw)
Loop

filevlr.Close
filevlrback.Close


' ======= Отправляем сообщение об успешном входе в группу =======

Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = "Вы успешно подключились к разговору. " + MessageNowInGroup
objMsg.Send()
End If


' Обработка запроса на вход в группу, если абонент уже находится в ней

If (Message = "#1") And (Flaguser = 2) Then
FlagVlr = 0
FlagSymbol = 0

Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = "Вы уже подключены к разговору. " + MessageNowInGroup
objMsg.Send()
End If


' Обработка повторного запроса на выход из группы

If (Message = "#0") And (Flaguser = 1) Then
FlagSymbol = 0
End If


' Обработка запроса на выход из группы

If (Message = "#0") And (FlagVlr = 1) Then
FlagVlr = 0
FlagSymbol = 0


Set filevlr = objFSO.OpenTextFile(vlr, 1)
Set filevlrback = objFSO.OpenTextFile(vlr_back, 2)

Do Until filevlr.AtEndOfStream
sLine = filevlr.ReadLine()
nSpace = InStr(sLine, " ")

If nSpace > 0 Then
Number_vlr = Left(sLine, nSpace - 1)
Name_vlr = Trim(Right(sLine, Len(sLine) - nSpace))
rec = Number_vlr + " " + Name_vlr
End If

If (Number_vlr <> Number) Then
filevlrback.WriteLine(rec)
End If



Loop

filevlr.Close
filevlrback.Close

Set filevlr = objFSO.OpenTextFile(vlr, 2)
Set filevlrback = objFSO.OpenTextFile(vlr_back, 1)
Do Until filevlrback.AtEndOfStream
rec = filevlrback.ReadLine()
filevlr.WriteLine(rec)
Loop
filevlr.Close
filevlrback.Close


' ======= Отправляем сообщение об успешном выходе из группы =======

Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = "Вы успешно покинули группу."
objMsg.Send()

End If


' Обработка запроса на получение списка собеседников

If (Message = "#?") And (FlagVlr = 1) Then
FlagVlr = 0
FlagSymbol = 0

Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = MessageNowInGroup
objMsg.Send()
End If


' Обработка неверной или несуществующей команды

If (FlagSymbol = 1) And (FlagHlr = 1) Then
FlagVlr = 0
FlagSymbol = 0

Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = "Команда не распознана. Команды: #1 - вход, #0 - выход, #? - список собеседников."
objMsg.Send()

End If


' Обработка пустого сообщения

If (Message = "") And (FlagVlr = 1) Then
FlagVlr = 0

Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = MessageEmpty
objMsg.Send()
End If


' Обработка непустого сообщения

If (FlagVlr = 1) Then
Message = Trim(Message)
Set objFSO = CreateObject("Scripting.FileSystemObject")
Set filevlr = objFSO.OpenTextFile(vlr, 1)
Set objSMSDriver = CreateObject("HeadwindGSM.SMSDriver")
objSMSDriver.Connect()
Do Until filevlr.AtEndOfStream
sLine = filevlr.ReadLine
nSpace = InStr(sLine, " ")
If nSpace > 0 Then
Number_buffer = Left(sLine, nSpace - 1)
Name_buffer = Trim(Right(sLine, Len(sLine) - nSpace))
If (Number_buffer <> Number) Then
Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number_buffer
objMsg.Body = Name & ": " & Message
objMsg.Send()
End If
End If
Loop
filevlr.Close

Count_receipt = Count - 1

' ======= Отправляем квитанцию =======

Set objMsg = CreateObject("HeadwindGSM.SMSMessage")
objMsg.To = Number
objMsg.Body = "Message send to " & Count_receipt & " users. Text: '" & Message & "'"
objMsg.Send()

' ======= /Отправляем квитанцию =======


End If


' ======= Конец скрипта =======

WScript.Quit








Таким макаром мы получили простенький СМС-чат, который сейчас трудится на благо отечественных инженеров. Надеемся, что пригодится и вам.

Original source: habrahabr.ru (comments, light).

http://habrahabr.ru/post/259057/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество
rss_rss_hh_new

Уязвимость 19-летней давности позволяет захватить компьютер через Internet Explorer

Среда, 12 Ноября 2014 г. 17:23 (ссылка)

Исследователи из IBM X-Force обнаружили опасную уязвимость CVE-2014-6332, которой, по их заявлениям, подвержены все версии Microsoft Windows, начиная с Windows 95. Основное потенциально уязвимое приложение с этим багом — Internet Explorer, начиная от версии 3.0. Уязвимость позволяет получать несанкционированный доступ к пользовательским данным или удалённо запускать вредоносные программы на атакованном компьютере. При этом атакующий может обойти такие защитные механизмы, как «песочница» Enhanced Protected Mode, используемая в IE 11, и система безопасности Enhanced Mitigation Experience Toolkit (EMET).



image



Уязвимость появилась в коде приложений Windows ещё в 1996 году с выходом IE 3.0, где стал использоваться Visual Basic Script (VBScript). Атаки на основе этой уязвимости относятся к классу «манипуляции данными», то есть являются более редкой и более опасной техникой, чем «переполнение буфера» и другие классические способы взлома. Уязвимость связана с некорректной отработкой процедуры изменения размера массивов SafeArray, что позволяет незаметно сбивать адресацию и получать доступ к данным по любому адресу, а не только в рамках заданного массива.



Хакер также может использовать эту возможность для более сложных атак: например, запускать небезопасные скрипты с произвольными параметрами в обход систем контроля. Именно такую технику показал в этом году на конференции Black Hat USA китайский специалист по безопасности Ян Ю в своём докладе под названием «Vital Point Strike».



Что же касается экспертов из IBM X-Force, то они впервые обнаружили данную уязвимость ещё в мае этого года. За прошедшие месяцы они пока не наблюдали случаев эксплуатации данной уязвимости в полевых условиях. Однако авторы исследования подчёркивают, что уязвимость ещё не закрыта, и сейчас её активно изучают не только специалисты по безопасности, но и злоумышленники.

Original source: habrahabr.ru (comments, light).

http://habrahabr.ru/post/243047/

Метки:   Комментарии (0)КомментироватьВ цитатник или сообщество

Следующие 30  »

<vbscript - Самое интересное в блогах

Страницы: [1] 2 3 ..
.. 10

LiveInternet.Ru Ссылки: на главную|почта|знакомства|одноклассники|фото|открытки|тесты|чат
О проекте: помощь|контакты|разместить рекламу|версия для pda