Thursday, March 1, 2018

Restrictions Restrictions

      Welcome back to my blog posts. I hope the information I'm providing on my blog has been of use to atleast some of you. Leave a note in the comments section to tell me what information you find useful and what information you're looking forward to. I will do my best to post them (without giving away business secrets obviously *wink wink*)

      Cognos has the capability of providing authentication against Active Directory. In case you're not aware, in a simple answer, Active Directory is your windows domain authentication.The username and password that you use to login into windows can also be used to login into Cognos.

      This setup is usually good enough for the majority of installations. It allows everyone with a windows username and password to login and run reports. Cognos also honors groups and roles at the Active Directory level, so its easy to assign permissions based on the role or membership of a user in a role.

      This also has the undesired effect of leaving the system wide open to everyone with a username and password. Imagine a situation where a user in the IT department is able to view the financial information of the entire company. Scary!

      While Cognos allows one to lock down the ability to run reports or look at report outputs based on role membership, it would be most beneficial if it didn't allow users to login in the first place.

      On a environment that is configured with the appropriate set of roles and memberships, setting the value of the option 'Restrict users to built-in namespace' to true completely locks down the environment, preventing users from logging in unless they're members of a pre-configured group of users that is allowed access.

   

Sunday, November 19, 2017

Pause and Resume

               Its been a while since I last posted. Other items occupied my time, most notably the apple of my eye, my kind and my 9 - 5 job, which pretty much turned into a 9 - 7 due to multiple factors.

               While life was passing on, this blog was never far from my mind. I always yearned to get back to  writing, which, in the 21st century, is blogging :-)

               A lot of interesting requests came my way over the past two years, and I'm going to try and pick the most interesting ones to talk about.

              One very common request was to disable users from being able to attach report outputs via email, be it either scheduled reports or interactive reports.This is important for a variety of reasons, the most obvious one being security. If the user's email is compromized, atleast the direct report output (financial data in many cases) isn't available directly in the inbox!

              This is a request with a very simple solution. Navigate to your cognos installation folder and browse to templates/ps/portal. Open the system.xml file in your favorite text editor and add the bolded section. If the bolded section already exists, just add the tag CC_RUN_OPTIONS_email_attachment.

             You will need to save the system.xml file and restart cognos for this change to come into affect.


      
 

<system>

<BLAH PARAMS />


<param name="ui_hide">
 <!--list of user interface elements-->

<CC_RUN_OPTIONS_email_attachment/>

</param>


</system>

Monday, September 7, 2015

Advanced configuration settings

         I was working on something a few weeks ago that required me to look up the configuration settings on a few dispatchers. You know .. when you go to Launch -> Cognos Administration -> System -> Configuration -> Properties .. THAT one.

        I had to add changes to the configuration settings without making any changes to the existing options. I wasn't able to find a very efficient method of doing it, but what I did discover is that these configuration settings are returned in an XML format. And who can't work with XML ;-)

        So I whipped up a quick script to retrieve the existing advanced configuration values (if any) and add new values to it.

       Below is a generic format of how the settings are returned.

       

<settings>
<setting name='settingname'>settingvalue</setting>
<!-- below is an example of a configuration setting -->
<setting name='CM.DbConnectPoolMax'>50</setting>
</settings>


