Quantcast
Channel: Scripting Languages
Viewing all 42 articles
Browse latest View live

Review: Use Limits of SAP ActiveX Libraries in .NET Environment PowerShell

$
0
0

Hello community,

 

in a normal case you can use the COM libraries, like the SAP ActiveX, very easily in PowerShell scripting language.

 

$SAPFunc = New-Object -ComObject "SAP.Functions"

 

This should be sufficient to use the SAP ActiveX libraries. But in this case you don't have access to the members of the library.

001.JPG

At this point I use the way I described here, I use the helper functions. In this case you can use the ActiveX libraries, but you are missing the advantages of the Integrated Script Environment (ISE) of PowerShell, e.g. code completion.

 

To compensate this disadvantage I create with the type library importer (tlbimp) of the Microsoft .NET SDK an interoperability library.

 

[Reflection.Assembly]::LoadFile("C:\Dummy\Interop.wdtfuncs.dll")

$SAPFunc = New-Object Interop.wdtfuncs.SAPFunctionsClass

 

Now it works all as expected.

002.JPG

So far so good, but the next problem is in front of the door.

 

In a normal case you use the Connection property in the next step.

 

$Connection = $SAPFunc.Connection

 

It works, you get the object, but not all members.

003.JPG

Now I do the same steps with wdtlog.ocx and want to cast the object variable on different ways into the connection class type, but without success.

 

[Interop.wdtlog.ConnectionClass]$Connection = $SAPFunc.Connection

$Connection = [Interop.wdtlog.ConnectionClass]$SAPFunc.Connection

$Connection -As [Interop.wdtlog.ConnectionClass]

$Connection -Is [Interop.wdtlog.ConnectionClass]

 

As far as I can see it is not possible to cast a System.__ComObject to another in PowerShell.

 

Maybe someone has a solution for this problem.

 

Another insight: It is not in any case possible to use reference variables with COM libraries. If you work with an interoperability library it is as well not possible.

 

From these points it seems reasonable to use NCo, which I described here and here.

 

 

2015/09.20 - Addendum: The casting method that I described here doesn't work also. It crashes PowerShell with the errors System.AccessViolationException and System.RuntimeType.ForwardCallToInvokeMember at the point where the first property is assigned..

 

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

 

  #-Sub Main------------------------------------------------------------

    Function Main() {

 

      $Path = $PSScriptRoot

      [Reflection.Assembly]::LoadFile($Path + "\wdtlog.dll")

      [Reflection.Assembly]::LoadFile($Path + "\wdtfuncs.dll")

      [Reflection.Assembly]::LoadFile($Path + "\wdtaocx.dll")

 

      $SAPFunc = New-Object wdtfuncs.SAPFunctionsClass

      If ($SAPFunc -eq $Null) {

        Break

      }

 

      $SAPFunc.AboutBox()

 

      $Connection = $SAPFunc.Connection

      If ($Connection -eq $Null) {

        Break

      }

 

      [wdtlog.Connection]$Connection =

        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Connection,

        [wdtlog.ConnectionClass])

 

      $Connection.Client = "001"

      $Connection.User = "BCUSER"

      $Connection.Password = "minisap"

      $Connection.Language = "EN"

      $Connection.System = "NSP"

      $Connection.HostName = "ABAP702"

      $Connection.SystemNumber = 0

    

      $SAPConnection = $Connection.Logon(0, -1)

      If ($SAPConnection -ne 0) {

        Write-Host "Check connection in SAP system with transactin SMGW"

 

      }

 

    }

 

  #-Main----------------------------------------------------------------

    Main

 

#-End-------------------------------------------------------------------

 

Cheers

Stefan


How To Use NCo With PowerShell: Client Apps (PowerShell uses .NET Connector)

$
0
0

Hello community,

 

at the beginning of this year I presented here, here and here different possibilities to use SAPs .NET Connector (NCo) in the context of the scripting language PowerShell. Now with new experience and knowledge I can say that the use of this combination is very profitably. You can try different programming situations fast, without a special IDE. Also you can use it to automate a lot of things, e.g. to download and compare data (customizing on different systems). The PowerShell ISE (Integrated Script Environment) with the integrated debugger offers a good range of functions, e.g. like syntax highlighting and code completion. All in all I can recommend PowerShell unlimited. As a further outlook for the future, a combination of SAP GUI Scripting, NCo and PowerShell seems very interesting. We will see...

 

Here now two more examples. The first shows how to ping an SAP system via RFC_PING and the build-in ping from NCo. The second shows how to get system via the function module RFC_SYSTEM_INFO. The code is commented and I think easy to understand. It shows, in conjunction with the links above, all variants of parameters.

 

 

1st example - Ping

 

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


  <#

    .Synopsis

      Calls PING of an SAP system.

    .Description

      Calls the function module RFC_PING and the build-in function

      Ping of the .NET connector.

  #>

 

  #-Sub Load-NCo--------------------------------------------------------

    Function Load-NCo {

 

      $ScriptDir = $PSScriptRoot

 

      $Size = [System.IntPtr]::Size

      If ($Size -eq 4) {

        $Path = $ScriptDir + "\x86\"

      }

      ElseIf ($Size -eq 8) {

        $Path = $ScriptDir + "\x64\"

      }

 

      [Reflection.Assembly]::LoadFile($Path + "sapnco.dll") > $Null

      [Reflection.Assembly]::LoadFile($Path + "sapnco_utils.dll") > $Null

 

    }

 

  #-Function Get-Destination--------------------------------------------

    Function Get-Destination {

 

      #-Connection parameters-------------------------------------------

        $cfgParams = New-Object SAP.Middleware.Connector.RfcConfigParameters

        $cfgParams.Add("NAME", "TEST")

        $cfgParams.Add("ASHOST", "ABAP")

        $cfgParams.Add("SYSNR", "00")

        $cfgParams.Add("CLIENT", "001")

        $cfgParams.Add("USER", "BCUSER")

 

        $SecPasswd = Read-Host -Prompt "Passwort" -AsSecureString

        $ptrPasswd = [Runtime.InteropServices.Marshal]::SecureStringToBStr($SecPasswd)

        $Passwd = [Runtime.InteropServices.Marshal]::PtrToStringBStr($ptrPasswd)

        $cfgParams.Add("PASSWD", $Passwd)

 

      Return [SAP.Middleware.Connector.RfcDestinationManager]::GetDestination($cfgParams)

 

    }

 

  #-Sub Execute-Ping----------------------------------------------------

    Function Execute-Ping () {

 

      $destination = Get-Destination

 

      #-Metadata--------------------------------------------------------

        [SAP.Middleware.Connector.IRfcFunction]$rfcFunction =

          $destination.Repository.CreateFunction("RFC_PING")

 

      #-Variant 1: Call function module---------------------------------

        Try {

          $rfcFunction.Invoke($destination)

          Write-Host "Ping successful"

        }

        Catch {

          Write-Host "Exception" $_.Exception.Message "occured"

        }

 

      #-Variant 2: Call build-in function-------------------------------

        Try {

          $destination.Ping()

          Write-Host "Ping successful"

        }

        Catch {

          Write-Host "Exception" $_.Exception.Message "occured"

        }

 

    }

 

  #-Sub Main------------------------------------------------------------

    Function Main () {

      If ($PSVersionTable.PSVersion.Major -ge 3) {

        Load-NCo

        Execute-Ping

      }

    }

 

  #-Main----------------------------------------------------------------

    Main

 

