Есть ли способ запустить VbScript в EA из командной строки? - PullRequest
0 голосов
/ 04 мая 2020

Я хотел бы запустить свой код VBScript, написанный на EA из командной строки (как ночная работа). Есть ли способ сделать это, кроме как скопировать его в файл .vbs и запустить его так? У меня есть куча! IN C - включенных в скрипт, и это будет означать двойное обслуживание, чтобы поддерживать обе версии в актуальном состоянии. Есть ли решение?

1 Ответ

2 голосов
/ 04 мая 2020

Здесь нет готового решения. Но вы можете написать код VBScript в mimi c, что делает EA, когда запускает скрипт, т.е.

  • получить код скрипта из таблицы t_script
  • получить все iclude (! IN C script_group.script_name)
  • заменить строки! IN C включенным текстом сценария
  • поместить сценарий во временный файл .VBS и запустить его

Кроме того, вам необходимо обеспечить замену всех функций, легко доступных в EA при запуске скрипта, по крайней мере

  • создать экземпляр объекта Repository как глобальную переменную
  • replace all all операторы Session.Output для получения вывода на консоль (в качестве альтернативы вы можете реализовать и создать свой собственный класс Session)

Поскольку EA является 32-разрядным приложением, вам необходимо вызвать 32-разрядную версию обработчика сценариев (cscript.exe) для запуска сценария, взаимодействующего с EA API, обычно по адресу C: \ Windows \ SysWOW64 \ cscript.exe

Все перечисленные выше задачи скомпилированы в следующую папку код сценария wing:

option explicit
'(c) Martin Jecny 2020

'WScript.Echo "Scripting Engine: " & ScriptEngine & " ver. " & ScriptEngineMajorVersion & "." & ScriptEngineMinorVersion & "." & ScriptEngineBuildVersion
'WScript.Echo "Creating Repository object"
dim Repository 'as EA.Repository  'defined as global, as it is default in EA environment
set Repository=CreateObject("EA.Repository")
dim ses 'as EA.Session
WScript.Echo "Start: " & Now
runIt(WScript.Arguments) 'complete script name, -v|--verbose
WScript.Echo "End: " & Now
'cleanup
on error resume next
Repository.exit
set Repository=Nothing
on error goto 0

sub runIt(argList)
  dim result 'as Variant
  if argList.Count <1 then
    WScript.Echo "Usage: runEaScript <scriptGroup>.<scriptName> [-v|--verbose] [-c|--copysource]"
    result=cleanup(Nothing)
    WScript.Quit(0)
  end if  

