Скрипт установки корневых сертификатов

Программирование на языке СБиС++, создание обработчиков событий, редактирование окон, создание отчетов и т.д.

Правила форума
Тема закрыта! Все обсуждения теперь ведутся в группе СБИС 2.Х
Подробнее о том как найти группы и вступить в них.

Скрипт установки корневых сертификатов

С вашего сайта можно скачать самораспаковывающийся архив install_certs.exe, который после распаковки запускает install.vbs
Код вашего скрипта на текущий момент
Код: Выделить всё
'Данный скрипт пробегается по всем файлам в заданной папке
'по маске "*.cer" и применяет certmgr.exe для установки сертификатов
path = "\Root\"
Set WshShell = WScript.CreateObject( "WScript.Shell" )
Set objNetwork = CreateObject( "WScript.Network" )
set fso = CreateObject( "Scripting.FileSystemObject" )
Set fLog = fso.OpenTextFile( "!log_root_certs.txt", 8, True )
fLog.write vbCrLf & "=Начало=" & Now( ) & vbCrLf
fLog.write "Имя компа: " & objNetwork.ComputerName & vbCrLf
fLog.write "Имя пользователя: " & objNetwork.UserName & vbCrLf
fLog.write "Были установлены следующие сертификаты:" & vbCrLf  & vbCrLf
i = 0

for each f in FSO.GetFolder( WshShell.CurrentDirectory & path ).Files
if right(f.name, 4) = ".cer" then
   WshShell.Run "certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root", 7, true
   fLog.write f.name & vbCrLf
   i = i + 1
end if
next

fLog.write vbCrLf  & "Установлено сертификатов: " & i & vbCrLf  & vbCrLf
fLog.close


Итак. Берем этот экзешник, запускаем его ("От имени администратора". ИМХО, не нужно, но раз в ТП сказали, то будем запускать так).
Указываем путь распаковки.
Все проходит успешно, в логе читаем запись.
Установлено сертификатов: 27

Но вот проблема, мы перед этим специально удалили из наших доверенных корневых сертификатов (Далее, ДКС) uc_tensor_44-2017.cer. И после установки он так и не появился там снова. Открываем сам файл сертификата - нет доверия.
Почему? Наверное, потому что certmgr был запущен с ключами -s -r localMachine.
Посмотрим что там в локалмашин.
Запускаем mmc, добавляем оснастку сертов под локальный компьютер - нет, нету там в ДКС никакого Тензора. Ни нашего целевого сертификата, ни остальных сертификатов Тензора на localMachine нет вообще.

Если мы будем обращаться к certmgr не через оболочку shell vbs, а напрямую интерактивно (из cmd), то при выполнении вот такого запроса
Код: Выделить всё
CertMgr -add -c root/uc_tensor_44-2017.cer -s -r localMachine root

сертификат успешно установится. Мы увидим фразу CertMgr Succeeded и наш сертификат появится таки в ДКС локального компьютера, и перестанет быть без доверия.

Так в чем же тут проблема? Давайте добавим вывод результата каждого вызова WshShell.Run и посмотрим.
Делаем:
Код: Выделить всё
Wscript.Echo WshShell.Run("certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root", 7, true)

Получаем ErrorCode 13. Что он значит в данном случае - информации не нашел. Скажу лишь, что при успешной установке код возврата должен быть 0.

Попробуем вызвать тоже самое через .Exec
Код: Выделить всё
      Set oExec = WshShell.Exec("certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root")
      x = oExec.StdOut.ReadLine
      Wscript.Echo x

И видим, что каждый вызов вернул CertMgr Succeeded со всеми вытекающими. Т.е. когда мы использовали exec вместо run, сертификаты успешно встали. Но в чем же разница? А в том, что метод .Exec создает инстанс cmd и интерактивно выполняет код, а .Run к cmd не обращается, если этого не указано явно. Вместо этого .Run будет обращаться к CertMgr непосредственно и ожидать от него навыков external command-line. Коим он не является, как мне кажется.

Поэтому мы делаем ВЖУХ и получаем вот такой код, с которым все серты поставятся.
Код: Выделить всё
'Данный скрипт пробегается по всем файлам в заданной папке
'по маске "*.cer" и применяет certmgr.exe для установки сертификатов
'End it works as intended