#-End-------------------------------------------------------------------

 

 

2nd example - RFC_SYSTEM_INFO

 

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

 

  <#

    .Synopsis

      Calls RFC_SYSTEM_INFO of an SAP system.

    .Description

      Calls the function module RFC_SYSTEM_INFO and writes the result

      on the screen.

  #>

 

  #-Sub Load-NCo--------------------------------------------------------

    Function Load-NCo {

 

      $ScriptDir = $PSScriptRoot

 

      $Size = [System.IntPtr]::Size

      If ($Size -eq 4) {

        $Path = $ScriptDir + "\x86\"

      }

      ElseIf ($Size -eq 8) {

        $Path = $ScriptDir + "\x64\"

      }

 

      [Reflection.Assembly]::LoadFile($Path + "sapnco.dll") > $Null

      [Reflection.Assembly]::LoadFile($Path + "sapnco_utils.dll") > $Null

 

    }

 

  #-Function Get-Destination--------------------------------------------

    Function Get-Destination {

 

      #-Connection parameters-------------------------------------------

        $cfgParams = New-Object SAP.Middleware.Connector.RfcConfigParameters

        $cfgParams.Add("NAME", "TEST")

        $cfgParams.Add("ASHOST", "ABAP")

        $cfgParams.Add("SYSNR", "00")

        $cfgParams.Add("CLIENT", "001")

        $cfgParams.Add("USER", "BCUSER")

 

        $SecPasswd = Read-Host -Prompt "Passwort" -AsSecureString

        $ptrPasswd = [Runtime.InteropServices.Marshal]::SecureStringToBStr($SecPasswd)

        $Passwd = [Runtime.InteropServices.Marshal]::PtrToStringBStr($ptrPasswd)

        $cfgParams.Add("PASSWD", $Passwd)

 

      Return [SAP.Middleware.Connector.RfcDestinationManager]::GetDestination($cfgParams)

 

    }

 

  #-Sub Get-SystemInfo--------------------------------------------------

    Function Get-SystemInfo () {

 

      $destination = Get-Destination

 

      #-Metadata--------------------------------------------------------

        [SAP.Middleware.Connector.IRfcFunction]$rfcFunction =

          $destination.Repository.CreateFunction("RFC_SYSTEM_INFO")

 

      #-Call function module--------------------------------------------

        Try {

          $rfcFunction.Invoke($destination)

 

          [SAP.Middleware.Connector.IRfcStructure]$Export =

            $rfcFunction.GetStructure("RFCSI_EXPORT")

 

          #-Get information---------------------------------------------

            Write-Host $Export.GetValue("RFCHOST")

            Write-Host $Export.GetValue("RFCSYSID")

            Write-Host $Export.GetValue("RFCDBHOST")

            Write-Host $Export.GetValue("RFCDBSYS")

 

        }

        Catch {

          Write-Host "Exception" $_.Exception.Message "occured"

        }

 

    }

 

  #-Sub Main------------------------------------------------------------

    Function Main () {

      If ($PSVersionTable.PSVersion.Major -ge 3) {

        Load-NCo

        Get-SystemInfo

      }

    }

 

  #-Main----------------------------------------------------------------

    Main

 

#-End-------------------------------------------------------------------

 

If you like you can find the same functionalityhere, with SAP NetWeaver RFC SDK and FreeBASIC, to compare it.

 

Enjoy it.

 

Cheers

Stefan

From PowerShell Zero To SAP GUI Scripting Hero

$
0
0

Hello community,

 

I wrote here about the possibility to use SAP GUI Scripting inside PowerShell. The basis of this approach is Visual Basic Script (VBS) resp. the Microsoft Script Control. On this way it is very easy to use the existing scripts furthermore. Here I have compared the use of .NET invoke methods with the use of MSScriptControl. This was a step forward to .NET, but the disadvantage is that you can't use the advantages of the Integrated Script Environment (ISE) like code completion.

 

To walk around this shortcoming I searched for a method to cast the ___COMObject types to correct data types in a namespace of a .NET assembly. I found the method CreateWrapperOfType. All I have to do is to build with the type library importer (TLBIMP) a .NET assembly from the SAPFEWSE.OCX library - thats all. If you don't habe the possibility to build it at your own, look in your NWBC or SapDtsCOMFramework directory, here you find the assembly Interop.SAPFEWSELib.dll, it is also possible to use this assembly.

 

Hint: The assembly of the NWBC use the namespace Interop.SAPFEWSELib, the assembly of the Dynamic Test Script framework use only SAPFEWSELib. I find that very awkward. If you use the assembly of the NWBC you must modfy the types below and add Interop. in front of the type names.

 

A code line with a ___COMObject casting to another type of a SAP GUI Scripting object looks like this:

[SAPFEWSELib.GuiApplication]$Application =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Application,

    [SAPFEWSELib.GuiApplicationClass])

Here I cast the variable $Application from the type System.___COMObject to GuiApplication - our base friend of the SAP GUI Scripting object hierarchy. I think it is easy to understand what happens.

 