'parse arguments
  dim scriptFullName 'as String
  scriptFullName=argList(0)
  dim arg
  dim verbose 'as Boolean
  verbose=false
  dim copysource 'as Bollean
  copysource=false
  for each arg in argList
    select case arg
      case "-v", "--verbose"
        WScript.Echo "Verbose mode on"
        verbose=true
      case "-c", "--copysource"
        copysource=true
        if verbose then
          WScript.Echo "Copy of the produced code will be stored to current directory"
        end if
    end select
  next

  if verbose then WScript.Echo "Requested script to run: '" & scriptFullName & "'"
  if verbose then WScript.Echo "Opening cloud Repository ..."
  Repository.OpenFile ("mycloudrepository --- ;Connect=Cloud=protocol:http,address:cloudhost,port:80;Data Source=modelname;DSN=modelname;LazyLoad=1;")

  if verbose then WScript.Echo "Retrieving main script code ..."
  dim sql 'as String
  dim mainScriptCode 'as String
  mainScriptCode=getScriptCode(scriptFullName)
  if Len(mainScriptCode)<1 then 
    WScript.Echo "500002" & ": " & "Main script code retrieval failed."
    result=cleanup(Nothing)
    WScript.Quit(3)
  end if
  if verbose then WScript.Echo "Resolving !INCludes ..."
  dim startPos 'as Integer 'position of !INC in the code
  dim endOfPreviousLinePos 'as Integer 'position before start of the !INC line
  dim startToInc 'as String ' string between start of line and !INC directive
  dim endLinePos 'as Integer 'end position of !INC line
  dim endIncPos 'as Integer 'end of included script name within the line
  startPos=1 'start position of !INC in script code
  endLinePos=0 
  endIncPos=0 
  dim includeList 'as Scripting.Dictionary 'list of already included scripts
  set includeList=CreateObject("Scripting.Dictionary")
  includeList.RemoveAll
  dim includeString 'as String '!INC <script> string
  dim toBeReplaced 'as String 'usualy full line with !INC string
  do while startPos<>0

    'detect !INC
    startPos = InStr(1,mainScriptCode,"!INC ")

    'detection and removal of !INC within commented line
    if startPos > 0  then       
     endLinePos=InStr(startPos,mainScriptCode,chr(10))
     endOfPreviousLinePos=InStrRev(mainScriptCode, chr(10),startPos)
     if endOfPreviousLinePos <> (startPos-1) then
       startToInc=mid(mainScriptCode,endOfPreviousLinePos,startPos-endOfPreviousLinePos)
       if InStr(startToInc,"'")>0 then
         if verbose then WScript.Echo "Skipping commented reference " & startToInc & toBeReplaced
         toBeReplaced=mid(mainScriptCode,startPos,endLinePos-startPos)
         mainScriptCode=Replace(mainScriptCode,toBeReplaced,"",1,1)
         startPos=InStr(1,mainScriptCode,"!INC ")
       end if
     end if
    end if

    'including the code if not already included
    if startPos > 0  then    
      endLinePos=InStr(startPos,mainScriptCode,chr(10))
      includeString=trim(mid(mainScriptCode,startPos+5,endLinePos-(startPos+5))) 'ommit !INC string
      toBeReplaced=mid(mainScriptCode,startPos,endLinePos-startPos)
      'remove comment from reference line
      endIncPos=InStr(1,includeString,"'") 'comment?
      if endIncPos>0 then 'strip comment after reference
        includeString=left(includeString,endIncPos-1)
      end if
      includeString=trim(includeString)
      Err.Clear 'probably not necessary, just for sure
      on error resume next
        includeList.Add includeString,includeString 'Dictionary object has natively unique index
        if Err.Number >0  then 'already exists 
          if verbose then WScript.Echo includeString & " already included, removing the reference."
          mainScriptCode=Replace(mainScriptCode,toBeReplaced,"",1,1)
        else 'new one found
          if verbose then WScript.Echo "Including '" & includeString & "'"
          mainScriptCode=Replace(mainScriptCode,toBeReplaced,getScriptCode(includeString),1,1)
        end if
      on error goto 0
    end if
  loop

  'adapt code for running in pure VBS environment
  if verbose then WScript.Echo "Adapting the code ..."
  mainScriptCode=adaptToPureVbsCode(mainScriptCode)

  'make file with the code to run
  dim tempFileName 'as String
  dim fso 'as Scripting.FileSystemObject
  dim tempFolder 'as Folder
  set fso=CreateObject("Scripting.FileSystemObject")
  set tempFolder=fso.GetSpecialFolder(2) 'get temp diectory
  tempFileName=fso.GetSpecialFolder(2).Path & "\" & fso.getTempName
  dim mainScriptFile 'as File
  set mainScriptFile=fso.createTextFile(tempFileName)
  result=mainScriptFile.Write(mainScriptCode) '@TODO error handling
  result=mainScriptFile.Close
  if verbose then WScript.Echo "Written to file: " & tempFileName
  if copysource then
    dim scriptdir 'as Folder
    scriptdir = fso.GetParentFolderName(WScript.ScriptFullName)
    result=fso.CopyFile (tempFileName, scriptdir & scripFullName& ".vbs",true) 'overwrite allowed
  end if
  executeGlobal fso.openTextFile( tempFileName).readAll() 'run the complete script from temporary file

  if verbose then Wscript.Echo "000000" & ": " & "Successful exit"
  WScript.Quit(0)