Below is a function to retrieve advanced settings. It retrieves the configuration values in the above XML format. A few general points of note.


  1. The language used is C#
  2. m_CMS is an object of type contentmanagerservice1
  3. log is an object of type Category from log4net logging library (http://logging.apache.org/log4net/). Its the .NET implementation of log4j and is an amazing library. 


       
public String GetAdvancedSettings()
{
    String config = "<settings></settings>";
    try
    {
        searchPathMultipleObject spmo = new searchPathMultipleObject();

        // Default and hard-coded search path of /configuration
        spmo.Value = "/configuration";

        /**
        * Make sure you use ONLY the properties that you want
        * I tried selecting ALL properties A-Z one time ...
        * turns out it wasn't one of my finest moments ;-)
        */
        propEnum[] props = new propEnum[] { propEnum.searchPath, propEnum.defaultName, propEnum.advancedSettings };

        baseClass[] bcConf = m_CMS.query(spmo, props, new sort[] { }, new queryOptions());

        if (bcConf.Length > 0)
        {
            configuration conf = (configuration)bcConf[0];
            anyTypeProp atp = (anyTypeProp)conf.advancedSettings;

            config = atp.value;
            log.Debug("Successfully retrieved advanced settings.");
        }
        else {
            log.Debug("No advanced settings set. Retrieved empty result");
        }
    }
    catch (Exception ex)
    {
        log.Error("Error in setting configuration. Error: " + ex.Message);
    }
    return config;
}


And below is a function that makes use of the above function and saves additional settings to the content store.



       

public Boolean SetAdvancedSettings(String configname, String configvalue)
{
    try
    {
        String config = GetAdvancedSettings();
        // Dirty hack instead of using a proper XML reader / writer
        // Gets the job done ;-)

        config = config.Replace("</settings>", "");
        config += "<setting name=\"" + configname + "\">" + configvalue + "</setting></settings>";

        anyTypeProp atp = new anyTypeProp();
        atp.value = config;

        configuration conf = new configuration();
        conf.advancedSettings = atp;

        m_CMS.update(new baseClass[] { conf }, new updateOptions());

        log.Debug("Successfully set advanced settings.");
        return true;
    }
    catch (Exception ex)
    {
        log.Error("Error in setting configuration. Error: " + ex.Message);
        return false;
    }
}

       
 

Tuesday, January 6, 2015

Copying (and pasting) new year resolutions .. and a few other things as well

My new years' resolution for 2015 is to complete my resolution from 2014, which is to make sure I post more often on my blog which I continued in 2013 that I started in 2012!!

So, without further ado .. here goes!!

As part of a recent deployment, I was asked to copy a specific report (or maybe even a group of reports) to the 'My Folders' of multiple users.

There are two ways around this.
  1. Create the report under the [Public Folders], provide the path to the report to the end users, and ask them to copy it to their [My Folders]. 
  2. If you want something done right, do it yourself!!

Now, we know how *ahem* efficient users can be when asked to perform certain tasks. Some had updated versions of the report because they followed the instructions, and the rest, obviously didn't.

Vox populi not working well in this situation? Probably.

I pulled up a small script to copy the new report from one source path to multiple destinations. Obviously, one would have to call this code multiple times based on the destination.

Few important pointers.

  • sourceSearchPath is a string variable with the path of the folder where the source report exists. NOTE: Report Name should NOT be in the sourceSearchPath
  • GetAllPropsList is a function that returns ALL properties
  • destinationSearchPath is a string variable with the path of the destination folder


Try

            ' Interesting to note that the source search path is an object of type searchPathMultipleObject.
            ' This shows that multiple source objects can be copied

            Dim spmo As New searchPathMultipleObject
            spmo.Value = sourceSearchPath

            Dim bcrpt() = m_CMS.query(spmo, GetAllPropsList, New sort() {}, New queryOptions)

            ' Destination search path is an object of type searchPathSingleObject.
            ' The logic would be that multiple source objects can be copied to a single destination

            Dim spso As New searchPathSingleObject
            spso.Value = destinationSearchPath

            Dim co As New copyOptions
            co.updateAction = updateActionEnum.replace
            co.recursive = True

            m_CMS.copy(bcrpt, spso, co)
            LogWriter("Report " & reportName & " copied from " & sourceSearchPath & " to " & destinationSearchPath)
            Return True
        Catch ex As Exception
            LogWriter("Error in copy report: " & ex.Message)
            Return False
        End Try

Monday, September 30, 2013

Of Busy Schedules and (busier) Recurring Schedules!!

I was recently asked to create a schedule for multiple reports and jobs. Now, creating the schedule for one report is fairly simple. You login into the portal, navigate to the report that you would like to schedule, set the schedule options, and viola! You are all set.

Creating the schedule for multiple reports posed more of a challenge. I did not want to manually navigate to each report path and edit the schedule for each report when I could whip up a simple script for doing the same automatically. Little did I know that the simple script would turn out to be not-so-simple.

I had a looooooong list of requirements that pretty much included having the entire list of options available on the portal UI such as

  • Having the flexibility of being able to choose which of the output formats (HTML, PDF, XLS 2003, XLS 2007, CSV) would be needed for which report.
  • Having the flexibility of being able to choose if the report should be saved to the file system.
  • Having the flexibility of being able to choose if the report (link or attachment or both) should be emailed, and if yes then the list of email addresses.
  • And of course, the schedule (daily / weekly / monthly), start time, end time, recurrence pattern, etc.

The below code snippets are part of what I use to perform these operations. They are written in VB.NET. Some of the code is taken from the original Cognos SDK sample code. The part that is not, is mine.

Create a new Schedule object

            Dim newSched As New schedule()

Set up options to set the schedule start time and date, frequency / recurrence pattern, etc
These are available as methods under the newSched object which is of class schedule

For the schedule to work, the system has to have valid user credentials. Below code gets the user credentials. That would be the current logged on user through the SDK

getCredential is a function that I wrote to get the credential of the current logged on user

            Dim schedCred As credential = getCredential()
            Dim credentials As New baseClassArrayProp()
            credentials.value = New baseClass() {schedCred}
            newSched.credential = credentials

Save the report output. Note that this saves the output under the same report output and not as a reportView

            saveOutput.name = runOptionEnum.saveOutput
            saveOutput.value = True

Set schedule email options

            Dim deliveryOptionString As New deliveryOptionString
            deliveryOptionString.name = deliveryOptionEnum.subject
            deliveryOptionString.value = reportName

            Dim deliveryOptionAddrSMTPArray As New deliveryOptionAddressSMTPArray
            deliveryOptionAddrSMTPArray.name = deliveryOptionEnum.toAddress
            Dim addrSMTP As addressSMTP() = New addressSMTP(1) {}
            addrSMTP(0) = New addressSMTP
            addrSMTP(0).Value = "email@emailprovider.com"

            addrSMTP(1) = New addressSMTP
            addrSMTP(1).Value = "email2@emailprovider.com"

            deliveryOptionAddrSMTPArray.value = addrSMTP

            Dim deliveryOptionMemoPart As New deliveryOptionMemoPart
            deliveryOptionMemoPart.name = deliveryOptionEnum.memoPart

            Dim memoPart As New memoPartComposite
            memoPart.contentDisposition = smtpContentDispositionEnum.inline
            memoPart.contentType = smtpContentTypeEnum.alternative

            deliveryOptionMemoPart.value = memoPart

            Dim parts As memoPart() = New memoPart(1) {}

            Dim memoPartString As New memoPartString
            memoPartString.contentDisposition = smtpContentDispositionEnum.inline
            memoPartString.text = "Report Body"

            Dim memoPartMIMEAttachment As New memoPartMIMEAttachment
            memoPartMIMEAttachment.contentDisposition = smtpContentDispositionEnum.inline
            memoPartMIMEAttachment.dataType = "text/html"
            memoPartMIMEAttachment.dataSize = "0"

            Dim bArr() As Byte = System.Text.Encoding.UTF8.GetBytes("asdf")

            memoPartMIMEAttachment.data = bArr ' Byte array
            parts(0) = memoPartString
            parts(1) = memoPartMIMEAttachment

            emailAsAttachment.name = runOptionEnum.emailAsAttachment
            emailAsAttachment.value = True

            emailAsUrl.name = runOptionEnum.emailAsURL
            emailAsUrl.value = True

            email.name = runOptionEnum.email
            email.value = True

END Set schedule email options

Once the schedule email options are added, these options need to be added into an array of type 'option'.

Dim opts() As [option] = New [option](5) {}
            opts(0) = emailAsAttachment
            opts(1) = emailAsUrl
            opts(2) = deliveryOptionString
            opts(3) = deliveryOptionAddrSMTPArray
            opts(4) = deliveryOptionMemoPart
            opts(5) = email

Next, this options array will have to be added to the schedule object
           
            Dim schOpts As New optionArrayProp
            schOpts.value = opts
            newSched.options = schOpts

Finally, create a new schedule (or update an existing schedule) for the report / job by using the add method of the contentmanagerservice1 class

Thursday, March 14, 2013

Of stubborn wives and stubborn-er content stores

So it seems like I have been away for a long time. In my defense, I was busy. I got married and have been navigating the joys (and perils!!) of married life!!

The perils usually came when I had to work late on getting Cognos environments up for our customers and my stubborn wife insisted on staying up and keeping me company (shooting daggers at me all the time, mind it) while I was up troubleshooting issues with IBM ;-)

