Install
$ agentstack add skill-efeumutaslan-sap-skills-sap-gui-scripting Open-source listing — not yet scanned by AgentStack. Follow the source repository for install instructions.
Security review
⚠ Flagged1 finding(s); flagged for manual review. · v0.1.0 How review works →
- • Prompt-injection patterns
- • Secret / credential exfiltration
- • Dangerous shell & filesystem operations
- • Untrusted network calls
- • Known-malicious package signatures
- high Dangerous shell/eval execution.
What it can access
- ✓ Network access No
- ✓ Filesystem access No
- ● Shell / process execution Used
- ✓ Environment & secrets No
- ✓ Dynamic code execution No
From automated source analysis of v0.1.0. “Used” means the capability is present in the source — more access means more to trust, not that it’s unsafe.
About
SAP GUI Scripting & Automation
Related Skills
sap-build-process-automation— Desktop Agent uses GUI scripting under the hoodsap-testing-quality— Automated GUI testing with eCATT/CBTAsap-s4hana-extensibility— When to use API vs. GUI scripting
Quick Start
Prerequisites:
- Enable scripting on SAP server:
RZ11→ parametersapgui/user_scripting=TRUE - Enable on client: SAP GUI → Options → Accessibility & Scripting → Enable scripting
- Disable notification popups: uncheck "Notify when script attaches" and "Notify when script opens connection"
Record your first script:
- Open SAP GUI → transaction you want to automate
- Menu: Customize Local Layout (Alt+F12) → Script Recording and Playback
- Click Record, perform actions, click Stop
- Save as
.vbsfile — this is your starting template
Minimal VBScript — Run Transaction:
If Not IsObject(application) Then
Set SapGuiAuto = GetObject("SAPGUI")
Set application = SapGuiAuto.GetScriptingEngine
End If
Set connection = application.Children(0)
Set session = connection.Children(0)
session.findById("wnd[0]/tbar[0]/okcd").text = "/nMM03"
session.findById("wnd[0]").sendVKey 0
session.findById("wnd[0]/usr/ctxtRMMG1-MATNR").text = "MAT-001"
session.findById("wnd[0]").sendVKey 0
Core Concepts
Object Hierarchy
GuiApplication
└── GuiConnection (SAP system connection)
└── GuiSession (user session / window)
└── GuiFrameWindow (wnd[0], wnd[1]...)
├── GuiToolbar (tbar[0] = command, tbar[1] = app)
├── GuiUserArea (usr/)
│ ├── GuiTextField, GuiCTextField
│ ├── GuiComboBox, GuiCheckBox, GuiRadioButton
│ ├── GuiTableControl, GuiGridView (ALV)
│ ├── GuiTab, GuiTabStrip
│ └── GuiTree
├── GuiStatusbar (sbar/)
└── GuiTitlebar (titl/)
Element ID Pattern
Format: wnd[N]/area/type[row,col]
wnd[0]/tbar[0]/okcd— Command field (OKCode)wnd[0]/usr/ctxtFIELD-NAME— Context field (F4 help available)wnd[0]/usr/txtFIELD-NAME— Text input fieldwnd[0]/usr/chkFIELD-NAME— Checkboxwnd[0]/usr/radFIELD-NAME— Radio buttonwnd[0]/usr/btnBUTTON-NAME— Push buttonwnd[0]/usr/tblTABLE/ctxtFIELD[row,col]— Table cellwnd[0]/usr/cntlGRID/shellcont/shell— ALV Grid controlwnd[0]/sbar— Status bar (messages)
Virtual Keys (sendVKey)
| Key | Code | Description | |-----|------|-------------| | Enter | 0 | Confirm/execute | | F2 | 2 | Choose/display | | F3 | 3 | Back | | F5 | 5 | Refresh | | F8 | 8 | Execute report | | F12 | 12 | Cancel | | Shift+F4 | 16 | Save as variant | | Ctrl+S | 11 | Save | | Ctrl+Shift+F3 | 43 | Delete |
Common Patterns
Pattern 1: Python Automation with win32com
import win32com.client
import time
def get_sap_session():
"""Connect to running SAP GUI session."""
sap_gui = win32com.client.GetObject("SAPGUI")
app = sap_gui.GetScriptingEngine
connection = app.Children(0)
session = connection.Children(0)
return session
def run_transaction(session, tcode):
"""Navigate to transaction."""
session.findById("wnd[0]/tbar[0]/okcd").text = f"/n{tcode}"
session.findById("wnd[0]").sendVKey(0)
def get_status_message(session):
"""Read status bar message."""
sbar = session.findById("wnd[0]/sbar")
return {
"type": sbar.MessageType, # S=Success, E=Error, W=Warning, I=Info
"text": sbar.Text
}
Pattern 2: Table Data Extraction
def extract_alv_grid(session, grid_id="wnd[0]/usr/cntlGRID/shellcont/shell"):
"""Extract all data from ALV grid."""
grid = session.findById(grid_id)
columns = grid.ColumnCount
rows = grid.RowCount
col_names = [grid.GetColumnTitles(i) for i in range(columns)]
data = []
for row in range(rows):
grid.SetCurrentCell(row, grid.GetColumnName(0))
record = {}
for col in range(columns):
col_name = grid.GetColumnName(col)
record[col_name] = grid.GetCellValue(row, col_name)
data.append(record)
return data
def extract_table_control(session, table_id):
"""Extract data from classic table control (scroll-aware)."""
table = session.findById(table_id)
all_rows = []
visible = table.VisibleRowCount
total = table.RowCount
for offset in range(0, total, visible):
table.VerticalScrollbar.Position = offset
for row in range(min(visible, total - offset)):
row_data = {}
for col in range(table.Columns.Count):
cell = table.GetCell(row, col)
row_data[table.Columns(col).Name] = cell.Text
all_rows.append(row_data)
return all_rows
Pattern 3: Batch Data Entry (e.g., Mass Material Change)
def mass_material_change(session, materials):
"""Change multiple materials via MM02."""
results = []
for mat in materials:
run_transaction(session, "MM02")
session.findById("wnd[0]/usr/ctxtRMMG1-MATNR").text = mat["matnr"]
session.findById("wnd[0]").sendVKey(0)
# Select views
for view in session.findById("wnd[0]/usr/tabsTABSPR1").Children:
if hasattr(view, "Selected"):
view.Selected = view.Text in mat.get("views", ["Basic Data 1"])
session.findById("wnd[0]").sendVKey(0)
# Update fields
for field_id, value in mat.get("fields", {}).items():
try:
session.findById(field_id).text = value
except Exception as e:
results.append({"matnr": mat["matnr"], "status": "ERROR", "msg": str(e)})
session.findById("wnd[0]").sendVKey(12) # Cancel
continue
session.findById("wnd[0]").sendVKey(11) # Ctrl+S
msg = get_status_message(session)
results.append({"matnr": mat["matnr"], "status": msg["type"], "msg": msg["text"]})
return results
Pattern 4: Handle Popups and Modal Dialogs
def handle_popup(session, action="confirm"):
"""Handle unexpected popup windows."""
try:
popup = session.findById("wnd[1]")
if action == "confirm":
popup.findById("wnd[1]/usr/btnBUTTON_1").press() # Yes/OK
elif action == "cancel":
popup.findById("wnd[1]/usr/btnBUTTON_2").press() # No/Cancel
elif action == "close":
popup.Close()
return True
except Exception:
return False # No popup present
def safe_action(session, action_func, max_popups=3):
"""Execute action and handle any resulting popups."""
action_func()
for _ in range(max_popups):
time.sleep(0.3)
if not handle_popup(session, "confirm"):
break
Pattern 5: Login Automation
def login_sap(system, client, user, password, language="EN"):
"""Open new SAP GUI connection and login."""
import subprocess
sap_logon = r"C:\Program Files (x86)\SAP\FrontEnd\SAPgui\saplogon.exe"
subprocess.Popen([sap_logon])
time.sleep(3)
sap_gui = win32com.client.GetObject("SAPGUI")
app = sap_gui.GetScriptingEngine
connection = app.OpenConnection(system, True)
session = connection.Children(0)
session.findById("wnd[0]/usr/txtRSYST-MANDT").text = client
session.findById("wnd[0]/usr/txtRSYST-BNAME").text = user
session.findById("wnd[0]/usr/pwdRSYST-BCODE").text = password
session.findById("wnd[0]/usr/txtRSYST-LANGU").text = language
session.findById("wnd[0]").sendVKey(0)
# Handle multiple logon popup
handle_popup(session, "confirm")
return session
Pattern 6: Error-Resilient Script Template
import logging
logging.basicConfig(level=logging.INFO, format="%(asctime)s %(levelname)s %(message)s")
log = logging.getLogger("sap_script")
def run_with_retry(session, func, max_retries=3, *args, **kwargs):
"""Run GUI action with retry on transient errors."""
for attempt in range(max_retries):
try:
result = func(session, *args, **kwargs)
msg = get_status_message(session)
if msg["type"] == "E":
log.warning(f"Attempt {attempt+1}: SAP error: {msg['text']}")
if attempt < max_retries - 1:
session.findById("wnd[0]").sendVKey(3) # Back
continue
return result
except Exception as e:
log.error(f"Attempt {attempt+1}: Exception: {e}")
if attempt == max_retries - 1:
raise
return None
Error Catalog
| Error | Message | Root Cause | Fix | |-------|---------|------------|-----| | Runtime error: -2147352567 | Object not found | Element ID wrong or screen changed | Use Script Recorder to get correct ID | | Scripting disabled | Server rejected script | sapgui/user_scripting = FALSE | Set via RZ11 or profile parameter | | No SAP GUI instance | GetObject failed | SAP GUI not running | Start SAP GUI before script | | Session busy | Cannot attach | Transaction is processing | Add time.sleep() before action | | Modal dialog open | Cannot access main window | Popup blocking | Handle wnd[1] before wnd[0] | | ALV: Invalid cell | GetCellValue error | Row index out of range | Check RowCount before access | | Multiple logon | Popup at login | User already logged in | Handle popup or close other session | | Authorization | No authorization for scripting | Missing S_SCR auth object | Assign auth via SU01/role |
Performance Tips
- Disable screen updates — Not natively supported; minimize visual impact by running in background session
- Batch via BDC/BAPI first — GUI scripting is last resort; prefer RFC/BAPI/OData for bulk operations
- Reuse sessions — Don't login/logout per record; reuse connection for batch processing
- Minimize findById calls — Cache element references:
field = session.findById(...)then reusefield - Handle scrolling — For table controls, read
VisibleRowCountand scroll incrementally - Parallel sessions — SAP allows up to 6 sessions per user; parallelize with
connection.Children(N) - Avoid hardcoded waits — Use status bar checks instead of fixed
time.sleep()where possible
Gotchas
- Screen variants: Same transaction can show different screens based on user settings — always verify screen number
- Language dependency: Element IDs can differ by logon language for some older transactions
- ALV vs. Table Control:
GuiGridView(ALV) andGuiTableControlhave completely different APIs - SAP GUI version: Scripting API changes between versions; test on target version
- Security policy: Many organizations disable scripting in production — always check policy
- 64-bit Python + 32-bit SAP GUI: COM interop may fail; use matching architecture
Source & license
This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.
- Author: efeumutaslan
- Source: efeumutaslan/SAP-SKILLS
- License: MIT
Install and usage instructions live in the source repository linked above.
Reviews
No reviews yet — be the first.
Write a review
Versions
- v0.1.0 Imported from the upstream source.