'--------------------- Defines and variables
Dim str_cmd, fLog_path, debug, tempFile, tempResult
debug = true
tempFile = "temp.txt"
tempResult = ""
path = "\Root\"

'--------------------- Prepare Objects
Set WshShell = WScript.CreateObject( "WScript.Shell" )
Set objNetwork = CreateObject( "WScript.Network" )
set fso = CreateObject( "Scripting.FileSystemObject" )

' Create temp.txt for stdOut
call void_PrepareTempFile(fso, tempFile)

Set fLog = fso.OpenTextFile( "!log_root_certs.txt", 2, True )
fLog_path = fso.GetAbsolutePathName(tempFile)

fLog.write vbCrLf & "=Начало=" & Now( ) & vbCrLf
fLog.write "Имя компа: " & objNetwork.ComputerName & vbCrLf
fLog.write "Имя пользователя: " & objNetwork.UserName & vbCrLf
fLog.write "Были установлены следующие сертификаты:" & vbCrLf  & vbCrLf
i = 0

for each f in FSO.GetFolder( WshShell.CurrentDirectory & path ).Files
   ' Better prevent .CER or .cEr or .cER etc. files to be ignored by this script. LCase helps
   if LCase(fso.getExtensionName(f.path)) = "cer" then
      'Invoking cmd /c is vital
      str_cmd = "cmd /c " & fn_Quot(fn_CertmgrThis(f, fLog_path, debug))

      WshShell.Run str_cmd, 7, true

      ' If we was writing StdOut we need to read it next.
      With fso.OpenTextFile(tempFile, 1)
         tempResult = ""
         Do Until .atEndOfStream
              tempResult = tempResult & " - " & .readLine
         Loop
      End With

      fLog.write f.name & tempResult & vbCrLf
      i = i + 1
   end if
next

fLog.write vbCrLf  & "Установлено сертификатов: " & i & vbCrLf  & vbCrLf
fLog.close

' delete temp.txt
call void_DeleteTempFile(fso, tempFile)

MsgBox("All done. See !log_root_certs.txt for debug info.")

'--------------------- Support Functions
Function fn_Quot(str)
   fn_Quot = """" & str & """"
End Function

Function fn_CertmgrThis(f, log_path, debug)
   'WshShell.Run "certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root", 7, true
   fn_CertmgrThis = "certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root"
   if not debug = false then
      fn_CertmgrThis = "certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root > " & fn_Quot(log_path) & " 2>&1"
   end if
End Function

Sub void_PrepareTempFile(fso, tempFile)
   If fso.FileExists(tempFile) Then
      fso.DeleteFile(tempFile)   
   End If
   fso.CreateTextFile(tempFile)
End Sub

Sub void_DeleteTempFile(fso, tempFile)
   If fso.FileExists(tempFile) Then
      fso.DeleteFile(tempFile)   
   End If
End Sub
sdtadm 
» 04 апр 2018, 21:42


Спасибо. Наконец то сертификаты не придётся ставить на каждый компьютер вручную.
nkozlov 
» 09 апр 2018, 16:24


Немного вариативности
Т.к. скрипт изначально ставит серты в ветку HKLM, то таки права локального администратора могут понадобиться.
Если установить в скрипте значение ask_me_where = true (по умолчанию = false), то при запуске будет задан вопрос - ставить на localMachine или для currentUser.
.png
.png (8.8 Кб) Просмотров: 881

Тут важен один нюанс при многократном запуске - для localMachine вопросов о перезаписи не задается и все серты поставятся без вариантов, а для currentUser - будет задан вопрос на удаление + вопрос на запись. А для некоторых уже существующих вообще вопроса не будет, они сразу отвалятся с ошибкой добавления.
Но, собственно, если сертификата нет ни в HKLM, ни в HKCU, то он установится для юзера успешно и без вопросов.

Код: Выделить всё
'Данный скрипт пробегается по всем файлам в заданной папке
'по маске "*.cer" и применяет certmgr.exe для установки сертификатов
'End it works as intended

'--------------------- Defines and variables
Dim str_cmd, debug, ask_me_where

debug = true
ask_me_where = false

tempFile = "temp.txt"
tempResult = ""
path = "\Root\"
location = "-r localMachine root"
'currentUser or localMachine