Here now the complete code:

 

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

 

  [Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic")

 

  [Reflection.Assembly]::LoadFile("SAPFEWSELib.dll")

 

  $SapGuiAuto = [Microsoft.VisualBasic.Interaction]::GetObject("SAPGUI")

  If ($SapGuiAuto -eq $Null) {

    Break

  }

 

  $Application = $SapGuiAuto.GetType().InvokeMember("GetScriptingEngine",

        [System.Reflection.Bindingflags]::InvokeMethod,

        $null, $SapGuiAuto, $null, $null, $null, $null)

  [SAPFEWSELib.GuiApplication]$Application =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Application,

    [SAPFEWSELib.GuiApplicationClass])

  If ($Application -eq $Null) {

    Break

  }

 

  $Connection = $Application.Children.Item(0)

  [SAPFEWSELib.GuiConnectionClass]$Connection =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Connection,

    [SAPFEWSELib.GuiConnectionClass])

  If ($Connection -eq $Null) {

    Break

  }

 

  $Session = $Connection.Children.Item(0)

  [SAPFEWSELib.GuiSession]$Session =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Session,

    [SAPFEWSELib.GuiSessionClass])

  If ($Session -eq $Null) {

    Break

  }

 

  $Mandt = $Session.FindById("wnd[0]/usr/txtRSYST-MANDT")

  [SAPFEWSELib.GuiTextField]$Mandt =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Mandt,

    [SAPFEWSELib.GuiTextFieldClass])

  $BName = $Session.FindById("wnd[0]/usr/txtRSYST-BNAME")

  [SAPFEWSELib.GuiTextField]$BName =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($BName,

    [SAPFEWSELib.GuiTextFieldClass])

  $Langu = $Session.FindById("wnd[0]/usr/txtRSYST-LANGU")

  [SAPFEWSELib.GuiTextField]$Langu =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Langu,

    [SAPFEWSELib.GuiTextFieldClass])

  $BCode = $Session.FindById("wnd[0]/usr/pwdRSYST-BCODE")

  [SAPFEWSELib.GuiPasswordField]$BCode =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($BCode,

    [SAPFEWSELib.GuiPasswordFieldClass])

 

  $Mandt.Text = "001"

  $BName.Text = "BCUSER"

  $Langu.Text = "EN"

  $Bcode.Text = "minisap"

 

  $MainWin = $Session.FindById("wnd[0]")

  [SAPFEWSELib.GuiMainWindow]$MainWin =

    [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($MainWin,

    [SAPFEWSELib.GuiMainWindowClass])

  $MainWin.SendVKey(0)

 

#-End-------------------------------------------------------------------

 

This example is equivalent to the examples in the links above. Sure it is more complex as VBScript, but it offers all adavantages of the integration in the .NET environment.

 

001.jpg

 

This possibility opens now the gate wide to use SAP GUI Scripting seamlessly in PowerShell and in any other language ot the .NET environment.

 

Hint after: As far as I know uses the NetWeaver Business Client (NWBC), version 4 and 5, as well as the Dynamic Test Scripts (DTS) framework the same method. SAP dts is a test framework which enables automation of testing SAP applications. Look at US patent US 20120023485 A1 for more information about DTS.

 

Enjoy it.

 

Cheers

Stefan

Use Named References of SAP ActiveX Libraries in VBA for Easy Programming

$
0
0

Hello community,

 

many Microsoft Office programmers uses the SAP ActiveX libraries of the SAP GUI for Windows installation. The reason for this descision is the availability of the libraries. To use the libraries it is necessary to reference it.

 

Menu Tools > References

101.jpg

Browse > Add Reference

102.jpg

It is necessary to add wdtfuncs.ocx, wdttaocx.ocx, wdtlog.ocx and optional wdobapi.ocx. You can find the files in the directory of the SAP GUI, C:\Program Files (x86)\SAP\FrontEnd\sapgui.

 

103.JPG

Hint: The wdtlog.ocx is in the directory C:\Program Files (x86)\Common Files\SAP Shared.

 

Hint: You can also use the unicode versions of the libraries, the filenames ends with an u.

 

104.jpg

So far the prelude. You can find a very good equivalent description here.

 

But many Office programmers declare their object variables in VBA only as Object. If they choose this method is it at first not necessary to reference the libraries and on second they lose the very good code completion functionality.


'-Begin-----------------------------------------------------------------

  Sub Test()

 

    '-Variables---------------------------------------------------------

      Dim oFunc As Object

      Dim oConn As Object

      Dim SAPConn As Integer

    

    Set oFunc = CreateObject("SAP.Functions.Unicode")

    If Not IsObject(oFunc) Then

       MsgBox "CreateObject(SAP.Functions.Unicode) failed", vbOKOnly, _

         "Error"

       Exit Sub

    End If

 

    Set oConn = oFunc.Connection()

    If Not IsObject(oConn) Then

      MsgBox "SAPFunc.Connection failed", vbOKOnly, "Error"

      Exit Sub

    End If

 

    SAPConn = oConn.Logon(0, vbFalse)

    If SAPConn <> 0 Then

 

      oConn.Logoff

    Else

      MsgBox "Connection.Logon failed", vbOKOnly, "Error"

    End If

 

  End Sub

'-End-------------------------------------------------------------------


If you want to benefit from the advantages, is it necessary to change the source like this:


'-Begin-----------------------------------------------------------------

  Sub Test()

 

    '-Variables---------------------------------------------------------

      Dim oFunc As SAPFunctionsOCX.SAPFunctions

      Dim oConn As SAPLogonCtrl.Connection

      Dim SAPConn As Integer

    

    Set oFunc = CreateObject("SAP.Functions.Unicode")

    If Not IsObject(oFunc) Then

       MsgBox "CreateObject(SAP.Functions.Unicode) failed", vbOKOnly, _

         "Error"

       Exit Sub

    End If

 

    Set oConn = oFunc.Connection()

    If Not IsObject(oConn) Then

      MsgBox "SAPFunc.Connection failed", vbOKOnly, "Error"

      Exit Sub

    End If

 

    SAPConn = oConn.Logon(0, vbFalse)

    If SAPConn <> 0 Then

 

      oConn.Logoff

    Else

      MsgBox "Connection.Logon failed", vbOKOnly, "Error"

    End If

 

  End Sub

'-End-------------------------------------------------------------------

 

As you can see is the source equivalent but the declarations of the variables oFunc and oConn are now not longer Objects, they are now definitive types from the library. And now the VBA IDE offers the code completion.

 

105.jpg

If you reference the SAP ActiveX libraries you should also declare your variables with the correct types, otherwise it makes no sense.

 

Hint: You can find information how to use SAP ActiveX libraries without SAP GUI for Windows here.

 

Cheers

Stefan

How to Use PowerShell for Automated Login to SAP

$
0
0

Hello community,

 

here is an interesting discussion how to automated logon to an SAP system via VBScript. But VBScript offers not really a function to detect the moment if the session is available. Here now an implementation how to do same with PowerShell. PowerShell offers with its interface to the Windows API an easy way to detect the availability of the new session.

 

Here now the code how to detect the availability of the session:

 

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

 

$Sig = @'

[DllImport("user32.dll", CharSet = CharSet.Auto)]

public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

'@

 

  #-Add FindWindow function---------------------------------------------

    $Win32 = Add-Type -Namespace Win32 -Name Funcs -MemberDefinition $Sig -PassThru

 

  #-Set the path to the SAP GUI directory-------------------------------

    $SAPGUIPath = "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\"

 

  #-Set the SAP system ID or the IP address-----------------------------

    $SID = "NSP"

 

  #-Set the instance number of the SAP system---------------------------

    $InstanceNo = "00"

 

  #-Starts the SAP GUI--------------------------------------------------

    $SAPGUI = $SAPGUIPath + "sapgui.exe"

    & $SAPGUI $SID $InstanceNo

 

  While ($Win32::FindWindow("SAP_FRONTEND_SESSION", "SAP") -eq 0) {

    Start-Sleep -Milliseconds 250

  }

 

  Write-Host "Here now your script..."

 

#-End-------------------------------------------------------------------

 

Here now the code how to logon automatically:

 

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

 

  #-Includes------------------------------------------------------------

    ."COM.ps1"

 

  #-Signatures----------------------------------------------------------

    $Sig = @'

[DllImport("user32.dll", CharSet = CharSet.Auto)]

public static extern IntPtr FindWindow(string lpClassName, string lpWindowName);

'@

 

  #-Add FindWindow function---------------------------------------------

    $Win32 = Add-Type -Namespace Win32 -Name Funcs -MemberDefinition $Sig -PassThru

 

  #-Set the path to the SAP GUI directory-------------------------------

    $SAPGUIPath = "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\"

 

  #-Set the SAP system ID-----------------------------------------------

    $SID = "localhost"

 

  #-Set the instance number of the SAP system---------------------------

    $InstanceNo = "00"

 

  #-Start the SAP GUI---------------------------------------------------

    $SAPGUI = $SAPGUIPath + "sapgui.exe"

    & $SAPGUI $SID $InstanceNo

 

  #-Wait until the session is available---------------------------------

    While ($Win32::FindWindow("SAP_FRONTEND_SESSION", "SAP") -eq 0) {

      Start-Sleep -Milliseconds 250

    }

 

  #-Logon to SAP GUI session--------------------------------------------

    $SapGuiAuto = Get-Object("SAPGUI")

    $application = Invoke-Method $SapGuiAuto "GetScriptingEngine"

    $connection = Get-Property $application "Children" @(0)

    $session = Get-Property $connection "Children" @(0)

 

    $ID = Invoke-Method $session "findById" @("wnd[0]/usr/txtRSYST-MANDT")

    Set-Property $ID "Text" @("001")

    $ID = Invoke-Method $session "findById" @("wnd[0]/usr/txtRSYST-BNAME")

    Set-Property $ID "Text" @("BCUSER")

    $ID = Invoke-Method $session "findById" @("wnd[0]/usr/pwdRSYST-BCODE")

    Set-Property $ID "Text" @("minisap")

    $ID = Invoke-Method $session "findById" @("wnd[0]/usr/txtRSYST-LANGU")

    Set-Property $ID "Text" @("EN")

 

    $ID = Invoke-Method $session "findById" @("wnd[0]")

    Invoke-Method $ID "sendVKey" @(0)

 

#-End-------------------------------------------------------------------

 

You can find the COM include file here.

 

Enjoy it.

 

Cheers

Stefan

How to Find the Next Logon Screen of a SID with SAP GUI Scripting

$
0
0

Hello community,

 

based on the discussion here I developed a function how to find the next logon screen of a given SID. The function delivers the connection number.

 

'-Begin--------------------------------------------------------------

 

  '-Directives-------------------------------------------------------

    Option Explicit

 

  '-Function GetConnectionNo-----------------------------------------

  '-

  '- Function to get connection number of the given SID with

  '- logon screen

  '-

  '------------------------------------------------------------------

    Function GetConnectionNo(Application, SID)

 

      '-Variables----------------------------------------------------

     Dim i, Connection, SessionInfo, ConnectionNo

 

      If Application.Children.Count > 0 Then

        For i = 0 To Application.Children.Count - 1

          Set Connection = Application.Children(CInt(i))

          Set SessionInfo = Connection.Children(0).Info

          If SessionInfo.SystemName = SID And _

            SessionInfo.Program = "SAPMSYST" Then

            ConnectionNo = Mid(Connection.Id, InStr(Connection.Id, "[") + 1)

            ConnectionNo = Left(ConnectionNo, Len(ConnectionNo) - 1)

            GetConnectionNo = CStr(ConnectionNo)

          End If

        Next

      Else

        GetConnectionNo = -1

      End If

 

    End Function

 

  '-Sub Main---------------------------------------------------------

    Sub Main()

 

      '-Variables----------------------------------------------------

        Dim SapGuiAuto, Application, ConnNo

 

      If Not IsObject(application) Then

        Set SapGuiAuto  = GetObject("SAPGUI")

        Set Application = SapGuiAuto.GetScriptingEngine

      End If

 

      ConnNo = GetConnectionNo(Application, "NSP")

 

      MsgBox ConnNo

 

    End Sub

 

  '-Main-------------------------------------------------------------

    Main

 

'-End----------------------------------------------------------------

 

Enjoy it.

 

Cheers

Stefan

How to Find the Next Not Busy Session of a SID in AutoIt

$
0
0

Hello community,

 

via e-mail I received a question how to get the next input-ready session of a SID in AutoIt scripting language. Here a solution.

 

It should now not be difficult to combine this approach with this approach to find a special session, e.g. the logon screen. It is only necessary to add the SessionInfo.Program attribute.

 

;-Begin-----------------------------------------------------------------

 

  ;-Directives----------------------------------------------------------

    AutoItSetOption("MustDeclareVars", 1)

 

  ;-Function GetSessionOfSID--------------------------------------------

  ;-

  ;- Delivers the first non busy session of a SID

  ;-

  ;---------------------------------------------------------------------

    Func GetSessionOfSID($Application, $SID)

 

      ;-Local Variables-------------------------------------------------

        Local $i, $Connection, $j, $Session, $SessionInfo

   

      If $Application.Children.Count > 0 Then

        For $i = 0 To $Application.Children.Count - 1

          $Connection = $Application.Children($i)

          For $j = 0 To $Connection.Children.Count - 1

            If $Connection.Children($j).Busy = False Then

              $Session = $Connection.Children($j)

              $SessionInfo = $Session.Info

              If $SessionInfo.SystemName = $SID Then

                Return $Session

              EndIf

            EndIf

          Next

        Next

      EndIf

   

    EndFunc

 

  ;-Sub Main------------------------------------------------------------

    Func Main()

 

      ;-Local Variables-------------------------------------------------

        Local $SAPROT, $SapGuiAuto, $Application, $Session

   

      $SAPROT = ObjCreate("SapROTWr.SAPROTWrapper")

      If Not IsObj($SAPROT) Then

        Return

      EndIf

 

      $SapGuiAuto = $SAPROT.GetROTEntry("SAPGUI")

      If Not IsObj($SapGuiAuto) Then

        Return

      EndIf

 

      $Application = $SapGuiAuto.GetScriptingEngine()

      If Not IsObj($Application) Then

        Return

      EndIf

 

      $Session = GetSessionOfSID($Application, "NSP")

      If IsObj($Session) Then

 

        ;Your script code here

        MsgBox(0, "", $Session.Id)

 

      EndIf

     

      $Application = 0

      $SapGuiAuto = 0

      $SAPROT = 0

     

    EndFunc

 

  ;-Main----------------------------------------------------------------

    Main()

 

;-End-------------------------------------------------------------------

 

Enjoy it.

 

Cheers

Stefan

Tip: How to Restart the SAPLogon via AutoIt

$
0
0

Hello community,

 

AutoIt is an incredible scripting language, it offers so much possibilities, e.g. to control processes and windows. Here now an example how to restart the SAPLogon on the fly:

 

;-Begin-----------------------------------------------------------------

 

  ;-Sub RestartProcess--------------------------------------------------

    Func RestartProcess($ProcessName)

 

      $PID = ProcessExists($ProcessName)

      If $PID Then

 

        $oWMI = ObjGet("winmgmts:\\.\root\CIMV2")

        If IsObj($oWMI) Then

          $Process = $oWMI.ExecQuery("Select * From win32_process " & _

            "Where Name = '" & $ProcessName & "'")

          If IsObj($Process) Then

            $ProcessPath = $Process.ItemIndex(0).ExecutablePath

          EndIf

        EndIf

 

        ProcessClose($PID)

        ProcessWait($PID)

 

        Run($ProcessPath)

 

      EndIf

 

    EndFunc

 

  ;-Sub Main------------------------------------------------------------

    Func Main()

 

      RestartProcess("saplogon.exe")

      WinWait("SAP Logon ")

      Sleep(4096)

 

    EndFunc

 

  ;-Main----------------------------------------------------------------

    Main()

 

;-End-------------------------------------------------------------------

 

As you can see it is absolut easy to get the process ID (PID), to close the process and to restart the process - here with the aid of Windows Management Instrumentarium (WMI).

 

Important hint: This script closes and restarts the saplogon process immediately, without any requests - all changes will be lost.

 

This script is excellent for stray processes on the frontend server.

 

Enjoy it.

 

Cheers

Stefan


SAP GUI Scripting Recorder with PowerShell

$
0
0

Hello community,

 

here a SAP GUI Scripting Recorder in PowerShell scripting language.

 

#-Begin-----------------------------------------------------------------  #-Sub Main------------------------------------------------------------    Function Main() {      [Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") > $Null      [Reflection.Assembly]::LoadFile($PSScriptRoot + "\SAPFEWSELib.dll") > $Null      $SapGuiAuto = [Microsoft.VisualBasic.Interaction]::GetObject("SAPGUI")      If ($SapGuiAuto -eq $Null) {        Break      }      $Application = $SapGuiAuto.GetType().InvokeMember("GetScriptingEngine",        [System.Reflection.Bindingflags]::InvokeMethod,        $null, $SapGuiAuto, $null, $null, $null, $null)      [SAPFEWSELib.GuiApplication]$Application =        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Application,        [SAPFEWSELib.GuiApplicationClass])      If ($Application -eq $Null) {        Break      }      $Connection = $Application.Children.Item(1)      [SAPFEWSELib.GuiConnectionClass]$Connection =        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Connection,        [SAPFEWSELib.GuiConnectionClass])      If ($Connection -eq $Null) {        Break      }      $Session = $Connection.Children.Item(0)      [SAPFEWSELib.GuiSession]$Session =        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Session,        [SAPFEWSELib.GuiSessionClass])      If ($Session -eq $Null) {        Break      }      $Session.Record = $True      Register-ObjectEvent -InputObject $Session -EventName "Change" -SourceIdentifier "Action" > $Null      While ($true) {        Write-Host "Waiting for event..."        $Event = Wait-Event -SourceIdentifier "Action" -Timeout 10        If ($Event -eq $Null) {          Write-Host "No event received for 10 seconds."          Break        }        #$event.SourceArgs        Write-Host "ID: " $event.SourceArgs[1].Id        Write-Host "Type / Method / Parameter: " $event.SourceArgs[2].SyncRoot        Remove-Event -SourceIdentifier "Action"      }      Unregister-Event -SourceIdentifier "Action"      $Session.Record = $False    }  #-Main----------------------------------------------------------------    Main
#-End--------------------------------------------------------------------

 

As you can see I use the normal SAP GUI Scripting commands to get the application, connection and session. I set the property record of the session object to true and register the change event to record my activities. Now in the while loop, which exits after 10 seconds if no event is fired, I catch the parameters via $event.SourceArgs. Last but not least I unregister the event and set record to false.

 

Here the result of one activity:

 

Waiting for event...

 

Name                   : ses[0]

Type                   : GuiSession

TypeAsNumber           : 12

ContainerType          : True

Id                     : /app/con[1]/ses[0]

Parent                 : System.__ComObject

Children               : System.__ComObject

ActiveWindow           : System.__ComObject

Info                   : System.__ComObject

Record                 : True

TestToolMode           : 0

RecordFile             :

Busy                   : False

IsActive               : True

SaveAsUnicode          : True

ShowDropdownKeys       : False

PassportTransactionId  : 0A64C954920015101318093545917000

PassportPreSystemId    : CRS/crs_CRS_92

PassportSystemId       : CRS/crs_CRS_92

ErrorList              : System.__ComObject

AccEnhancedTabChain    : False

AccSymbolReplacement   : False

IsListBoxActive        : False

ListBoxTop             : 0

ListBoxLeft            : 0

ListBoxWidth           : 0

ListBoxHeight          : 0

ListBoxCurrEntryTop    : 0

ListBoxCurrEntryLeft   : 0

ListBoxCurrEntryWidth  : 0

ListBoxCurrEntryHeight : 0

ListBoxCurrEntry       : -1

ProgressPercent        : 0

ProgressText           :

SuppressBackendPopups  :

 

Name          : shell

Type          : GuiShell

TypeAsNumber  : 122

ContainerType : True

Id            : /shell

Parent        :

 

Length         : 3

LongLength     : 3

Rank           : 1

SyncRoot       : {SP, selectedNode, F00002}

IsReadOnly     : False

IsFixedSize    : True

IsSynchronized : False

Count          : 3

 

Waiting for event...

No event received for 10 seconds.

 

As you can see you get a lot of information. Important is the ID and the SyncRoot. With these information you can build a scripting recorder of your mind.

 

Enjoy it.

 

Cheers

Stefan

New NWBC Property at GUIConnectionClass of SAP GUI Scripting API

$
0
0

Hello community,

 

in the actual version 7400.2.5.255 offers the SAP GUI Scripting API a new property in the GUIConnectionClass, called ChildrenForNWBC.

It is not documented yet. It delivers an IDispatch of GUIComponentenCollection, like Children property.

The difference between ChildrenForNWBC and Children is at the moment not clear, because ChildrenForNWBC delivers also a result if NWBC doesn't run. This means it delivers the same result when it is called only with SAP GUI for Windows and the result is also the same as Children property.

 

Here a picture of the methods and properties of ChildrenForNWBC.

001.JPG

 

Cheers

Stefan

Parallel Using of Identical DisplayNames in the Running Object Table (ROT)

$
0
0

Hello community,

 

a few month ago I wrote here about the non uniqueness of IDs of the parallel using of SAP GUI for Windows and NWBC with SAP GUI Scripting. Also I wrote here about polyvalence entries from SAP GUI for Windows and NWBC in the Running Object Table (ROT). Here is now a new variant:

If you use the SAP GUI for Windows and NWBC parallel and you call in a script the method GetScriptingEngine, after GetObject with SAPGUISERVER - the DisplayName of the NWBC - , the entry of SAPGUISERVER is doubled on a SAPGUI entry. Thus you have the problem, if you run SAP GUI for Windows and NWBC at the same time, that you can't differentiate clearly between the SAPGUI objects from the ROT, because it exists twice by name. The DisplayName is in this case not unique. You have two entries with an equal DisplayName at the same time. I try it with the SAP GUI for Windows 7.40 PL 5 and the NWBC 5 PL 9.

 

Hint: The problem which I described here is also present.

 

All in all it is better, from the perspective of the SAP GUI Scripting, to use SAP GUI for Windows and NWBC not parallel and to open only one instance of the NWBC at the same time.

 

Cheers

Stefan

Recorded Script in SAP to open more than the first session.

$
0
0

Hi I am totally new to SAP. So please bear with me and my missing skills. I have tried to record a session to log into SAP. And open the first session i need.

 

It works good. But i normally work with more than one session. I tried to record this but it only create 2 new sessions. Below is my recorded script.

 

I need to open 2 more with the name fbl5n and udm_bp. My script below open the first session and then it just create 2 blank sessions.

 

Please try help with this. I have of course in below script removed my password.

 

Sincerely

 

Abjac

 

If Not IsObject(application) Then

   Set SapGuiAuto  = GetObject("SAPGUI")

   Set application = SapGuiAuto.GetScriptingEngine

End If

If Not IsObject(connection) Then

   Set connection = application.Children(0)

End If

If Not IsObject(session) Then

   Set session    = connection.Children(0)

End If

If IsObject(WScript) Then

   WScript.ConnectObject session,     "on"

   WScript.ConnectObject application, "on"

End If

session.findById("wnd[0]").maximize

session.findById("wnd[0]/usr/txtRSYST-BNAME").text = "Y99DEW838"

session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = "***********"

session.findById("wnd[0]/usr/pwdRSYST-BCODE").setFocus

session.findById("wnd[0]/usr/pwdRSYST-BCODE").caretPosition = 11

session.findById("wnd[0]").sendVKey 0

session.findById("wnd[0]/tbar[0]/okcd").text = "/n/hoag/akon "

session.findById("wnd[0]/tbar[0]/btn[0]").press

session.findById("wnd[0]/tbar[1]/btn[17]").press

session.findById("wnd[1]/usr/cntlALV_CONTAINER_1/shellcont/shell").selectedRows = "0"

session.findById("wnd[1]/usr/cntlALV_CONTAINER_1/shellcont/shell").doubleClickCurrentCell

session.findById("wnd[0]/tbar[1]/btn[8]").press

session.createSession

session.createSession

Function FindAllByType and FindAllByTypeEx in SAP GUI Scripting

$
0
0

Hello community,

 

here are two functions to detect all controls of one type of a collection, called FindAllByType and FindAllByTypeEx. The function FindAllByType has the parameters obj which describes a collection of objects and strType which describes the type of the control as string, e.g. GuiLabel. The function FindAllByTypeEx has the parameters obj which describes a collection of objects and lngType which describes the type of the control as long, e.g. 30 for GuiLabel. Both delivers an array of objects of the required type of the control.

 

'-Begin-----------------------------------------------------------------

 

  '-Directives----------------------------------------------------------

    Option Explicit

 

  '-Global Variables----------------------------------------------------

    Dim gColl()

 

  '-Function FindAllByType----------------------------------------------

    Function FindAllByType(Obj, strType)

 

      '-Variables-------------------------------------------------------   

        Dim cntObj, i, j, Child

 

      On Error Resume Next    

      cntObj = Obj.Children.Count()    

      If cntObj > 0 Then    

        For i = 0 To cntObj - 1    

          Set Child = Obj.Children.Item(CLng(i))    

          FindAllByType Child, strType

          If UCase(Child.Type()) = UCase(strType) Then

            ReDim Preserve gColl(j)

            Set gColl(j) = Child

            j = j + 1

          End If

        Next    

      End If    

      On Error Goto 0  

      FindAllByType = gColl

 

    End Function

 

  '-Function FindAllByType----------------------------------------------

    Function FindAllByTypeEx(Obj, lngType)

 

      '-Variables-------------------------------------------------------   

        Dim cntObj, i, j, Child

 

      On Error Resume Next    

      cntObj = Obj.Children.Count()    

      If cntObj > 0 Then    

        For i = 0 To cntObj - 1    

          Set Child = Obj.Children.Item(CLng(i))    

          FindAllByTypeEx Child, lngType

          If Child.TypeAsNumber() = lngType Then

            ReDim Preserve gColl(j)

            Set gColl(j) = Child

            j = j + 1

          End If

        Next    

      End If    

      On Error Goto 0  

      FindAllByTypeEx = gColl

 

    End Function

 

  '-Sub Main------------------------------------------------------------

    Sub Main()

 

      '-Variables-------------------------------------------------------

        Dim SapGuiAuto, application, connection, session, Coll, i

        Dim OutText

 

      If Not IsObject(application) Then

        Set SapGuiAuto = GetObject("SAPGUI")

        Set application = SapGuiAuto.GetScriptingEngine

      End If

 

      If Not IsObject(connection) Then

        Set connection = application.Children(0)

      End If

 

      If Not IsObject(session) Then

        Set session = connection.Children(0)

      End If 

 

      Erase gColl

      Coll = FindAllByType(session, "GuiLabel")

      For i = 0 To UBound(Coll)

        OutText = OutText & Coll(i).ID() & vbCrLf

      Next

 

      Erase gColl

      Coll = FindAllByTypeEx(session, 31) 'GuiTextField

      For i = 0 To UBound(Coll)

        OutText = OutText & Coll(i).ID() & vbCrLf

      Next

 

      MsgBox OutText

   

    End Sub

 

  '-Main----------------------------------------------------------------

    Main

 

'-End-------------------------------------------------------------------

 

Enjoy it.

 

Cheers

Stefan

New SAP GUI Scripting API help

$
0
0

Hello community,

 

the actual patch level 5 of the SAP GUI for Windows 7.40 offers a facelifted SAP GUI Scripting API help.

 

The font styles has been changed.

001.jpg

The node structure has been changed - the nodes Overview and Members does not exists anymore and for the single methods and properties there are also no longer own nodes.

002.jpg

The syntax description is now in VB.NET.

003.jpg

The file size is significantly reduced.

 

All in all the new help file looks much smarter - thank you for that

 

Cheers

Stefan

How to make SAP ROT Wrapper library available in a 64-bit environment

$
0
0

Hello community,

 

the SAP ROT (Running Object Table) Wrapper library offers the possibility to get access to the ROT. But the library is only for x86 - 32-bit. With the standard installation is it not possible to use the library with x64 programming languages. Here is a description how to make the SAP ROT Wrapper library available for this kind of environments:

 

  1. Add in the registry the entry DllSurrogate in the key HKCR\Wow6432Node\AppID\{E2779C61-F87E-4038-98A0-1D9E71334706} without a value.
    999.JPG
  2. Create a new key in HKLM\Software\Classes\AppID with the GUID {E2779C61-F87E-4038-98A0-1D9E71334706} without any values.

 

That is all, now you can enjoy the the SAP GUI ROT Wrapper in an x64 environment.

 

Here a test script in PowerShell:

 

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

 

  #-Sub Main------------------------------------------------------------

    Function Main() {

 

      [Reflection.Assembly]::LoadFile($PSScriptRoot + "\saprotwrlib.dll") > $Null

      [Reflection.Assembly]::LoadFile($PSScriptRoot + "\sapfewselib.dll") > $Null

 

      $Size = [System.IntPtr]::Size

      If ($Size -eq 4) {

        Write-Host "`r`nVersion x86`r`n"

      }

      ElseIf ($Size -eq 8) {

        Write-Host "`r`nVersion x64`r`n"

      }

 

      $Wrapper = New-Object -ComObject "SapROTWr.SapROTWrapper"

      #[Reflection.Assembly]::LoadWithPartialName("Microsoft.VisualBasic") > $Null

      #$Wrapper = [Microsoft.VisualBasic.Interaction]::CreateObject("SapROTWr.SapROTWrapper")

      If ($Wrapper -eq $Null) {

          Break

      }

 

      $RotSAPGUI = $Wrapper.GetROTEntry("SAPGUI")

      If ($RotSAPGUI -eq $Null) {

        Break

      }

 

      $Application = $RotSAPGUI.GetType().InvokeMember("GetScriptingEngine",

        [System.Reflection.Bindingflags]::InvokeMethod,

        $null, $RotSAPGUI, $null, $null, $null, $null)

      [sapfewselib.GuiApplication]$Application =

        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Application,

        [sapfewselib.GuiApplicationClass])

      If ($Application -eq $Null) {

        Break

      }

 

      $Connection = $Application.Children.Item(0)

      [sapfewselib.GuiConnectionClass]$Connection =

        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Connection,

        [sapfewselib.GuiConnectionClass])

      If ($Connection -eq $Null) {

        Break

      }

 

      $Session = $Connection.Children.Item(0)

      [sapfewselib.GuiSession]$Session =

        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($Session,

        [sapfewselib.GuiSessionClass])

      If ($Session -eq $Null) {

        Break

      }

 

      $SessionInfo = $Session.Info

      [sapfewselib.GuiSessionInfo]$SessionInfo =

        [System.Runtime.InteropServices.Marshal]::CreateWrapperOfType($SessionInfo,

        [sapfewselib.GuiSessionInfoClass])

      If ($SessionInfo -eq $Null) {

        Break

      }

 

      Write-Host $SessionInfo.SystemName

      Write-Host $SessionInfo.Client

      Write-Host $SessionInfo.Transaction

 

    }

 

  #-Main----------------------------------------------------------------

    Main

 

#-End-------------------------------------------------------------------

 

998.jpg

 

Hint:It could be possible that the SAP GUI ROT wrapper has another GUID. You can find it in the GuidAttribute of the manifest of the assembly.

 

Enjoy it.

 

Cheers

Stefan


How to get OS and Shell Architecture as well as Version of VBScript

$
0
0

Hello community,

 

to work with x64 systems is now a normal scenario in the business. x86 (32 bit) and x64 (64 bit) programs works simultaneously peaceful hand in hand. But for the scripts it is sometimes a big difference to work on an x86 or x64 system, and whether it is an x86 or x64 process. Here a VBScript with two functions to differentiate between all those constellations.

 

'-Begin-----------------------------------------------------------------

 

  '-Directives----------------------------------------------------------

    Option Explicit

 

  '-Constants-----------------------------------------------------------

    Const WMIPath = "winmgmts:root\cimv2:Win32_Processor='cpu0'"

 

  '-WhichOS-------------------------------------------------------------

    Function WhichOS()

      If GetObject(WMIPath).AddressWidth = 32 Then

        WhichOS = "x86"

      ElseIf GetObject(WMIPath).AddressWidth = 64 Then

        WhichOS = "x64"

      End If

    End Function

 

  '-WhichShell----------------------------------------------------------

    Function WhichShell()

 

      '-Variables-------------------------------------------------------

        Dim WshShell, WshProcEnv, ProcArch

 

      Set WshShell =  CreateObject("WScript.Shell")

      Set WshProcEnv = WshShell.Environment("Process")

      ProcArch = WshProcEnv("PROCESSOR_ARCHITECTURE")

      If ProcArch = "AMD64" Or ProcArch = "IA64" Or _

        ProcArch = "EM64T" Then

        WhichShell = "x64"

      Else

        WhichShell = "x86"

      End If

      Set WshProcEnv = Nothing

      Set WshShell = Nothing

 

    End Function

 

  '-Main----------------------------------------------------------------

    MsgBox "VBScript " & WScript.Version & " on " &  WhichShell() & _

      " Shell on " & WhichOS() & " OS"

 

