Wednesday, December 30, 2009

How to Analyse a Dump File

First of all I would like to point out that I am not an expert on debugging applications - in fact far from it. I only know the basic steps required to analyze a dump file allowing you find out what is causing your system to crash. Analyzing dump is a very technical area, by reading this I hope to make it easier for you!

I'm going to provide you with two ways on how to analyze dump files, an old method I used years and years ago and the new method using the new Debugging Tools for Windows.

The old method using dumpchk and pstat

I have only used this method windows server 2000 and it was many years ago. I do not know if it will work on the new operating systems such as server 2008 or windows 7!

Before we proceed you can get a copy of dumpchk.exe from the Windows 2003 Support Tools which can be downloaded from here:

http://www.microsoft.com/downloads/details.aspx?FamilyId=6EC50B78-8BE1-4E81-B3BE-4E7AC4F0912D&displaylang=en

pstat.exe can be downloaded from the Windows 2000 Resource kit found here:

http://support.microsoft.com/kb/927229

First run dumpchk.exe against your dump file. It can be handy piping this to a text file so you can read it easier.

dumpchk.exe C:\WINDOWS\Minidump\Mini102609-01.dmp > c:\dumpchkresults.txt

From the data gathered in the text file your looking specifically for the "ExceptionAddress".

MachineImageType i386
NumberProcessors 1
BugCheckCode 0xc000021a
BugCheckParameter1 0xe1270188
BugCheckParameter2 0x00000001
BugCheckParameter3 0x00000000
BugCheckParameter4 0x00000000

ExceptionCode 0x80000003
ExceptionFlags 0x00000001
ExceptionAddress 0x8014fb84


In this instance the ExceptionAdderss is 0x8014fb84.

The next step is boot the server up and run pstat.exe against it. Again it is good to pipe the results to a text file. What pstat shows us is all the drivers and what memory ranges they are using.

