Skip to Content

Tip: Complete Launch Sequence of SAP GUI Scritping in PowerShell

In the context of a discussion I developed and presented a complete launch sequence of SAP GUI Scripting in VBScript. But for the future it seems better to use PowerShell, for reasons which I have described here. Now the equivalent in PowerShell script language:

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

  #-Includes------------------------------------------------------------
    . "$PSScriptRoot\COM.ps1"

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

      $OpenNewConnFlag = $false

      if (-Not (Get-Process saplogon -ErrorAction silentlycontinue)) {
        Start-Process "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\saplogon.exe"
         do {
           Start-Sleep -Milliseconds 250
         } until(Get-Process | where {$_.mainWindowTitle -like "SAP Logon 740"})
      }
      $SapGuiAuto = Get-Object( , "SAPGUI")
      $application = Invoke-Method $SapGuiAuto "GetScriptingEngine"
      $connection = Get-Property $application "Children" @(0)
      if ($connection -eq $Null) {
        $OpenNewConnFlag = $true
        Invoke-Method $application "OpenConnectionByConnectionString" `
          @("/H/10.100.200.300/S/3200", $true) > $Null
        $connection = Get-Property $application "Children" @(0)
      }
      $session = Get-Property $connection "Children" @(0)

      if ($OpenNewConnFlag -eq $true) {
        $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)
      }

      Free-Object $session
      Free-Object $connection
      Free-Object $application
      Free-Object $SapGuiAuto

    }

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

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

Here now the facelifted COM include, which I introduced here:

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

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

  #-Function Create-Object----------------------------------------------
  Function Create-Object([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([String]$pathName, [String]$class) {
    [Microsoft.VisualBasic.Interaction]::GetObject($pathName, $class)
  }

  #-Sub Free-Object-----------------------------------------------------
  Function Free-Object([__ComObject]$object) {
    [Void] [System.Runtime.Interopservices.Marshal]::ReleaseComObject($object)
  }

  #-Function Get-Property-----------------------------------------------
  Function Get-Property([__ComObject]$object, [String]$propertyName,
    $propertyParameters) {
    $objectType = [System.Type]::GetType($object)
    $objectType.InvokeMember($propertyName,
      [System.Reflection.Bindingflags]::GetProperty,
      $null, $object, $propertyParameters)
  }

  #-Sub Set-Property----------------------------------------------------
  Function Set-Property([__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([__ComObject]$object, [String]$methodName, 
  	$methodParameters) {
    $objectType = [System.Type]::GetType($object)
    $output = $objectType.InvokeMember($methodName,
      "InvokeMethod", $NULL, $object, $methodParameters)
    if ( $output ) { $output }
  }

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

Hint: This code is a different perspective from the solution here.

 

And here a further development of the approach above:

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

  If ($PSVersionTable.PSVersion.Major -eq 2) {
    $PSScriptRoot = Split-Path $($MyInvocation.InvocationName) -Parent
  } 

  #-Includes------------------------------------------------------------
    ."$PSScriptRoot\COM.ps1"

  #-Function Logon------------------------------------------------------
  Function Logon() {

    $SecPasswd = Read-Host -Prompt "Passwort" -AsSecureString
    $ptrPasswd = [Runtime.InteropServices.Marshal]::SecureStringToBStr($SecPasswd)
    $Passwd = [Runtime.InteropServices.Marshal]::PtrToStringBStr($ptrPasswd)

    Invoke-Method $application "OpenConnectionByConnectionString" `
      @("/H/10.100.200.300/S/3200", $True) > $Null
    $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" @($Passwd)
    $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)

    $connection
    $session
  }

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

    $Found = $False

    If (-Not (Get-Process saplogon -ErrorAction silentlycontinue)) {
      Start-Process "C:\Program Files (x86)\SAP\FrontEnd\SAPgui\saplogon.exe"
       do {
         Start-Sleep -Milliseconds 250
       } until(Get-Process | where {$_.mainWindowTitle -like "SAP Logon 740"})
    }

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

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

    $connections = Get-Property $application "Connections"
    If ($connections -isnot [__ComObject]) { 
      $Ret = Logon
      $connection = $Ret[0]
      $session = $Ret[1]
    } Else {

      $connections = Get-Property $application "Connections"

      :found
      ForEach ($connection In $connections) {
        $sessions = Get-Property $connection "Sessions"
        ForEach ($session In $sessions) {
          If ($session.Busy() -eq 1) {
            Continue
          }
          $sessionInfo = Get-Property $session "Info"
          $SID = Get-Property $sessionInfo "SystemName"
          $TAC = Get-Property $sessionInfo "Transaction"
          If ($SID -eq "NSP" -and $TAC -eq "SESSION_MANAGER") {
            $Found = $True
            Break found
          }
        }
      }

      If ($Found = $False) {
        $Ret = Logon
        $connection = $Ret[0]
        $session = $Ret[1]
      }

    }

    #-------------------------------------------------------------------
    #-
    #- In the variables $connection and $session are now the required
    #- information
    #-
    #-------------------------------------------------------------------



    Free-Object $SapGuiAuto

  }

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

#-End-------------------------------------------------------------------
4 Comments
You must be Logged on to comment or reply to a post.
  • I work as an auditor and have automated few SAP Application controls with SAP GUI scripting but the only challenge I have been facing is capturing screenshots as we keep going in the process. I know powershell has the ability to capture screenshots. Can you please help me convert my SAP GUI Vbs script to powershell and show some light.

    • Hello Abhignya Chiruguri,

      it should be not difficult to convert VBScript to PowerShell. My approach uses two steps for a single VBS line. The first detects the ID and the second do the activity like Set- or Get-Property or Invoke-Method, as you can see in the example above. Please post your VBScript and we will talk about handcraft approaches of converting.

      Best regards
      Stefan

    • Taking screenshots has not to be specific to PowerShell. SAP GUI Scripting has the methods HardCopy and HardCopyToMemory in object GuiFrameWindow.

  • I would like to automate the creation of new SAP user accounts with Powershell.

    To do so manually, I need to open the SAP GUI, then open the WP1 system, enter a transaction code to get to the interface where I can create the user.

     

    I tried to run your script, but I only managed to have the SAP GUI open up.

     

    Sorry, I'm not familiar at all with SAP...

     

    We're on SAP GUI 7.60 with SSO.

     

    It would be great if you could show me the way to go. Thanks a lot in advance.

     

    Best regards,

    Michael