One of the cool feature of OpsMgr 2007 is that you can test a script outside the OpsMgr environment, simply running it from a command line by using CScript.exe (http://msdn.microsoft.com/en-us/library/bb437526.aspx). I use this feature often to debug my scripts while creating Management pack or for troubleshoot problems with Management pack not written by me. Sometimes this does not work and even if the script completes successfully no output is returned in console. So I started to investigate to understand the cause of the problem.
The first step was to identify which method or function is responsible for print out the the console output. I debugged a working script with Microsoft Script Debugger and I was able to identify that the console output is written by the MOMScriptAPI.Return method.
The second step was to debug that method to understand why in some case it doesn’t produce any output. With WinDbg I found that this method prepare the xml output that the script should write the the console and it put it in a variable as we can see below :
0:004> g
MOMScriptAPI+0x45bb:
574145bb 51 push ecx this is the pointer to the address of the string that will be filled with the xml document (ecx = 0013ed68)
0:000> t
MOMScriptAPI+0x45bc:
574145bc 57 push edi
0:000> p
MOMScriptAPI+0x45bd:
574145bd ff9088000000 call dword ptr <Unloaded_elp.dll>+0×87 (00000088)[eax] ds:0023:5880a468={msxml6!DOMNode::get_xml (58865897)}
after the execution of the call to msxml6!DOMNode::get_xml we can dump the address of the string :
0:000> dc 0013ed68 (value of ecx at the time of ‘push ecx’ instruction)
0013ed68 001a6ffc 019a67f8 96cf5fb5 0013ed48
and then we can dump the content of the string :
0:000> du 001a6ffc L 260
001a6ffc <DataItem type=’System.DiscoveryData’ time=’2010-03-28T19:44:19.
001a707c 9712688+02:00′ sourceHealthServiceId=’EF2F97F2-72D7-D872-D2B5-C7
001a70fc 770F50B95F’><DiscoveryType>0</DiscoveryType><DiscoverySourceType
001a717c >0</DiscoverySourceType><DiscoverySourceObjectId>{50BDB348-03CB-
001a71fc 418B-8F7B-5873DDF83C64}</DiscoverySourceObjectId><DiscoverySourc
001a727c eManagedEntity>{F6DEC1E0-6526-47C9-A36C-673EF934184F}</Discovery
001a72fc SourceManagedEntity><ClassInstances><ClassInstance TypeId=’{7655
001a737c ba11-dd69-45a0-8b04-8e6a2ed6f5df><Settings><Setting><Name>{678
001a73fc f1531-9cf2-4b10-b20b-a09e99797ce7}</Name><Value>srvname.domain</
To write the string to the console, an handle to the stdout is retrieved using the API GetStdHandle with STD_OUTPUT_HANDLE (DWORD –11 = 0FFFFFFF5h) as parameter :
0:004> g
MOMScriptAPI+0x4a35:
57414a35 6af5 push 0FFFFFFF5h ( = STD_OUTPUT_HANDLE)])
0:000> t
MOMScriptAPI+0x4a37:
57414a37 ff15a8114157 call dword ptr [MOMScriptAPI+0x11a8 (574111a8)] ds:0023:574111a8={kernel32!GetStdHandle (77e6b437)}
and then that handle retrieved is passed to the function WriteFile
0:000> kv
ChildEBP RetAddr Args to Child
0013ed9c 57414a44 00000007 01eb0048 0000d0b9 kernel32!WriteFile (FPO: [SEH])
where 00000007 is the handle retrieved by GetStdHandle, 01eb0048 is the address to the buffer to be written :
0:000> dc 01eb0048 l34
01eb0048 7461443c 65744961 7974206d 223d6570 <DataItem type=’
01eb0058 74737953 442e6d65 6f637369 79726576 System.Discovery
01eb0068 61746144 69742022 223d656d 30313032 Data’ time=’2010
01eb0078 2d33302d 31543832 34343a39 2e39313a -03-28T19:44:19.
01eb0088 32313739 2b383836 303a3230 73202230 9712688+02:00′ s
01eb0098 6372756f 61654865 5368746c 69767265 ourceHealthServi
01eb00a8 64496563 4645223d 37394632 372d3246 ceId=’EF2F97F2-7
01eb00b8 2d374432 32373844 4232442d 37432d35 2D7-D872-D2B5-C7
01eb00c8 46303737 39423035 3e224635 7369443c 770F50B95F’><Dis
01eb00d8 65766f63 79547972 303e6570 69442f3c coveryType>0</Di
01eb00e8 766f6373 54797265 3e657079 7369443c scoveryType><Dis
01eb00f8 65766f63 6f537972 65637275 65707954 coverySourceType
01eb0108 2f3c303e 63736944 7265766f 756f5379 >0</DiscoverySou
and 0000d0b9 (= 53433) is the size of the buffer to be written.
internally the function WriteFile calls WriteConsole :
0:000> kv
ChildEBP RetAddr Args to Child
0013ed4c 77e720eb 00000007 01eb0048 0000d0b9 kernel32!WriteConsoleA (FPO: [5,0,0])
0013ed9c 57414a44 00000007 01eb0048 0000d0b9 kernel32!WriteFile+0×64 (FPO: [SEH])
the function WriteConsole fails with error code 8 :
MOMScriptAPI!DllGetClassObject+0x2ebd:
5741963c ff1544114157 call dword ptr [MOMScriptAPI+0x1144 (57411144)] ds:0023:57411144={ntdll!RtlGetLastWin32Error (7c829e08)}
0:000> r eax
eax=00000008
0:000> !error eax
Error code: (Win32) 0×8 (8) – Not enough storage is available to process this command. (ERROR_NOT_ENOUGH_MEMORY)
This is confirmed by the OpsMgr trace log (TracingGuidsNative.log) :
[ModulesScript] [] [Error] [] [WriteScriptOutput] [MOMScriptAPI_cpp240]Unable to write output, WriteFile returned 8(ERROR_NOT_ENOUGH_MEMORY)
According to MSDN WriteConsole could fail with the error ERROR_NOT_ENOUGH_MEMORY if the parameter nNumberOfCharsToWrite exceeds 64 KB. in my case this is not true, I found that a value of 0000d0b9 (= 52.18 K) is too much and a value of 0000cf9a is OK. The error is set inside the function WriteConsoleInternal after a call to CsrAllocateCaptureBuffer.
0013ec4c 77e4448f 00000008 00000007 00000000 kernel32!SetLastError (FPO: [1,0,0])
0013ed20 77e7210d 00000007 01eb0048 0000d0b9 kernel32!WriteConsoleInternal+0×113 (FPO: [SEH])
0013ed3c 77e720eb 00000007 01eb0048 0000d0b9 kernel32!WriteConsoleA+0×18 (FPO: [5,0,0])
0013ed8c 57414a44 00000007 01eb0048 0000d0b9 kernel32!WriteFile+0×64 (FPO: [SEH])
So the problem seems to be related with the size of the output to be written, I’m not sure that this limit is identical in every machine because I tested it only on a Windows Server 2003 SP2 x86. The limit should be 64K (according to MSDN) but in my test the limit seems near 52K, but for the moment I didn’t investigate more.
One possible solution to this problem could be to write a wrapper that call cscript and redirect stdout to a file. If stdout is redirected, WriteFile shoud write to the handle opened by the calling process and not to the console using WriteConsole. I will try this and I will write the result in a future post.
– Fabrizio
This posting is provided “AS IS” with no warranties, and confers no rights.
#1 by joel hendrickson on May 1, 2010 - 6:20 am
I’ve been told that snapshot discoveries are limited to 64K — i wonder if this is the reason
#2 by Fabrizio Guaitolini on May 16, 2010 - 8:14 pm
Hi joel, while I was testing and debugging this issue I’m quite sure that a discovery with an output of more than 64k was accepted and handled by OpsMgr (at least R2, I didn’t try older versions). I will check it out and I will post an article on this in case it is confirmed what you have been told.
#3 by Jonathan Almquist on March 29, 2010 - 10:51 pm
Thanks for writing this up. I always enjoy your posts. Can I call you the “mad scientist”?