Goatee PFE

Blog of Microsoft Premier Field Engineer Ashley McGlone featuring PowerShell scripts for Active Directory.

Use PowerShell to Find Windows XP Computers Still Alive in Your Active Directory Domain

Use PowerShell to Find Windows XP Computers Still Alive in Your Active Directory Domain

  • Comments 8
  • Likes

PS PSA – PowerShell Public Service Announcement

Windows XP

Usually I like to offer deep technical content on the blog, but today I’m going to keep it simple. Everyone should be keenly aware that Windows XP support officially ends on April 8, 2014. Many companies are migrating from Windows XP and need a quick script to check their progress. This is a simple solution with a couple variations to meet your needs.

Get-ADComputer

If you have tinkered at all with the AD PowerShell module, then this cmdlet should be familiar to you. Lucky for us Active Directory tracks the operating system of computers. Listing all the Windows XP computers in the domain can be as simple as this:

PS C:\> Import-Module ActiveDirectory
PS C:\> Get-ADComputer -Filter {OperatingSystem -like "*XP*"}

It is worth noting that the OperatingSystem attribute is not stored in the global catalog, so you will need to query each domain separately.

Beyond the basic attributes returned in the default set it would be nice to see date stamp fields that can help us determine if the Windows XP computer account is still active.  In a previous post I discussed some tips on working with date fields in AD, and we’re going to use that technique here.  We’ll also snag the relevant operating system attributes. Notice that I’m not using the infamous “-Properties *” option. For efficiency I list only the specific fields that I want to query and display. Finally, I’ve thrown in some PowerShell magic to grab the owner recorded on the account.

PS C:\> $XP = Get-ADComputer -Filter {OperatingSystem -like "*XP*"} `
    -Properties Name, DNSHostName, OperatingSystem, `
        OperatingSystemServicePack, OperatingSystemVersion, PasswordLastSet, `
        whenCreated, whenChanged, LastLogonTimestamp, nTSecurityDescriptor, `
        DistinguishedName |
    Select-Object Name, DNSHostName, OperatingSystem, `
        OperatingSystemServicePack, OperatingSystemVersion, PasswordLastSet, `
        whenCreated, whenChanged, `
        @{name='LastLogonTimestampDT';`
          Expression={[datetime]::FromFileTimeUTC($_.LastLogonTimestamp)}}, `
        @{name='Owner';`
          Expression={$_.nTSecurityDescriptor.Owner}}, `
        DistinguishedName

Next we will insert a Where-Object in the middle of the pipeline to restrict the output to only machines that have been active in the last 90 days.  We do this by filtering on the whenChanged attribute.  This date is updated anytime the AD computer object is updated for any reason.  It is a shortcut to checking account staleness. Adjust this number to your needs.

PS C:\> $XP = Get-ADComputer -Filter {OperatingSystem -like "*XP*"} `
    -Properties Name, DNSHostName, OperatingSystem, `
        OperatingSystemServicePack, OperatingSystemVersion, PasswordLastSet, `
        whenCreated, whenChanged, LastLogonTimestamp, nTSecurityDescriptor, `
        DistinguishedName |
    Where-Object {$_.whenChanged -gt $((Get-Date).AddDays(-90))} |
    Select-Object Name, DNSHostName, OperatingSystem, `
        OperatingSystemServicePack, OperatingSystemVersion, PasswordLastSet, `
        whenCreated, whenChanged, `
        @{name='LastLogonTimestampDT';`
          Expression={[datetime]::FromFileTimeUTC($_.LastLogonTimestamp)}}, `
        @{name='Owner';`
          Expression={$_.nTSecurityDescriptor.Owner}}, `
        DistinguishedName

Once we have our results in a variable, $XP, we can work with the output a number of ways: display it in a handy gridview, export it to CSV, or get a count of active XP machines.

PS C:\> $XP | Out-GridView
PS C:\> $XP | Export-CSV .\xp.csv
PS C:\> ($XP | Measure-Object).Count

I have posted the script samples above over at the TechNet Script Gallery for you to download and modify to your needs.

How much time do I have?

You may be curious how to calculate the number of support days remaining. The cmdlet New-Timespan makes this easy:

PS C:\> (New-TimeSpan -End (Get-Date -Day 8 -Month 4 -Year 2014 `
    -Hour 0 -Minute 0 -Second 0)).TotalDays

Windows XP Migration Resources

Here is a list of related resources for Windows XP end-of-life:

Support for Windows XP and Office 2003 ends (including countdown timer)
http://www.microsoft.com/en-us/windows/business/retiring-xp.aspx

Microsoft Security Essentials ends for Windows XP
http://windows.microsoft.com/en-us/windows/end-support-help

Windows XP to Windows 7 Migration Guide
http://technet.microsoft.com/en-us/windows/ee150430

Windows 8.1 Migration Resources
http://technet.microsoft.com/en-us/windows/hh771457

Windows XP end of support enterprise resources
http://www.microsoft.com/en-us/windows/enterprise/endofsupport.aspx

Jumpstart your Windows XP Migration with the help of Microsoft Services
http://www.microsoft.com/en-us/microsoftservices/windows_xp_migration_jumpstart_service.aspx

Attachment: Get-XP.ps1

Can you help me?  Yes!

If you would like to have me or another Microsoft PFE visit your company and assist with the ideas presented in this blog post, then contact your Microsoft Premier Technical Account Manager (TAM) for booking information.

For more information about becoming a Microsoft Premier customer email PremSale@microsoft.com.  Tell them GoateePFE sent you.

Sharing Links
Comments
  • Is LastLogonDate not the already-prettified version of LastLogonTimestamp?

  • Here is a classic article that explains the nuances of LastLogonTimeStamp that I used in this one-liner.
    http://blogs.technet.com/b/askds/archive/2009/04/15/the-lastlogontimestamp-attribute-what-it-was-designed-for-and-how-it-works.aspx

  • When I use the variable $XP, the lastlogontimestamp isn't included in the .csv, but it displays when I don't use the variable and displays on the screen.

  • Hi Brian, I would need to see your code to understand why this is happening.

  • Hi Ashley, thanks for this post. This has been a big help for a non-code expert guy like me, appreciate much ;-) Anyway, just a quick query. Isn't it better to use "LastLogonDate" in the where_object line instead of the "whenChanged"? I tried to use LastLogonTimestamp but it returns a lot of error due to conversion I think. Also, the description of this attribute seems does not fit as well for our need since its an "older value" as described by Microsoft.
    -> http://msdn.microsoft.com/en-us/library/ms676824(v=vs.85).aspx

    In the same manner, I tried to use LastLogon (I believe this should be the best attribute we need) but the returned values are not in a date format even I changed the format settings in the Excel/CSV output file.
    -> http://msdn.microsoft.com/en-us/library/ms676823(v=vs.85).aspx

    As the word suggest and as per the link below, "whenChanged" is the attribute if there are any changes only on that object. Thus, it cannot be incorporated with the last logon of that object from my perspective.
    -> http://msdn.microsoft.com/en-us/library/ms680921(v=vs.85).aspx

    I tried to add "LastLogonDate" attribute (though this term is not specifically one of the official attributes in the object Properties) in the properties portion and use it as well in the where_object portion. I've got the output and seems to be acceptable from my analysis.

    Will highly appreciate your inputs on this action. Hope you can copy my personal email on your feedback: ail.lara@yahoo.com.

    Thanks in advance.

  • Helpful, thanks a bunch! :)

Your comment has been posted.   Close
Thank you, your comment requires moderation so it may take a while to appear.   Close
Leave a Comment