MODULENAME Load Addr Code Data Paged LinkDate
----------------------------------------------------------------------
Ntoskrnl.exe 80100000 270272 40064 434816 Sun May 11 00:10:39 1997
Hal.dll 80010000 20384 2720 9344 Mon Mar 10 16:39:20 1997
Aic78xx.sys 80001000 20512 2272 0 Sat Apr 05 21:16:21 1997
Scsiport.sys 801d7000 9824 32 15552 Mon Mar 10 16:42:27 1997
Disk.sys 80008000 3328 0 7072 Thu Apr 24 22:27:46 1997
Class2.sys 8000c000 7040 0 1632 Thu Apr 24 22:23:43 1997
Ino_flpy.sys 801df000 9152 1472 2080 Tue May 26 18:21:40 1998
Ntfs.sys 801e3000 68160 5408 269632 Thu Apr 17 22:02:31 1997
Floppy.sys f7290000 1088 672 7968 Wed Jul 17 00:31:09 1996
Cdrom.sys f72a0000 12608 32 3072 Wed Jul 17 00:31:29 1996
Cdaudio.sys f72b8000 960 0 14912 Mon Mar 17 18:21:15 1997
Null.sys f75c9000 0 0 288 Wed Jul 17 00:31:21 1996
Ksecdd.sys f7464000 1280 224 3456 Wed Jul 17 20:34:19 1996
Beep.sys f75ca000 1184 0 0 Wed Apr 23 15:19:43 1997
Cs32ba11.sys fcd1a000 52384 45344 14592 Wed Mar 12 17:22:33 1997
Msi8042.sys f7000000 20192 1536 0 Mon Mar 23 22:46:22 1998
Mouclass.sys f7470000 1984 0 0 Mon Mar 10 16:43:11 1997
Kbdclass.sys f7478000 1952 0 0 Wed Jul 17 00:31:16 1996
Videoprt.sys f72d8000 2080 128 11296 Mon Mar 10 16:41:37 1997
Ati.sys f7010000 960 9824 48768 Fri Dec 12 15:20:37 1997
Vga.sys f7488000 128 32 10784 Wed Jul 17 00:30:37 1996
Msfs.sys f7308000 864 32 15328 Mon Mar 10 16:45:01 1997
Npfs.sys f7020000 6560 192 22624 Mon Mar 10 16:44:48 1997
Ndis.sys fccda000 11744 704 96768 Thu Apr 17 22:19:45 1997
Win32k.sys a0000000 1162624 40064 0 Fri Apr 25 21:17:32 1997
Ati.dll fccba000 106176 17024 0 Fri Dec 12 15:20:08 1997
Cdfs.sys f7050000 5088 608 45984 Mon Mar 10 16:57:04 1997
Ino_fltr.sys fc42f000 29120 38176 1888 Tue Jun 02 16:33:05 1998
Tdi.sys fc4a2000 4480 96 288 Wed Jul 17 00:39:08 1996
Tcpip.sys fc40b000 108128 7008 10176 Fri May 09 17:02:39 1997
Netbt.sys fc3ee000 79808 1216 23872 Sat Apr 26 21:00:42 1997
El90x.sys f7320000 24576 1536 0 Wed Jun 26 20:04:31 1996
Afd.sys f70d0000 1696 928 48672 Thu Apr 10 15:09:17 1997
Netbios.sys f7280000 13280 224 10720 Mon Mar 10 16:56:01 1997
Parport.sys f7460000 3424 32 0 Wed Jul 17 00:31:23 1996
Parallel.sys f746c000 7904 32 0 Wed Jul 17 00:31:23 1996
Parvdm.sys f7552000 1312 32 0 Wed Jul 17 00:31:25 1996
Serial.sys f7120000 2560 0 18784 Mon Mar 10 16:44:11 1997
Rdr.sys fc385000 13472 1984 219104 Wed Mar 26 14:22:36 1997
Mup.sys fc374000 2208 6752 48864 Mon Mar 10 16:57:09 1997
Srv.sys fc24a000 42848 7488 163680 Fri Apr 25 13:59:31 1997
Pscript.dll f9ec3000 0 0 0
Fastfat.sys f9e00000 6720 672 114368 Mon Apr 21 16:50:22 1997
Ntdll.dll 77f60000 237568 20480 0 Fri Apr 11 16:38:50 1997
---------------------------------------------------------------------
Total 2377632 255040 1696384


With this information you can then get the ExceptionAddress and find out which memory range it fits into using the data provided by pstat.exe. This is just an example but in this case the crash was caused by Ntoskrnl.exe. Microsoft wrote a KB article documenting this procedure:

http://support.microsoft.com/kb/192463

The new method using Debugging Tools for Windows

The recommended way for analyzing dump files is using Debugging Tools for Windows. This is not a tool, it is a toolkit containing a wide variety of diagnostic tools. There is a 32bit and 64bit version of the product, install the correct one depending on what platform your system is running.

As of this writing the latest version is 6.11.1.404.

Download the 32bit version from here:

http://www.microsoft.com/whdc/devtools/debugging/installx86.Mspx

Download the 64bit version from here:

http://www.microsoft.com/WHDC/DEVTOOLS/DEBUGGING/INSTALL64BIT.MSPX

Again the Debugging Tools are very complicated - below I am only going to show you the basic steps on how to find out what caused your system to crash. Lets begin.

Before you can analyse a dump file you first need symbol files. Symbol files contain symbolic information such as function names and data variable names and are created when an application is built. Symbol files have a .dbg or .pdb extension. These files are used by various debuggers from different vendors including Debugging Tools for Windows which we are going to use below. Without these files call stacks which show how functions are called would be inaccurate or incorrect causing function names from being omitted from the call stack. Only Microsoft can provide symbol files for the Microsoft core components such as kernel32.dll, ntdll.dll, user32.dll and other core windows components as Microsoft are the ones that developed these. Microsoft also provides symbol files for many other third party applications and drivers.

For more about Symbol files see KB311503 - this is more of a developers thing.

If you have some idea into what is causing the blue screen you can download the symbol files for just a few files which you want to analyse. However in this case we have no idea what is causing the blue screen so I want to download all symbol files for each of my drivers and windows application files in C:\Windows\System32.

