« 10 Rental Car Tips | Main | LoadRunner - Date Handling (2 of 3) - C Date/Time Functions »
Sunday
Aug262012

LoadRunner - Date Handling (3 of 3) - Powershell

If you are using LoadRunner, you've probably encountered date and time values in your scripts. These values should be evaluated and dealt with.

 Recap of Part 1 and 2

  • Part 1 : lr_save_datetime. Works well for dates relative to the current date.
  • Part 2 : C date/time functions. User must handle format codes and locale.

Let's solve the problem using Powershell.

 Initial Thoughts

  • lr_save_datetime and C date/time functions can handle all situations.
  • Looking for an easier, more robust solution.
  • LoadRunner does not natively support Powershell.
  • How can I call any Powershell command, not just date/time commands?

Below are 3 different ways to call Powershell commands within LoadRunner.

 Support Code

  • Used by all 3 implementations.
  • Save Powershell output to a unique file (per virtual user).
  • Retrieve Powershell output from the file and save in a LoadRunner parameter.
Generate Unique File Name
int iVuserId;
char strFile[100];

lr_whoami (&iVuserId, NULL, NULL);
if (iVuserId <= 0) { iVuserId = 1; }
sprintf (strFile, "d:\\dt-%03d.txt", iVuserId);
Save Powershell Output To A LoadRunner Parameter
int GetParamValue (char *strFile, char *strParam)
{
    long fs;
    char strLine[128];

    // -------------------------------------------------------------------------
    // Read the updated file that contains the new date.
    // Create a new LoadRunner parameter.
    // -------------------------------------------------------------------------

    fs = fopen (strFile, "r");
    fgets (strLine, 128, fs);
    fclose (fs);

    strLine[strlen(strLine)-1] = 0;
    lr_save_string (strLine, strParam);

    return 0;
}

 Using system

  • Executes an operating system command.
  • Directly available in LoadRunner.
  • Displays a command window while the command is executing.
GetNewDate_system
int GetNewDate_system (char *strDate, char *strFormat, char *strFile,
                       char *strChange, int iChangeAmount, char *strParam)
{
    char strCommand[256];
    sprintf (strCommand, 
             "powershell \"$a=get-date '%s'; $a=$a.%s(%ld); $a=get-date $a -format '%s'; "
             "$a|out-file -encoding ascii -filepath %s;\"", 
             strDate, 
             strChange,
             iChangeAmount, 
             strFormat, 
             strFile);

    system (strCommand);
    GetParamValue (strFile, strParam);
    return 0;
}

 Using ShellExecuteA

  • Opens, prints or executes a file using the Windows shell.
  • Returns immediately after performing specified action.
  • Sleep of 1 second is used to allow processing to complete.
GetNewDate_shellexecute
int GetNewDate_shellexecute (char *strDate, char *strFormat, char *strFile,
                             char *strChange, int iChangeAmount, char *strParam)
{
    char strCommand[256];
    sprintf (strCommand, 
             "$a=get-date '%s'; $a=$a.%s(%ld); $a=get-date $a -format '%s'; "
             "$a|out-file -encoding ascii -filepath %s;", 
             strDate, 
             strChange,
             iChangeAmount, 
             strFormat, 
             strFile);

    ShellExecuteA(NULL, "open", "powershell.exe", strCommand, "", "", 0);
    sleep(1000);  // Is enough of a delay for the command to complete - not dependable
    GetParamValue (strFile, strParam);
    return 0;
}

 Using CreateProcessA

  • Creates a new process and its primary thread.
  • The new process runs in the security context of the calling process.
GetNewDate_createprocess
typedef void *PVOID;
typedef PVOID HANDLE;
typedef struct _PROCESS_INFORMATION
{
	HANDLE hProcess;
	HANDLE hThread;
	DWORD dwProcessId;
	DWORD dwThreadId;
} PROCESS_INFORMATION;
	
typedef const char *LPTSTR;
typedef unsigned char far *LPBYTE;
	
typedef struct _STARTUPINFO {
  DWORD  cb;
  LPTSTR lpReserved;
  LPTSTR lpDesktop;
  LPTSTR lpTitle;
  DWORD  dwX;
  DWORD  dwY;
  DWORD  dwXSize;
  DWORD  dwYSize;
  DWORD  dwXCountChars;
  DWORD  dwYCountChars;
  DWORD  dwFillAttribute;
  DWORD  dwFlags;
  WORD   wShowWindow;
  WORD   cbReserved2;
  LPBYTE lpReserved2;
  HANDLE hStdInput;
  HANDLE hStdOutput;
  HANDLE hStdError;
} STARTUPINFO, *LPSTARTUPINFO;

PROCESS_INFORMATION pi = {0};
STARTUPINFO si = {0};