One such situation was when I had to work with IBM support on getting an environment up that refused to come up, no matter what we tried to do. The content store was on a Microsoft SQL Server environment and the startup process would complete successfully. The only exception was that the dispatcher would not complete initialization successfully.

The environment was a default install with all components installed and configured with the default settings. The dispatcher, gateway and content manager were set with the default settings. There was no configuration that was edited or customized.

All startup tasks would complete successfully. The content manager was initialized successfully. Even the BiBus process started successfully (doh!). I could see connections going from the content manager to the MS SQL content store.

We created a completely new content store on the same DB environment (to eliminate any environment problems) and Cognos started fine. This eliminated any issues with the app environment and left the db / content store environment.

We took a backup of the existing content db from MSSQL and recreated it on a completely separate environment. We then pointed an app environment to this content db and this started fine!

The problem that we had now was to get this back into our production environment. We did a regular full content store export from Cognos Administration and imported this export into the production environment.

To this day, we have no idea why the original production environment failed to start.

One important lesson that I learnt that day was that having a file level backup of the content db just wasn't enough. In addition to it, a full content store export as an additional backup is also a good idea. 

Saturday, May 5, 2012

Sample Script to Login

This is a sample script that is part of the various scripts that I use to login into a Cognos environment using  SDK. Once the contentManagerService1 object has the logged in credentials, you can use it to perform any task such as automatically importing / exporting a package, create a new DSN, create a new skin, basically anything that you would use the portal / UI for.