To download all the symbol files for c:\windows\system32 use the synchk.exe tool which comes as part of the Debugging Tools. Use the /r switch which means perform a recursive query. In my example I am placing the symbol files in C:\symbols.

Run the following command:

symchk /r c:\windows\system32 /s SRV*c:\symbols\*http://msdl.microsoft.com/download/symbols

It will give you out put similar to this:



Note it is saying FAILED because it cannot find the symbol file in c:\symbols which is normal. If it cannot find the file, it goes and downloads it. Note this will take a while - for my server it took just over an hour to download all the symbol files ending up to be 558 MB of data.



You will now have symbol files for all the different drivers and application libaries in your system32 directory.



You also need a copy of the i386 directory from the windows CD to analyze the dump. Ensure this is the same service pack as the system you are running. I'm using Windows Server 2003 SP2 so I had to track down a Windows Server 2003 SP2 CD.

Now that you have the symbol files and the i386 directory it is now possible to analyse the dump.

Use the following command from Microsoft KB 315263:

windbg -y SymbolPath -i ImagePath -z DumpFilePath

In my case I used:

windbg -y c:\symbols -i D:\i386 -z C:\WINDOWS\Minidump\Mini123009-01.dmp



This comes up and tells me what file triggered the crash:



Now that I know bxnd52x.sys caused the crash I now need to link it to a driver. As I described in my article "Permently Remove Driver" all drivers are referenced OEM*.INF files in c:\windows\inf. To find out which driver caused the crash search all files in C:\Windows\inf for any that contain the text string "bxnd52x.sys". You can do this using the following command:

find /c "bxnd52x.sys" c:\windows\inf\*.inf | find ":" | find /v ": 0"

This came back with two INF files containing this string.



If we open these files up we can see it is the broadcom network driver!



Note I have two because I have already updated the driver to see if that would fix the problem which it didn't. See how one was version 2.8.13 and the new one is version 5.0.13. The old drivers still stay in place for the "roll back driver functionality" in device manager. The fact that upgrading the driver did not fix the problem means that the problem is with the broadcom network adapter itself. This network adapter is onboard so it looks like im going to have to contact HP and arrange for a new mainboard.

One more thing I would like to point out is in windbg.exe you can enter additional commands to find more information as described on KB315263.

The !analyze -v command displays verbose output.



This comes back and shows you a few pages of information on how it determined that bxnd52x.sys caused the issue. Most of this is beyond me but its good to know as Microsoft or a vendor could request for this information.



There are lots of other commands for finding more information. For example the command "lm N T" can give you all the drivers and modules running on the system at the time of the crash.





I hope you have learnt something out of this. As always I'm always looking forward to feedback so please leave me a comment or shoot me an email to clint@kbomb.com.au.

The Low-Down on Password Policies

