Classic ASP with Oracle database 12c 64Bit

July 11, 2018

Hi guys

Yesterday I was contacted by one of the visitors after referring my posts about Classic ASP connection to Oracle databases in general & I revisited this “area” after a long time. It took a while for me to setup everything, however the results were pretty awesome. So here comes one more post about Classic ASP with Oracle database, this time Oracle 12c 64Bit.

OS: Windows 10/64Bit Windows Server OS

Prerequisites

  • Setup IIS for publish classic ASP with Oracle 12c database

Software requirement(s):

  • Oracle client 32Bit, 12c (for best connectivity)

Launch IIS and create a new application pool, as shown with the image.

clip_image002

Now go to the advanced settings for the application pool that you have created & switch “Enable 32-Bit Applications” from “false” to “True”

clip_image004

Connection possibilities

There are two ways to connect to Oracle database from Classic ASP

  1. Using DSN (Data Source Name)
  2. DSN less connections. Here we will use the Oracle tnsnames.ora file to identify and connect to the database. We have to insure that the TNS_HOME directory is set at the environment level, or the client that is used is 1st entry in the environment variable “PATH” for Oracle products in case of multi Oracle homed hosts.

Create a DSN

Classic ASP could interact with only 32Bit environment, hence the IIS server hosting machine must have the latest Oracle 32-Bit client installed (older clients may not connect to later databases properly). As I am writing this post, Oracle 12c 12.2.0 is the latest client available.

Logged with an account having “Administrator” privileges, Open ODBC Data Source (32-bit)

clip_image005

Please note, my box has multiple Oracle products, hence don’t get confused by the names in next few screens.

clip_image007

If your installation for the Oracle client was correct, you should able to see an entry for the Oracle driver like the one you could see the image above.

Click “Finish”. This will pop up another window. Under the “System DSN” tab we have to create our new DSN

clip_image008

Provide a name of your choice for the “Data Source Name” and “Description”

Make sure you have the “TNS Service Name” already available with the listener.ora file. Oracle 12c passwords are case sensitive. Hence make sure you are going to provide the case sensitive password while testing the connection.

If you don’t have previous experiences with creating net service names, please follow the instructions below.

clip_image009

Start “Net Configuration Assistant” from the Oracle Home and follow the images below.

clip_image010

Read the help texts available, especially if you are new to Oracle

clip_image011

Provide the service name, which is your database name usually.

clip_image012

 

clip_image013

Provide the FQDN (fully qualified domain name), ie, your computer name like “rajesh-pc.abc.com” in case if you are connected to a domain, else just the name of your computer, like “rajesh-pc”

clip_image014

I would suggest doing a test, if you are sure that all the details provided are correct & no need to test, you can skip this step

clip_image015

clip_image016

By default the configuration tool would suggest you the Oracle service name as new net service name, which you can change to any name. Just make sure that you will remember it.

clip_image017

clip_image018

Now let us test the new service name we have just created.

clip_image019

Once the Net Service Name is created, we will see both the scenarios using 2 different asp files, both using different connection approaches

(ASP sample was copied from here)

1. Connecting to 12c using DSN


<html>
<head>
<title>Connecting to an Oracle database using ODBC and DSN connection</title>
</head>
<body>
<% 
SET myConn=SERVER.createobject("adodb.connection")
myConn.Open "DSN=BAC;" & _ 
"Uid=APPS;" & "Pwd=APPS" 
SQLStr="SELECT BANK_ID, BANK_NAME, BANK_TYPE FROM BAC_BANKS" 
SET result=adoCon.execute(SQLStr) 
IF NOT result.EOF thEN 
response.write("<h2>Oracle ASP Example</h2>") 
response.write("<p>Connecting to the Oracle11g database using ODBC & without a DSN</p>")
response.write("<table BORDER=3 BGCOLOR=#0099CC><tr><th>BANK ID</th>" & _
"<th>Name</th><th>TYPE</th>") 
WHILE NOT result.EOF 
response.write("<tr><td>" & result("BANK_ID") & "</td>") 
response.write("<td>" & result("BANK_NAME") & "</td>") 
response.write("<td>" & result("BANK_TYPE") & "</td></tr>") 
result.movenext() 
WEND 
response.write("</table>") 
ELSE 
response.write("<p>Error retrieving bank data!!</p>") 
END IF 
adoCon.Close()
%>
</body>
</html>

