Dec 282013
 

I like building applications, and these days that means web applications. The challenge is enjoyable. During my vacation this year I decided to spend some time expanding some code that I’ve been working on over the years. In this case, a tool that runs on my PC that integrates with a database. Previously, I tended towards integrating with a local DB, be it via ODBC, a local text or Excel file, etc. This year I’m setting myself the challenge of integrating with a MySQL database over HTML.

The reason for this is because there is a substantial amount of information in my company’s online database (hosted by NetSuite), but getting access to it for any kind of automation can be tricky. However, it can be done if you’re willing to invest the development time to building an application (both sides of one). But, such a task is not something I’ve ever done before. So I’m combining a hobby and self improvement with the intention of building skills which may be useful at some point in the future at work.

As an example, an application which retrieves system information and helps organize and launch system connections (http, ssh, rdc) is a lot more portable if it retrieves the system information from a central database than something which requires all of the system information to be stored locally. If someone updates the system information and you don’t notice it, it means you could be attempting to connect to the wrong IP or server name. By automating the information retrieval you can save minutes (or over a calendar year, save hours or even days) worth of lookup time.

There are plenty of other uses, such as pulling information from a system, parsing it and then pushing it to a MySQL database directly, and then allowing that information to be displayed in an HTML format. Log parsing, etc., could be streamlined. Even, in one case, parsing the Microsoft hotfixes applied to servers and scrubbing it against a database for which hotfixes have been tested/approved by the manufacturer, would be a great application for my environment. Avaya already has something like that for the CS1000 that was created by the engineers back in the Nortel days. But they don’t have anything like that for the Avaya Aura Contact Center product line, even though they have the audit tool that would be necessary to implement the first half of that endeavor.

While tooling around with the XMLHTTP GET/POST integration for the client tool, I ran into an error on my website that was generated by Mod_Security. “An appropriate representation of the requested resource could not be found on this server. This error was generated by Mod_Security.

Upon further investigation, I managed to capture an error log out of the shared error log on my web host “ModSecurity: Access denied with code 406 (phase 2). Match of “rx ^0$” against “REQUEST_HEADERS:Content-Length” required. [file “/etc/httpd/modsecurity.d/10_asl_rules.conf”] [line “101”] [id “392301”] [rev “5”] [msg “Request Containing Content, but Missing Content-Type header”] [severity “NOTICE”]

The rest of the error is largely environment specific, so I’m omitting that info, but if you’ve run into this error yourself, you know what it looks like.

Here’s what I learned in my search (I’m effectively building a custom browser using Microsoft XMLHTTP— the mechanism isn’t too important, be it Power Shell, vbscript or jscript)

  1. Must declare RequestHeader User-Agent
  2. Must declare RequestHeader Content-Type
  3. For POST, must declare RequestHeader Content-Length

These are not mandatory for all HTML interactions, but some security configurations may require certain headers in order to process an XMLHTTP request. In the case of my web server (shared webhosting) and my custom browser application, for a GET request only the User-Agent and Content-Type were required. However, Mod_Security was configured on the shared webhost to mandate Content-Length.

What triggered this research and error was a typo in my code.

The typo came down to a bad choice in variable declaration. In a foreach ( item in array ) statement, I poorly chose the variables to be foreach ( item in items ) and, I’m sure you can see the typo risk already, I accidentally typed foreach ( item in item ). As such, the foreach loop did not properly iterate over the array… and since the foreach loop set the RequestHeaders, the request headers were not being set. Thus, the mod_security error.

I didn’t catch the typo initially, as the first error message was mostly meaningless and I couldn’t immediately determine the cause. Still, I saw a number of articles (including some wordpress blog support requests for this error, with some fixes involving changing the behavior of Mod_Security). While the Mod_Security error isn’t very meaningful, if you dig into the error_logs deep enough, you’ll find the error message which will lead you to the root cause of the problem. In my case, an HTTP 406 indicating that “Rquest Containing Content, but Missing Content-Type header.”

Once I found the typo in the code and fixed it, the XMLHTTP request worked perfectly (except that mod_security was also configured to require a content-length request header on POST requests, but once I’d fixed the one problem the other was easily to identify and fix.)

Oct 282013
 

