Skip to Content
Technical Articles
Author's profile photo Sarvjot Singh

SAP BusinessObjects Business Intelligence (BI) 4.x Monitoring Utility – A Different Approach

BI 4.x always had great monitoring capabilities and a wonderful community to help out Administrators such as me.

 

There are some wonderful articles and even description in the Administration Guide to configure them which covers variety of areas that an Admin may need and here is good example to start:

https://blogs.sap.com/2013/01/08/sap-businessobjects-40-monitoring-configuration-part1/

 

However, the inbuilt BI 4 monitoring relies heavily on the Adaptive Processing Server (APS) & the Central Management Server (CMS), so if they both go down, we would essentially have an outage on our hands.

Now, there are several third party tools out there to do the exe monitoring and not everyone has access to them and even if you might find one in your organization, it may come at cost or some tinkering with agent installation. Still, it may cover CMS’s exe or some other known servers like Web Intelligence servers but what about APS, which runs as java.exe and if you have a bunch of them (APS) its difficult to figure out which APS is which.

 

Therefore with above questions and with time on my hand, I wanted to try out a personal quick setup monitoring method that would require minimal configuration and precise reporting as per my needs and ofcourse contribute back to the community that has been always generous to me.

 

So I began my work with a Windows based deployment & my small powershell toolkit, out came this utility that I would like you all to review and share your feedback and feel free to use it (if you find a use case in your landscape)

 

Synopsis:

This utility is targeted for windows based BI 4 deployments

It requires you allocate a license, so with Named user license type you may have some reservation

You would have to schedule this utility on the BI 4 server

Its not for Linux / Unix / AIX installation but the approach may work via the shell script (since I dont have the landscape, hence I couldnt write one or needed one)

 

Setting up the Utility

  1. A user created in BO, with member of only Everyone Group. The user needs to be assigned “View” on all the servers at top level (Inherit from Parent Group Needs to be unchecked, else like Everyone, it will not be able to view servers). This ensures that this user is only for monitoring, since in this utility the password has to be written in Clear Text in this utility. The user need not be of a specific authentication type, it can be Enterprise or Windows AD or LDAP. However SAP Authentication or any other authentication type will not work.
  2. Make sure that the powershell script, Server_Parameters.txt, Server_Exception_List.txt file all are placed in the same location. If they are not in the same location, the program will not work.
  3. This program assumes that you are running this program with a member of administrator group & are aware of basic workflow of scheduling tasks using Windows task scheduler.
  4. This utility requires that none of the services are in disabled or stopped state. It means that all servers & services should be in running state, if something is not running & enabled, the utility treats that as problem & will send an alert
  5. While scheduling the exe with Windows Task scheduler, ensure that the “START IN (OPTIONAL)” Field needs to be populated and give the location of the directory which contains the exe & Server_Parameters.txt file
  6. If you have any server that you want to exclude from the alert, then add that server name to Server_Exception_List.txt file. Server Name can be obtained from Server Properties>Server Name in CMC. ONLY 1 NAME SHOULD BE WRITTEN IN EACH LINE, NO ‘,’ OR ‘;’ OR QUOTES OR DOUBLE QUOTES ALLOWED
  7. Ensure that path till Win64_x64 of BOBJ is added in PATH variable, else the executable will not run
  8. DO NOT RENAME ANY FILE. ELSE THE PROGRAM WILL NOT WORK

 

In total you would have 3 files:

  1. The script
  2. Server_Parameters.txt
  3. Server_Exception_List.txt

The description of the files is as shared below:

  • The Script:
##Declaring Variables as null
$Results = $null
$SendMail = $null
$CmsDown = $null
$Result = $null

#Getting the excution directory of script excution
$Location = Get-Location

#Making Server Parameters file location
$Source_File = Join-Path -Path $Location.Path -ChildPath "\Server_Parameters.txt"