2. Connecting to 12c without DSN


<%
Dim adoCon 'Holds Connection
Dim rsViewRecords 'Holds Record Set

' Initiate connection

Set adoCon = Server.CreateObject("ADODB.Connection")

adoCon.Open "provider=oraoledb.oracle;data source=SCT;user id=APPS;password=APPS"

if Err.Number <> 0 then
Response.Clear()
response.Write "<hr>ORASESSION Error<br>" & err.number & " -- " & err.Description & "<hr>"
response.End
end if

SQLStr="SELECT BANK_ID, BANK_NAME, BANK_TYPE FROM BAC_BANKS"
SET result=adoCon.execute(SQLStr)
IF NOT result.EOF thEN
response.write("<h2>Oracle ASP Example</h2>")
response.write("<p>Connecting to the Oracle11g database using ODBC & without a DSN</p>")
response.write("<table BORDER=3 BGCOLOR=#0099CC><tr><th>BANK ID</th>" & _
"<th>Name</th><th>TYPE</th>")
WHILE NOT result.EOF
response.write("<tr><td>" & result("BANK_ID") & "</td>")
response.write("<td>" & result("BANK_NAME") & "</td>")
response.write("<td>" & result("BANK_TYPE") & "</td></tr>")
result.movenext()
WEND
response.write("</table>")
ELSE
response.write("<p>Error retrieving bank data!!</p>")
END IF
adoCon.Close()
%>

Hope this helps few “Classic ASP” guys out there ;)

regards,

rajesh

Advertisements

Unified domain profiler | Software

April 11, 2018

Hi guys

Trust me! throughout the last may years, I made few dozen attempts to “learn” C# systematically. Due to my ever growing responsibilities as IT manager & Oracle applications lead support, always something else came in front as more important and I kept losing the progresses I have ever made with this interesting development stack.

Well, enough said. Today I am going to share a compact software that could generate moderately detailed information about the Windows domain member computers, servers and users from a single console, that I started developing almost 2 years back.

This software helps you to export the fetched details to an excel sheet for future references. While there are no restrictions exclusively available for the software, the source code for the application is ONLY available against written requests. Refer the readme.txt file for more details.

Please download the zip file from this link and extract to a single folder. Double click open “WpfWMI” to run the software (No installations required). We are using open source EPPlus.dll for the excel export and you must insure that the dll file is within the same folder of the executable file (WpfWMI.exe)

Pre-requisites: The computer you are running this software MUST have .Net framework 4.5 installed.

Test it & post your comments and suggestions.

regards,

rajesh