'-End-------------------------------------------------------------------

 

The function WhichOS differentiate between the OS architecture via Windows Management Instrumentarium (WMI) and the function WhichShell differentiate between the process architecture via the system variable PROCESSOR_ARCHITECTURE. On this way you can safely detect the existing constellation.

 

Here an example of the script in different command shells on an x64 Windows.

001.JPG

 

Enjoy it.

 

Cheers

Stefan

Tip: How to Differentiate Between x86 and x64 Versions of Libraries and Executables

$
0
0

Hello community,

 

more and more 64-bit programs and libraries comes into our focus and very often exists the question, how to differentiate which program or library is x86 or x64. It is very easy to differentiate, if you find in the first 280 bytes the hex 50 45 00 00 4C (PE..L - PE means portable executable) it is an x86 version. If you find 50 45 00 00 64 (PE..d) it is an x64 version. You can open each program or library with notepad.

 

x86 (32-bit) version:

001.jpg

x64 (64-bit) version:

002.jpg

 

Enjoy it.

 

Cheers

Stefan

Tip: How To Analyze Missing RFC Authorization Objects with CCo

$
0
0

Hello community,

 

to create a user ID with the correct (minimal) rights to call an RFC function modul you can use CCo and the following method.

 

  1. Create a new user ID with the TAC SU01, e.g. ZRFCTEST, with the user type Communication and don’t set any role assignments.

  2. Try a simple connect with the following script:

    '-Begin-----------------------------------------------------------------

      '-Directives----------------------------------------------------------
        Option Explicit

      '-Variables-----------------------------------------------------------

        Dim SAP, hRFC, rc

      '-Main----------------------------------------------------------------
       Set SAP = CreateObject("COMNWRFC")
       If IsObject(SAP) Then
        hRFC = SAP.RfcOpenConnection("ASHOST=ABAP, SYSNR=00, " & _
          "CLIENT=000, USER=ZRFCTEST, PASSWD=minisap")
        If hRFC Then
          MsgBox "Check connection with TAC SMGW in the SAP system"
          rc = SAP.RfcCloseConnection(hRFC)
        End If
        Set SAP = Nothing
      End If

    '-End-------------------------------------------------------------------

  3. Now, when you execute the script, you get the following error message:
    001.jpg
    Also you can find more information with the TAC ST22.

    002.jpg
  4. Now create with the TAC PFCG a new role, e.g. ZRFCTEST, and maintain the authorization data. Add manually the authorization object S_RFC.

    001.jpg
  5. Add the activity execute (16) with the type function group and the name SYST, as you see in the error message.

    001.jpg
  6. Generate the role and add user ID in the user tab. Now you see the role in the role tab of TAC SU01.
    001.jpg
  7. Now all should work as expected.

    001.jpg

 