Part of this script is taken from the original SDK sample code that is provided. I have just customized it for my own use in my environment.

Try
            Dim m_CMS as New contentManagerService1
            m_CMS.url = "http://localhost:9300/p2pd/servlet/dispatch"
            Dim m_nmsp, m_uname, m_pwd as String


            Dim credentialXML As StringBuilder
         
            credentialXML = New StringBuilder("<credential>")

            credentialXML.Append("<namespace>")
            credentialXML.Append(m_nmsp)
            credentialXML.Append("</namespace>")

            credentialXML.Append("<username>")
            credentialXML.Append(m_uname)
            credentialXML.Append("</username>")

            credentialXML.Append("<password>")
            credentialXML.Append(m_pwd)
            credentialXML.Append("</password>")

            credentialXML.Append("</credential>")

            Dim encodedCredentials As String = credentialXML.ToString()
            Dim xmlEncodedCredentials As New xmlEncodedXML
            xmlEncodedCredentials.Value = encodedCredentials

            m_CMS.logon(xmlEncodedCredentials, Nothing)

            MsgBox("Success in logon!")
            Return True

Catch ex as Exception
       MsgBox ex.Message
       Return False
End Try


About me


I work for a company that manages the Cognos services for multiple customers. This entails having one Cognos instance for every customer. It becomes difficult once the number of customers reached a sizable number, so I started looking into how I could use the Cognos SDK to automate certain tasks.

I work with both .NET technologies (VB.NET, C#) and JAVA in building apps that can be used to deploy changes across the board for multiple instances.Changes might also involve advanced configuration, package deployment, security management, etc.