end sub


function getScriptCode(scriptFullName)
  if Len(scriptFullName)<1 then
    WScript.Echo "500001" & ": " & "No script name provided"
    getScriptCode=""
    exit function
  end if
  if InStr(scriptFullName,".")<2 then
    WScript.Echo "500004" & ": " & "No group - provide full script name in the form  <Group>.<Script>"
    getScriptCode=""
    exit function
  end if
  dim dotPos 'as Integer
  dotPos=InStr(scriptFullName,".")
  dim scriptGroupName 'as String
  dim ScriptName 'as String
  scriptGroupName=Left(scriptFullName,dotPos-1)
  scriptName=Mid(scriptFullName,dotPos+1)
  if Len(scriptName)<1 then
    WScript.Echo "500005" & ": " & "No script name - provide full script name in the form  <Group>.<Script>" 
    getScriptCode=""   
  end if
  dim sql
  sql="select s.script from t_script s, t_script g where s.scriptauthor=g.scriptname"
  sql = sql & " and g.script like '" & scriptGroupName & "'"
  sql = sql & " and s.notes like '%Script Name=""" & scriptName & """%'"
  dim scriptCode 'as String
  getScriptCode=getSqlSingleValue(sql)
end function



'* adapts the code to run in pure VBS outside of EA
'* @param String 'original EA VBS code
'* @return String 'code with replacements
function adaptToPureVbsCode(code)       '@TODO: replacement for Session.Input and Session.Prompt
  dim regEx 'as RegExp
  set regEx=New RegExp
  regEx.IgnoreCase=true
  regEx.Global=true
  regEx.Pattern=chr(10)
  'beautification of the code, mainly for debug purposes
  code=regEx.Replace(code,chr(13) & chr(10))
  'redirect outuput commands
  regEx.Pattern="session.output" 'replace output command
  code=regEx.Replace(code,"WScript.Echo")
  'comment out manipulation with script output window
  regEx.Pattern="Repository.EnsureOutputVisible \""Script\"""
  code=regEx.Replace(code,"'"& "Repository.EnsureOutputVisible ""Script""")
  regEx.Pattern="Repository.ClearOutput \""Script\"""  
  code=regEx.Replace(code,"'Repository.ClearOutput ""Script""")
  adaptToPureVbsCode=code
end function




'* returns single (or first) value from single column; SQL query must comply to this; returns empty string if not found
'* @param sql as String  SQL query
'* @return String
public function getSqlSingleValue(sql) 'as String
        dim xmlDoc 'as MSXML2.DomDocument60 '1.2.0
        set xmlDoc=CreateObject("Msxml2.DOMDocument.6.0") '1.2.0
    dim node 'as MSXML2.IXMLDomNode
    xmlDoc.loadXML(Repository.SQLQuery(sql))    '@TODO fails with field names like COUNT(*) on "("; needs escaping
    set node= xmlDoc.selectSingleNode("//Row[1]/child::node()")
    if node is nothing then
        getSqlSingleValue=""
        exit function
    end if
    if len(node.text)>0 then
        getSqlSingleValue=node.text
    else
        getSqlSingleValue=""
    end if
end function

'*@ Cleanup of the environment
'*@param FileSystemObject fso
'*@return void
function cleanup(fso)
  on error resume next
    Repository.CloseFile
    Repository.Exit
    set Repository=nothing
    result=fso.DeleteFile(tempFileName)
    set fso=nothing
  on error goto 0
end function

использование сценария

"C: \ Windows \ SysWOW64 \ cscript.exe" "C: \ Users \ пользователь \ Documents \ jobs \ runEaScript .vbs "" Моя группа сценариев. Имя моего сценария "--verbose / nolo go

Следует отметить, что текстовые операции VBScript не являются чрезвычайно быстрыми, и подготовка сценария может занять некоторое время. Если вам нужно очень часто запускать скрипт, внедрите некоторое кэширование полученного файла VBS.

...