With this method you have the possibility to analyze missing S_RFC authorization objects with your script step by step and to create therewith a user with the correct (minimal) authorization objects. As you can see from this example a simple RfcOpenConnection needs the S_RFC authorization object with activity execute and the function group SYST.

 

Hint: In newer SAP releases you have also the possibility to name the function module.

 

001.jpg

 

Enjoy it.

 

Cheers

Stefan

Scripting Language PowerShell 5.0 is Available

$
0
0

Hello community,

 

since five days offers the Microsoft PowerShell Team the RTM (Release To Manufacturing) of PowerShell 5.0. It is part of the Windows Management Framework (WMF) 5.0. It replaces the production preview.

 

  • You can find the official note here.
  • You can find the release note here.
  • You can download it here.

 

A nice christmas present for all PowerShell script programmers.

 

 

Enjoy it.

 

Cheers

Stefan

Download Workload Statistics as CSV via RFC and CCo

$
0
0

Hello community,

 

RFC connections offers a lot of possibilities. Here is an example how to download workload statistics as CSV file. Normally you get this information via the Workload Monitor - TAC ST03. On this way you have the possibility to download this kind of information from different systems automatically For this example I use COM connector (CCo) and VBScript. The information I get from the FM SWNC_GET_WORKLOAD_STATISTIC. I get the top response time of dialog steps and top DB accesses of dialog steps.

 

