Performance Consideration of an SAP GUI for Windows Automation

A few days ago I discussed with my colleague performance perspectives in the context of RPA and SAP. He told me that the performance aspect in this scenario could be very critical, if you have one use case but you have to execute it many times, e.g. 10000 times. So I created a test case to check and to get a solid statement for this case.

I automate a very simple process: Call transaction code SE16 with table TFDIR, press button Number of Entries and read the number, and this ten times. This process exists in two ways. The first is a PowerShell script which uses SAP GUI Scripting and the second is a recorded activity sequence. The PowerShell script is also executed in the context of UiPath. The execution platform is thus identical in both cases.

At first I record the script with my Tracker and implement it in UiPath Studio. That was very easy.

#-Begin-----------------------------------------------------------------

#-Load assembly---------------------------------------------------------
[Void][Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")
[Void][Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms")

#-Function Create-Object------------------------------------------------
Function Create-Object {

  Param(
    [String]$objectName
  )

  Try {
    New-Object -ComObject $objectName
  } Catch {
    [Void][System.Windows.Forms.MessageBox]::Show(
      "Can't create object", "Important hint", 0)
  }

}

#-Function Get-Object---------------------------------------------------
Function Get-Object {

  Param(
    [String]$pathName,
    [String]$class
  )

  [Microsoft.VisualBasic.Interaction]::GetObject($pathName, $class)

}

#-Sub Free-Object-------------------------------------------------------
Function Free-Object {

  Param(
    [__ComObject]$object
  )

  [Void][System.Runtime.Interopservices.Marshal]::ReleaseComObject($object)

}

#-Function Get-Property-------------------------------------------------
Function Get-Property {

  Param(
    [__ComObject]$object,
    [String]$propertyName, 
    $propertyParameter
  )

  $objectType = [System.Type]::GetType($object)
  $objectType.InvokeMember($propertyName,
    [System.Reflection.Bindingflags]::GetProperty,
    $null, $object, $propertyParameter)

}

#-Sub Set-Property------------------------------------------------------
Function Set-Property {

  Param(
    [__ComObject]$object,
    [String]$propertyName,
    $propertyValue
  )

  $objectType = [System.Type]::GetType($object)
  [Void] $objectType.InvokeMember($propertyName,
    [System.Reflection.Bindingflags]::SetProperty,
    $null, $object, $propertyValue)

}

#-Function Invoke-Method------------------------------------------------
Function Invoke-Method {

  Param(
    [__ComObject]$object,
    [String]$methodName,
    $methodParameters
  )

  $objectType = [System.Type]::GetType($object)
  $output = $objectType.InvokeMember($methodName,
    "InvokeMethod", $NULL, $object, $methodParameters)
  if ( $output ) { $output }

}

#-Sub Main--------------------------------------------------------------
Function Main() {

  $SapGuiAuto = Get-Object( , "SAPGUI");
  If ($SapGuiAuto -isnot [__ComObject]) {
    Exit;
  }

  $application = Invoke-Method $SapGuiAuto "GetScriptingEngine";
  If ($application -isnot [__ComObject]) {
    Free-Object $SapGuiAuto;
    Exit;
  }

  $connection = Get-Property $application "Children"@(0);
  If ($Null -eq $connection) {
    Free-Object $SapGuiAuto;
    Exit;
  }

  $session = Get-Property $connection "Children"@(0);
  If ($Null -eq $session) {
    Free-Object $SapGuiAuto;
    Exit;
  }

  For($i = 1; $i -le 10; $i++) {
    $ID = Invoke-Method $session "findById" @("wnd[0]/tbar[0]/okcd");
    Set-Property $ID "text" @("/nse16");
    $ID = Invoke-Method $session "findById" @("wnd[0]");
    Invoke-Method $ID "sendVKey" @(0);
    $ID = Invoke-Method $session "findById" @("wnd[0]/usr/ctxtDATABROWSE-TABLENAME");
    Set-Property $ID "text" @("TFDIR");
    $ID = Invoke-Method $session "findById" @("wnd[0]/usr/ctxtDATABROWSE-TABLENAME");
    Set-Property $ID "caretPosition" @(5);
    $ID = Invoke-Method $session "findById" @("wnd[0]");
    Invoke-Method $ID "sendVKey" @(0);
    $ID = Invoke-Method $session "findById" @("wnd[0]/tbar[1]/btn[31]");
    Invoke-Method $ID "press";
    $ID = Invoke-Method $session "findById" @("wnd[1]/usr/txtG_DBCOUNT");
    $Result = Get-Property $ID "text"
    $ID = Invoke-Method $session "findById" @("wnd[1]/tbar[0]/btn[0]");
    Invoke-Method $ID "press";
    $Result
  }

}

#-Main------------------------------------------------------------------
Main;
  
#-End-------------------------------------------------------------------

002

It delivers the correct result and the execution time is 7 seconds.

003

Then I recorded the same activity sequence with UiPath and put it in a loop.

That was very easy too. Now I execute this branch.

001

It delivers the correct result, but the execution time is 36 seconds.

005

That result reveals us that in this case the using of a PowerShell script with a recorded SAP GUI Scripting activity in UiPath is 5 times faster as the same activity recorded in UiPath. I think this way could be a validated approach for SAP use cases which must be processed in very large quantities.

6 Likes

Very nice! Im using ur tool for get the script, but i have a question, with UiPrime library i cant set ‘Selected’ or others methods through assign activities, how can i implement the function through Invoke Com Method?

Hello @BryannLuna,

welcome in the UiPath Community.

UiPrime does not implements at the moment all classes of the SAP GUI Scripting, e.g. GuiTabStrip or GuiCustomControl are missing. Also in the existing classes it does not supports all possible methods or properties. It seems that UiPrime wraps the methods of the SAP GUI Scripting API. In my opinion it is not or very awkward possible to add missing methods via Invoke COM. I suggest you to choose another way.

Best regards
Stefan