#Fetching Exception List
$Exception_File = Join-Path -Path $Location.Path -ChildPath "\Server_Exception_List.txt"

#Uploading Server Exception List
$Server_Exception_List = Get-Content $Exception_File

#Making Hash Table from User defined variables in Server Parameter File
$Server_Parameter = Get-Content $Source_File | Out-String | ConvertFrom-StringData

#Appending & Making path to ccm executable
$Server_Parameter.BO_INSTALL_FOLDER = Join-Path -Path $Server_Parameter.BO_INSTALL_FOLDER -ChildPath "\win64_x64\"

#Changing Directory to Win64_x64 so we can run ccm.exe
cd $Server_Parameter.BO_INSTALL_FOLDER

$Result= ccm.exe -cms $Server_Parameter.CMS_MACHINE_NAME -display -username $Server_Parameter.CMS_USERNAME -password $Server_Parameter.CMS_PASSWORD -authentication $Server_Parameter.CMS_USER_AUTHENTICATION

##Removing tabs from the lines of results, so everything starts from beginning of line
$Result = $Result.replace("`t","")


##If CMS is down. Dont run rest of the code & send email with custom message
$CmsDown = $Result | Select-String -Pattern 'Unable to logon to CMS'
if($CmsDown -ne $null){$SendMail += 1}
Else{

##Declaring arrays for States
$Stopped = @()
$Initializing = @()
$Starting = @()
$Stopping = @()
$Running =@()
#Declaring array to hold exception
$Exceptioned_Server = @()

#Ensuring that buffer is null for Line Numbers
$StoppedLineNumber = $null
$InitializingLineNumber = $null
$StartingLineNumber = $null
$StoppingLineNumber = $null
$RunningLineNumber = $null
#Declaring Liner Number buffer for exception & making an array out of it
$ExceptionedLineNumber = $null
$ExceptionedLineNumber = @()

    #Getting exception Numbers First
    Foreach($Exceptioned_Server_Name in $Server_Exception_List){
        $ExceptionedLineNumber += $Result | Select-String -Pattern $Exceptioned_Server_Name | Select-Object -ExpandProperty 'LineNumber'
    }

    #Extracting the Exceptioned Servers in $Exceptioned Array
        Foreach ($Number in $ExceptionedLineNumber){

          $Exceptioned_Server += [PSCustomObject] @{  
          ServerName = $Result[$Number - 1].replace("Server Name: ","");  
          State = $Result[$Number].replace("State: ","");  
          Status = $Result[$Number+1].replace("Enabled: ","");}

          #removing the exceptioned lines from $Result File, as they have been already extraced to Exceptioned Server Array
          $Result[$Number - 1] = ''
          $Result[$Number] = ''
          $Result[$Number + 1] = ''
          $Result[$Number + 2] = ''
          $Result[$Number + 3] = ''
          $Result[$Number + 4] = ''
        }

    
    #Find Line number where State is found and add them in $LineNumber variable
    $StoppedLineNumber = $Result | Select-String -Pattern 'State: Stopped' | Select-Object -ExpandProperty 'LineNumber'
    $InitializingLineNumber = $Result | Select-String -Pattern 'State: Initializing' | Select-Object -ExpandProperty 'LineNumber'
    $StartingLineNumber = $Result | Select-String -Pattern 'State: Starting' | Select-Object -ExpandProperty 'LineNumber'
    $StoppingLineNumber = $Result | Select-String -Pattern 'State: Stopping' | Select-Object -ExpandProperty 'LineNumber'
    $RunningLineNumber = $Result | Select-String -Pattern 'State: Running' | Select-Object -ExpandProperty 'LineNumber'

    Foreach ($Number in $StoppedLineNumber){

          $Stopped += [PSCustomObject] @{  
          ServerName = $Result[$Number - 2].replace("Server Name: ","");  
          State = $Result[$Number - 1].replace("State: ","");  
          Status = $Result[$Number].replace("Enabled: ","");}

        }

    Foreach ($Number in $InitializingLineNumber){
 
          $Initializing += [PSCustomObject] @{  
          ServerName = $Result[$Number - 2].replace("Server Name: ","");  
          State = $Result[$Number - 1].replace("State: ","");  
          Status = $Result[$Number].replace("Enabled: ","");}

      }

        Foreach ($Number in $StartingLineNumber){

          $Starting += [PSCustomObject] @{  
          ServerName = $Result[$Number - 2].replace("Server Name: ","");  
          State = $Result[$Number - 1].replace("State: ","");  
          Status = $Result[$Number].replace("Enabled: ","");}
        }

        Foreach ($Number in $StoppingLineNumber){

          $Stopping += [PSCustomObject] @{  
          ServerName = $Result[$Number - 2].replace("Server Name: ","");  
          State = $Result[$Number - 1].replace("State: ","");  
          Status = $Result[$Number].replace("Enabled: ","");}
  }

        Foreach ($Number in $RunningLineNumber){

          $Running += [PSCustomObject] @{  
          ServerName = $Result[$Number - 2].replace("Server Name: ","");  
          State = $Result[$Number - 1].replace("State: ","");  
          Status = $Result[$Number].replace("Enabled: ","");}
  }

if($StoppedLineNumber -ne $null)  
{  
    $SendMail += 1
    $OutputreportStopped = "<div><H2>[Servers(s) Stopped]</H2><Table border=1 cellpadding=5 cellspacing=0><TR bgcolor=gray align=center><TD><B>Server Name</B></TD><TD><B>State</B></TD><TD><B>Status</B></TD></TR>"  
    Foreach($Entry in $Stopped)  
    {  
    switch ($Entry.State) 
        { 
        "Stopped" {$OutputreportStopped += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        default {$OutputreportStopped += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        } 
        $OutputreportStopped += "<TD>$($Entry.ServerName)</TD><TD align=center>$($Entry.State)</TD><TD align=center>$($Entry.Status)</TD></TR>"  
    }  
    $OutputreportStopped += "</Table></div>"  
}  
 
if($StoppingLineNumber -ne $null)  
{  
    $SendMail += 1
    $OutputreportStopping = "<div><H2 style='color:black;'>[Server(s) Stopping]</H2><Table border=1 cellpadding=5 cellspacing=0><TR bgcolor=gray align=center><TD><B>Server Name</B></TD><TD><b>State</b></TD><TD><B>Status</B></TD></TR>"  
    Foreach($Entry in $Stopping)  
    {  
    switch ($Entry.State) 
        { 
        "Stopping" {$OutputreportStopping += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        default {$OutputreportStopping +=  "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        } 
        $OutputreportStopping += "<TD>$($Entry.ServerName)</TD><TD align=center>$($Entry.State)</TD><TD align=center>$($Entry.Status)</TD></TR>"  
    }  
    $OutputreportStopping += "</Table></div>"  
}  
 
if($StartingLineNumber -ne $null)  
{  
    $SendMail += 1
    $OutputreportStarting = "<div><H2 style='color:black;'>[Server(s) Starting]</H2><Table border=1 cellpadding=5 cellspacing=0><TR bgcolor=gray align=center><TD><B>Server Name</B></TD><TD><b>State</b></TD><TD><B>Status</B></TD></TR>"  
    Foreach($Entry in $Starting)  
    {  
    switch ($Entry.State) 
        { 
        "Starting" {$OutputreportStarting += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        default {$OutputreportStarting +=  "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        } 
        $OutputreportStarting += "<TD>$($Entry.ServerName)</TD><TD align=center>$($Entry.State)</TD><TD align=center>$($Entry.Status)</TD></TR>"  
    }  
    $OutputreportStarting += "</Table></div>"  
}  

if($InitializingLineNumber -ne $null)  
{  
    $SendMail += 1
    $OutputreportInitializing = "<div><H2 style='color:black;'>[Server(s) Initializing]</H2><Table border=1 cellpadding=5 cellspacing=0><TR bgcolor=gray align=center><TD><B>Server Name</B></TD><TD><b>State</b></TD><TD><B>Status</B></TD></TR>"  
    Foreach($Entry in $Initializing)  
    {  
    switch ($Entry.State) 
        { 
        "Initializing" {$OutputreportInitializing += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        default {$OutputreportInitializing += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        } 
        $OutputreportInitializing += "<TD>$($Entry.ServerName)</TD><TD align=center>$($Entry.State)</TD><TD align=center>$($Entry.Status)</TD></TR>"  
    }  
    $OutputreportInitializing += "</Table></div>"  
} 

if($ExceptionedLineNumber -ne $null)  
{  
#    $SendMail += 1
    $OutputreportException = "<div><H2 style='color:blue;'>[Server(s) Excluded From This Scan As Per Exception List]</H2><Table border=1 cellpadding=5 cellspacing=0><TR bgcolor=gray align=center><TD><B>Server Name</B></TD><TD><b>State</b></TD><TD><B>Status</B></TD></TR>"  
    Foreach($Entry in $Exceptioned_Server)  
    {  
    switch ($Entry.State) 
        { 
#        "Initializing" {$OutputreportInitializing += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        default {$OutputreportException += "<TR bgcolor='#D6FFFF' style='color:#000;'>"} 
        } 
        $OutputreportException += "<TD>$($Entry.ServerName)</TD><TD align=center>$($Entry.State)</TD><TD align=center>$($Entry.Status)</TD></TR>"  
    }  
    $OutputreportException += "</Table></div>"  
}

if($Running.Status -eq ('Disabled')){  
    $SendMail += 1
    $OutputreportRunningButDisabled = "<div><H2 style='color:black;'>[Server(s) Running But Disabled]</H2><Table border=1 cellpadding=5 cellspacing=0><TR bgcolor=gray align=center><TD><B>Server Name</B></TD><TD><b>State</b></TD><TD><B>Status</B></TD></TR>"  
    Foreach($Entry in $Running)  
    {  
    if ($Entry.Status.Contains('Disabled')){ 
#    Write-Host $Entry.ServerName   
    switch ($Entry.State) 
        { 
        "Running" {$OutputreportRunningButDisabled += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        default {$OutputreportRunningButDisabled += "<TR bgcolor='#FF704D' style='color:#000;'>"} 
        } 
        $OutputreportRunningButDisabled += "<TD>$($Entry.ServerName)</TD><TD align=center>$($Entry.State)</TD><TD align=center>$($Entry.Status)</TD></TR>"      
    
    } 
    } 
    $OutputreportRunningButDisabled += "</Table></div>"
} 

$Results = "<div>BO Server Availability Report - " + $Server_Parameter.ENVIRONMENT + " see results below:</div>" 
$Results += "<TITLE style='color:grey;'>[Errors] BO Server Availability Report</TITLE><BODY background-color:peachpuff>$OutputreportStopped $OutputreportStopping $OutputreportStarting $OutputreportInitializing $OutputreportRunningButDisabled $OutputreportException</BODY>" 
$Date = (Get-Date -format "dd-MM-yyyy_hh-mm-ss") 
#$OutputFile = "D:\sarv\scripts\ServerStatusCheck_$Date.htm"
#$Results | out-file $OutputFile 
#Write-Host "Mail Count Variable : " $SendMail

}

if ($SendMail -gt 0) { 
    #Send email with atachment 
    $EmailFrom = $Server_Parameter.MAIL_FROM
    $EmailTo = $Server_Parameter.MAIL_TO
    $SMTPServer = $Server_Parameter.SMTP_SERVER 
    $EmailSubject = $Server_Parameter.MAIL_SUBJECT
    $EmailCC = $Server_Parameter.MAIL_CC
 
    #Send mail with output 
    $mailmessage = New-Object system.net.mail.mailmessage  
    $mailmessage.from = ($EmailFrom)  
    $mailmessage.To.add($EmailTo) 
    $mailmessage.Subject = $EmailSubject 
    $mailmessage.IsBodyHTML = $true
    if ($Server_Parameter.MAIL_CC -ne ''){
        $mailmessage.CC.Add($EmailCC)
    }
    
    if($CmsDown -eq $null){
        $mailmessage.Body = $Results

#        Write-Host "NOT WORKING"
    }
    if($CmsDown -ne $null){
#        Write-Host "NOT WORKING"
        $mailmessage.Body = $Server_Parameter.MAIL_MESSAGE
#        Write-Host $mailmessage.Body
    }
    $SMTPClient = New-Object Net.Mail.SmtpClient($SmtpServer,$Server_Parameter.SMTP_SERVER_PORT)
    
    if($Server_Parameter.IS_SMTP_SSL -eq 'TRUE'){   
        $SMTPClient.EnableSsl = $true
    }

    if($Server_Parameter.USE_SMTP_CREDENTIALS -eq 'TRUE'){
        $SMTPClient.Credentials = New-Object System.Net.NetworkCredential($Server_Parameter.SMTP_USERNAME,$Server_Parameter.SMTP_USER_PASSWORD);
    }
    $SMTPClient.Send($mailmessage) 
}

 

  • The “Server_Parameters.txt” file
##############################################################################  
##  *****ONLY CHANGE THE PARAMETERS BELOW, DO NOT CHANGE VARIABLE NAMES*********
##  *****ANY OTHER CHANGE WILL CAUSE THE PROGRAM TO FAIL*********
##  *****REFER SAMPLES BELOW FOR GUIDANCE*********
## BO Server Availability Monitoring & Alerting 
## Implemented by: Sarvjot Singh Mann 
## Date : XX XXX 20XX | Modification Date XX XXX 20XX 
## Version : 2.0  
## Email: 
## Change Log: (1)V2 now allows server exception List, where servers marked as exceptions will not be alerted upon. (2)Mail CC can be allowed as empty
##############################################################################

###Specify what kind of environment is this, as this will be title keyword of the body of the report generated & emailed to you
ENVIRONMENT=BO-PROD (@BOPROD)

###If you have a custom port for CMS, make sure you specify it / Or use cluster name here.
CMS_MACHINE_NAME=Hostname.COM:6400
CMS_USERNAME=Server_Monitoring
CMS_PASSWORD=Password123

###It can be any authentication type, as long as the user has rights to vew server objects, see Read Me First.txt for more details.
CMS_USER_AUTHENTICATION=secEnterprise

#####SPECIFY YOUR BO INSTALL LOCATION WITH DOUBLE \\ ONLY, ELSE THE PROGRAM WILL NOT WORK SINCE \S IS CONSIDERED AS ESCAPE SEQUENCE. DO NOT PUT THE PATH IN QUOTES OR DOUBLE QUOTES. WRITE AS SHOWN BELOW
BO_INSTALL_FOLDER=D:\\SAP BusinessObjects\\SAP BusinessObjects Enterprise XI 4.0\\


##############MAIL SERVER / RECEPIENTS / SENDER DETAILS #####################################################
SMTP_SERVER=smtp.company.com
##Usually the SMTP port is 
SMTP_SERVER_PORT= 25

##If your mail Server is running with SSL Mark the 'IS_SMTP_SSL=TRUE' ELSE Mark it as 'IS_SMTP_SSL=FALSE' (Marking SMTP SSL status is MANDATORY).
IS_SMTP_SSL=FALSE

##If your mail server only allows mails to be sent after authentication, set USE_SMTP_CREDENTIALS=TRUE, ELSE set USE_SMTP_CREDENTIALS=FALSE *****THIS FLAG IS MANDATORY else mail will not be sent out
USE_SMTP_CREDENTIALS=FALSE

#### If your mail SMTP requires credentials in then you must fill the SMTP_USERNAME & SMTP_USER_PASSWORD ELSE Leave them as blank
SMTP_USERNAME=
SMTP_USER_PASSWORD=


##Write your mail addresses here, however seperated by comma(,)
MAIL_TO=DL@company.com
MAIL_CC=
MAIL_FROM=Sender@company.com


##Write your custom subject here. NO NEED TO ENCLOSE THEM IN QUOTES OR DOUBLE QUOTES. ENCLOSING THEM IN QUOTES OR DOUBLE QUOTES WILL CAUSE THE MAIL TO FAIL
MAIL_SUBJECT=SERVER-ALERT!!! BOBJ SERVICES DOWN OR NOT WORKING ON BO-PRODUCTION!!!


###################################
## Incase CMS is down or unreachable, write your Custom Mail below
## **Replace text as it is or be sure to apply proper HTML formatting, ensure that all the message is in 1 line assigned to this variable
## **You can give new lines with <br> tag, as shown below, see example below
###################################
MAIL_MESSAGE=Dear Team <br><br>The CMS on this machine is down!!!!. The server status report generated failed with CMS Error: Could not connect to CMS, the CMS is either Down / Disabled . Kindly check and take necessary action if required.<br><br> <br>Regards,<br>BO Admin Alerts

 

  • Server_Exception_List.txt
    • Only add lines of server names, copied from server properties in CMC
    • An example is done below
Host.ExplorerMasterServer
Host.ExplorerExplorationServer
Host.ExplorerIndexingServer
Host.ExplorerMasterServer
Host.ExplorerSearchServer

 

Save the files in one directory and schedule the powershell script to run every 15 minutes (I run it every 15 minutes) and when some server goes from running & enabled to anything else; I get an email. As you can see below:

 

 

I have scheduled it on all my landscapes with modified parameters file and presto, instant alert before user complains / tickets or if some of my server suffers any kind of issue

 

 

It has reduced mine & my team’s manual monitoring activities to zero and helps us to take preemptive action before our users experience any discontinuity or problems with their usage of the environment.

I havent got the chance to test it with BI 4.3, however it works with BI 4.0, 4.1 & 4.2, so in my opinion it will work on BI 4.3 as well and that’s whats my next course of testing is (till I get my hands on a BI 4.3 systems); If not then, I hope someone from our community using BI 4.3 can share any feedback if they have a need for such a utility.

Though the utility covers all major scenarios of server state combination, however if you find any improvements or have suggestions, then feel free to let me know and I will try to improve it as much as I can.

 

Thank you for reading, upvote and share it if you find it useful and as always your feedback is greatly appreciated….

 

Regards,

Sarvjot Singh Mann

Assigned tags

      2 Comments
      You must be Logged on to comment or reply to a post.
      Author's profile photo Denis Konovalov
      Denis Konovalov

      If what you said here occurs:
      "However, the inbuilt BI 4 monitoring relies heavily on the Adaptive Processing Server (APS) & the Central Management Server (CMS), so if they both go down, we would essentially have an outage on our hands."

      Your utility will not run either it'll just return an outage...

      Author's profile photo Sarvjot Singh
      Sarvjot Singh
      Blog Post Author

      Hey Dennis,

       

      Thanks for taking out the time to review, I appreciate it and you have said it spot on, however all that this utility would do is send me an email that either my CMS or my APS is down or whichever state they are in, if not running and enabled.

       

      That was what my requirement, that I get an alert before users find it out, have an extra layer of monitoring on server availability in addition to BI 4 inbuilt monitoring and I won't have to rely on other tools to do this like BMC or Dynatrace etc.

       

      Regards,

      Sarvjot