'--------------------- Ask where to store certs
if ask_me_where then
   msg_text = "Установить сертификаты для всех пользователей?" & _
      vbCrLf & _
      vbCrLf & "Да - для всех пользователей компьютера. (могут потребоваться права администратора)" & _
      vbCrLf & "Нет - только для текущего пользователя." & _
      vbCrLf & "Отмена - выход из программы."
   answLocation = MsgBox(msg_text, vbYesNoCancel + vbQuestion + vbDefaultButton1, "Куда вы хотите установить сертификаты?")
   if answLocation = vbYes then
      location = "-r localMachine root"
   elseif answLocation = vbNo then
      location = "-r currentUser root"
   else
      WScript.Quit
   end if
end if
'--------------------- Prepare Objects
Set WshShell = WScript.CreateObject( "WScript.Shell" )
Set objNetwork = CreateObject( "WScript.Network" )
set fso = CreateObject( "Scripting.FileSystemObject" )

' Create temp.txt for stdOut
call void_PrepareTempFile(fso, tempFile)

Set fLog = fso.OpenTextFile( "!log_root_certs.txt", 2, True )
tempLog_path = fso.GetAbsolutePathName(tempFile)

fLog.write vbCrLf & "=Начало=" & Now( ) & vbCrLf
fLog.write "Имя компа: " & objNetwork.ComputerName & vbCrLf
fLog.write "Имя пользователя: " & objNetwork.UserName & vbCrLf
fLog.write "Режим установки: " & location & vbCrLf
fLog.write "Были установлены следующие сертификаты:" & vbCrLf  & vbCrLf
i = 0
err_i = 0
for each f in FSO.GetFolder( WshShell.CurrentDirectory & path ).Files
   ' Better prevent .CER or .cEr or .cER etc. files to be ignored by this script. LCase helps
   if LCase(fso.getExtensionName(f.path)) = "cer" then
      'Invoking cmd /c is vital
      str_cmd = "cmd /c " & fn_Quot(fn_CertmgrThis(f, location, tempLog_path, debug))

      WshShell.Run str_cmd, 7, true

      ' If we was writing StdOut we need to read it next.
      if debug then
         With fso.OpenTextFile(tempFile, 1)
            tempResult = ""
            Do Until .atEndOfStream
               curLine = .readLine
                 tempResult = tempResult & " - " & curLine
            Loop
            if curLine = "CertMgr Failed" then
               err_i = err_i + 1
            end if

         End With
      end if

      fLog.write f.name & tempResult & vbCrLf
      i = i + 1
   end if
next


if debug then
   fLog.write vbCrLf  & "Попыток установки сертификата: " & i & vbCrLf
   i = i - err_i
   fLog.write vbCrLf  & "Успешно установлено: " & i & vbCrLf
   fLog.write vbCrLf  & "Ошибок установки: " & err_i & vbCrLf  & vbCrLf
else
   fLog.write vbCrLf  & "Установлено сертификатов: " & i & vbCrLf  & vbCrLf
end if

fLog.close

' delete temp.txt
call void_DeleteTempFile(fso, tempFile)

MsgBox("All done. See !log_root_certs.txt for debug info.")

'--------------------- Support Functions
Function fn_Quot(str)
   fn_Quot = """" & str & """"
End Function

Function fn_CertmgrThis(f, location, log_path, debug)
   'WshShell.Run "certmgr -add -c " & chr(34) & f & chr(34) & " -s -r localMachine root", 7, true
   fn_CertmgrThis = "certmgr -add -c " & chr(34) & f & chr(34) & " -s " & location
   if not debug = false then
      fn_CertmgrThis = "certmgr -add -c " & chr(34) & f & chr(34) & " -s " & location & " > " & fn_Quot(log_path) & " 2>&1"
   end if
End Function

Sub void_PrepareTempFile(fso, tempFile)
   If fso.FileExists(tempFile) Then
      fso.DeleteFile(tempFile)   
   End If
   fso.CreateTextFile(tempFile)
End Sub

Sub void_DeleteTempFile(fso, tempFile)
   If fso.FileExists(tempFile) Then
      fso.DeleteFile(tempFile)   
   End If
End Sub

Архив со скриптом, certMgr.exe и пустой папкой root
certs.zip
(32.83 Кб) Скачиваний: 109
sdtadm 
» 17 апр 2018, 08:32


спасибо за проделанную работу!
Благушин Виктор 
» 17 апр 2018, 09:30




Вернуться в Разработка и администрирование в СБиС++