Saturday, June 18, 2011

Managing lots of Cisco consoles from one location

Repost from old blog

Any who. The issue: Lets say you have 16 or so Cisco devices (extreme works also) that connect to various parts of your network. Now you want to be able to manage these devices remotely but not make a huge security hole using Vlans and attempting to keep it all secure with ACLs.

So the easy way is to do all the management via the console port. No ACLs to worry about and easier to secure.

So I have 16+ Cisco devices from Routers to switches (2950s, 3550s, 2621s, 2651s, 3750s, 4912s and even an AS5300) all in my lab. So with all those in my lab I got myself a DIGI portserver TS 16 Rack mount device (we use them for kernel debugging also). With a special digi to cisco cable (yes I will give you the pin-outs if you want them) I connect each cisco's console port to the digi and then the DIGI's Ethernet port to my "management network". The management network is where my management workstation lives.

The digi device will let you telnet or ssh (SSH is better) into it. Then from there connect to each of its ports (using the connect command). Now where the fun comes in is how to setup the DIGI to talk to the cisco. Then create a menu so you dont alway have to know the port number each device is connected to.

So below are the steps to allow you to connect the DIGI to the cisco (once you have the cable).
1.Make sure your device is up to date. I am using 82000685_E.bin and 82000684_L.bin
2.Know your port numbers (we are going to use ports 1-16)
3.Set the port type to printer (set ports range=1-16 dev=prn)
4.set the ip on your digi (set config dhcp=off ip= submask=)

At this point you should be able to use "connect 1" and connect to port 1. A few hits of the enter key and it should show you the cisco console.

Now we need to secure the device a little more by turning off things that are not needed. This will leave only telnet and ssh on (I would turn off telnet also but if you dont have an ssh client then it is kinda hard to use).
1.set secureaccess http=off snmp=off rlogin=off rsh=off https=off realport=off securerealport=off
2.set secureaccess reversessh=off securesockets=off reversetcp=off reversetelnet=off

We need to make our menu before we assign a user to use it. This will be an example of ports 1-3 with a title bar
1.set menu range=1 t1="Cisco management" t2="Make sure you save!" name=menu1
2.set menu range=1 m1="cisco 1" c1="connect 1"
3.set menu range=1 m2="cisco 2" c2="connect 2"
4.set menu range=1 m3="cisco 3" c3="connect 3"

Now lets make a user that we will connect with to see our menu
1.set user name= defaultaccess=menu menu=1

Set the password for our new digi user
1.newpass name=

Now a little know tip. When use the default escape char with digi it will leave the port open and not let you reconnect until you do a kill tty= (you can see the ttys by running the 'who' command). But if you use the escapekill command (default is a . (that is a period)) then it will close the tty when you escape. So the default escape command is "+]" . Now add a period after that and hit enter and you will kill the connection not just disconnect so a "+].". Now you press the control and ] key in one key stroke then the period in another.

Now you should be able to telnet or ssh into your ip and get a menu. Press 1 to connect cisco 1, 2 to connect to cisco 2, and 3 to connect to cisco 3.

How great!

Disk Quota and .net (WMI and Microsoft.DiskQuota.1)

Repost from old Blog

Today I had a con-call to talk about disk quota and how to automate the setting and reading of Quota. So i thought that I would post a little about Disk quota stuff.

There are 2 okay options.

#1 WMI (way to slow for a lot of things (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/wmisdk/wmi/disk_quota_provider.asp))

#2 Microsoft.DiskQuota.1

So my team needed a way to enumerate a users current quota limits and then + or - from them. WMI was very slow to do this. But DiskQuota.1 is quite fast. It is not well documented that it works on remote servers either. So I wrote a little something up.

So here is some cs (and vb.net) that has functions on how to get and set quota info with Microsoft.diskquota.1

CSharp: http://dl.dropbox.com/u/3275573/blog/QuotaFunctions.cs.txt
VB.NET: http://dl.dropbox.com/u/3275573/blog/QuotaFunctions.vb.txt

Regular Expressions and IP addresses (ipv4 and IPv6)

Repost from old blog

Over the last year or so I have been writing automation that uses IPv4 and IPv6 addresses. In the beginning I had to dig up and make some regular expressions for verifying that a given value was a valid IPv4 or IPv6 address.

The ones I came up with are (in VB.net)

Const strIPv4Pattern as string = "\A(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\z" 'IPv4 Address Regex pattern (x.x.x.x)