One of the things that I find useful to understand when building tools on an existing framework is where the hooks are for scripting. I’ve been doing a lot of scripting over the last two years to optimize my company’s NetSuite deployment. A short list of some of the things that I’ve worked on include:

  • Time Entry Automation improvements
    • auto-format memos on time entries with date, ticket/project/task, and the event subject
    • Validation on Service Item, Payroll Item, Class– certain combinations are verboten but must be restricted via scripting as there is no built-in validation
    • Auto-complete Service Item, Payroll Item, Class– certain combinations are only allowed to be entered a certain way
  • Ticket validation improvements
    • Tickets are changed from New to In Progress when Engineer assigned
    • Repair tickets not allowed for T&M customers
    • Mandate entry of certain information when the ticket type is a certain value
    • Prevent internal tickets from CCing to customer contacts
  • Customer validation improvements
    • Validation on lots of fields including verifying that IP addresses and subnet mask info entered is valid for IPv4 format. Validate that DNS addresses follow the public standard. Auto-name records to reduce data entry. etc.
    • Enforce entry of critical information on new records (no half-creating a record allowed– sublist fields can’t be marked as mandatory except via scripting.)
  • Project validation improvements
    • Ensure certain roles are exempt from mandatory field requirement (conditionally required field based on role of person editing/creating the record)
  • Solutions validation improvements
    • Pre-formatting the Abstract and Details via custom button

When working on all of these, it’s important to understand the best place to hook the action into.

  • Do you want to prevent a user from entering certain values or values outside of the accepted format? Use validateField.
  • After changing a field value and post sourcing occurs (i.e., updating the customer on a ticket causes the contact to be cleared), do you want to ensure the original field value is restored (if possible)? Use postSourcing (note: in some cases, the parent value might prevent use of the child value because the child value is not an acceptable value under the new parent.)
  • Do you want to prevent a user from inserting new sublist (time entry) records to a closed event? Use validateLine within the parent event, use onSave from the Time Entry form.

 

Here’s the diagram that I’ve been keeping in my head (because NetSuite doesn’t supply one). I thought other NetSuite admins/consultants/programmers might find it handy.

 

 

I welcome comments, questions and feedback. I don’t normally post NetSuite or scripting related stuff to my blog as my primary role is not a coding role (even though I enjoy it on a limited basis. I prefer to use coding/scripting to enhance my primary job function, rather than my primary function being to code.)

Feb 192013
 

I’m a big fan of Joe Son’s Netsuite blog. He shares some interesting stories about his learning curve with Netsuite development.

In his latest, Scripting tip-35:When deleting a record gives you “Owner of Child Record” – Knowledge Share Care, Joe talks about how an error message “Owner of child record …” was generated while trying to delete a (sales) Lead record. Apparently the Lead owns the contact records associated with the lead and when you attempt to delete the Lead, you cannot simply detach the contact records from the lead, you have to Mass Update the ownership of those Contact Records so that they do not point back to the Lead record.

Feb 192013
 

function changePassword(){

//Gather Employee Information from Case
var empId = nlapiGetFieldValue(‘company’);
var empName = nlapiGetFieldText(‘company’);
var itUser = nlapiGetUser();

//Set Case Field Values
nlapiSetFieldValue(‘assigned’,itUser);
nlapiSetFieldValue(‘status’,8);
nlapiSetFieldValue(‘insertsolution’,14);

//Reset User password
empPass(empId);

//Compile Outgoing Email
var itUserName = nlapiGetFieldText(‘assigned’);
var outgoingmessage = empName + ‘,

Your password has been reset to 1234user.’ + ‘

Thanks,
’ + itUserName;

//Set Compiled Email to Send to Employee
nlapiSetFieldValue(‘outgoingmessage’,outgoingmessage);

}

function empPass(empId){

//Load Employee Record and set New Passwords
var recEmp = nlapiLoadRecord(‘employee’,empId,null);
var password = ’1234user’;
var password2 = ’1234user’;

//Change Old Passwords to New Passwords
recEmp.setFieldValue(‘password’,password);
recEmp.setFieldValue(‘password2′,password2);
var empId = nlapiSubmitRecord(recEmp);

return empId;
}

via Automation: Making User Management Easy – Spearheadchange.com.

Sep 132012
 

Summary problem: For some reason the Default Printer I was using (CutePDF) prevented me from opening a Visio 2010 Database Model Diagram.

Summary solution: Change the default printer to Microsoft XPS Document.

Story:

I’m working on documenting my additions to my employer’s CRM solution (Netsuite). The additions are designed to support a more streamlined systems information management system. (i.e., dial up information, windows server information, network device information, and credentials information.) For the last few years we’ve used the CRM solution with 50 or so custom fields that appear on each customer record, spread across 8 or so tabs. This is sufficient for 80-90% of our customers, but if we need to extend the data we need to track it isn’t very flexible.

The system I’m setting up will allow us to track multiple vendor equipment, multiple devices, and scales “infinitely.” Need to record a new credential? Create a new credential record and associate it with the customer. (and so forth…)

Here’s a diagram I did in Visio:

The problem I ran into was after creating the document, I couldn’t open it. Whenever I tried, Visio would hang: “Not Responding.”

I searched off and on this week for a solution and finally came across: Visio 2010 not responding when opening Database Model Diagrams – Microsoft Answers. After reading this, I tried changing the default printer to the Microsoft XPS Document as suggested and the Visio DMD document was accessible.