The Windows Experience Index and PowerShell

I thought that the Windows Experience Index was pretty useless until I wanted to compare the speed of systems that I was preparing to donate.  One had Windows 7, the other was a lab PC running Windows 8.1.  I was surprised to find that I could not find the Windows Experience Index (WEI) on the Win 8.1 computer.  The WEI is calculated by Windows using the Windows System Assessment Tool (WSAT), (see: for a good overview).  The attached script requires PowerShell 3, and so run natively on Windows 8 and 8.1. What it does is permits you to see your current WEI for your Windows 8.1 computer.  This is written for people with an understanding of PowerShell.  If you have your execution policy set to unrestricted, you may find that Get-WINSATScore.ps1 is easiest to run from the ISE.

Delete Inactive User Profiles with PowerShell

Written to replace DelProf, this script deletes inactive user profiles from a local or remote computer.  It supports arguments by position, and has a test parameter.  If you run it locally, you may supply host name, localhost or “.” The logfile is tab delimited, you may use XLS extension to open in Excel.  If you run the script interactively the log opens when the action is complete.  This is written to be loaded with “dot sourcing”, ex:

PS C:\>. "c:\mypsscripts\Delete-InactiveProfiles.ps1"

After you have loaded the module you can use Get-Help Delete-InactiveProfiles.ps1 for more information on syntax.

Delete-InactiveProfiles.ps1 is heavily commented so you can see what it is doing.  I am using WMI to get the list of local users, and query NTUser.DAT for last logon time.  Remember to rename from Delete-InactiveProfiles_ps1.txt to Delete-InactiveProfiles.ps1.

Get User’s Email Address from SmartCard with PowerShell

Someone asked me whether I could pull the email address of a user from an inserted SmartCard.  I knew I could dump the information in Windows 7 using the CertUtil command and wanted to experiment with parsing information with PowerShell.  The code can be very compact:

$certInfo = certutil -scinfo -silent  | Select-String -Pattern "RFC822" | Get-Unique
$UPN =  $certInfo.ToString().Replace("SubjectAltName: RFC822 Name=","").trim()


In the first line the command output from certutil -scinfo -silent  is piped to Select-String.  The pattern pulls out lines with “RFC822″.  Since we all know that the RFC822 Name is the email address we are pulling out lines with that info from the output.  Then we select unique results only.  Happily that gives us one line with the email address together with the other information on the line.  In line 2 we are using Replace to delete the extra text, and Trim to remove the leading and trailing spaces.  All in all, a pretty neat demonstration of the power of PowerShell.

Enabling ISE and ActiveDirectory module on Windows 2008 R2 Member Server

So, I wrote a pretty cool script and sent it to a co-worker.  I wrote it on a Windows 7 PC with the RSAT tools installed.  My friend tried to run it on a 2008 R2 server with PowerShell 3.0, but the ActiveDirectory module would not load.  I tried to edit the script, but ISE would not load.  After some research, I found a couple of one-liners:

#Installs AD Module and ISE on 2008 R2 server
import-module servermanager
add-WindowsFeature PowerShell-ISE
add-WindowsFeature RSAT-AD-Tools

For me the RSAT tools required a reboot.  It is not clear to me whether the ISE also requires a reboot.

Manage Nework Recycle Bin Size

If you redirect the Documents folder (or My Documents on XP) to a network drive, an instance of the Recycle Bin is created on the user’s home directory.  And, because the default size for the Recycle Bin is 10% of available space, you can end up with a huge amount of space chewed up by these hidden folders.

