Executing an OpsMgr 2007 script manually may result in an empty console output (part 2)


As promised in my previous post, I tried to find a way to retrieve the complete output of an OpsMgr script, when launched with cscript out of Operations Manager. As I said before, the limitation seems related to the WriteConsole function, and a redirected stdout should not suffer this problem. To confirm this hypothesis I needed a way to redirect stdout of the script to something different from the Console. My first Idea was to write a C++ wrapper as in the sample “Creating a Child Process with Redirected Input and Output”, but then I realize that there is a simpler and easier way to do this, without the need of a compiler. WshShell Object contains an Exec method that provides access to stdin, stdout and stderr stream, so I wrote a WSH utility that reads stdout of the original script in small pieces, and then writes those small pieces to console. Since the utility writes the output in buffers of small size, the limitation present in the function WriteConsole should not affect the result.

The script (OpsMgrScriptUtility.vbs) is very simply :

Option Explicit

Dim WshShell, oExec, i, szCmdLine , szOut
Set WshShell = CreateObject(“WScript.Shell”)

if Wscript.Arguments.count < 1 Then
    Wscript.echo “No script specified”
    Wscript.quit(87)
end if

szCmdLine = “cscript.exe //Nologo “

For i = 0 to Wscript.Arguments.count -1
    szCmdLine = szCmdLine & “””” & Wscript.Arguments(i) & “”” “
next

Set oExec  = WshShell.Exec(szCmdLine )

With oExec
    Do While .Status = 0
        WScript.Sleep 10
        Do While Not .StdOut.AtEndOfStream
            szOut = “”
            szOut = .StdOut.Read(400) 
           If trim(szOut) <> “” then
                WScript.StdOut.Write szOut
            End if
        Loop

        If Not .StdErr.AtEndOfStream Then
            szOut = “”
            szOut =  .StdErr.ReadLine
            if trim(szOut) <> “” then
                WScript.StdErr.Write szOut
            End if
        End if

   Loop
End With

Set oExec = Nothing
Set WshShell = Nothing

The utility takes as the first argument the name of the OpsMgr script to launch, and as subsequent arguments the script arguments. For example if the original call to a script is similar to the following :

cscript.exe “c:\temp\SampleDiscvovery.vbs” “{26bcefc2-ecbf-4c62-bd5a-54f70ec778fb}” “{e0da1815-6673-429c-af86-84049e0a7062}” “host.domain.local”

the call at the same script using the utility should be similar to the following :

cscript.exe OpsMgrScriptUtility.vbs “c:\temp\SampleDiscvovery.vbs” “{26bcefc2-ecbf-4c62-bd5a-54f70ec778fb}” “{e0da1815-6673-429c-af86-84049e0a7062}” “host.domain.local”

it is possible to redirect the output to a file :

cscript.exe OpsMgrScriptUtility.vbs “c:\temp\SampleDiscvovery.vbs” “{26bcefc2-ecbf-4c62-bd5a-54f70ec778fb}” “{e0da1815-6673-429c-af86-84049e0a7062}” “host.domain.local” //Nologo > c:\temp.xml

I uploaded a zip HERE containing the utility and 2 scripts useful to simulate the problem (file should have a “.zip” extension, I added the “.doc” extension only to do the upload since zip files are not allowed). The script Progel.Discovery.Test.Class1.Discovery.vbs called without arguments, on a machine with OpsMgr Agent installed, should print the discovery xml stream on the console. The script Progel.Discovery.Test.Class1.Discovery.NoOutput.vbs called without arguments, on a machine with OpsMgr Agent installed, should not print the discovery xml stream on the console, because the output exceed 64k. The difference between those 2 scripts is that the first discovers only 100 instances and the second discovers 1000 instances. Using the utility OpsMgrScriptUtility.vbs it is possible to retrieve the xml output even in the second script.

– Fabrizio (the mad scientist) :)

This posting is provided “AS IS” with no warranties, and confers no rights.

About these ads

  1. #1 by Ashutosh on June 7, 2010 - 4:21 am

    HI,

    I want to run follwoung command in SCOM Coommand shell. I have paste this command in notepad and saved as ps1 file. I want to schedule this script to run on event night.. how can i do this.
    =============================================================================
    $agts=get-agent | where {$_.PrimaryManagementServerName -eq “MS FQDN”}
    foreach ($a in $agts){
    get-failovermanagementserver -AgentManagedComputer $a | ft $a.ComputerName,Name | out-file ‘c:\temp\MS FQDN.csv’ -append
    }
    =============================================================================
    Ashutosh

    • #2 by Fabrizio Guaitolini on June 18, 2010 - 9:54 am

      Hi Ashutosh,

      you could create an OS scheduledtask that executes the ps1 script.

      To do this you should create a scheduledtask with a command line similar to the following :
      powershell -Command “&{.\scriptname.ps1}”
      where scriptname should be substituted with your ps1 script name.

      Since in the previous command line a relative path is used, you should set the “Start in” parameter of the scheduledtask to the folder conaining the ps1 script.

      To access to Operations Manager Cmdlets, functions, default connection and startup banner you should add the following lines at the beginning of your ps1 script (note that this initialization is based on the assumption that OpsMgr is installed in the default localtion, if a different path is used you should change the $CommandShellPath to the correct path) :

      $CommandShellPath=$env:Programfiles + ‘\system center operations manager 2007′
      Add-PSSnapin “Microsoft.EnterpriseManagement.OperationsManager.Client”;
      cd “$CommandShellPath”
      .\Microsoft.EnterpriseManagement.OperationsManager.ClientShell.Startup.ps1

      The final script should be similar to the following :

      =============================================================================
      $CommandShellPath=$env:Programfiles + ‘\system center operations manager 2007′
      Add-PSSnapin “Microsoft.EnterpriseManagement.OperationsManager.Client”;
      cd “$CommandShellPath”
      .\Microsoft.EnterpriseManagement.OperationsManager.ClientShell.Startup.ps1

      $agts=get-agent | where {$_.PrimaryManagementServerName -eq “MS FQDN”}
      foreach ($a in $agts){
      get-failovermanagementserver -AgentManagedComputer $a | ft $a.ComputerName,Name | out-file ‘c:\temp\MS FQDN.csv’ -append
      }
      =============================================================================

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

Follow

Get every new post delivered to your Inbox.

Join 348 other followers

%d bloggers like this: