Sunday, April 14, 2013

Arduino Based Kegerator / Keezer Build

So I decided it was time to build a kegerator... Due to space (front to back depth) constraints in my garage I couldn't use a normal fridge/freezer like I wanted, so I had to use a chest freezer.  I needed something less than 25" deep and with a bit of research the GE 7 cubic foot chest freezer - Model FCM7SUWW - fit the bill perfectly.

It will fit 3 home brew / ball lock corny kegs on the bottom (the 4th one just BARELY doesn't fit), and with a 10" collar you can fit another on the hump.

More importantly, because I'm a nerd and I've never worked with an Arduino I decided it would be fun to play with one.  I ended up with an Arduino controlling an LCD for each of the 3 taps I installed, displaying what beer is on tap and how much beer is left in the keg.  For funzies I added a couple temp sensors, one to measure the keezer temp, and one to measure the outdoor temp (I plan to move this to my deck in the summers)

I also decided I wanted to do this without making any permanent modifications to the chest freezer so I can easily put it back to original condition.

Planning:
  1. Buy a chest freezer and all of the keg equipment (CO2, regulators, taps, etc.).
    1. I used 12' of 2x10 to build my collar, making it tall so I could fit another keg on the hump if i needed, and to give me room to install the taps/LCDs.  Measure and make sure you get what you need.
    2. I used L brackets to help assemble the collar and make it more sturdy.
    3. I used a 80mm computer case fan and an old 12v AC adapter to circulate air so the air temperature is consistent across the entire keezer.
    4. I also used an Eva-dry E-500 dehumidifier to keep the electronics from getting ruined
  2. Buy a temp controller that can regulate the temperature of the chest freezer at beer temps, I used the STC-1000 which is a popular choice for this task.
  3. For my Arduino build I used:
    1. Arduino Mega R3
    2. Ethernet Shield
    3. 16gb Micro SD Card from an old phone
    4. 3x Flow Sensors
    5. 6x 1/2" to 1/4" adapters
    6. 3x LCD's
    7. 2x DS18B20 Temp Sensors
    8. 2x Breadboard / jumper wire / 22 gauge regular wire
Tools Required:
  1. Circular, table, or chop saw (I used a chop saw)
  2. Jigsaw to cut the LCD holes for the LCD's
  3. Router w/ Rabbet bit to make the LCD fit in the hole flush (I used 1 & 3/8, 1 & 1/2 would have been easier to work with, the LCD's just BARELY fit)
  4. Drill w/ 1" spade to make holes for the tap shanks
  5. Soldering iron for the Arduino work

Getting started:
  1. Build the collar
    1. Using the chopsaw I cut my lumber to the dimensions I needed (20.75" on the sides, 37" on front & back), using Miter cuts so it would look clean
    2. With all the cuts made I test fit my collar to make sure it was perfect
    3. To make life easier, before assembling the collar I did all of the work to the pieces
      1. Drill the holes for the taps
      2. Drill a hole in the back for wires to pass through, including power for the arduino and fan, and a temp sensor. Later we will caulk this hole.
      3. Use a Jigsaw to cut a hole for the STC-100 Temp controller
      4. Use a Jigsaw cut the holes for the LCD screen
      5. Because the LCD is smaller than the PCB it is attached to I used a router to carve out the back side of the 2x10 so the LCD would be flush mounted in the board.  
    4. Apply wood glue to each miter cut, assemble the collar and line it up just the way you want it and use a ratchet strap (I saw somebody else do this, great idea) to hold it together and keep it square while the glue dried.  I did mine directly on the keezer so I could control exactly how it lined up.  I wiped up the excess glue after a few minutes, and then again the next morning.
    5. For added strength, once the glue dried I cut some 1.5x1.5x8 strips and screwed them in to the corners, letting them hang a little low in to the freezer to help hold the collar in place.  This seems to work quite well.  I didn't account for the freezer lid fitting properly so I had to remove them, cut them an inch shorter, and reinstall.  Make sure you pay attention to that :)
    6. I applied the first coat (of two) of primer to the inside and while that dried I tested the temp controller
    7. To wire the STC-1000 I removed the side plate from the freezer, popped out the built in controller, disconnected all the wires from that, and wired it like so (I used butt connectors on the freezer side to tap in to the existing wiring without having to modify it):
      1. Black from power plug - Pin 1
      2. White from power plug (shared with white to compressor) - Pin 2
      3. Black to compressor - Pin 7
      4. Jumper wire from Pin 1 to Pin 8
      5. It works :)
      6. I put 2 coats of primer on the inside, and then stained the outside:
  2. With the collar built it's time for final construction.  I ran 3/16" white weather stripping around the top of the freezer and then installed the collar with the original hinges making it easier to get kegs in, and purchased generic indoor door hinges to attach the freezer lid to the collar.  I drilled a couple new holes in each door hinge to match the layout of the holes on the original lid.  When I want to open the main collar I have to be careful because the lid falls open, so I use a piece of tape to temporarily hold it shut.




  3. I ran all the wires and stapled them (BAD idea, the staples ended up bridging some of the smaller wires so use tape instead) to the inside of the collar, and then cut channels in the back of the styrofoam so it would fit flush, then attached a second piece over the first so it is well insulated.  I used  the expanding spray foam stuff to insulate the back of the LCD's and hold them in place.  Don't get it on your hands, it's suuuper sticky and impossible to get off.




  4. An 80mm PC fan to help circulate air so the temp is consistent from top to bottom, and a mini breadboard to easily connect the flow sensors to the Arduino.  This is important, without it the top of the freezer is considerably warmer than the bottom and the beer pours foamy (I turned it off to see how much of an affect it has, and it's quite drastic).




  5. And a final view of the rats nest / co2 tank.
  6. The last thing I did was put one of the baskets in the freezer (I stacked them together), which works great for holding chilled glasses. It currently rests between the power controller on the front and the sytrofoam on the back, but I plan to come up with a more permanent solution.
The final product, ready to be moved to the deck.  I haven't decided what to do for a drip tray yet.


Arduino

To simplify debugging I built the Arduino in stages.  First I worked with the LCD's, figured out how the pinouts worked and how to address them.  I read a post about which pins could be combined but had other issues and ended up running all of the wires directly to the arduino (except power, those all went to the breadboard).  I did combine the contrast pins so one pot can control them all. Then I attached the flow sensors, and modified the sample code from adafruit.  I simply blew through a flow sensor to make the wheel spin and test it. Once I had that working I fully wired the 3 LCD's on the kitchen table just the way it would be installed, and then carefully moved it to the collar and put it in place.  One at a time I positioned each LCD the way I wanted it, and then used expanding sprayfoam insulation to insulate and hold it in place (be careful, don't pack it in too much or it might ooze in to the LCD display).  

For the collar to hinge I had to put a breadboard in the back corner so the flow sensors wouldn't be pulled on when the lid was opened.  The flow sensors terminate to the mini breadboard which has jumper wires to the main breadboard and arduino input pins for the flow sensors.

Finally, I wanted the Arduino to be fully self contained, so I used a webserver (available in the comments on this page) for configuration, and an SD card for persistent memory.  This was tricky to work with, at one point I broke the webserver by using pin 51 for a flow sensor, which interferes with the ethernet module. whoops.

Once I finish the code I will post it.  In the meantime if you would like a copy contact me and I'll be happy to share it with you.

Monday, February 18, 2013

Dell md3600/md3620 Review

We recently built a new virtualization cluster using two new Dell PowerEdge R620's and a new Dell PowerVault md3620f configured with dual controllers, 14x 300gb 10k RPM drives and 3x 1tb 7200 RPM drives. Each controllers has 4x 8gb FC ports.  With this, if you are using MPIO you can connect 4 hosts directly, if you are not using MPIO you could connect up to 8 hosts directly via Fibre Channel without using FC switches.

The md3620f is a 2U SAN that holds 24 disks, with expansion shelves it can expand up to 192 drives (requires additional license to go above 120).  Each controller has 2GB of cache.

There are also SAS and iSCSI versions available, known as the md3620i and md3620 for sas.  The md3600 series is similar, except the shelves hold 12x 3.5" drives instead of the 24x 2.5" drives in the md3620 series.

I connected a watt meter to it, and on 110v AC it was consuming 200 watts of power at idle, and never more than 240 under load.

As of firmware 7.84 Windows Server 2012 is supported, but previous revisions do not so make sure you upgrade to the latest possible firmware revision.

Also of note is that the Dell md3620f does NOT work with Microsoft's System Center Data Protection Manager 2012 w/ SP1, Dell's VSS provider crashes and appfaults, and this isn't something Dell is willing to fix.  Unfortunately Dell has not supported DPM since 2007, and recommends you uninstall their VSS provider because they are too lazy to fix it.  You can simply tell DPM to bypass the VSS provider by creating a new registry key here: [HKLM\Software\Microsoft\Microsoft Data Protection Manager\Agent\UseSystemSoftwareProvider]


Moving on... The Dell SAN uses "Modular Disk Storage Manager" which is the configuration software (rather than a web interface) that you must install on any computer you would like to manage your cluster from, and in the latest version of 7.84 it is much more stable / reliable.  The software is still "clunky" and dated, but at least it is functional.  One of my biggest complaints with it is how long it takes to connect to the SAN, ranging from 10 to 120 seconds to connect.  Additionally, if one of the controllers is offline (unplugged ethernet cable for instance) you are unable to manage LUN's, etc.  making the redundancy of this unit questionable.

Here are some basic screenshots of the MDSM.


The host mappings page is a bit clunky to work with compared to our Compellent and HP systems, but again it works. 

The hardware overview is a nice little page.

The performance monitor setup is much nicer than the HP & Compellent systems I've used, but I don't think the IO/second numbers are accurate, 7 300GB 10k drives can't do 2,500 IOPS, and 3 1TB sata drives can't do 1707.


We provisioned our md3620f as follows:
Disk Group 1 - 7x 300gb in Raid 5
Disk Group 2 - 8x 300gb in Raid 5
Disk Group 3 - 3x 1tb in Raid 5

Each test was run a couple times and averaged, but there may have been minimal load on the SAN at the time so the numbers aren't perfect science, but they are pretty good.  File Read / Write was done via file copies to & from the SAN and represents the real world performance I've seen from this SAN over the last 3 months.  Raw read/write was done using HD Tune Pro File Benchmark with a 20GB file length and random data pattern.

Disk Group 1 (7x 300gb in Raid 5)
File Read - 229M/s
File Write - 180M/s
Raw Read - 590M/s
Raw Write - 255M/s

Disk Group 2 (8x 300gb in Raid 5)
File Read - 290M/s
File Write - 209M/s
Raw Read - 610M/s
Raw Write - 240M/s

Disk Group 3 (3x 1tb Raid 5) Performance:
File Read - 115M/s
File Write - 76M/s
Raw Read - N/A
Raw Write - N/A

Then I tested Disk Group 1 & Disk Group 2 (owned by different controllers) at the same time using HD Tune Pro, and here are the results:

Disk Group 1 (7x 300gb in Raid 5)
Raw Read - 595M/s
Raw Write - 225M/s


Disk Group 2 (8x 300gb in Raid 5)
Raw Read - 640M/s
Raw Write - 220M/s

Combined Max:
Raw Read - 1,420M/s
Raw Write - 457M/s

Sunday, February 3, 2013

How to Upgrade Forefront Unified Access Gateway (UAG) from RTM to SP2

If you have an RTM install of Microsoft Forefront UAG 2010 and want to upgrade to the latest Service Pack 2 it isn't the easiest or most direct process.  You have to jump through a few hoops, and in my case I had errors that prevented me from even running the install, including "Setup failed during Forefront UAG prerequisites installation", and a simple error 1603 saying check the logfiles which weren't helpful.  Eventually, this was my process, i hope this saves somebody else some pain and suffering.



The updates are not cumulative, so to get to UAG SP2 from RTM you must install UAG SP1, then UAG SP1 Update 1, then Threat Management Gateway Service Pack 2 and THEN UAG SP2.


  1. Open UAG Manager, and edit any portal sites you have provisioned and make sure the download and upload policies are not set to Sharepoint or CRM specific policies.  I set mine to always for now, and made a note to go back and fix those later.
  2. With Service Pack 1 downloaded I was not able to run it directly, I had to extract it using this command: 
    1. UAGSP1_KB2285712_ENU.exe
  3. Then from an admin command prompt launch the UAG-KB2285712-ENU.msp patch file.
    1. Once the install is done restart your server.
  4. Once it reboots log in, open an admin command prompt, and install the SP1 Update 1 UAG-KB2585140-v4.0.1773.10100-ENU.msp
  5. Open UAG Manager and export the configuration, you will need it later.
  6. Stop all of the Forefront services, and then install the TMG SP2 update from the admin command prompt
  7. Then install UAG SP2: UAG-KB2710791-v4.0.2095.10000-ENU.msp from the admin command prompt
  8. In my case the schema did not work, the server was effectively blank.  Therefore I had to use the UAGSchemaUpgradeUtil.exe file found in common\bin on the exported copy of the configuration to fix everything.  According to the technet article an in place upgrade shouldn't require this, but in my case it did.
  9. Then re-assign your upload and download policies, and test everything to make sure your upgrade went smoothly.

HTH!

Credits:
How to fix error 1603
http://social.technet.microsoft.com/Forums/eu/forefrontedgeiag/thread/965f29fd-d7ec-44ab-b5ab-609eb24dc8fc

Thursday, January 31, 2013

How To Create a Windows 8 Unattended Answer File For [WDS] Silent deployment


If you want to deploy Windows 8 silently (ex: by using Windows Deployment Services) you will need to create an answer file (aka unattend.xml).

Here are the steps I followed:
  1. Install the Deployment Tools feature included in the Windows Assessment and Deployment Kit for Windows 8.
  2. Extract your Windows 8 ISO
  3. Launch the Windows System Image Manager
  4. Under Windows Image right click and select a windows image, navigate to the sources\install.wim file from your extracted ISO or your DVD
  5. It will ask you about creating a catalog of the image, say yes
  6. Once that is done, under Answer File right click and select new answer file
  7. Drag Microsoft-Windows-Shell-Setup_neutral to the "4 specialize" section
    1. Enter your product key
  8. Drag Microsoft-Windows-International-Core_neutral to "7 oobeSystem"
    1. Set InputLocale to 0409:00000409
    2. SystemLocal, UILanguage, and UserLocal all to en-US
  9. Drag Microsoft-Windows-Shell-Setup_neutral to "7 oobeSystem"
    1. In order to make the installation completely silent and not need any user interaction, under OOBE set each of the following to true: HideEULAPage, HideLocalAccountScreen, HideOEMRegistrationScreen, HideOnlineAccountScreen, HideWirelessSetupInOOBE
    2. Set NetworkLocation to Work
    3. Set ProtectYourPC to 1 (This enables windows update with recommended settings)
  10. If you do not specify a local account in the answer file you will be forced to create one during image deployment, so be sure to create a new Local Account under UserAccounts -> LocalAccounts
    1. I have found that you can create a new account that is the same name as one that is already in the image for simplicity
  11. If you need to join to a domain, drag Microsoft-Windows-UnattendedJoin_Neutral to "4 specialize"
    1. Set your domain name in JoinDomain, set UnsecureJoin to false
    2. Enter credentials with domain join privileges -- **They WILL be stored in plain text in the file

Save your unattend.xml file.  At this point if you are using WDS you can select the image in the WDS console and attach the unattend.xml file to that image.

If you want to slip the unattend.xml file in to the image itself, copy it to c:\windows\system32\sysprep, and run sysprep like this:
sysprep /generalize /oobe /shutdown /unattend:c:\windows\system32\sysprep\unattend.xml
*I chose not to do it this way so i could easily update the unattend file without having to rebuild my image.

And here is my answer file:

<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">
    <settings pass="oobeSystem">
        <component name="Microsoft-Windows-International-Core" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <InputLocale>0409:00000409</InputLocale>
            <SystemLocale>en-US</SystemLocale>
            <UILanguage>en-US</UILanguage>
            <UILanguageFallback></UILanguageFallback>
            <UserLocale>en-US</UserLocale>
        </component>
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <AutoLogon>
                <Password>
                    <Value>removed</Value>
                    <PlainText>false</PlainText>
                </Password>
                <Enabled>true</Enabled>
                <LogonCount>1</LogonCount>
                <Username>admin</Username>
                <Domain>removed</Domain>
            </AutoLogon>
            <OOBE>
                <HideEULAPage>true</HideEULAPage>
                <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
                <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
                <ProtectYourPC>1</ProtectYourPC>
                <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
                <NetworkLocation>Work</NetworkLocation>
                <HideLocalAccountScreen>true</HideLocalAccountScreen>
            </OOBE>
            <UserAccounts>
                <AdministratorPassword>
                    <Value>removed</Value>
                    <PlainText>false</PlainText>
                </AdministratorPassword>
                <LocalAccounts>
                    <LocalAccount wcm:action="add">
                        <Password>
                            <Value>removed</Value>
                            <PlainText>false</PlainText>
                        </Password>
                        <Description>admin</Description>
                        <DisplayName>admin</DisplayName>
                        <Name>admin</Name>
                        <Group>administrators</Group>
                    </LocalAccount>
                </LocalAccounts>
            </UserAccounts>
        </component>
    </settings>
    <settings pass="specialize">
        <component name="Microsoft-Windows-Shell-Setup" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <ProductKey>XXXXX-XXXXX-XXXXX-XXXXX-XXXXX</ProductKey>
            <RegisteredOrganization>removed</RegisteredOrganization>
            <RegisteredOwner>removed</RegisteredOwner>
            <ComputerName>*</ComputerName>
        </component>
        <component name="Microsoft-Windows-UnattendedJoin" processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35" language="neutral" versionScope="nonSxS" xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
            <Identification>
                <Credentials>
                    <Domain>removed</Domain>
                    <Password>removed</Password>
                    <Username>removed</Username>
                </Credentials>
                <JoinDomain>removed</JoinDomain>
            </Identification>
        </component>
    </settings>
    <cpi:offlineImage cpi:source="wim:c:/isoextract/sources/install.wim#Windows 8 Enterprise" xmlns:cpi="urn:schemas-microsoft-com:cpi" />
</unattend>

Wednesday, December 26, 2012

How to send email "from" another user in Outlook 2013

I've seen a few people run in to this:

If you have permission to send on behalf of another user in Exchange, and would like to send from that user from Outlook 2010 or 2013, it's quite simple.

  1. Open outlook
  2. Create a new email message
  3. Click the Options tab
  4. Click the "From" button
  5. In the From: dropdown above To: select the account you would like to send from

Monday, December 3, 2012

Windows Failover Cluster Live Migration Failures with Hyper-V 2012

After moving from one datacenter to another we started experiencing issues live migrating virtual machines from one host to another in our 2 node failover cluster.  The migration would instantly fail, and there would be no error other than:
Live migration of 'Virtual Machine VMNAME' failed.

If I did a quick migration it works, but live did not.  I started looking at the security logs of the hosts and noticed some intermittent errors:

An account failed to log on.

Subject:
Security ID: SYSTEM
Account Name: HYPERVHOSTCOMPUTER$
Account Domain: OURDOMAIN
Logon ID: 0x3E7

Logon Type: 8

Account For Which Logon Failed:
Security ID: NULL SID
Account Name: HYPERVHOSTCOMPUTER
Account Domain: OURDOMAIN.com

Failure Information:
Failure Reason: Unknown user name or bad password.
Status: 0xC000006D
Sub Status: 0xC000006A

Process Information:
Caller Process ID: 0xd30
Caller Process Name: C:\Windows\Cluster\rhs.exe

Network Information:
Workstation Name: HYPERVHOSTCOMPUTER
Source Network Address: -
Source Port: -

Detailed Authentication Information:
Logon Process: Advapi  
Authentication Package: Negotiate
Transited Services: -
Package Name (NTLM only): -
Key Length: 0

This event is generated when a logon request fails. It is generated on the computer where access was attempted.

The Subject fields indicate the account on the local system which requested the logon. This is most commonly a service such as the Server service, or a local process such as Winlogon.exe or Services.exe.

The Logon Type field indicates the kind of logon that was requested. The most common types are 2 (interactive) and 3 (network).

The Process Information fields indicate which account and process on the system requested the logon.

The Network Information fields indicate where a remote logon request originated. Workstation name is not always available and may be left blank in some cases.

The authentication information fields provide detailed information about this specific logon request.
- Transited services indicate which intermediate services have participated in this logon request.
- Package name indicates which sub-protocol was used among the NTLM protocols.
- Key length indicates the length of the generated session key. This will be 0 if no session key was requested.

Then I noticed errors in the cluster itself, at the same times:

Cluster network name resource 'Cluster Name' failed registration of one or more associated DNS name(s) for the following reason:
The handle is invalid.
.

Ensure that the network adapters associated with dependent IP address resources are configured with at least one accessible DNS server.

I looked at a domain controller and noticed a lot of Audit Failures for that computer object.  I opened the computer object in ADSI Edit, and noticed that the last login was 11/23 (the day we moved), and the last password reset was 11/24, which is incredibly odd.  The last bad login attempt was a few minutes ago.  I'm not sure how, but I think a password reset may have been attempted while the domain controllers were unavailable.

How I fixed it:

  1. Open Failover Cluster Manager
  2. Navigate to Cluster Core Resource
  3. Right click on the cluster network name and take it offline
  4. Right click on the cluster name and navigate to more actions -> repair


A few seconds later the cluster was repaired, I turned the cluster name back on and live migrations work.



Mystery solved.

HTH!

Tuesday, September 18, 2012

Auto Provision Lync 2010 Users Via LDAP

We have tools that automatically create Active Directory Users, Exchange mailbox, and Microsoft Lync 2010 accounts to simplify the hiring process.  I figured somebody might find this information useful, so in order to provision a user for Lync 2010 automatically I use a slightly altered version of this (in perl, using Net::LDAP):

use Net::LDAP;


$ldap = Net::LDAP->new("ldap://domain.local", debug =>0) or die("Could not connect to LDAP server.");
my $mesg = $ldap->bind('myUserDN',
password => 'myUserPassword')  or die("Could not bind to LDAP server.");

 $mesg = $ldap->search( # perform a search
base   => "dc=domain,dc=local",
filter => "(&(samAccountName=$username))"
  );

$mesg->code && die $mesg->error;

#there should only be one result in here anyway
foreach $entry ($mesg->entries) { 
$userdn = $entry->dn;
}



$rtn = $ldap->modify($userdn, replace => { "msrtcsip-userenabled" => "TRUE"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-optionflags" => "449"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-primaryhomeserver" => "CN=Lc Services,CN=Microsoft,CN=1:1,CN=Pools,CN=RTC Service,CN=Microsoft,CN=System,DC=domain,DC=local"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-primaryuseraddress" => "sip:$email"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-line" => "tel:+$astextension;ext=$extension"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-deploymentlocator" => "SRV:"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-federationenabled" => "TRUE"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-internetaccessenabled" => "TRUE"});
$rtn = $ldap->modify($userdn, replace => { "msrtcsip-userpolicies" => [("21=7", "0=1434923910")]});



You may find it best to provision a user the way you like, open the user in ADSI Edit to see all the parameters, and adjust this accordingly.  

That said, this should set you off in the right direction for how to fully provision a Lync user automatically.