Const strIPv6Pattern as string = "\A(?:[0-9a-fA-F]{1,4}:){7}[0-9a-fA-F]{1,4}\z"

Const strIPv6Pattern_HEXCompressed as string = "\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)::((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?)\z"

Const StrIPv6Pattern_6Hex4Dec as string = "\A((?:[0-9A-Fa-f]{1,4}:){6,6})(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\z"

Const StrIPv6Pattern_Hex4DecCompressed as string = "\A((?:[0-9A-Fa-f]{1,4}(?::[0-9A-Fa-f]{1,4})*)?) ::((?:[0-9A-Fa-f]{1,4}:)*)(25[0-5]|2[0-4]\d|[0-1]?\d?\d)(\.(25[0-5]|2[0-4]\d|[0-1]?\d?\d)){3}\z"

Now because an IPv6 address can take a few forms we have 4 different expressions for IPv6. If someone finds a bug in one of these please let me know. Because RegExp is something that I am not good at.

Hope these will help some one.

IPv6 6over4 tunnels with Windows and Cisco

Repost from old blog
A few years ago I began working with Art Shelest here at Microsoft to get Native IPv6 running in my lab.  After a few weeks we had it up and running. 
We had to work with MSIT (was known as ITG at the time) to get a 6over4 tunnel setup so that we could connect to the 6bone even though my upstream routers did not support IPv6 (still don't at this time).  Once the tunnel was setup on the ITG Router we ran a command on my Windows IPv6 Router in my lab and it was up and running. 
We run our entire lab IPv6 network on Windows Routers.  We use Windows Server 2003 but you could use Windows XP Pro if you wanted.  Unlike RRAS the IPv6 routing stack is included in Windows XP.  And after Windows XP SP1 this stack was fully supported by Microsoft support.  So if you follow the steps at http://www.microsoft.com/resources/documentation/windows/xp/all/proddocs/en-us/sag_ip_v6_imp_lab_node.mspx you can get your internal test network setup.
Now to create a 6over4 tunnel to another router you simply run the below commands from a cmd prompt on your main IPv6  router
  1. netsh
  2. int ipv6
  3. add v6v4tunnel interface="V6v4 Tunnel" localaddress=<local ipv4 address> remoteaddress=<remote ipv4 address>
  4. set interface "v6v4 Tunnel for=en
  5. add address int="v6v4 tunnel" address=<IPv6 address from provider>
  6. add route ::/0 "v6v4 tunnel" <remote IPv6 address> publish=yes
Key things to note with the above
  • The Local IPv4 address is the IP address that the tunnel is going to use to talk to the Upstream V6 Router (With my example below it would be 1.1.1.1). 
  • The Remote IPv4 Address is the IP address of the upstream V6 router (with my example below it would be 2.2.2.1).
  • The IPv6 address from provider would be a IPv6 address that you get from your v6 provider (with my example below it would be 3ffe:ffee:100:2::2)
  • The Remote IPv6 address is the IPv6 address of the upstream IPv6 router (with my example below it would be 3FFE:FFEE:100:2::1)
The Cisco side of the config looks like this
interface Tunnel1
 description v6in4 tunnel to  lab 1.1.1.1/3FFE:FFEE:100:2::2
 no ip address
 ipv6 address 3FFE:FFEE:100:2::1/64
 tunnel source 2.2.2.1
 tunnel destination 1.1.1.1
 tunnel mode ipv6ip



Once the machines are all setup important things to know are "how do you back up your ipv6 configuration?" Well with netsh it could not be easier.
Simply run 'netsh int ipv6 dump > c:\ipv6backup.txt'  this will dump all the ipv6 config out to the txt file.  Now if the router was to ever go down you can run the command  'netsh exec c:\ipv6backup.txt'.   With these 2 commands it will backup and restore your ipv6 configuration..  You can also modify the backup command to be 'netsh dump > c:\netshbackup.txt' and it will back up 99% of all the settings for your network configuration.
If you would like to know more about how I have my IPv6 network setup please let me know.  Also I recommend the Microsoft Press Book Understanding IPv6 (http://www.microsoft.com/MSPress/books/4883.asp) ISBN: 0-7356-1245-5

How does IIS generate the Site ID?

Repost from old blog

So in IIS 6 (and maybe IIS 7) when you create a new site programmatically you have the option to specify a SiteID or you can let IIS 6 do it for you. 

If you let it do it for you it will make this kinda hash of the site name.  You have to use this ID when you are doing any modifications to the site (programmatically).  So it would be the value in IIS://<servername>/W3SVC/<SiteID>

So how do you get the SiteID?

  • Well you could create the site then enumerate it from WMI or ADSI. 
  • Use my little c# function below to generate the sitename

 



public static uint GenerateSiteID(string SiteName)
{
uint id = 0;
char[] arr = SiteName.ToCharArray(); //Convert the sitename to a Char Array
for (int i = 0; i < arr.Length; i++)
{
char c = arr[i];
int intc = c;

int upper = intc & '\x00df'; //Upper case the letter
id = (
uint)(id * 101) + (uint)upper;
}
return (id % Int32.MaxValue) + 1; //do a MOD and add 1
}

Now a good thing to remember is that this might not be the sitename the IIS is using.  If there is a SiteID collision then IIS will try to move the ID up by 1 digit then try again.  So dont let this be the end all be all of how this is determined. 

Using the code above is much faster then parsing through all the sites via ADSI or WMI to get the siteID.  So if you have 2000 sites on a server the site was created most recently (bottom of the Metabase) will take longer to query for then the first site created (top of the metabase). 

Also note that if you try to convert this code to VB.net you will get an exception becasue VB.net does more bounds checking.

How to speed up Queries to MicrosoftDNS with WMI

Repost from old blog

So there are many key things to remember when creating your WMI queries make them as specific as you can.

For example if you have ~5000 zones on your Microsoft DNS server and you are looking to see if a single record exists in one of those zones the wrong query could take 1 min+ to complete.

Why?

If you do a query like Select * from MicrosoftDNS_AType where ownername="www.mydomain.com" it is going to take a while. Because you did not specify where to look for this record it is going to look in the RootHints and in the DNS Cache also. So if you have a public DNS server that does recursive lookups it could have a few hundred thousand extra records.

So a better query would be Select TextRepresentation from MicrosoftDNS_AType where containername="mydomainname" and domainname="mydomain.com" and ownername=www.mydomain.com

You can use a vbscript like the one below to test your queries. This will show you the correct domainname and other settings to use in your query. You can remove the where clause to show all the data on the server.

The containername will be the name of the zone that holds the records that you want to query for (Ie mydomain.com). If you leave the containername empty it will also search through the DNS cache.

The domainname specifies the child folder (don’t know how else to describe it). So if you have www.user.mydomain.com the domainname is user.mydomain.com

Now the domainname will change depending on if there are sub domains to the subdomain (ie www from example above). So if www does not exist then the domainname is mydomain.com. And of course there are exceptions to this rule. If there ever was a child to the sub (you deleted www but left user.mydomain.com) then the domainname is user.mydomain.com. If you don’t want to attempt to do the logic around making sure you have the correct domainname you can omit it. But if you have a large number of records it could make it slow.

Like SQL the order of the statements in the query is also important.

If you know the full record info (hostname, TYPE, data) it is fastest to generate the text representation and query on that. You can do that by adding changing your query to something like:

Select * from MicrosoftDNS_AType where containername=”test.com” and domainname=”test.com” and TextRepresentation="test.com IN A 192.168.0.1"



on error resume next
servername = "."
domainname = "test.com"

recordtype = "A"

set dnsserver = Getobject("winmgmts:{Authenticationlevel=pktPrivacy}!\\" & servername & "\root\MicrosoftDNS")

query = "Select * from MicrosoftDNS_" & recordtype & "Type where containername=""" & domainname & """"
wscript.echo "Query=" & query

Set colItems = dnsserver.ExecQuery(query,,48)
if colitems.count <> 0 then
For Each objItem in colItems
Wscript.Echo "ContainerName: " & objItem.ContainerName
Wscript.Echo "DnsServerName: " & objItem.DnsServerName
Wscript.Echo "DomainName: " & objItem.DomainName
Wscript.Echo "OwnerName: " & objItem.OwnerName
Wscript.Echo "PrimaryName: " & objItem.PrimaryName
Wscript.Echo "RecordClass: " & objItem.RecordClass
Wscript.Echo "RecordData: " & objItem.RecordData
Wscript.Echo "TextRepresentation: " & objItem.TextRepresentation
Wscript.Echo "Timestamp: " & objItem.Timestamp
Wscript.Echo "TTL: " & objItem.TTL
Next
end if

L2TPv3 performance tweaks for HyperV GeoCluster Live Migration

L2TPv3 is a great feature for extending a Layer2 network across sites. This is very useful when you are using Live Migration with HyperV or when you want to pass traffic (at Layer 2) to a different location. 
 
Recently while working on a SAN GeoClustering test case we want to do a stretched VLan from one lab to another (in different buildings). This gets tricky because we (my team) don’t own or manage the network infrastructure between these buildings. Many companies will use MPLS/VPLS to create a VPN or VLL (Virtual Leased Line) between two sites. This can be expensive and a pain to get setup if you only need a link for a short period of time.
 
Stretched VLans are becoming more and more common as feature like Live Migration allow the moving of a system from one datacenter to another at the push of a button (well mouse clicks). 
 
The setup:
Sites: We were testing at labs that are about &frac14; of a mile apart from each other on opposite sides of Main Campus
 
The test network consisted for 4 vlans. These networks were duplicated at both sites
·         Public -- internet facing for request to HyperV hosted servers
·         Cluster – heartbeat network for Fail over Cluster
·         Live Migration – network to pass server state during live migration
·         Management – backend network to access remove desktop to servers and devices
 
Servers: We had 6 physical servers for the test (3 at each site). Each site had the same setup for servers
·         Server 1 – Host infrastructure systems (AD, DNS, DHCP, WDS)
·         Server 2 &3 – Fail over cluster hosts that would host the workload VMs
 
To interconnect the 4 vlans across buildings we uses the existing IPv4 infrastructure and 2 cisco routers. The building infrastructure offers > 1gbps in an out of each lab, so we connected with 1gig interfaces to uplinks. We also do not have visibility into MTU on building (intra and inter) infrastructure.
 
So down to what we found and what we changed:
Original Setup (poor performance): - config shown below
·         Single L2TPv3 Tunnel between sites
·         Lab facing interfaces were connected to switch that was a trunk port allowing our 4 VLans
          o   Switchport mode trunk
Original design findings:
·         Traffic passed (with 802.1q tags) correctly through tunnel
·         MAX bandwidth when coping files/Live Migration from site to site was 20-30mbps
·         Large amount of dropped packets in queue
·         CPU maxed at 100%
 
Tweaked design (best performance)
·         4 tunnels (one for each vlan) using sub interfaces
·         No change to switch trunk config
·         Modified hold-queue on each physical interface
·         Enabled MTU tuning on pseudowire-class (ip pmtu)
·         Enabled Don’t Fragment bit on pseudowire-class (ip dfbit set)
Tweaked design Findings:
·         Traffic passed correctly through tunnel
          o   Each VLan correctly mapped on either side
·         MAX bandwidth when coping files/Live Migration from site to site was ~800mbps
·         CPU would be around 40%
 
Original Config (each site was identical except swapped xconnect ip with interface ip address) – SLOW!
---
l2tp-class class1
authentication
password 0 123456789
!
pseudowire-class ethernet
encapsulation l2tpv3
protocol l2tpv3 class1
ip local interface GigabitEthernet0/1
!
interface GigabitEthernet0/0
no ip address
duplex full
speed auto
no cdp enable
xconnect 10.216.44.47 125 pw-class ethernet
!
interface GigabitEthernet0/1
ip address 10.197.251.215 255.255.255.240
duplex auto
speed auto
no cdp enable
!
ip route 0.0.0.0 0.0.0.0 10.197.251.209
!
no cdp run
!
End
 
Tweaked Design
--
l2tp-class class1
authentication
password 0 123456789
!
pseudowire-class ethernet
encapsulation l2tpv3
protocol l2tpv3 class1
ip local interface GigabitEthernet0/1
ip pmtu
ip dfbit set
!
interface GigabitEthernet0/0
no ip address
duplex full
speed auto
no cdp enable
hold-queue 2048 in
hold-queue 2048 out
!
interface GigabitEthernet0/0.2996
encapsulation dot1Q 2996
no cdp enable
xconnect 10.216.44.47 126 encapsulation l2tpv3 pw-class ethernet
!
interface GigabitEthernet0/0.2997
encapsulation dot1Q 2997
no cdp enable
xconnect 10.216.44.47 127 encapsulation l2tpv3 pw-class ethernet
!
interface GigabitEthernet0/0.2998
encapsulation dot1Q 2998
no cdp enable
xconnect 10.216.44.47 128 encapsulation l2tpv3 pw-class ethernet
!
interface GigabitEthernet0/0.2999
encapsulation dot1Q 2999
no cdp enable
xconnect 10.216.44.47 125 encapsulation l2tpv3 pw-class ethernet
!
interface GigabitEthernet0/1
ip address 10.197.251.215 255.255.255.240
duplex auto
speed auto
no cdp enable
hold-queue 2048 in
hold-queue 2048 out
!
ip route 0.0.0.0 0.0.0.0 10.197.251.209
!
no cdp run
!
 

Programmatically Controlling Pioneer Receivers and BluRay Players

I recently got a new Pioneer Elite SC-35 receiver (http://www.pioneerelectronics.com/PUSA/Products/HomeEntertainment/AV-Receivers/EliteReceivers/ci.SC-35.Kuro).  This receiver has an ethernet plug on the rear and is supported by the iPhone/iPOD app called iControlAV. 
While the receiver has a web interface called "Pioneer Web Control System" I wanted a way to control this receiver via script. The web interface has support for
  • Powering the receiver on/off
  • Changing the Volume including mute
  • Changing the Input (Zones 1-3)
  • Changing the "Listening Mode"
The iControlAV app for iPhone supports the same plus a few more options.
The iControlAV uses SSDP query to find the receiver. Which runs NU-OS 1.13.  You can Browse to http://<Receiver IP>/BasicDevice.xml to get the info on your device. 
My receiver has port 23 (telnet) open along with 80 and 8102 (referenced in BasicDevice.xml)
Basic process:
  • Send command as ASCII on telnet (23) or TCP/8102 (see your BasicDevice.xml)
  • Commands that check status or query the device begin with a ?
  • Commands that perform a command sometimes have parameters (input number) at begining, some at end
  • You can monitor the telnet window to see the "response" for each command sent.  This includes commands sent through IR remote or from the device its self.
Basic Commands (more commands to come in another post):
?P
Is Device powered ON?
PWR0 Device is ON
PWR1 Device is OFF
PF Power Device OFF
PO Power Device ON
?M  Is Zone MAIN muted
MUT1 Zone is NOT Muted
MUT0 Zone is Muted
MO  Mute MAIN zone
MF  unMute MAIN zone
?V Get Current Volume level
VOLxxx Current volume level, xxx is 000-200
VOL121 -20.0db
VOL081 -40.0db
XXXVL Set Volume Level to XXX (000 - 200)
001VL Set Volume Level to -80.0db
081VL Set Volume Level to -40.0db
?RGC Get inputs on device (i think)
RGC111001002 *Unknown*
?RGBxx Get inputs Name (related to above command), available inputs will change based on model
?RGB01 RGB010CD
?RGB02 RGB020TUNER
?RGB03 RGB030CD-R/TAPE
?F Get current input (use ?RGB to get name)
FN19 Input 19
FN15 Input 15
XXFN Set current input (XX = Input number)
XX Input number
19FN Set to input 19
15FN Set to input 15
?BP *UNKNOWN*
BPR1
?AP *UNKNOWN*
APR1
Example
Turn on device, set input to HDMI1 (19 in my case), and volume to -40db

PO

19FN

081VL

(Update: 7/17/2011)
I was able to find a doc that has all the commands (better than what I was able to determine). 
http://dl.dropbox.com/u/3275573/2010%20USA%20AVR%20RS-232C%20%26%20IP%20Commands%20for%20CI.pdf

Configuring Dell EqualLogic management interface

The Dell EqualLogic iSCSI SAN supports an out-of-band management network interface. This is for managing the device from a separate network than the iSCSI traffic is on.
The documentation for the PS6000E is some of the worse I have ever seen. In addition to that the CLI (command line interface) is about as bad as a big pile of dog poo.
 
 
So this is a quick set of commands that are used to configure the management (eth2) interface on the device. The web interface is nice and all but you have to have your 10Gig network setup before you can access it. Also the "setup" does not really give you an easy option to configure the management interface.
 
 
Steps:

Login to Console Port with grpadmin username and grpadmin password.

After you run setup you will need to know the "member name". You can get your member name by running the "member show" command. This will list the name, Status, Version, Size information for each member configured on the array.
 
grpname> member show
Name Status Version Disks Capacity FreeSpace Connections
---------- ------- ---------- ----- ---------- ---------- -----------
EEC-DellEqual online V4.3.6 (R1 16 621.53GB 0MB 0
grpname>
The member name for my device is EEC-DellEqual.
Once you know the member name you will need to set the IP address for your management interface. This IP address will need to be one that you can access from your management network. The port is an untagged port similar to other out-of-band management ports on devices (network switches).
To configure the IP use the member command again.
First set the interface to be management ONLY
-member select EEC-DellEqual eth select 2 mgmt-only enable
Set the IP address and Network Mask
-member select EEC-DellEqual eth select 2 ipaddress xxx.xxx.xxx.xxx netmask 255.255.255.0
Enable the interface (by default the MGMT (eth2) interface is disabled and will not provide a LINK).
-member select EEC-DellEqual eth select 2 up
You will be asked to confirm that you wish to enable the Management port
This port is for group management only. If enabling, make sure it is connected to a dedicated management network. If disabling, make sure you can access the group through another Ethernet port.
Do you really want to enable the management interface? (y/n) [n] y
To view current IP and state of an Eth interface use
-member select <member Name> show eths
Once that is complete you can use the management IP address to create an http or https connection to the Array.
 

Securing a TS connection with Smart Cards

Repost from old blog
Well today is going to be a busy day here at the Microsoft Enterprise Engineering Center. At about 11:30 I am going to have lunch some of the RedvsBlue people (http://www.redvsblue.com). Then I have the job of setting up and testing a remote access solution for a customer. Note that the steps below are technical and you should know a little something about Active Directory and PKI before you start.

The problem: How do you provide a customer secure remote access into a scenario?
Solution: Smart cards and Terminal Services on Windows Server 2003! Smart cards keep the Private PKI key stored on the card, and cannot be removed from the card. It requires two-factor authentication. Something you have (the smart card) and something you know (the PIN).

How: First we set up a DC (or 2). Then install cert services on box (domain member). Then install Terminal Services on to another box (aka the Jump box).

We are using the Microsoft Base CSP (http://www.microsoft.com/resources/documentation/WindowsServ/2003/all/techref/en-us/Default.asp?url=/Resources/Documentation/windowsserv/2003/all/techref/en-us/w2k3tr_certs_how.asp) on some Amtel Smart cards.

I create user accounts in the Domain for each person that will need remote access. Each Account has a Very LONG and Very RANDOM password. This is because the user will never use a password. They will not be able to use their smart card. Once the users are created make sure that you go in the properties of each user and under the Account tab select the following options: User Cannot change password, Password never expires and Smart Card is required for interactive logon.

Now create a separate Admin account. This will be the account that I use to manage the TS (terminal Services) jump box and issue the smart cards. Make sure it has a secure password.
 
To issue a smart card the issuing user account must have an Enrollment Agent Cert. To get this cert you must first enable it on the CA. (Open the CA MMC snapin -> select Certificate Templates -> Right-click on Certificate Templates -> Select New -> Select Certificate Template to issue. In the list select Enrollment Agent.

Repeat the steps above to also add the Smart Card Logon Cert. This is the cert that we will put on each Smart Card.

After you have enabled that cert (Enrollment Agent) you must now request it with the user account that will be issuing the Smart Cards. So for my solution that is the separate admin account. I will use runas.exe /u:<domainName>\<adminUser> "mmc certmgr.msc". This will allow me to open the MMC without logging in as that user.

To request the new cert select personal -> right-click on personal -> select all tasks -> select Request new Cert... Once the Wizard opens select Next to start it -> Select Enrollment Agent -> Select Next -> Enter a Name (like SC enrollment Cert) -> Select Next -> then Select Finish to issue the cert.

Now we will need to make sure we have our smart card reader installed on the machine that has our enrollment Cert and http access to the CA. With all of the above done you can now open a web browser to http://<CA Machine Name>/certsrv/certsces.asp (note: that you might have to add this site to your trusted sites to get the Active X control to load).

From this browser window we can select the type of Cert we want to put on the Smart Card. We are going to use Smart Card Logon Cert. You will need to select the Microsoft Base Smart Card Crypto Provider as your CSP. The Administrator Signing Certificate is the Enrollment Cert that we requested earlier. At this point you can select any user in the domain to issue a smart card for.

One thing to note is that when you have a smart card for user account it does not matter if the user changes their password. The smart card will allow the user to be authenticated without a password. So make sure that you keep accounts that have the Enrollment Agent Cert secure.

In the future I will also write about how to use the AD to further secure the Solution.