int GetNewDate_createprocess (char *strDate, char *strFormat, char *strFile,
                              char *strChange, int iChangeAmount, char *strParam)
{
    char strCommand[256];
    sprintf (strCommand, 
             "powershell \"$a=get-date '%s'; $a=$a.%s(%ld); $a=get-date $a -format '%s'; "
             "$a|out-file -encoding ascii -filepath %s;\"", 
             strDate, 
             strChange,
             iChangeAmount, 
             strFormat, 
             strFile);

    si.cb = sizeof(si);
    CreateProcessA (NULL, strCommand, NULL, NULL, FALSE, 0x08000000, NULL, NULL, &si, &pi);
    WaitForSingleObject (pi.hProcess, 10000);
    CloseHandle (pi.hProcess);
    CloseHandle (pi.hThread);
    GetParamValue (strFile, strParam);
    return 0;
}

 Calling Code

Calling Code
int iVuserId;
char strFile[100];
char *strDate   = "17-Aug-2012 06:49:41";
char *strFormat = "dd-MMM-yyyy HH:mm:ss";

lr_load_dll("shell32.dll");     // ShellExecuteA
lr_load_dll("kernel32.dll");    // CreateProcessA

// -------------------------------------------------------------------------
// Generate a unique file name for each vuser.  Used for output of the 
// powershell command.
// -------------------------------------------------------------------------

lr_whoami (&iVuserId, NULL, NULL);
if (iVuserId <= 0) { iVuserId = 1; }
sprintf (strFile, "d:\\dt-%03d.txt", iVuserId);

// -------------------------------------------------------------------------
// LoadRunner system command examples.
// -------------------------------------------------------------------------

GetNewDate_system (strDate, strFormat, strFile, "AddYears",   70, "pNewDate");
GetNewDate_system (strDate, strFormat, strFile, "AddMonths",  70, "pNewDate");
GetNewDate_system (strDate, strFormat, strFile, "AddDays",    70, "pNewDate");
GetNewDate_system (strDate, strFormat, strFile, "AddHours",   70, "pNewDate");
GetNewDate_system (strDate, strFormat, strFile, "AddMinutes", 70, "pNewDate");
GetNewDate_system (strDate, strFormat, strFile, "AddSeconds", 70, "pNewDate");

// -------------------------------------------------------------------------
// ShellExecute command examples.
// -------------------------------------------------------------------------

GetNewDate_shellexecute (strDate, strFormat, strFile, "AddYears",   70, "pNewDate");
GetNewDate_shellexecute (strDate, strFormat, strFile, "AddMonths",  70, "pNewDate");
GetNewDate_shellexecute (strDate, strFormat, strFile, "AddDays",    70, "pNewDate");
GetNewDate_shellexecute (strDate, strFormat, strFile, "AddHours",   70, "pNewDate");
GetNewDate_shellexecute (strDate, strFormat, strFile, "AddMinutes", 70, "pNewDate");
GetNewDate_shellexecute (strDate, strFormat, strFile, "AddSeconds", 70, "pNewDate");

// -------------------------------------------------------------------------
// CreateProcess command examples.
// -------------------------------------------------------------------------

GetNewDate_createprocess (strDate, strFormat, strFile, "AddYears",   70, "pNewDate");
GetNewDate_createprocess (strDate, strFormat, strFile, "AddMonths",  70, "pNewDate");
GetNewDate_createprocess (strDate, strFormat, strFile, "AddDays",    70, "pNewDate");
GetNewDate_createprocess (strDate, strFormat, strFile, "AddHours",   70, "pNewDate");
GetNewDate_createprocess (strDate, strFormat, strFile, "AddMinutes", 70, "pNewDate");
GetNewDate_createprocess (strDate, strFormat, strFile, "AddSeconds", 70, "pNewDate");

 Moving Forward

  • Add error checking.
  • Experiment with other Powershell commands using these techniques.
  • Instead of writing output to a file, output to SQUID.
  • Create a C/C# dll to handle date/time manipulations, call from within LoadRunner.

References (1)

References allow you to track sources for this article, as well as articles that were written in response to this article.
  • Response
    Response: Expanded Reading
    I would like to thank you for the efforts you have put in writing this website. I'm hoping the same high-grade website post from you in the upcoming as well. In fact your creative writing skills has encouraged me to get my own website now. Really the blogging is spreading its ...

Reader Comments (1)

Excellent stuff. Just what I needed. You rock!

September 1, 2012 | Unregistered CommenterCBA

PostPost a New Comment

Enter your information below to add a new comment.

My response is on my own website »
Author Email (optional):
Author URL (optional):
Post:
 
Some HTML allowed: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <code> <em> <i> <strike> <strong>