Learning WPF, CSharp(C#) with me | Part #2

December 6, 2017

Part #2

Subject: Why each trainer stick to console based development when my intention is to learn how to make “real” applications?

Hi guys,

Have you taken a training for development recently? If you are an established developer in any technology stack, the most frustrating thing could be the “basics”, you would groan and stir loads in the seat when a junior trainer goes through the concepts, basic commands set etc & would try to make the logic behind the approach

For example, if you want to learn C#, that you could use Web applications or desktop applications, you have a preset mind that wants to develop the applications those a user could interact with visibly. Not something that open a console and shows you few outputs and closes down.

I have asked the same question to many junior trainers during the courses and none was ever able to give me satisfactory answer. During my last attempt to refresh my C# skills I came to a conclusion towards this irritating question and it is simple like this

A console application when you want to print something on the screen, you just write a code snippet like this

static void Main(){

Console.WriteLine(“Hello World”);

}

And if you want to do the same with a Desktop application, the efforts are like this

You design a form (I will not use the real technical terms here, not at this stage)

You will add textboxes or labels to show “Hello World” (and you don’t really know how to make them at the first level)

Then you will develop the code part that should show the “Hello World” finally when the application starts

So for a trainer it becomes easy to deal with code part, which is the most important element of an application, rather than trying to teach a student the GUI development.

I will try to explain what I have assumed using real examples

Hellow World console application

using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

namespace HellowWorldConsole

{
class Program
{
static void Main(string[] args)
{
Console.WriteLine("Hellow World");
}
}

}

Running the application will open a console window and show you the following

image

Now let us develop the same Hello World application using WPF

My GUI part has the following XAML Code

<Window x:Class="HelloWorldWPF.MainWindow"
xmlns="<a href="http://schemas.microsoft.com/winfx/2006/xaml/presentation"">http://schemas.microsoft.com/winfx/2006/xaml/presentation"</a>
xmlns:x="<a href="http://schemas.microsoft.com/winfx/2006/xaml"">http://schemas.microsoft.com/winfx/2006/xaml"</a>
Title="MainWindow" Height="350" Width="525" Loaded="Window_Loaded">
<Grid>
<TextBox x:Name="HWorld" Margin="95,150,117,124"/>
</Grid>

</Window>

and the code behind is


using System;

using System.Collections.Generic;

using System.Linq;

using System.Text;

using System.Threading.Tasks;

using System.Windows;

using System.Windows.Controls;

using System.Windows.Data;

using System.Windows.Documents;

using System.Windows.Input;

using System.Windows.Media;

using System.Windows.Media.Imaging;

using System.Windows.Navigation;

using System.Windows.Shapes;

namespace HelloWorldWPF

{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}

private void Window_Loaded(object sender, RoutedEventArgs e)
{
this.HWorld.Text = "Hello World";
}
}

}

and the output of both portion is seen as below

image

Now, it’s a common tendency of a seasoned programmer to perfect the GUI, because it creates the initial appeal. As you could see my textbox and the text appearing is not in sync, the height of the textbox is much bigger than the text that it looks somewhat mismatch…the time spent to perfect the GUI could become a real hurdle to progress with the training which must be limited certain hours per course!

Instead the trainers would approach the course, trying to teach the student the maximum coding part, then once the students are familiar with the technology, letting them explore the GUI development (Unless the course has the GUI development exclusively listed under the curriculum)

Once the above idea settled within me comfortably, I managed to sit patiently and learn the “basics” better than ever & was able to map what I learned to GUI much easily. Interested? However, my approach with this series will be developing GUI elements along with the basic coding. Do you have a different approach? do let me know through comments.

with the 1st part of this series I have posted a complete WPF solution to demonstrate what C# with WPF could do. That solution has many issues, like I am not handling folder/file access permissions or threading which is a must requirement when a program is going to run for unprecedented periods.

Be with me and we will be looking at much of them in coming parts.

regards,

rajesh