Below we will be looking at password policies in detail as this can get confusing in some circumstances. I will cover generic domain password policies as well as the new server 2008 granular Password Settings Objects (PSO's). There are many articles on the Internet around password policies for windows networks. The reason for writing this is I have found many of the articles are missing some key points that are very important! These missing points will be my main focus in this post.

Where do I link the password policy?

Many of the articles on the Internet discussing password policies describe how to configure the password security object but not where to link it and why. Password policies are applied to computer objects not user objects in active directory. There can only be one password policy "per account database".

Microsoft says:

There can be only a single password policy for each account database. An Active Directory domain is considered a single account database, as is the local account database on stand alone computers.There can be only a single password policy for each account database. An Active Directory domain is considered a single account database, as is the local account database on stand alone computers.

Taken from:

http://technet.microsoft.com/en-us/library/cc875814.aspx

If you were to link your password policy to the "Domain Controllers" OU, this would mean that your password policy would apply to active directory and all user accounts in Active Directory.

If you were to link your password policy at root domain level, this would hit all computer objects in the active directory database including domain controllers assuming you do not have block policy inheritance set on the domain controllers organisational unit. The password policy will hit the local SAM database for all member workstations in the active directory domain meaning that not only will active directory accounts use the password policy but also machine-local accounts on member workstations will also now need to adhere to the password policy.

Microsoft recommends always linking your password policy at the root domain level to ensure the policy covers local accounts as well as active directory accounts for obvious reasons. It is silly having a strict password policy for your domain user accounts but not for your local user accounts. If someone cracked a local user account on a member workstation they could still rootkit a PC which they could then use as an access point to attack the active directory domain.

Here is a quick structure from Microsoft on where to link your policies:

Default Domain Security Policy Settings:
- Password Policy
- Domain Account Lockout Policy
- Domain Kerberos Policy

Default Domain Controller Security Policy Settings:
- User Rights Assignment Policy
- Audit Policy


Taken from:

http://technet.microsoft.com/en-us/library/cc773164.aspx

Do I create a new GPO or use the existing default group policy objects?

Microsoft recommends never modifying the "default domain policy" and "default domain controllers policy". Create a new group policy object called something like "Corporate Password Policy" and link it at the root domain level. Ensure to assign it a higher priority to the Default Domain Policy to ensure the settings override.

Taken from Microsoft:

It is a best practice to avoid modifying these built-in GPOs, if you need to apply password policy settings that diverge from the default settings, you should instead create a new GPO and link it to the root container for the domain or to the Domain Controllers OU and assign it a higher priority than the built-in GPO: If two GPOs that have conflicting settings are linked to the same container, the one with higher priority takes precedence.

Reference:

http://technet.microsoft.com/en-us/library/cc875814.aspx

The reason behind this is because doing so makes it much easier to recover from serious problems with security settings. If the new security settings create problems, you can temporarily disable the new Group Policy object until you isolate the settings that caused the problems.

I want to see who is Logging in and out in my Domain?

This is not part of password policies, this is actually an audit policy. Audit policies need to be configured on the Domain Controllers OU as I mentioned above. This Microsoft article describes what policies should be configured on the domain root level and which policies need to be configured.

Two audit policies I want to draw attention to are "Audit logon events" and "Audit account logon events" as they cause much confusion.

"Audit account logon events" are when user accounts try to authenticate against a domain controller. It can log success or failure depending on how you configure it. This basically checks the users credentials are correct (right username and password).

"Audit logon events" generates events for the creation and destruction of logon sessions. For example things that trigger these events are things like accessing a share. Your already "authenticated" on the network, your just using your kerberos key to access network resources.

For information on the various audit policies see this post:

http://www.enterprisenetworkingplanet.com/netos/article.php/624921

I recommend only configuring audit policies you need. Do not audit everything, if so your event logs will be spammed. Personally I only audit "Account logon events" as I only want to see when people logged in and out of the network, and any failed logon attempts.

So what are these Password Settings Objects in Server 2008?

As I mentioned above password policies apply on a database level meaning that every account in the Active Directory database needs to adhere to a password policy. In Server 2000/2003 if you want to have a different password policy for different departments or user groups, the only way to achieve this was to create another domain within the same forest.

Windows 2008 gets around this with the new Password Settings Objects called PSO's for short. PSO's can be configured to effect specific users and groups in an active directory domain.

PSO's sometimes get refered to as "Granular Password Settings" or "Fine-Grained Password Policy". One thing I would like to point out a PSO is not a policy. A PSO is an object in the active directory database much like a user account or computer account. There are two AD Classes that make this work:
- Password Settings Container
- Password Setting Objects

To use PSO's your domain functional level must be server 2008. With PSO's they do not replace your domain password policy - you still need to configure this. It is there more as a fallback encase the PSO does not get applied to particular users.

If you want a step by step guide on how to configure Password Settings Objects please read these two articles by Jakob H. Heidelberg from windowsecurity.com:

http://www.windowsecurity.com/articles/Configuring-Granular-Password-Settings-Windows-Server-2008-Part-1.html

http://www.windowsecurity.com/articles/Configuring-Granular-Password-Settings-Windows-Server-2008-Part2.html

Wednesday, December 23, 2009

Outlook MAPI Access Exchange 2007 vs 2010

One major difference administrators need to plan for when deploying exchange 2010 is the changes to the client access server. In Exchange 2007 outlook clients talked MAPI directly to the exchange 2007 mailbox server roles. In Exchange 2010 the only device that talks to the mailbox servers is client access server. Exchange 2010 client access server proxies the MAPI requests on to the exchange mailbox server and applies smarts. This stops the mailbox server being spammed with multiple TCP connections from different sources like it was in exchange 2003 and 2007. This is also adds to how Microsoft have achieved the 70% reduction in disk I/O with the 2010 mailbox server, see:

http://clintboessen.blogspot.com/2009/11/microsoft-recommends-sata-for-exchange.html

In exchange 2007 the client access servers did not use much resources. In exchange 2010 ensure you take into account the client access servers will under a heavier load dealing with all the MAPI requests from end clients.

There is a new service on the Exchange 2010 client access server called the "Microsoft Exchange RPC Client Access Service" that is responsible for talking MAPI to the outlook clients on the internal network. The RPC Client Access service also talks to active directory on behalf of outlook clients, something that outlook use to do directly! Outlook connects to an NSPI endpoint on the Client Access Server, and NSPI then talks to the Active Directory via the Active Directory driver. The NSPI endpoint replaces the DSProxy component as we know from Exchange 2007.

This not only improves the consistency, when applying business logic to clients, but also provides a much better client experience during switch-over and fail-overs when you have deployed a highly available solution that makes use of the new Database Availability Group (DAG) HA feature.

Monday, December 21, 2009

Failed to change domain affiliation, hr=800704f1

Performing an Active Directory Migration from a windows server 2008 FFL forest to another windows server 2008 FFL forest. User accounts migrate fine, so do computer accounts. However when the ADMT agent goes to update the domain membership on the member computers in one domain I recieve the following error in the ADMT Agent logs:

2009-12-22 14:21:15 ERR3:7075 Failed to change domain affiliation, hr=800704f1 The system detected a possible attempt to compromise security. Please ensure that you can contact the server that authenticated you.

To get around this ensure that you have "Allow cryptography algorithms compatible with Windows NT 4.0" enabled on the default domain controllers policy in both the source and destination domain.

To do this follow Microsoft KB Article 942564:

http://support.microsoft.com/kb/942564

Thursday, December 17, 2009

View System Hardware Information in Linux

You want to be able to view information about a system from a linux shell in terms of what disks it has, what processor, the system model the vendor etc.

There is a program in linux called dmidecode which pulls this information straight from the systems BIOS.

You can run dmidecode by simply typing "dmidecode" in a linux shell. However it spits out a lot of information so I recommend running it through "more" or "less".

Run:

dmidecode | more

or

dmidecode | less



You can then scroll through this information and find out all kinds of cool information about the system such as what model it is!

hpacucli Create Hot Spare

I have a ProLiant DL360 G5 running Red Hat 4.1.2-14.

This server has a Smart Array 6400 with 13 300GB SCSI disks allocated in two arrays and 1 disk unallocated.

This server also has a Smart Array P400i with 4 disks allocated in 2 arrays and 1 disk unallocated.

My goal is to add the unallocated disk as a spare to both arrays on each controller. This server does not have a GUI so I must use the HP Array Configuration Utility CLI called "hpacucli".

To run the HP Array Configuration Utility CLI simply type "hpacucli" in the shell.

Next lets look at all our arrays using the following command:

ctrl all show config



We can see that Smart Array 6400 is in Slot 2 and Smart Array P400i is in Slot 0. We can also see the unassigned disks are physicaldrive 1:8 and physicaldrive 2I:1:5.

To assign the drives as hot spares run the following commands:

ctrl slot=2 array all add spares=1:8



ctrl slot=0 array all add spares=2I:1:5



We specify "array all" as we want to make the disk available to all disks on the controller. We could go "array A" if we wanted to make the spare available to just onje array... I don't know why you would though!

Now if we run the "ctrl all show config" command again we see it's added it in as a spare:



If you want more information about performing other tasks using hpacucli the following link is the best documentation I could find:

http://people.freebsd.org/~jcagle/hpacucli-readme

Monday, December 14, 2009

0x800700005 when creating scheduled task

When creating a scheduled task the following error was experianced:

Error: 0x800700005 access denied when creating a new task

This is because administrators do not have permission to the task scheduler folder for some reason. To fix this perform the following:

1. Open a command prompt
2. Run “Net Use T: \\%computername%\C$\Windows\Tasks /Persistent:No”
3. Open Explorer, right-click Tasks (T:), goto ‘Properties’ Click the [Security]
tab. In security permissions grant Administrators and System Full Control if they do not already have it, and then click [Apply]. Then click [Advanced], check [x] Replace permission entries on all child objects, and click [Ok]. Restart the "Task Scheduler" service and give it another try.

Wednesday, December 9, 2009

Sysprep 2008 Server

You have a virtual environment, and you create a 2008 template server. You need to sysprep it to ensure the system is unique.

Sysprep is located under c:\Windows\System32\sysprep\sysprep.exe on every 2008 server install.

Tick the box "Generalize", this ensures the server has a new SID. Change the shutdown options to shutdown.



When the virtual server shuts down begin cloning it.

Wednesday, December 2, 2009

Exchange 2010 Deploy Assist

If you are looking to migrate to Exchange 2010 from 2003 or 2007, or prehaps perform a new Exchange 2010 installation there is a cool tool Microsoft has just released called Deploy Assist.

The Deployment Assist tool asks you a series of questions about your environment. Based on these questions it will then provide you with step by step instructions on how to perform the migration or fresh installation of exchange 2010. This is very handy as it tackles all kinds of network environments.



To use this tool go to the following link:

http://technet.microsoft.com/exdeploy2010

Tuesday, December 1, 2009

Software Inventory Powershell Script

I wrote a powershell script for inventorying software on all PC's on a windows domain. Below I will show you how to use it and provide you with a copy of the code.

Preparation

For this program to work you will need a computer running Microsoft Powershell. Windows 7 and 2008 R2 come with powershell pre-built into them. For windows XP, 2003 and 2008 you need to manually download and install the powershell component. This PC must be a member of the domain!

Get powershell from here:

http://www.microsoft.com/windowsserver2003/technologies/management/powershell/download.mspx

Next you need to configure powershell to allow unsigned scripts to run. By default powershell is set to RemoteSigned meaning it will not run any scripts that have not been signed by an external certificate authority. To digitally sign scripts you need to buy a certificate for each piece of code you want to sign! Open powershell with administrator rights to the local system. You may have to “Run as Administrator” due to UAC!



Close the window and open another powershell window that has domain admin rights. This means you need to run the power shell window as another user. To perform “Run As” on windows 7 or Vista please see:

http://clintboessen.blogspot.com/2009/11/use-old-run-as-windows-7-and-windows.html

Running the Script

This powershell script will go through every computer account in active directory, ping the computer name, if it replies then perform the WMI query. This avoids the script failing for computers that are not turned on.

From the powershell session running as a domain admin account, navigate to the folder containing the script and run it.



You can see it will go through and skip any PC’s that are turned off. This data will get pushed into a csv which is placed in your user’s profile. Remember if you’re running as a domain admin, the csv file will be located in the domain admin user’s profile, not yours!

Reviewing the Results

Note: You must not open this file while the script is still running. This will prevent the script being able to write to it as excel takes ownership of it.

Open the CSV file up in excel and format it so it is easier to read. All the software will be listed in order along with which computer the application is installed on. Any PC’s that have any problems with WMI will not be able to perform the audit, however in a healthy windows domain all PC’s should be able to respond to WMI queries.



Script Requirement

To be able to query a PC's software you need the Management and Monitoring Tools --> WMI Windows Installer Provider windows component installed from add and remove windows components. This feature is automatically built into windows vista, 2008 and windows 7. If this is not installed the script will return the following error:



You will also recieve errors when you perform manual WMI queries related to software against these machines that do not have this component:



Don't worry I wrote up a blog post on this problem and have developed a way to mass deploy this windows component out to all PC's your trying to audit. Find this here:

http://clintboessen.blogspot.com/2009/11/wmi-error-invalid-class-0x80041010-fix.html

Copy of the Script

Here is the full copy of my script:

$datetime = Get-Date -Format "yyyyMMddhhmmss";
$strCategory = "computer";

# Create a Domain object. With no params will tie to computer domain
$objDomain = New-Object System.DirectoryServices.DirectoryEntry;

$objSearcher = New-Object System.DirectoryServices.DirectorySearcher; # AD Searcher object
$objSearcher.SearchRoot = $objDomain; # Set Search root to our domain
$objSearcher.Filter = ("(objectCategory=$strCategory)"); # Search filter

$colProplist = "name";
foreach ($i in $colPropList)
{
$objSearcher.PropertiesToLoad.Add($i);
}

$colResults = $objSearcher.FindAll();


# Add column headers
Add-Content "$Env:USERPROFILE\softwareaudit $datetime.csv" "Computer,Caption,Description,Identifying Number,Installation Date,Installation Date 2,Installation Location,Installation State,Name,Package Cache,SKU Number,Vendor,Version";

foreach ($objResult in $colResults)
{
$objComputer = $objResult.Properties;
$computer = $objComputer.name;

$ipAddress = $pingStatus.ProtocolAddress;
# Ping the computer
$pingStatus = Get-WmiObject -Class Win32_PingStatus -Filter "Address = '$computer'";

if($pingStatus.StatusCode -eq 0)
{
Write-Host -ForegroundColor Green "Ping Reply received from $computer.";

write-host "Connecting to $computer..."

$colItems = get-wmiobject -class "Win32_Product" -namespace "root\CIMV2" `
-computername $computer

write-host "#############################"
write-host "Computer: " $computer
write-host "#############################"
write-host
write-host

foreach ($objItem in $colItems)
{
write-host "Caption: " $objItem.Caption
$caption = $objItem.Caption
write-host "Description: " $objItem.Description
$description = $objItem.Description
write-host "Identifying Number: " $objItem.IdentifyingNumber
$identifier = $objItem.IdentifyingNumber
write-host "Installation Date: " $objItem.InstallDate
$installdate = $objItem.InstallDate
write-host "Installation Date 2: " $objItem.InstallDate2
$installdate2 = $objItem.InstallDate2
write-host "Installation Location: " $objItem.InstallLocation
$installlocation = $objItem.InstallLocation
write-host "Installation State: " $objItem.InstallState
$installstate = $objItem.InstallState
write-host "Name: " $objItem.Name
$name = $objItem.Name
write-host "Package Cache: " $objItem.PackageCache
$packagecache = $objItem.PackageCache
write-host "SKU Number: " $objItem.SKUNumber
$skunumber = $objItem.SKUNumber
write-host "Vendor: " $objItem.Vendor
$vendor = $objItem.Vendor
write-host "Version: " $objItem.Version
$version = $objItem.Version
write-host

# Need to add in a special character for " as some of the values from the WMI query has commers in them that mess up the csv file
$sc = [char]34

Add-Content "$Env:USERPROFILE\softwareaudit $datetime.csv" "$sc$computer$sc,$sc$caption$sc,$sc$description$sc,$sc$identifier$sc,$sc$installdate$sc,$sc$installdate2$sc,$sc$installlocation$sc,$sc$installstate$sc,$sc$name$sc,$sc$packagecache$sc,$sc$skunumber$sc,$sc$vendor$sc,$sc$version$sc"
}
}
else
{
Write-Host -ForegroundColor Red "No Ping Reply received from $computer.";
}

}


It automatically pulls the domain information from the local computers domain membership.

Deleting old Computer Accounts

If you find there are hundreds of computer accounts that are no longer in use, and the script is sitting there pinging computer account after computer account taking ages to move through the list you may want to clean up old computer accounts in active directory.

To find all computers that have been inactive for the last four weeks and remove them run the following command on a domain controller:

dsquery computer -inactive 4 | dsrm