Enjoy it.

 

Cheers

Stefan

 

 

'-Begin-----------------------------------------------------------------

'-

'- To execute this script your user needs a role with the authorization

'- object S_RFC, the activity execute (16), the type Function group and

'- with the names RFC1, SCSM_GLOB_SYSTEM, SDIFRUNTIME and SYST

'-

'-----------------------------------------------------------------------

 

  '-Directives----------------------------------------------------------

    Option Explicit

 

  '-Constants-----------------------------------------------------------

    Const RFC_OK = 0

    Const Sep = ";"

 

  '-Sub getStat---------------------------------------------------------

    Sub getStat(strConn, SID, PeriodStart)

 

      '-Variables-------------------------------------------------------

        Dim SAP, hRFC, rc, hFuncDesc, hFunc, hTable, RowCount, i, hRow

        Dim charBuffer, Stat, fltBuffer, FSO, oFile

 

      Set SAP = CreateObject("COMNWRFC")

      If IsObject(SAP) Then

        SAP.UsePwdRequest = 0

        rc = SAP.RfcSetIniPath("C:\Dummy")

        hRFC = SAP.RfcOpenConnection(strConn)

        If hRFC Then

 

          hFuncDesc = SAP.RfcGetFunctionDesc(hRFC, _

            "SWNC_GET_WORKLOAD_STATISTIC")

          If hFuncDesc Then

            hFunc = SAP.RfcCreateFunction(hFuncDesc)

            If hFunc Then

 

              rc = SAP.RfcSetChars(hFunc, "SYSTEMID", SID)

              rc = SAP.RfcSetChars(hFunc, "INSTANCE", "TOTAL")

              rc = SAP.RfcSetChars(hFunc, "PERIODTYPE", "M")

              rc = SAP.RfcSetDate(hFunc, "PERIODSTRT", PeriodStart)

 

              If SAP.RfcInvoke(hRFC, hFunc) = RFC_OK Then

 

                '-Top Response Time of Dialog Steps (All data)----------

                If SAP.RfcGetTable(hFunc, "HITLIST_RESPTIME", hTable) = _

                  RFC_OK Then

 

                  rc = SAP.RfcGetRowCount(hTable, RowCount)

                  rc = SAP.RfcMoveToFirstRow(hTable)

 

                  Stat = ""

 

                  For i = 1 To RowCount

                    hRow = SAP.RfcGetCurrentRow(hTable)

 

                    rc = SAP.RfcGetChars(hRow, "ACCOUNT", charBuffer, 12)

                    Stat = Stat & charBuffer & Sep                 'User

                    rc = SAP.RfcGetChars(hRow, "TCODE", charBuffer, 20)

                    Stat = Stat & charBuffer & Sep 'Report / Transaction

                    rc = SAP.RfcGetChars(hRow, "REPORT", charBuffer, 40)

                    Stat = Stat & charBuffer & Sep 'Name of ABAP Program

                    rc = SAP.RfcGetFloat(hRow, "DBCALLS", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep           'Calls

                    rc = SAP.RfcGetFloat(hRow, "RESPTI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep      'Resp. Time

                    rc = SAP.RfcGetFloat(hRow, "PROCTI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep      'Proc. Time

                    rc = SAP.RfcGetFloat(hRow, "QUEUETI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep       'Wait Time

                    rc = SAP.RfcGetFloat(hRow, "CPUTI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & vbCrLf     'CPU Time

 

                    If i < RowCount Then

                      rc = SAP.RfcMoveToNextRow(hTable)

                    End If

                  Next

 

                  Set FSO = CreateObject("Scripting.FileSystemObject")

                  Set oFile = FSO.CreateTextFile("C:\Dummy\" & SID & _

                    "_" & PeriodStart & "_Hitlist_Resptime.csv", True)

                  oFile.Write "ACCOUNT" & Sep & "TCODE" & Sep & _

                    "REPORT" & Sep & "DBCALLS" & Sep & "RESPTI" & _

                    Sep & "PROCTI" & Sep & "QUEUETI" & Sep & _

                    "CPUTI" & vbCrLf

                  oFile.Write Stat

                  oFile.Close

                  Set FSO = Nothing

 

                End If

 

                '-Top DB Accesses of Dialog Steps (All data)------------

                If SAP.RfcGetTable(hFunc, "HITLIST_DATABASE", hTable) = _

                  RFC_OK Then

 

                  rc = SAP.RfcGetRowCount(hTable, RowCount)

                  rc = SAP.RfcMoveToFirstRow(hTable)

 

                  Stat = ""

 

                  For i = 1 To RowCount

                    hRow = SAP.RfcGetCurrentRow(hTable)

 

                    rc = SAP.RfcGetChars(hRow, "ACCOUNT", charBuffer, 12)

                    Stat = Stat & charBuffer & Sep                 'User

                    rc = SAP.RfcGetChars(hRow, "TCODE", charBuffer, 20)

                    Stat = Stat & charBuffer & Sep 'Report / Transaction

                    rc = SAP.RfcGetChars(hRow, "REPORT", charBuffer, 40)

                    Stat = Stat & charBuffer & Sep 'Name of ABAP Program

                    rc = SAP.RfcGetFloat(hRow, "DBCALLS", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep           'Calls

                    rc = SAP.RfcGetFloat(hRow, "RESPTI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep      'Resp. Time

                    rc = SAP.RfcGetFloat(hRow, "PROCTI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep      'Proc. Time

                    rc = SAP.RfcGetFloat(hRow, "QUEUETI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & Sep       'Wait Time

                    rc = SAP.RfcGetFloat(hRow, "CPUTI", fltBuffer)

                    Stat = Stat & CStr(fltBuffer) & vbCrLf     'CPU Time

 

                    If i < RowCount Then

                      rc = SAP.RfcMoveToNextRow(hTable)

                    End If

                  Next

 

                  Set FSO = CreateObject("Scripting.FileSystemObject")

                  Set oFile = FSO.CreateTextFile("C:\Dummy\" & SID & _

                    "_" & PeriodStart & "_Hitlist_Database.csv", True)

                  oFile.Write "ACCOUNT" & Sep & "TCODE" & Sep & _

                    "REPORT" & Sep & "DBCALLS" & Sep & "RESPTI" & _

                    Sep & "PROCTI" & Sep & "QUEUETI" & Sep & _

                    "CPUTI" & vbCrLf

                  oFile.Write Stat

                  oFile.Close

                  Set FSO = Nothing

 

                End If

              End If

              rc = SAP.RfcDestroyFunction(hFunc)

            End If

          End If

 

          rc = SAP.RfcCloseConnection(hRFC)

        End If

        Set SAP = Nothing

      End If

 

    End Sub

 

  '-Sub Main------------------------------------------------------------

    Sub Main()

 

      '-Variables-------------------------------------------------------

        Dim PeriodStart

 

      PeriodStart = "20151201"

 

      getStat "DEST=NSP", "NSP", PeriodStart

      getStat "DEST=NPL", "NPL", PeriodStart

 

      MsgBox "Ready"

 

    End Sub

 

 

  '-Main----------------------------------------------------------------

    Main()

 

'-End-------------------------------------------------------------------

 

Viewing all 42 articles
Browse latest View live


<script src="https://jsc.adskeeper.com/r/s/rssing.com.1596347.js" async> </script>