Search This Blog

17 July 2011

Redefining (mapping) Dynamics Ax EventLogs

Ever tried to monitor Dynamics Ax events with a monitoring tool that does only work with EventIds? Dynamics Ax does unfortunately writes nearly all relevant events with the eventId 110 (here a complete list). It is possible to create your own events, but it isn't possible to change the standard events.
For that reason I scripted a small tool that collects the events that are defined in a list (by EventId, EventType and a fragment of the EventMessage) from a list of servers (SourceServers)  and writes them locally based on mapping rules defined in the Xml-configuration file. so that it is now possible to create fine grained eventLogs. The scripts creates for each SourceServers a cookie to store the creation-DateTime of the last message, so that the script just reads out all newly created messages. Here's an example for an configuration

    
        
              
        
     
      
     
    

The XmlElement SourceServers does define the list of servers with its logName (for standard Ax EventLogs it is "Application"). The XmlElement Events does define the mapping-rules with:
  • EventId (id)
  • The part of the message (no wildcard character)
  • EventType (Information, Warning, Error)


  • The local eventSource (defined with the attribute destinationEventSource on the XmlElement Events) is automatically created if it does not already exist. The eventSource needs to be unique on the machine (1), so you can only define it once and not use it with another eventLog. You need to run the script with the EventPackage-name as argument (see documentation in the script) as with Administrator rights for the UAC. Please be aware that the local path is actually security reasons hardcoded for:
    $scriptPath = "C:\Scripts\MapEventIds\";
    
    This script is just an example. Feel free to customize it for your needs.

    Update: (23/07/11) Refactored the code so that it is now using the pipeline instead of referenced arguments. Please use the FQN instead of the IP to avoid issues with the machine name resolution. (hope that the cache on the WebServer refreshes the next hours...)

    Dynamics Ax EventIds

    The only information Google finds about Dynamics Ax EventIds from Microsot is in Italian and very old (2005). Translationg it with BabelFish gives at least the chance to understand it (for a non Italian-speaking person). Would be great if Microsoft could at least publish this document in English, which shouldn't be a big deal, since this is the same text as in the original message definition file and publish it for Ax 2009 and 2012, too.

    16 July 2011

    AOS service does not stop and stays pending (what happens when the AOS stops)

    In my article about stopping AOS services via PowerShell, I implemented a timeout for stopping the AOS gracefully before killing that service. In that script I set the timeout to 60 sec, which should be more then enough under normal circumstances. If this timeout needs to be different for you, just change that. But at the end, you need to be sure that the AOS service is stopped, and if it isn't, the service needs to be stopped by killing the process.

    Why can an AOS stuck in a pending state? 
    First an explanation what the AOS does when it is stopped: The AOS is managed by the service control manager (MSDN/Wiki) (SCM). This SCM does send the messages STOP, PAUSE, CONTINUE and SHUTDOWN to the AOS, which does react on these messages. In my script, I'm using the .Net class ServiceController to work with the SCM in a very comfortable way because the .Net class wraps the Win32 API (PInvoke) and guarantees you a safe way to work with windows services. By calling the Stop method, the script just sends a STOP message via SCM to the AOS and, if the main-thread of the AOS service does have time to handle that message, it will set the first set the service in a pending state and then trigger the Shutdown. The shutdown of an AOS does first interrupt all user sessions (you might find this message in the event-log: "Object Server 01: RPC error: Client provided an invalid session ID 9") , then terminates the server session ("Object Server 01: Server main session is being destroyed.") and once all these sessions are closed, it will then remove the RPC interface from the RPC run-time library registry and then stop listening to the RPC calls. Only then the SCM sets the status of the AOS to stopped. (This article on MSDN shows in a very simple example what the AOS does for disposing the RPC, too).
    So there shouldn't be any problem when stopping the AOS, but unfortunately the AOS does sometimes not succeed to stop the service gracefully and this happens only from time to time when the AOS is under stress and it is therefore difficult to reproduce. But because the shutdown waits until the ServerSession is terminated, it is enough to freeze the thread of the AOS session with a sleep.
    public server static void FreezeAOSSessionThread()
    {
        ;
        sleep(60000);
    }
    
    Calling the sleep on the client wouldn't work, because the client-sessions are killed. In no case, the client can prevent the AOS to stop and hold him in a pending state (In all cases I could track back, the situation on the AOS was similar: The AOS-session could not be terminated). If you are looking for the cause, take a dump with ADPlus from the AOS and check the X++ call stack. Once again, thank you Tariq... Attach AdPlus to the process and kill the process with the task-manager. The dump will then automatically taken.
    Killing the AOS might terminate open connections to the SQL-Server as well. But because CUD (create, update and delete) operations are done within transactions, killing the AOS-service shouldn't break the database integrety - if no custom code breaks this best-practice. Just keep in mind that you will loose all data of non-committed transactions.

    14 July 2011

    My first AIF project is finally flying :-)

    Finishing a project is always the most thrilling moment in a project. Seeing finally the application been used by customers and colleagues is just magic and the major reason for me to work in the IT...
    7 months of hard work and the new EDI platform for the purchase and sales process is finally flying. The publicly visible part of the eCommerce is the WebShop which is a custom .Net Web-application that is communicating via BizTalk with the AIF framework. Because of the quite disappointing standard AIF-services, I decided to create a complete new EDI-platform on top of AIF. The platform is now online for the German subsidiary of Camfil, but it will be soon rolled out in most other European countries. I hope I will find the time to blog about some of the strategic key elements of that architecture in the next weeks (why not using the Enterprise Portal or the standard AIF services, how to prevent performance bottle necks, testing AIF services and integrating EDI smoothly into standard processes)
    A big thank you, Mathias, Alex, Sebastian, Markus, Peter and Bettina, for all your great work :-)

    13 July 2011

    Windows PowerShell Cookbook

    Because I already blogged about PowerShell-scripts for administration tasks, here a link to great online-book from Lee Holmes about everything you need to know about programming PowerShell and much, much more. You can order it on Amazon, too.

    12 July 2011

    Windows EventLogs with X++

    Here's a very small and simple class that makes it very easy to use the Windows EventLogs with X++. It creates, if necessary, a new log/source and logs the events there:
    Just derive from the abstract base-class "WinEventLogsBase" (as it is done in WinEventLogs_Batches) and overwrite the log/source and messageId, so that your events are unique.


    The job TestEventLogs is an example how to write EventLogs:
    static void TestEventLogs(Args _args)
    {
        WinEventLogsBase logs;
        System.Diagnostics.EventLogEntryType type = System.Diagnostics.EventLogEntryType::Error;
        System.Int32 eventId = 110;
    ;
        //Works well, but in the EventLog for Workflow events
        SysWorkflowHelper::writeEventLogEntry("Test simple error from Workflow.");
    
        //uses the EventSource for the Dynamics Server with the instance suffix to write a message
        System.Diagnostics.EventLog::WriteEntry("Dynamics Server 01", "Test simple error with WriteEntry.");
        //will result in:
        //The description for Event ID ( 0 ) in Source ( Dynamics Server 01 ) cannot be found.
        //because this source is linked to the ressource:
        //C:\Program Files\Microsoft Dynamics AX\50\Server\DynamicsAx1\Bin\Ax32Serv.exe
        //in HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Eventlog\Application\Dynamics Server 01
        //which doesn't know how to handle that EventId
    
        //now by selecting the Dynamics Ax standard EventId 110:
        System.Diagnostics.EventLog::WriteEntry("Dynamics Server 01", "Test simple error with WriteEntry.", type, eventId);
        //Works pretty fine, but: always the same EventSource and EventId, which is not possible to track for many
        //monitoring tools like for example Heroix Longitude which do only interpret the EventId.
    
        //now that little tool:
        logs = new WinEventLogs_Batches(); //specialization for logs
    
        //WinEventLogs_Batches uses an EventSource and EventLog on its own
        logs.writeError("Test simple error");  //uses a default EventId
        logs.writeInfo("Test simple info", 4711); //uses an explicit EventId
        logs.writeWarning("Test simple warning");
    
        logs = new WinEventLogs_Test(); //specialization that uses the Eventlog "Application" for the source
    
        //WinEventLogs_Test uses its own EventSource but "Application" as EventLog
        logs.writeError("Test simple error");
        logs.writeInfo("Test simple info", 4712);
        logs.writeWarning("Test simple warning");
        //because this tool links the registered EventSource to:
        //c:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\EventLogMessages.dll
        //it is now possible to use any custom EventId which is not predifined in the resource like in the
        //first example.
    }
    

    10 July 2011

    Authenticating a user with user-name and password against Windows with X++

    The AccountManagement Namespace was introduced with .Net 3.5 and provides some very useful classes which are, by referencing this assembly, available with X++, as well. At least if you've installed .Net 3.5.

    Here's an example how to authenticate a username and password against Windows with the PrincipalContext class and the ValidateCredentials-method.
    boolean isAuthenticated = false;
    System.DirectoryServices.AccountManagement.PrincipalContext principalContext;
    ;
    
    principalContext = new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType::Domain, "contoso.com");
    isAuthenticated = principalContext.ValidateCredentials("username", "password");
    principalContext.Dispose();
    
    if (isAuthenticated)
    {
        //do something
    }
    else
    {
        //do something
    }
    

    Update: (15/07/11) And bcause of the Google search keywords: The username and password for the contoso.com VPC are Administrator and Passw0rd (or pass@word1 depends on the vpc) ... ;-)

    09 July 2011

    Authentication of the different components in Ax 2009

    One of the most annoying subjects in Ax2009 is installing and configuring the huge number of components which do need to authenticate each other. There are Reporting Services, Analysis Services, SharePoint Services (or MOSS) on IIS, AIF MSMQ, AIF WebServices, AIF BTS, the Ax AOS,  Internet Explorer, SMB for the application file-share and the Ax client (some do have BC.Net applications as well). If they are all installed on one box, this is quite easy to maintain. But a distributed installation (especially on a large scale) is extremely complicated and requires a profound understanding of Kerberos authentication.  Because I recently had to find an issue on my erroneous installation, here's a nice schema of my current Ax 2009 configuration which might help you as well:


    06 July 2011

    PowerShell script to restart Windows (AOS) services remotely


    Just a small script to restart a list of Windows-services (download here). It checks that they are stopped and kills them if they cannot be stopped and then starts them. If there are any errors, an email is sent and the user is informed about the progress in the tray-bar. All this is configurable in an Xml-file. It's a small script and should only be used as an example of how the PowerShell can be useful for the daily business (please understand that I don't publish the final version):

    • stopping and starting services remotely
    • killing a process remotely
    • getting ProcessId from service-name
    • sending a mail
    • executing WMI queries on remote machines
    • pinging machines
    • Info-bubble in the tray bar
    • creating and writing into EventLogs
    • handling exceptions
    • working with Xml-files
    • passing parameter to a function
    • working with ref-variables

    Update: (09/07/11) Updated script with some fixes and changes in the behavior.
    Update: (10/07/11)  As this was my first experience with PowerShell scripting, I rewrote the script with all what I learned during these days. The script does now restart remotely in a controlled way the services and tracks all info about the executed activities and anomalies during this process.
    Update: (23/07/11)  Still novice with PowerShell... :-( Refactored the code so that it is now using the pipeline instead of referenced arguments.