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.

Batch File to Prestage a Computer Account

Batch files are not dead.  Microsoft has said that batch files, and vbscript will be supported into the indefinite future.  And I still write an occasional batch file because the really are quick and easy.  I use the .CMD extension, instead of .BAT, but it does not really matter in execution.

Recently I was asked to write something that would allow for prestaging a computer account in Active Directory.   The code works but is painfully slow.  Still, you may find it useful in your environment.  You could use it with a FOR command to run it against a list of machines overnight:

@echo off
:: Alan Kaplan, loosely based on 
:: ************* mandatory edits here ******************
rem omit LDAP://
set NewPCOU=OU=Windows 7,OU=Test Lab,DC=contoso,DC=com
rem this is the group to grant permission to join
:: ********** end edits ******************************

if %1z == z echo PC Accounts will be added to "%NewPCOU%"
if %1z == z echo Granting permissions to %UserOrGroup%
if %1z == z set /p PCName=Add what computer account? &goto AddPC
set PCName=%1

set ComputerDN=cn=%PCName%,%NewPCOU%
dsadd computer "%ComputerDN%"
Echo Granting Permissions to %UserOrGroup%

REM full control of object.  This is really slow ....
dsacls "%ComputerDN%" /G %UserOrGroup%:GA

REM specific join computer rights
REM This is 6 times slower than full control
REM dsacls "%ComputerDN%" /G %UserOrGroup%:CALCGRSDDTRC;;
REM dsacls "%ComputerDN%" /G %UserOrGroup%:WP;description;
REM dsacls "%ComputerDN%" /G %UserOrGroup%:WP;sAMAccountName;
REM dsacls "%ComputerDN%" /G %UserOrGroup%:WP;displayName;
REM dsacls "%ComputerDN%" /G %UserOrGroup%:WP;userAccountControl;
REM dsacls "%ComputerDN%" /G %UserOrGroup%:WS;"Validated write to service principalname";
REM dsacls "%ComputerDN%" /G %UserOrGroup%:WS;"Validated write to DNS host name";

echo %PCName% added to %NewPCOU%
echo Granted permissions to %UserOrGroup% 
echo %NewPCOU%


You will need to edit the script to make it work.  I have set it to Full Permissions, but as  you can see, you can switch to more granular permissions.