Technical Articles
How to Program and Run an ABAP Report from PowerShell via NCo
The RFM RFC_ABAP_INSTALL_AND_RUN offers great possibilities to achieve a high integration level between ABAP and an external scripting language, from the perspective of the scripting language. In this post I describe how to do that with PowerShell and the dotNET Connector (NCo).
In the last years I wrote posts how to use RFM RFC_ABAP_INSTALL_AND_RUN with COM Connector (CCo) or via NW RFC SDK for:
- VBScript and AutoIt (2013)
- HTA (2013)
- Python (2014)
- PHP (2016)
You can find detailed explantions how to use NCo with PowerShell here:
- How to use PowerShell Script Language via dotNET Connector (NCo) in SAP Context
- PowerShell Functions: Load NCo in Relation to Shell and Get Destination with Password Requester
Here now the first script, which includes the ABAP code as here string at the top. It loads the NCo libraries and gets the destination. Then it loads the ABAP code line by line into the PROGRAM table of the RFM RFC_ABAP_INSTALL_AND_RUN and executes it. Last but not least it prints the result from the WRITES table.
#-Begin-----------------------------------------------------------------
$ABAPCode = @"
"-Begin-----------------------------------------------------------------
Report zTest Line-Size 256.
Write: 'Hello World from'.
Write: sy-sysid.
"-End-------------------------------------------------------------------
"@
#-Sub Load-NCo--------------------------------------------------------
Function Load-NCo {
[String]$ScriptDir = $PSScriptRoot
If ([Environment]::Is64BitProcess) {
[String]$Path = $ScriptDir + "\x64\"
} Else {
[String]$Path = $ScriptDir + "\x86\"
}
[String]$File = $Path + "sapnco.dll"; Add-Type -Path $File
$File = $Path + "sapnco_utils.dll"; Add-Type -Path $File
}
#-Function Get-Destination--------------------------------------------
Function Get-Destination {
#-Connection parameters---------------------------------------------
$cfgParams = New-Object SAP.Middleware.Connector.RfcConfigParameters
$cfgParams.Add("NAME", "Test")
$cfgParams.Add("ASHOST", "NSP")
$cfgParams.Add("SYSNR", "00")
$cfgParams.Add("CLIENT", "001")
$cfgParams.Add("USER", "BCUSER")
$cfgParams.Add("PASSWD", "minisap")
Return [SAP.Middleware.Connector.RfcDestinationManager]::GetDestination($cfgParams)
}
#-Sub Run-ABAP--------------------------------------------------------
Function Run-ABAP () {
$destination = Get-Destination
#-Metadata----------------------------------------------------------
$rfcFunction = `
$destination.Repository.CreateFunction("RFC_ABAP_INSTALL_AND_RUN")
#-Call function module----------------------------------------------
Try {
[SAP.Middleware.Connector.IRfcTable]$Table = `
$rfcFunction.GetTable("PROGRAM")
$ABAPLines = $ABAPCode -Split [System.Environment]::NewLine
ForEach($ABAPLine In $ABAPLines){
$Table.Append()
$Table.SetValue("LINE", $ABAPLine)
}
$rfcFunction.Invoke($destination)
[SAP.Middleware.Connector.IRfcTable]$Table = `
$rfcFunction.GetTable("WRITES")
ForEach ($Line In $Table) {
Write-Host $Line.GetValue("ZEILE")
}
} Catch {
Write-Host "Exception occured:`r`n" $_.Exception.Message
}
}
#-Sub Main------------------------------------------------------------
Function Main () {
If ($PSVersionTable.PSVersion.Major -ge 5) {
Load-NCo
Run-ABAP
}
}
#-Main----------------------------------------------------------------
Main
#-Error routine-------------------------------------------------------
Trap {
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $Null
[Void] [System.Windows.Forms.MessageBox]::Show( `
$_.Exception.GetType().FullName + `
[System.Environment]::NewLine + [System.Environment]::NewLine + `
$_.Exception.Message, "An Error Occurred", 0)
Exit
}
#-End-------------------------------------------------------------------
Here now another example which selects data from SFLIGHT table, returns it to the script and the script takes it into the SFlight array:
#-Begin-----------------------------------------------------------------
$ABAPCode = @"
"-Begin-----------------------------------------------------------------
"
" Important hint: Line-Size of the Report statement must be less or
" equal 256.
"
" Important hint: The length of a code line may not exceed 72
" characters.
"
"-----------------------------------------------------------------------
Report zTest Line-Size 256.
Data:
lt_SFlight Type Standard Table Of SFLIGHT,
lv_Price Type String
.
Field-Symbols:
Type SFLIGHT
.
Select *
Into Table lt_SFlight
From SFLIGHT
Where CARRID = 'LH'
.
Loop At lt_SFlight Assigning .
lv_Price = <ls_SFlight>-Price. Condense lv_Price.
Write: /
<ls_SFlight>-CarrID, ';', <ls_SFlight>-ConnID, ';',
<ls_SFlight>-FLDate, ';', lv_Price, ';',
<ls_SFlight>-PlaneType.
EndLoop.
"-End-------------------------------------------------------------------
"@
#-Sub LoadNCo-----------------------------------------------------------
Function LoadNCo {
[String]$ScriptDir = $PSScriptRoot
If ([Environment]::Is64BitProcess) {
[String]$Path = $ScriptDir + "\x64\"
} Else {
[String]$Path = $ScriptDir + "\x86\"
}
[String]$File = $Path + "sapnco.dll"; Add-Type -Path $File
$File = $Path + "sapnco_utils.dll"; Add-Type -Path $File
}
#-Function Get-Destination----------------------------------------------
Function Get-Destination {
#-Connection parameters-----------------------------------------------
$cfgParams = New-Object SAP.Middleware.Connector.RfcConfigParameters
$cfgParams.Add("NAME", "TEST")
$cfgParams.Add("ASHOST", "NSP")
$cfgParams.Add("SYSNR", "00")
$cfgParams.Add("CLIENT", "001")
$cfgParams.Add("USER", "BCUSER")
$cfgParams.Add("PASSWD", "minisap")
Return [SAP.Middleware.Connector.RfcDestinationManager]::GetDestination($cfgParams)
}
#-Sub RunABAP-----------------------------------------------------------
Function RunABAP {
$destination = Get-Destination
#-Metadata------------------------------------------------------------
$rfcFunction = `
$destination.Repository.CreateFunction("RFC_ABAP_INSTALL_AND_RUN")
#-Call function module------------------------------------------------
[SAP.Middleware.Connector.IRfcTable]$Table = `
$rfcFunction.GetTable("PROGRAM")
$ABAPLines = $ABAPCode -Split [System.Environment]::NewLine
ForEach($ABAPLine In $ABAPLines){
$Table.Append()
$Table.SetValue("LINE", $ABAPLine)
}
$rfcFunction.Invoke($destination)
[SAP.Middleware.Connector.IRfcTable]$Table = `
$rfcFunction.GetTable("WRITES")
$arrSFlight = New-Object System.Collections.Generic.List[Object]
ForEach ($Row In $Table) {
[String]$Line = $Row
$Elements = $Line.Replace("FIELD ZEILE=", "").Split(";")
$SFlight = New-Object PSObject -Property @{
CARRID = $Elements[0].Trim()
CONNID = $Elements[1].Trim()
FLDATE = $Elements[2].Trim()
PRICE = $Elements[3].Trim()
PLANETYPE = $Elements[4].Trim()
}
$arrSFlight.Add($SFlight)
}
$arrSFlight | Out-GridView -Title "SFLIGHT"
}
#-Sub Main--------------------------------------------------------------
Function Main {
If ($PSVersionTable.PSVersion.Major -ge 5) {
LoadNCo
RunABAP
}
}
#-Main------------------------------------------------------------------
Main
#-Error routine---------------------------------------------------------
Trap {
[System.Reflection.Assembly]::LoadWithPartialName("System.Windows.Forms") > $Null
[Void] [System.Windows.Forms.MessageBox]::Show( `
$_.Exception.GetType().FullName + `
[System.Environment]::NewLine + [System.Environment]::NewLine + `
$_.Exception.Message, "An Error Occurred", 0)
Exit
}
#-End-------------------------------------------------------------------
With this RFM it is very easy to use ABAP in the context of PowerShell. On this way you can use ABAP functionality inside your PowerShell script easily.
Hi Stefan. Thanks for publishing these articles. I learn NCo based on them.
I have a problem.
When I get to the point
I get a response that the message type is unknown:
Exception calling "CreateFunction" with "1" argument(s): "Message-Typ ist nicht bekannt."
Do you know what might cause this?