Learning WPF, CSharp(C#) with me | Part #1

December 4, 2017

Part #1

Subject: A Simple File Listing Utility using WPF & CSharp (C#)

Okay guys

Here I am once again! This time trying to learn WPF with C# to build my own small utilities to make my “Admin work” a lot easier. Further, I use my own blog as a reference guide most of them time! So, you are most welcome to use my “notes”

A WPF project always has two parts, XAML and the code behind. While XAML maintains the GUI part of it, Code part is where you write supporting code.

<Window x:Class="WpflisttoGrid.MainWindow"         xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"         Title="MainWindow" Height="513" Width="877" Loaded="Window_Loaded">
    <DockPanel>
<Menu DockPanel.Dock="Top" Height="24"></Menu>

        <StatusBar DockPanel.Dock="Bottom" Height="24">
            <StatusBarItem x:Name="StatusItem" Content="Ready" Width="Auto" HorizontalAlignment="Left" VerticalAlignment="top"></StatusBarItem>
        </StatusBar>

        <Grid>
            <GroupBox x:Name="MyParameters">
                <Grid x:Name="MyParameters_Grid">
                    <Label x:Name="lblPath" Content="Folder" HorizontalAlignment="Left" Margin="6,19,0,0" VerticalAlignment="Top"/>
                    <Label x:Name="lblFileType" Content="File Type" HorizontalAlignment="Left" Margin="6,47,0,0" VerticalAlignment="Top"/>
                    <TextBox x:Name="txtPath" HorizontalAlignment="Left" Height="23" Margin="83,22,0,0" TextWrapping="NoWrap" VerticalAlignment="Top" Width="258"/>
                    <TextBox x:Name="txtType" HorizontalAlignment="Left" Height="23" Margin="83,49,0,0" TextWrapping="Wrap" VerticalAlignment="Top" Width="120"/>
                    <Button x:Name="buttonFldrOpen" HorizontalAlignment="Left" Margin="346,22,0,0" VerticalAlignment="Top" Height="23" Click="buttonFldrOpen_Click" >
                        <StackPanel Orientation="Horizontal">
                            <Image Source="/Resources/folder_Open_32xMD.png" Stretch="Uniform" Height="18" Width="22"/>
                        </StackPanel>
                    </Button>
                    <Button Content="Process" HorizontalAlignment="Left" Margin="83,84,0,0" VerticalAlignment="Top" Width="75" Click="Button_Click"/>
                </Grid>
            </GroupBox>

            <DataGrid x:Name="Grid1" Margin="68,159,89,40" IsReadOnly="True" SelectionChanged="Grid1_SelectionChanged" MouseDoubleClick="Grid1_MouseDoubleClick" SelectionUnit="Cell"/>

        </Grid>

    </DockPanel>

</Window>

and the CSharp code portion as below

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.IO;
using System.Data;
//Required for folder browswer & so
using System.Windows.Forms;

namespace WpflisttoGrid
{
    ///
<summary>
    /// Interaction logic for MainWindow.xaml
    /// </summary>

    public partial class MainWindow : Window
    {
        public MainWindow()
        {
            InitializeComponent();
        }
        private void Button_Click(object sender, RoutedEventArgs e)
        {
            //Setup the gridview to generate columns automatically against the file lists
            this.Grid1.AutoGenerateColumns = true;
            //We will store the text box values into local variables for easy understanding
            //You may refer them straight away as defined columns
            string filepath = this.txtPath.Text;
            string filetype = this.txtType.Text;
            //We will build a LIST of class myFiles
            //Which will have chosen columns from the directory info file info results
            List<myFiles> newList = new List<myFiles>();
            try
            {
                foreach (FileInfo myfile in (new DirectoryInfo(@filepath).GetFiles(filetype, SearchOption.AllDirectories)))
                //SearchOption.TopDirectoryOnly lists files from the top folder, ie, if a folder has sub-folders within
                //SearchOption.TopDirectoryOnly will isolate the top folder & list all files from it
                //SearchOption.AllDirectories will recursively pick all files from all folders those match type of files PDF
                //As a developer who is learning
                //I will leave enhancements to your logic
                //This application could have
                //Files those matching certain "contents"
                //You can change the SearchOption.AllDirectories to SearchOption.TopDirectoryOnly programmatically...etc
                {
                   //Calculate the time difference between the file creation and as on this moment
                    double _fileAge = Math.Round((DateTime.Now - myfile.CreationTime).TotalDays, 0);
                    //Add rows to the new list using new instance of the "Constructor" myFiles by passing the file details
                   newList.Add(new myFiles(myfile.FullName.ToString(), myfile.CreationTime, _fileAge));
                }
                //The following you could use for showing additional details
                //this.StatusItem.Content = myfileList.Count().ToString();
                //this.Grid1.ItemsSource = myfileList;
                //System.Diagnostics.Debug.WriteLine(myfileList.Count());
                this.Grid1.ItemsSource = newList;
                this.Grid1.Columns[0].Header = "File Name";
                this.Grid1.Columns[1].Header = "Creation Time";
                this.Grid1.Columns[2].Header = "File Age(Days)";
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message + ex.Source);
            }
        }

        private void Grid1_SelectionChanged(object sender, SelectionChangedEventArgs e)
        {

        }
        private void Grid1_MouseDoubleClick(object sender, MouseButtonEventArgs e)
        {
            // System.Windows.MessageBox.Show()
            //https://stackoverflow.com/questions/47309073/c-sharp-wpf-gridview-will-not-show-data-unless-clicked
            try
            {
                var cellInfo = Grid1.SelectedCells[0];
                var content = (cellInfo.Column.GetCellContent(cellInfo.Item) as TextBlock).Text;
                //System.Windows.MessageBox.Show(content);
                System.Diagnostics.Process.Start(@content);
            }
            catch (Exception ex)
            {
                System.Windows.MessageBox.Show(ex.Message + ex.Source);
            }
        }

        private void buttonFldrOpen_Click(object sender, RoutedEventArgs e)
        {
            FolderBrowserDialog folderDlg = new FolderBrowserDialog();
            folderDlg.ShowNewFolderButton = false; //Don't allow users to create new folders from this dialogue
            folderDlg.RootFolder = Environment.SpecialFolder.MyComputer;
            // Show the FolderBrowserDialog.
            DialogResult result = folderDlg.ShowDialog();
            if (result == System.Windows.Forms.DialogResult.OK)
            {
                this.txtPath.Text = folderDlg.SelectedPath;
                Environment.SpecialFolder root = folderDlg.RootFolder;
            }
        }

        private void Window_Loaded(object sender, RoutedEventArgs e)
        {
            this.txtType.Text = "*.*";
        }
    }

    public class myFiles
    {
        public string fName { get; set; }
        public DateTime fCreationDate { get; set; }
        public double fAge { get; set; }

        public myFiles(string fname, DateTime fcdate, double fage)
        {
            fName = fname;
            fCreationDate = fcdate;
            fAge = fage;

        }

    }
}

This project should be used as a pilot to learn both WPF & CSharp (C#) rather than a commercial product as I am not using threading or channeling the background works. So once the Process button clicked, the GUI become irresponsive until the file lists populated, and could make a user feel the system is stuck.

Once the file list is populated in the GridView, one can double click the file name to start a fresh instance of associated program. So be careful, you may be running an executable that could cause unexpected problems.

Optionally you may download the Visual Studio Solution from here

regards,

rajesh


MS SQL Northwind & Pub databases | ‘sp_dboption’

November 6, 2017

Hi guys

Today I am going to upload two SQL scripts using which you could build Northwind & Pub databases against latest versions of MS SQL Server. The latest tested at my end is SQL Server 2014

I have packaged these scripts to avoid the error “Could not find stored procedure ‘sp_dboption’.” error that arises when Microsoft provided SQL scripts are executed against latest database technologies.

You may download the SQL scripts from this link

MD5: 5831113f5ec890986312d2ed532a13e2

SHA-1: 57484de9bea37c5e0b8ba84454e8093612d96df6

regards,

rajesh


C# A folder sync tool

January 26, 2017

Hi guys!

I’ve been busy with so many developments recently. Few projects for Oracle E-Business Suite R12 & few others for learning C#. I can say I’ve “learned” how to copy, paste, correct and use it with my projects to produce beautiful results!

My recent C# projects include a WPF solution that uses WMI classes to generate hardware details for entire Windows Domain (Linux boxes are not dealt) & today I’ve decided to build a small solution that could synchronize my C# projects with our file server.

This small project can,

  • Replicate source Directory, subdirectories & files to destination folder
  • While re-ran, check whether the destination files are older than the source files and, if yes, overwrite the old ones with newer ones.

Interested to try it yourself? here comes the code

(This project uses codes copied from both MSDN & http://www.stackoverflow.com. RecursiveFileProcessor is a MSDN example, while File exists snippet was copied from stackoverflow)

using System;
using System.IO;
using System.Collections;

//http://stackoverflow.com/questions/58744/copy-the-entire-contents-of-a-directory-in-c-sharp
//

namespace RecursiveFileProcessor
{
    class Program
    {
        public static void Main(string[] args)
        {
            string sourceDirectory = @"D:\MyProjects";
            string targetDirectory = @"\\network_share_location\MyProjects";
            Copy(sourceDirectory, targetDirectory);
            Console.WriteLine();
            Console.WriteLine("Task Completed. Press any key to continue");
            Console.ReadLine();

        }

        public static void Copy(string sourceDirectory, string targetDirectory)
        {
            DirectoryInfo diSource = new DirectoryInfo(sourceDirectory);
            DirectoryInfo diTarget = new DirectoryInfo(targetDirectory);

            CopyAll(diSource, diTarget);
        }

        public static void CopyAll(DirectoryInfo source, DirectoryInfo target)
        {

            Directory.CreateDirectory(target.FullName);

            // Copy each file into the new directory.
            foreach (FileInfo fi in source.GetFiles())
            {

                DateTime created = fi.CreationTime;
                DateTime lastmodified = fi.LastWriteTime;

                if (File.Exists(Path.Combine(target.FullName, fi.Name)))
                {
                    string tFileName = Path.Combine(target.FullName, fi.Name);
                    FileInfo f2 = new FileInfo(tFileName);
                    DateTime lm = f2.LastWriteTime;
                    Console.WriteLine(@"File {0}\{1} Already Exist {2} last modified {3}", target.FullName, fi.Name, tFileName, lm);

                    try
                    {
                        if (lastmodified > lm)
                        {
                            Console.WriteLine(@"Source file {0}\{1} last modified {2} is newer than the target file {3}\{4} last modified {5}",
                                fi.DirectoryName, fi.Name, lastmodified.ToString(), target.FullName, fi.Name, lm.ToString());
                            fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
                        }
                        else
                        {
                            Console.WriteLine(@"Destination File {0}\{1} Skipped", target.FullName, fi.Name);
                        }
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.Message);
                    }

                }
                else
                {
                    Console.WriteLine(@"Copying {0}\{1}", target.FullName, fi.Name);
                    fi.CopyTo(Path.Combine(target.FullName, fi.Name), true);
                }

            }

            // Copy each subdirectory using recursion.
            foreach (DirectoryInfo diSourceSubDir in source.GetDirectories())
            {
                DirectoryInfo nextTargetSubDir =
                    target.CreateSubdirectory(diSourceSubDir.Name);
                CopyAll(diSourceSubDir, nextTargetSubDir);
            }
        }

    }
}

Thumb rules:

  1. Do not set your source and destination folders the same.

This project uses Framework 4.5 & I am sure versions above 2.0 should support the classes referred.

If you are new to .net developments, create a project with the name “RecursiveFileProcessor”, which will let you copy and paste the whole code as it is to your project.

Do let me know whether you enjoyed your new sync toy!

regards,

rajesh


C# (CSharp, C-Sharp) Windows Active Directory last logon

January 7, 2017

Hi guys

Please note, many threads were referred in order to compile the script attached below & all I did was re-arranging in order for better reading/formatting

(And I insure that the script works under following scenarios:

  1. You are a domain administrator
  2. You are administrating Windows 2003 onwards Windows domain
  3. Your puter is connected to the domain network ;)

)

Referenced websites/threads

  1. http://stackoverflow.com/questions/15775264/searching-for-lastlogon-attribute-of-user-in-multiple-domain-servers
  2. https://www.codeproject.com/kb/security/lastlogonacrossallwindows.aspx#_comments
  3. http://codebeautify.org/csharpviewer (for formatting the C# code)

How to test the code

Start Visual Studio (I am using 2013 Professional edition, you can use any of the community editions to test the scripts)

Create a new C# Console Application and name it llogon (else you need to change the namespace name “llogon” according to the name you have chosen for your new project.

Add the following references to your project

  1. “Framework -> System.DirectoryServices”
  2. “Browse and add -> C:\Windows\System32\activeds.tlb”

 

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

//Added by Rajesh

//using System.Management;
//using System.Data;
using System.DirectoryServices;
using System.DirectoryServices.ActiveDirectory;
//http://stackoverflow.com/questions/33274162/the-namespace-of-iadslargeinteger
//ActiveDS namespace
using ActiveDs; // Namespace added via ref to C:\Windows\System32\activeds.tlb
//https://www.codeproject.com/kb/security/lastlogonacrossallwindows.aspx

namespace llogon
{
    class Program
    {
        static void Main(string[] args)
        {
            // Get the root entry
            DirectoryEntry rootDSE = new DirectoryEntry("LDAP://RootDSE");
            string configurationNamingContext =
             (string)rootDSE.Properties["configurationNamingContext"].Value;
            string defaultNamingContext =
             (string)rootDSE.Properties["defaultNamingContext"].Value;
            Dictionary<string, Int64> lastLogons = new Dictionary<string, Int64>();
            // Get all the domain controllers
            DirectoryEntry deConfig = new DirectoryEntry("LDAP://" + configurationNamingContext);
            DirectorySearcher dsConfig = new DirectorySearcher(deConfig);
            dsConfig.Filter = "(objectClass=nTDSDSA)";
            foreach (SearchResult srDomains in dsConfig.FindAll())
            {
                DirectoryEntry deDomain = srDomains.GetDirectoryEntry();
                if (deDomain != null)
                {
                    string dnsHostName =
                     deDomain.Parent.Properties["DNSHostName"].Value.ToString();
                    // Get all the users for that domain
                                   DirectoryEntry deUsers =
                     new DirectoryEntry("LDAP://" + dnsHostName + "/" + defaultNamingContext);
                    DirectorySearcher dsUsers = new DirectorySearcher(deUsers);
                    dsUsers.Filter = "(&(objectCategory=person)(objectClass=user))";
                    foreach (SearchResult srUsers in dsUsers.FindAll())
                    {
                        DirectoryEntry deUser = srUsers.GetDirectoryEntry();
                        if (deUser != null)
                        {
                            // Get the distinguishedName and lastLogon for each user
                            // Save the most recent logon for each user in a Dictionary object
                            string distinguishedName = deUser.Properties["distinguishedName"].Value.ToString();
                            Int64 lastLogonThisServer = new Int64();
                            if (deUser.Properties["lastLogon"].Value != null)
                            {
                                IADsLargeInteger lgInt =
                                 (IADsLargeInteger)deUser.Properties["lastLogon"].Value;
                                lastLogonThisServer = ((long)lgInt.HighPart << 32) + lgInt.LowPart;
                            }

                            // Save the most recent logon for each user in a Dictionary object
                            if (lastLogons.ContainsKey(distinguishedName))
                            {
                                if (lastLogons[distinguishedName] < lastLogonThisServer)
                                {
                                    lastLogons[distinguishedName] = lastLogonThisServer;
                                }
                            }
                            else
                            {
                                lastLogons.Add(distinguishedName, lastLogonThisServer);
                            }
                            string readableLastLogon = DateTime.FromFileTime(lastLogonThisServer).ToString();
                            Console.WriteLine("User: " + distinguishedName + "Last logon: " +readableLastLogon);
                        }
                    }
                    Console.ReadLine();
                }
            }

        }
    }
}

Try the code & if you are stuck somewhere, do let me through the comments. I am working on a WPF C# project for a simple Active Directory Reporter / Asset Management System using WMI. Stay tuned & I will soon post the entire solution here :)

regards,

rajesh