NetBinCleanup.vbs is based on a PowerShell script (  I decided to use it as an guideline for a vbscript which would only delete aged items on network based Recycle Bins.  Why vbscript?  Because in my environment, vbscript is easier to deploy an run on all computers than PowerShell.

There are some interesting things in the script, such as the StripHigh function which removes high ASCII and strips Unicode from a string.  The author of the PowerShell script suggest running the cleanup at logoff, but I suggest running it at logon with the command start /b cscript.exe netbincleanup.vbs.  If you set this as a logoff script, you will may delay logoff for an annoying amount of time.

I have hardcoded the retention days at 7 days as a constant in the script.  There is also a test variable which you can set to popup the results of the script.  I am sure that you would never put into production something you had not read an tested — so I put a lot of comments in this file to make clear what is going on.

Note:  The original version only deleted files.  The updated version of  NetBinCleanup.vbs adds deletion of recycled folders, too.

Windows 8: Change Network Connection Profile From Public To Private

Did you accidentally set you home network to connection profile to “Public”?  Windows 8 has a real easy way to change it to Private using PowerShell:

Get-netConnectionProfile | set-NetConnectionProfile  -NetworkCategory Private

If you are currently “Private” and want to change to “Public”: 

Get-netConnectionProfile | set-NetConnectionProfile  -NetworkCategory Public

I never did figure out how to do this from the Windows 8 GUI.

Convert data from Get-ADUser and Get-ADComputer for Export-CSV

If you have been following my blog, you know that I am an experienced vbscripter, but am relatively new to PowerShell.  I was excited that my long vbscripts to export data from Active Directory would be now one liners which I could send to a CSV file with the Export-CSV cmdlet.   Unfortunately, I found that getting the data I wanted was not as easy as I expected.  There is no automatic way of handling the different date strings in Active Directory.  And, although some of the data looked okay when output to the screen, values stored other than a simple string often gave me results like “Microsoft.ActiveDirectory.Management.ADPropertyValueCollection”.

Because of these issues, I set out to create my first PowerShell function.  My goals were to write something that I could use every day which would take the output of Get-ADUser,  Get-ADComputer and other Get-AD* cmdlets within the ActiveDirectory module and convert the data to strings which would properly output to Export-CSV.  As far as I can tell from my internet search, no one has written such a PowerShell function.   And, of course, the best way to learn a new programming language is to have a real project instead of just exercises.

I had some help with direction by the Scripting Guy himself, Ed Wilson.  I have been truly fortunate to be a member of a PowerShell user group with him as a member and regular speaker.  (For more about Ed and the group, read my previous post.)  Some of my discussion with Ed led to Scripting Guy articles about Active Directory and Export-CSV. Some of the code he sent me prior to the publication of these articles sent me on the right track to create Convert-ADValues.ps1.

Convert-ADValues pre-processes the output of the AD cmdlets, such as Get-ADUser and Get-ADComputer so that the output works with Export-CSV.  All dates appear properly.  ProxyAddresses and PostalAddress appear properly.  Binary data appears a a comma delimited string.

Example 1:
$u = Get-ADUser -Filter {surname -eq “smith”} -properties *
Convert-ADValues $u

Example 2:
$u = Get-ADUser -Filter {surname -eq “smith”} -properties *
$u | Convert-ADValues | Export-CSV -notypeInformation -Path $env:userprofile\desktop\ADInfo.csv

Example 3:
Get-ADComputer -Identity $env:COMPUTERNAME -Properties * |Convert-ADValues

To learn about running scripts and “dot sourcing”, examine the basics here.  I hope the comments within the script are adequate to explain what is being done.  Don’t hesitate to comment or email me with questions.

Updated 8-6-13. I fixed handling of binary, null and empty values, arrays in item, and changed delimiter to semi-colon for values with commas.  And yes, it isn’t pretty.
Updated 1/1/14. I added a switch for enumerating ACLs for the nTSecurityDescriptor attribute, changed names of variables away from users, improved comment based help.
Updated 1/2/14   Removed write-host of Security type added while debugging. Added Online Help.  Moved Load-Module ActiveDirectory to Begin statement, clarified Help to make clear that you must return nTSecurityDescriptor for it to be expanded with -GetSecurity. Removed return of PropertyNames and PropertyCount unless you use ReportPropertyNamesAndCount parameter. Changed output type to PSObject from Array. Added Requires statement for Version 3.