Query against 389 Directory Services (Open Source LDAP) with PowerShell

Recently I had the need to query an LDAP server running 389 Directory Services with PowerShell. I found my way to this website -> http://mikemstech.blogspot.com/2013/03/searching-non-microsoft-ldap.html#comment-form where you get the basics of connecting to a non-Microsoft LDAP directory using PowerShell, however in my case the steps provided didn’t work. Below are the steps I took in order to successfully query information on user accounts on the 389 Directory Services server in my environment.

I start off in my script with the following lines of code.

[System.Reflection.Assembly]::LoadwithPartialName(“System.DirectoryServices.Protocols”)
[System.Reflection.Assembly]::LoadwithPartialName(“System.Net”)
$c = New-Object System.DirectoryServices.Protocols.LdapConnection “LDAP-SERVER-NAME-HERE”
$c.SessionOptions.SecureSocketLayer = $false
$c.AuthType = [System.DirectoryServices.Protocols.AuthType]::Anonymous
$credentials = New-Object “System.Net.NetworkCredential”
$c.Bind($Credentials)
$basedn = “o=cas.org”
$scope = [System.DirectoryServices.Protocols.SearchScope]::subtree
$attrlist = “*”

The differences between what I did and what mikemstech did was that I disabled SSL and set the AuthType to Anonymous. My 389 DS refused connections if I had those two items set any other way. It’s hard to tell if this was due to it being a 389 DS server, or if it was a unique customization of the environment here.

The next thing I did in my script was create a function for querying user information, however you wouldn’t have to do this.

function Unix-LDAP {
Log (“Beginning Unix-LDAP”)
clear-variable LDAPuidNumber, filter, r, re
Clear-Variable TermEmp, ADsamAccountName, FoundUnix -Scope Global
$LDAPuidNumber = $args[0]
Log (“The UID number being queried in Unix LDAP is $LDAPuidNumber.”)
Log (“The ADsamAccountName variable is currently $Global:ADsamAccountName.”)
$filter = “(uidNumber=$LDAPuidNumber)”
$r = New-Object System.DirectoryServices.Protocols.SearchRequest -ArgumentList $basedn,$filter,$scope,$attrlist
$Error.Clear()
$Global:TermEmp = 0
$Global:FoundUnix = 0
$re = $c.SendRequest($r)
$Global:ADsamAccountName = $re.entries.attributes.uid[0]
$Error
If ($Error[0] -like “Cannot index into a null array.*”) {
Log (“ERROR: The user no longer has a Unix ID. Likely a terminated employee.”)
$Global:TermEmp = 1
}
Else {
Log (“The Unix-LDAP query returned a value of $Global:ADsamAccountName.”)
$Global:FoundUnix = 1
}
Log (“Finished Unix-LDAP”)
}

So the important lines from above are lines 8, 9, 14, and 15. In my case I was query users based upon their uidNumber, however you could replace uidNumber in line 8 with any other property you wanted to query on.

On line 14 you’ll see that at the end of $re.entries.attributes.uid I added [0]. This was something not mentioned on the site I linked to above that I ended up figuring out. Once again, I’m not sure if this is just a difference in how 389 DS operates, or a special configuration in my environment.

You’ll also see that I work with the $Error variable. I do this so that I can determine if the query succeeded or not.

Hopefully the above will save someone else out there a bunch of time.

Migrating from LCS 2005 to Lync 2010

Beginning around March of this year I took on the project of upgrading the environment where I work from LCS 2005 to Lync 2010. There had been a project to upgrade the LCS environment for some time, however since it hadn’t been broken no one had ever gotten around to doing it. Finally though some features of Communicator 2005 broke during the upgrade to Windows 7, so LCS had to be upgraded.

I figured I would document the whole project so that I could refer back to it myself, and perhaps assist anyone else out there looking to upgrade with a better inside view to the whole thing. Note that everything below is for a “simple” environment. It’s only used for internal IM/Collaboration purposes. Clearly the steps below can’t be followed step by step if you have a more complex setup.

Now, in all seriousness, the whole upgrade from LCS to Lync with no loss of user data could’ve occurred within a month or two. However, due to the way things work in a large business, it’s dragged on into August, and will likely drag on a couple more months. Due to the amount of information that I’m going to attempt to shove into this post, I’ll break the post down into the following sections. There will be a “Preparing LCS” section, a “Preparing for OCS 2007 R2” section, an “Installing OCS 2007 R2” section, a “Decommissioning LCS” section, a “Preparing for Lync 2010 section”, a “Installing Lync 2010” section, a moving users from 2005 client to Lync 2010 client, and finally a “Decommissioning OCS” section.

 

Preparing LCS 2005

So prior to doing any upgrading to LCS, you have to run through a number of things to prepare it for co-existence with OCS 2007 R2. That’s right, there’s no straight shoot from LCS 2005 to Lync 2010, you have to take a pit stop through OCS first. Don’t worry, it’s really not that big of a deal, and if you follow the steps below, your users will only see the Communicator 2005 client they’re using now and the Lync 2010 client at the end. They won’t even know you took a pit stop on OCS.

So here’s a list of the things that need done to LCS first. I’ll describe them in more detail in a moment.

So starting from the beginning of the list…

You have to first install KB911996 on your back end database server and front end servers so that they can handle having your settings in the configuration container in AD. (You’ll be moving your settings after this.) You need to first install this update on your database servers. Run “LCS2005-KB911996-x86-Usa.msi POOLNAME=poolname” on the SQL server, and then you’re done with that. You do not need to reboot your SQL server. You’ll then just need to run the MSI install on your LCS front end servers.

Once KB911996 is deployed, it’s time to run the Global Settings Migration. Go to the site specified above and download the “Microsoft Office Communications Server 2007 Global Settings Migration Tool”. You’ll get an MSI, however when you run it you’ll end up having a vbs script. Below are the steps for running the “MigrateOcsGlobalSettings.vbs” script. I would run these from a LCS 2005 front end server with a user account that’s a member of the Domain Admins group. It’s possible you could get away with less permissions, but I didn’t bother with it.

  1. Run “MigrateOCSGlobalSettings.vbs /Action:MigrateGlobalSettingsTree”
  2. Replicate AD
  3. Run “MigrateOCSGlobalSettings.vbs /Action:MigrateGlobalSettingsProperties”
  4. Replicate AD
  5. From the directory “C:Program FilesCommon FilesMicrosoft LC 2005” run “LcsCmd /Forest /Action:ForestPrep /Global:configuration”
  6. From the directory “C:Program FilesCommon FilesMicrosoft LC 2005″ run LcsCmd /Domain /Action:DomainPrep”
  7. Replicate AD
  8. Run “MigrateOCSGlobalSettings.vbs /Action:MigrateServerDnReferences /SearchBaseDN:DC=domain,DC=local” (Replace the SearchBaseDN parameters with information on your domain…)
  9. Run “MigrateOCSGlobalSettings.vbs /Action:MigrateUserDnReferences /SearchBaseDN:DC=domain,DC=local” (Once again, replace the SearchBaseDN parameters with information on your domain.) You might get this step failing a couple of times. Just keep re-running this until it succeeds.
  10. Reboot LCS 2005 Front End Server(s)

Now you need to install KB921543 on your LCS 2005 front end server(s). For some reason my documentation lacks the exact reason this patch needs installed, so I’ll come back and update this section if I find exactly why it needs installed. No reboot is needed after installing this patch.

Now you need to install KB950614 on your LCS 2005 front end server(s). This patch will allow Communicator 2005 clients with KB949280 installed to communicate properly.

Finally, you need to install KB949280 on your Communicator 2005 clients. This update allows for interoperability with OCS 2007 R2. You only need this patch if your Communicator 2005 clients are running on a lower build than 1.0.559.218.

After all of that, we’re done with preparing LCS and can move onto the preparing for OCS phase.

 

Preparing of OCS 2007 R2

There are three main sections for preparing for OCS 2007 R2. Those are

  • Preparing AD
  • Setting up SQL
  • Setting up a OCS front end server

Before any of those steps, I would start with creating a service account for OCS. The service account I created was a member of the following security groups.

  • Domain Admins
  • RTCComponentUniversalServices
  • RTCHSUniversalServices
  • RTCUniversalGuestAccessGroup
  • RTCUniversalServerAdmins

Note that it’s possible that you need to have this service account setup with local administrative permissions on the OCS server and the SQL back end server. In my case, my service account remained a Domain Admin throughout the upgrade, which made it a local admin on the servers.

You should now prepare AD for OCS. Launch the OCS installation media and first run the ‘Update Schema Wizard”. Be sure to run this step with a user account that’s a member of the Schema Admins group, and from a computer that has AD tools installed. Replicate AD after doing this.

You’ll then need to run the “Prepare Forest” wizard. If you’re running this on a Server 2008+ system or a Windows Vista+ system then you might have to run this using lcscmd.exe instead, and running that as an Administrator. After this is done, replicate AD.

Now run the “Prepare Domain” wizard. Once again, replicate AD after this.

You’re now done with preparing AD for OCS and can move onto setting up SQL.

When it comes to setting up your back end SQL server, it’s pretty simple. You need to first make sure that if you have SQL instances available, that you do not use one that’s already hosting a LCS/OCS environment, since some database names are re-used. Personally I would recommend just create a SQL instance for OCS. Either way, once you have your SQL instance you need to configure your OCS service account with full access to the instance. (Your SQL server needs to be at least SQL 2005 SP2+. You can use SQL 2008, 2008 R2.)

You now need to setup your OCS front end server. The steps below will guide you through setting up a Server 2008 R2 SP1 system for the OCS front end roles.

  1. Install Server 2008 R2 SP1, install all available patches.
  2. Install Windows Media Runtime
    c:windowssystem32dism.exe /online /add-package
    /packagepath:$env:windirservicingPackagesMicrosoft-Windows-Media-Format-Package~31bf3856ad364e35~amd64~~6.1.7601.17514.mum
    /ignorecheck /NoRestart /quie
  3. Install IIS
  4. Install Message Queuing
  5. Run ocsasnfix.exe
    http://support.microsoft.com/kb/982021
  6. Create and share the following folders
    1. MeetingContent
    2. MeetingArchive
    3. ApplicationDataStore
    4. MeetingMetaData
    5. AddressBookStore
    6. ClientUpdateStore
  7. Assign a static IP
  8. Create a Host A record in DNS with the name of whatever your OCS pool will be called and point it to the static IP of your front end server. (Assuming you’re doing a single FE server setup. Otherwise you would point that Host A record at a load balancer or something, which would then target all your FE servers.)

Now that everything has been prepared for OCS, we can move to installing OCS.

 

Installing OCS 2007 R2

The installation of OCS can be broken down into the following steps.

  • Run through the OCS 2007 R2 setup on your front end server
  • Install the OCS administrative console on an x86 system
  • Migrate users to your OCS pool
  • Enable Enhanced Presence for users in your OCS pool
  • Update DNS/GP

Now I’ll break down each of those sections.

First log into your OCS front end server with your OCS service account. Once logged in, launc the OCS 2007 R2 setup and run through the

  • Create Pool Wizard
  • Configure Pool Wizard
  • Install Archiving Server Role Wizard (optional)
  • Install Monitoring Server Role Wizard (optional)
  • Request and Generate Cert for your OCS pool
  • Install OCS 2007 R2 Enterprise Server
  • Install Administrative Console

All of the above is pretty simple to get through, except for potentially the step for getting your certificate. For Lync, there’s a built in wizard for doing this, however I recall OCS not having such a simple wizard for getting your certificate. Basically all you need to make sure of is that your certificate is valid for the FQDN of your pool. In my case, the certificate was issued to “ocspool1.domain.local” using the built in WebServer template. Once you get your certificate, just make sure that you’re importing the certificate at the system level and not for the user you’re logged in as. Also make sure that you install all the available updates for OCS. This will require updates being made to the back end SQL server as well. You can get away without installing these updates, however you won’t have any conferencing features. (No chatting between more than 2 people.) Plus it’s always good to be running the latest version of the software when doing production upgrades….

Once you have OCS running (which you should at this point, since with these instructions we’re simply covering how to setup a simple single FE environment, and we covered setting up the pools Host A record in the previous section…), you’ll need to first install the OCS 2007 R2 Administrative Console on a 32-bit Windows XP/Windows 7 system. This needs done so that the 32-bit OCS 2007 R2 console get interface with the 32-bit LCS environment. (This is my assumption, since I can’t find any solid documentation around this.) Whenever you need to move users from LCS to OCS, you’ll need to use the OCS console on the 32-bit system.

So now that you’re all setup there, I’m going to assume that you’ve already moved some test accounts and have verified everything is working. Assuming everything is working, you’re ready to migrate your users from LCS to OCS. This is a pretty painless step. Using the 32-bit OCS 2007 R2 console, move all your users from LCS over to OCS. When you move a user, their Communicator client will get briefly disconnected, however should automatically re-connect within about 30 seconds. All their contacts should get moved over as well. You don’t have to move all your users at once. This can be stretched out over time since users can chat with each other between environments.

Once all your users have been moved over to the OCS pool, you now need to enable enhanced presence for their accounts. From within a OCS 2007 R2 console (doesn’t matter if it’s from a 32-bit system or 64-bit system), enable enhanced presence for every user account. Now, from this point forward, be careful. If any of your users login to the Communicator 2007 R2 client, or some other 3rd party chat client that supports enhanced presence, their user account will be configured for enhanced presence. Once this happens they will no longer be able to login to Communicator 2005.

So at this point you should have a LCS environment with no users based out of it, a OCS environment with all your users based out of it, and a bunch of users still using Communicator 2005 as their chat client. Assuming that you did all your work overnight or on weekends, from a user perspective they have no idea anything is going on. Now onto decommissioning LCS.

 

Decommissioning LCS 2005

I’m going to be pretty brief on this section. It consists of six steps.

  • Verify all your users have been migrated to OCS
  • Update your SRV record in DNS or your GPO
  • De-activate your LCS 2005 FE server
  • De-activate your LCS Archive server (optional)
  • Remove your LCS pool
  • Shut down your LCS servers

The first step is simple. Open your LCS console and verify no users are left being hosted from LCS. In the event you leave some, it’s not too big of deal. You’ll still be able to move them to OCS, however they’ll loose their contacts.

Next, you need to update your SRV record in DNS or your GPO that configures your Communicator 2005 clients. Up until this point, they’ve been pointing to your LCS pool as the “server”, however when you decommission your LCS environment, any client still pointing to the LCS pool will stop working. So first identify whether your Communicator clients get their configuration automatically via a SRV record, or “manually” via a GPO. Either way, update both to instead specify your OCS pool. Before proceeding, make sure all clients update to using the new settings.

Assuming that all your clients are now talking with OCS, you can go through and deactivate each LCS FE server. If I recall correctly, this is as easy as right clicking each FE server in the LCS console and clicking “De-activate”.

Now, if you have an Archive server, now is the time to also de-active it as well. For compliance/legal purposes, you’ll likely want to export the archive database from your SQL server and save it in a safe place.

You’re now able to remove your LCS pool. Right click the pool in the LCS console and remove it.

At this point, you can just shut down all your LCS servers. They’re done with, and so is the SQL databases / SQL instance that went with them.

 

Preparing for Lync 2010

You’re now at the point where you can start preparing your environment for Lync. There are four areas that need prepared.

  • Setup a service account
  • Setup a server for the front end role
  • Setup the SQL backend
  • Prepare AD for Lync

Start with creating your Lync service account. Once it’s created, add it to the following security groups.

  • Domain Admins (Temporarily)
  • RTCUniversalServerAdminsGroup

The service account will also need to be a local administrator on your Lync servers and on the SQL back end server. As far as I can tell, this step only needs done if the Domain Admins group membership is ultimately removed.

Now that you have your service account, go ahead and setup a server to act as your Lync 2010 front end server. Install Server 2008 R2 and fully patch it. You’ll then need to do the following on that server.

  • Install .NET 3.5
  • Install Visual C++ 2008 x64
  • Install SQL Server 2008 Native Client
  • Install OCSWMIBC.msi
  • Install Silverlight
  • Disable IE ESC
  • Setup a static IP
  • Install IIS

Also, now that you have your front end server setup with a static IP, you should create a Host A record for your Lync pool and point it to your future front end server. (Assuming you’re only setting up a single front end server.)

Note as well that if you want to install the Monitoring role or the Archive role that you’ll need to setup an additional server to host those two roles, assuming that you’re installing Lync 2010 Enterprise. Based on what I’ve read, the Standard Edition allows for co-location of all the roles on a single box.

As for the SQL back end, just setup a SQL instance and configure your Lync service account to have full access. Once again, don’t configure Lync to co-exist in a SQL instance that’s already in use by OCS/LCS or another Lync pool.

Finally, run through the AD prep for Lync by running Setup from the Lync installation. You’ll need to do the following.

  • Prepare the Schema (with a user account that’s a member of the Schema Admins group)
  • Replicate AD
  • Prepare the Forest
  • Replicate AD
  • Prepare the Domain
  • Replicate AD
  • Create an OU and move all your newly created Lync security groups there (optional)
  • Add your Lync service account to the security group “CSAdministrator”

At this point you’re ready to install Lync.

 

Installing Lync 2010

Installing Lync 2010 is pretty straight forward. Start by launching Lync setup on your future front end server. Install Topology Builder and then build yourself your Lync topology. Once you’re satisfied with the Lync topology you’ve built, publish the topology.

You then need to go to your first (or only) front end server and launch Lync setup. Do the following.

  • Install the Local Configuration Store
  • Setup Lync Server Components (Setup will automatically install the correct components for the server you’re running setup from based on the topology you already published)
  • Request, Install SAN Certificate
  • Start Services
  • Verify services started
  • Install Lync updates

Now that Lync is installed you’re ready to merge your OCS environment and Lync environment. Merging the environments allows you to upgrade users from OCS to Lync, as well as allow for communication between the two environments.

First run the OCS Merge Utility in Topology Builder, and then publish the new topology with the OCS information. You then need to run the following command from the Lync Management Shell. “Import-CsLegacyConfiguration”

At this point you should be good to test moving a user account from OCS to Lync. Now here’s were things get a little bit complicated. Assuming you followed these instructions step by step, you never upgraded any of your users from Communicator 2005 to Communicator 2007 R2. Communicator 2005 doesn’t work with Lync. Therefore you have to upgrade a user to the Lync client at the same time you migrate their user account from the OCS server to the Lync server. Now, some people might be totally against this because of the amount of coordination this requires, but take into consideration the approach I took to it, and then consider how much of a cleaner upgrade this appears to your end users by simply upgrading clients once.

 

Coordinating user moves from Communicator 2005 to Lync 2010

In order for my approach to work for you, you’ll have to have an environment where for the most part people have assigned systems. And then on that assigned system there’s information either in the registry on in a text file that lists information on the owner of that system. For me, we have a key in the registry populated with a bunch of information on the user that’s assigned to the system. One of the pieces of information is the users email address, which since I use their email address as their SIP address, that makes things extra easy.

The next thing you need to do is configure some way to trigger a user account move in Lync after a users system has been upgraded to the Lync client. There’s several ways you could go about doing this, but I’m only going to cover the method I ended up using.

In my case, we wrap all our installs with a vbscript. I configured that vbscript to create a text file with the name of the users email address on a network share after the Lync client is successfully installed on a system. I then have a PowerShell script running on my Lync Archive/Monitoring server that handles the actual user move. Technically this script could go on any server as long as it has the Lync Management Shell installed on it and you’ve installed OCSWMIBC.msi. The script I’ve setup to handle the user migration is rather complex, allowing the script to fix any issues that are encountered, email special instructions to end users, logging, ect. However, the script really only needs to do the following.

  1. Monitor the network share that the text files with user information are uploaded to
  2. For each text file with user information, use the Active Directory and Lync PowerShell modules to gather additional information on the user
  3. Run “Move-CSLegacyUser” for each user
  4. Have the script sleep for 10-20 seconds between each user move. The more users that are moved at once, the slower things will get. Allowing for some time between the moves allows things to keep up.
  5. Repeat

Using this type of a setup will allow you to only have to worry about coordinating client upgrades, knowing that the user accounts are being moved automatically on the back end.

 

Decommissioning OCS 2007 R2

I haven’t gotten to this part in my own production environment yet since I’m still stuck on the coordinating user moves, however I can supply some basic steps based upon my testing in my Dev environment.

Based upon my notes, there are three main pieces to decommissioning OCS 2007 R2. They are

  • Updating your SIP SRV Record / GPO
  • Deactivating the OCS environment
  • Updating your Lync toplogy

Granted before you do any of the above, you should verify that you don’t have any users living in your OCS pool, and that all your workstations have been upgraded to Lync 2010.

Updating your SIP SRV Record or GPO is just like what was done when decommissioning LCS 2005. You’re simply pointing your Lync 2010 clients to your new Lync front end environment instead of the OCS front end environment. Failure to do so will result in a bunch of clients getting disconnected and not being able to re-connect.

The next thing you need to do is deactivate your OCS environment. This step actually consists of a bunch of smaller steps.

First thing you’ll want to do is check for any conference directories in your Lync environment that are tied to your OCS pool. You can do so by running “Get-CSConferenceDirectory” from the Lync Management Shell and then looking for a conference identity that has a service ID tied to your OCS pool. Assuming you find one, you can use “Remove-CsConferenceDirectory” to get rid of it.

Once you’re done there, remove your OCS archive servers and monitoring servers, then deactivate every other OCS role. Once that’s taken care of, you can remove the OCS pool from the OCS Admin Console.

Now you can begin uninstalling the OCS software from your front end server(s). I’m pretty sure this would be entirely optional, since you could likely just shut down the server and be done with it. However if you do want to uninstall the software, I’ve read that you need to do so in a particular order. Here’s the order for removing the software.

  1. Administrative Tools
  2. Conferencing Attendant
  3. Conferencing Announcement Service
  4. Response Group Service
  5. Outside Voice Control
  6. Application Host
  7. Application Sharing Server
  8. Audio/Video Conferencing SErver
  9. Web Conferencing Server
  10. Web Components Server
  11. Front End Server
  12. Core Components
  13. API Core
  14. API Speech
  15. API Windows

Once that’s taken care of, you should go into Lync Topology Builder and delete the “BackCompatSite”, then publish your topology.

That should be it. You should now be able to sit back and say you’ve upgraded an environment from LCS 2005 to Lync 2010.

Uploading photos to AD and setting them as the Windows 7 tile picture

I’ve currently been working on a project to upgrade the company I work for from LCS 2005 to Lync 2010. Now that I’ve finally got the Lync infrastructure setup and am just waiting for the testing/pilot phases to finish, I’ve had some time to tinker with some other items that have been on my list of things to do.

The first thing on the list was importing photo’s into AD and then automatically having the Windows 7 tile picture for a user change to that picture, all with straight PowerShell code. (So no 3rd party add-ons or anything.)

After hunting around for awhile, I was finally able to put together two scripts to accomplish the task.

This first script is for taking a JPG image and uploading it to the current users AD account. Clearly this type of an interface isn’t something you’d want to throw at an end user, however I’ll leave how you present it to the end users up to you. More than likely I’ll create some sort of a front end to this script using PrimalScript or something.

Function Get-FileName($initialDirectory)
{
[System.Reflection.Assembly]::LoadWithPartialName(“System.windows.forms”) |  Out-Null

$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog
$OpenFileDialog.initialDirectory = $initialDirectory
$OpenFileDialog.filter = “All files (*.*)| *.*”
$OpenFileDialog.ShowHelp = $true
$OpenFileDialog.ShowDialog() | Out-Null
$OpenFileDialog.filename
} #end function Get-FileName

$username = $env:username
$jpgFile = Get-FileName -initialDirectory “C:”
$dom = [System.DirectoryServices.ActiveDirectory.Domain]::GetCurrentDomain()
$root = $dom.GetDirectoryEntry()
$search = [System.DirectoryServices.DirectorySearcher]$root
$search.filter = “(&(objectclass=user)(objectcategory=person)(samaccountname=$username))”
$result = $search.findone()
$user = $result.GetDirectoryEntry() [byte[]]$jpg = Get-Content $jpgfile -encoding byte $user.put(“thumbnailPhoto”, $jpg)
$user.setinfo()

This second script will take the photo that’s been uploaded to the current users AD account and set it as their Windows 7 tile picture. Ideally you would configure this script to run upon login. The command line to have a scheduled task run is also below.

C:WindowsSystem32WindowsPowerShellv1.0powershell.exe” -Sta -executionpolicy bypass -noprofile -noninteractive -file “C:tempScript.ps1”

 

$code = @”
[DllImport(“shell32.dll”, EntryPoint = “#262”, CharSet = CharSet.Unicode, PreserveSig = false)]
public static extern void SetUserTile(string username, int whatever, string picpath);

public static void ChangeUserPicture(string username, string picpath) {
SetUserTile(username, 0, picpath);
}
“@

#Get current logged in user
$DomainUser = (Get-WmiObject Win32_ComputerSystem).UserName

#Check logged on user is not a local account
$computername = $env:computername
$local = $domainUser.StartsWith($computername)
If($local -eq $True){

exit}

#If domain user, then configure AD pic as tile
Else{

#get username
$Username = $env:username

#Set JPG temp file
$ImageFile = “$ENV:tempADuser.jpg”

#Find User thumbnail from AD
$root = [ADSI]”
$searcher = new-object System.DirectoryServices.DirectorySearcher($root)
$searcher.filter = “(&(objectClass=User)(sAMAccountName= $Username))”
$result = $searcher.findone()

$user = $result.GetDirectoryEntry()
$ADthumbphoto = $user.thumbnailphoto

#write AD thumbnail to temp JPG file
$ADThumbphoto | Set-Content $ImageFile -Encoding byte

#Configure Tile image
Add-Type -MemberDefinition $code -NameSpace NEW -Name ChangeUserTile
[NEW.ChangeUserTile]::ChangeUserPicture($DomainUser,$ImageFile)
}

 

Deploying Firefox

I was recently tasked with deploying Firefox to a large chunk of system in the organization as a secondary browser. My first thought was this would be painful as hell, however after looking into it, deploying Firefox isn’t that bad. First I’m going to skim over the few things that in my opinion you absolutely must do for a “enterprise” type of deployment.

  • Use the ESR version of Firefox.
  • Repackage the Firefox install as an MSI. I don’t know of any free tools that you can do this with, but some examples would be Wise Packaging Studio (I don’t think this is being sold anymore…), AdminStudio, or MSI Studio.
  • Install Firefox to a unique directory. For example, if the version is 10.0.7, install Firefox to a directory like C:Program FilesMozilla Firefox 10.0.7.
  • Add the version number and ESR to any shortcuts.
  • Create your own JS file under INSTALLDIRdefaultspref.
  • Use a override.ini file.
  • Create an encoded Mozilla.cfg file.

You should have your encoded cfg file, your ini file, and your JS file ready to go before you go to repackage the application.

So first, start off by going out to http://www.mozilla.org/en-US/firefox/organizations/ and grab the latest ESR of Firefox.

Next, open up Notepad and paste the following into  it.

[XRE]
EnableProfileMigrator=false

Save that as “override.ini”, and stash it somewhere.

Also in Notepad (new session), paste the following into it.

pref(“general.config.filename”, “mozilla.cfg”);
pref(“browser.startup.homepage”,”data:text/plain,browser.startup.homepage=http://www.intrntpirate.com/”);

Save this file as custom.js and also stash it somewhere. This JS file contains Firefox settings that can be changed by an end user. (Think preferences within group policy.) The first line references the configuration file we’ll create next.

Lastly, in Notepad (again, a new session), paste the following into it.

//
lockPref(“browser.rights.3.shown”, true);
lockPref(“startup.homepage_welcome_url”,””);
lockPref(“app.update.auto”,false);
lockPref(“extensions.blocklist.enabled”,false);
lockPref(“extensions.shownselectionUI”,true);
lockPref(“network.http.pipelining”,true);
lockPref(“network.http.proxy.pipelining”,true);
lockPref(“network.http.pipelining.maxrequests”,8);
lockPref(“network.http.max-connections”,96);
lockPref(“network.http.max-connections-per-server”,32);
lockPref(“security.enable_tls”,false);
lockPref(“browser.shell.checkDefaultBrowser”,false);
lockPref(“toolkit.telemetry.enabled”,false);
lockPref(“toolkit.telemetry.prompted”,2);
lockPref(“toolkit.telemetry.rejected”,true);
lockPref(“extensions.getAddons.get.url”, “127.0.0.1”);
lockPref(“extensions.getAddons.search.browseURL”, “127.0.0.1”);
lockPref(“extensions.getAddons.search.url”, “127.0.0.1”);
lockPref(“extensions.getMoreThemesURL”, “127.0.0.1”);
lockPref(“extensions.webservice.discoverURL”, “127.0.0.1”);
lockPref(“app.update.auto”,false);
lockPref(“app.update.channel”,””);
lockPref(“app.update.enabled”,false);
lockPref(“app.update.url”, “127.0.0.1”);
lockPref(“app.update.url.details”, “127.0.0.1”);
lockPref(“app.update.url.manual”, “127.0.0.1”);
lockPref(“application.use_ns_plugin_finder”,false);
lockPref(“browser.download.useDownloadDir”,true);
lockPref(“browser.search.update”,false);
lockPref(“dom.disable_window_open_feature.location”,true);
lockPref(“dom.disable_window_open_feature.resizable”,true);
lockPref(“dom.disable_window_open_feature.scrollbars”,true);
lockPref(“dom.disable_window_open_feature.toolbar”,true);
lockPref(“extensions.blocklist.url”, “127.0.0.1”);
lockPref(“extensions.dss.enabled”,false);
lockPref(“extensions.update.enable”,false);
lockPref(“extensions.update.autoUpdateDefault”,false);
lockPref(“extensions.update.url”, “127.0.0.1”);
lockPref(“security.enable_ssl3”,true);
lockPref(“security.enable_tls”,false);
lockPref(“signon.autofillForms”,false);
lockPref(“signon.rememberSignons”,false);
lockPref(“xpinstall.whitelist.required”,true);
lockPref(“browser.download.manager.scanWhenDone”,true);
lockPref(“browser.formfill.enable”,false);
lockPref(“extensions.autoDisableScopes”, 15);
lockPref(“xpinstall.enabled”, false);

Save this file and call it Mozilla.txt. Now, navigate out to the following site -> http://www.alain.knaff.lu/howto/MozillaCustomization/cgi/byteshf.cgi, upload your Mozilla.txt and then download an encoded Mozilla.cfg file. Stash this config file with your other two files. It’s worth noting however that you don’t have to encode the config file. I do it just so end users can’t easily edit the configuration file. If you choose not to encode the config file, then instead of originally saving the notepad document as a .txt file, save it as a .cfg file and then add the following line to your JS file.

pref(“general.config.obscure_value”, 0)

Now, in case you’re just following this blindly, I’ll go over what we just did briefly. The override.ini file is in place to prevent the Import Wizard from running the first time an end user launches Firefox. (Like all things in the files we just created, if you don’t want a setting or “feature”, change it or remove it.) The custom JS file I pasted in above contains a line telling Firefox to read a particular configuration file, and then it also sets a preference for what I would like the home page to be. By setting this in the JS file an end user can permanently change the home page to whatever they’d like. Finally, the configuration file is there to lock settings in place. It’s very possible you could put the homepage in the configuration file as a Pref instead of a lockPref, however I haven’t tried. I pasted in most of what I have in my configuration file. There are a few settings I’ll call out. The rest are all set because they make sense to me for having set in an enterprise environment.

  • startup.homepage_welcome_url : I set this to nothing so that when a user opens Firefox for the first time they only see 1 tab open with their home page. If this is set to a corporate intranet site which is the same as the homepage, the user will see 2 identical tabs. If you don’t configure this option with anything then the user will see a Firefox welcome site. I prefer the user get a clean looking browser without junk, so I’ve removed the welcome tab on first launch.
  • extensions.shownselectionUI = false : I set this to false so that the end user doesn’t get a window regarding add-ons appearing the first time they launch Firefox. This is a similar window as to what Internet Explorer has for ‘speeding up your browser’ by disabling add-ons. In my case, any add-ons present on the system are there for a reason, so the users here don’t need to see this screen.
  • browser.shell.checkDefaultBrowser = false : This prevents the “Do you want Firefox to be the default browser” box from showing up. In my case Internet Explorer is still the default browser. Setting this in no way prevents the user from manually changing firefox to being the default though.
  • toolkit.telemetry.rejected = true : This is setting 1 of 3 settings that prevents the ‘do you want to send info back to Mozilla’ bar from appearing during first launch.
  • toolkit.telemetry.prompted = 2 : This is setting 2 of 3
  • toolkit.telemetry.enabled = false : This is setting 3 of 3

All the extension. and app. settings have to do with preventing add-ons/extensions and preventing automatic updates and such. Where you see 127.0.0.1 I’m just telling the browser to look back at the local system for a update server and such. So far the settings I have set seem to be effective at keeping add-ons and updates away. For those who don’t understand why I wouldn’t want automatic updates, generally in large environments you want to control the version of the software being used.

So now that you understand what the various files you created are for, now it’s time to package the application. I would suggest using a snapshot mode to capture the installation, but you can do whatever you’d like. Keep in mind that it’s best to install to the unique installation directory using the Firefox setup, and to change shortcuts and add your files before you capture the results with your repackaging software.

In case I didn’t already say this,… which I don’t think I did, override.ini and mozilla.cfg both go in the installation directory right alongside Firefox.exe. Your custom JS file goes under .defaultspref.

One issue you might see during your deployment is the add-on window still appearing during the first launch of Firefox even though there’s a configuration item set telling it not to appear. I’ve found that in my cases, this happens when there’s already a Firefox profile in existence. If you open up the prefs.js file under %AppData%MozillaFirefoxProfilesflakdfja.default and remove the lines that contain “user_pref(“extensions.”, you won’t see this issue. My best guess is that the new version of Firefox has an issue with extensions that were registered under an older version. In my case, I created a VBScript to delete the lines from the JS file, then embedded this script in a custom action that ran during install and repairs of the MSI. This is where you find ActiveSetup rather useful.

If anyone reads this and finds that I’m doing something odd, or wants to point out another way of accomplishing the same task, let me know. This is my first run with deploying Firefox, and all of the above was figured out in just a couple of hours.

Deploying Microsoft SharePoint Designer 2010

The following steps you through deploying SharePoint Designer 2010 as well as uninstalling it using command line.

First you’ll want to download SharePoint Designer x86 or x64. You’ll get a executable that’s about 260-285MB. You’ll then want to extract the executable by running “SharePointDesigner.exe /extract:C:extractedfiles”. Yes, I know there are install parameters for the base executable that you download, however you can’t silently deploy the application in this state.

Once the files have been extracted you’ll find an Office 2007/2010 like structure of files. You’ll then want to create an MSP file like you would for Office. This is done by running “Setup.exe /admin” and then running through the configuration gui. Once you’ve created your MSP, you can silently install SharePoint Designer by running “Setup.exe /adminfile MYMSP.msp”.

In order to uninstall SharePoint Designer using command line, you’ll first need to create the below XML file.

<Configuration Product=”SharePointDesigner”>
<Display Level=”none” CompletionNotice=”no” SuppressModal=”yes” AcceptEula=”yes” />
<COMPANYNAME Value=”CAS” />
<OptionState Id=”WAC_SPD” State=”absent” Children=”force” /> //sharepoint designer
<Setting Id=”SETUP_REBOOT” Value=”Never” />
</Configuration>

Place your XML file in the same folder as Setup, then run “Setup.exe /uninstall sharepointdesigner /config uninstall.xml”.

Deploying Java Runtime Environment

Deploying JRE’s in my opinion has always been a pain, however my new employer has developers that write Java based applications, so obviously I’ve had to improve my skills with deploying JRE’s to business users. The first thing I’ve come to discover is that a JRE can be ran against a system in two different ways. The first way would upgrade an existing installation of JRE, where as the second way leaves an existing installation alone and installs itself as a stand alone instance, which allows you to install multiple versions of JRE on a system. If you’re looking to upgrade existing installations, you’ll start your Java deployment out by simply running the Java offline installer and then grabbing the MSI it extracts from your Application Data. If you want to install a stand alone instance of Java, you’ll run your Java offline installer with STATIC=1. (For example, “jre6.exe STATIC=1”) Once you’ve gotten the MSI that extracts from the offline installer I would recommend creating an MST with the following customization, however technically you could deploy it “as is” at this point.

  • Set the AUTOUPDATECHECK property in the MSI to 0
  • Create custom actions that run as deferred executions right before InstallFinalize that adjust registry entries for auto update and deletes the files java.exe, javaw.exe, and javaws.exe from %windir%system32. You need to make sure that these custom actions only run if the product is NOT installed. You also need to configure permissions on HKLMSoftwareJavaSoftJava Plugin-in so that users can write to that key.

After all of the above, you’ll end up with a decent JRE deployment.

Some additional things to know about JRE’s is the layout of the registry under HKLMSoftwareJavaSoft. Some key items that I feel are worth pointing out is that you can always find the default running version of Java by looking at “HKLMSoftwareJavaSoftJava Runtime Enviroment” and then reading the Reg_Sz item “BrowserJavaVersion” or “CurrentVersion”. You can then use those values to navigate to sub keys under the “Java Runtime Environment” key where you can find where Java is installed to. This is useful if you need to run Java.exe as part of a Java application install.

MSI Custom Actions using MSI Public variables

Recently I’ve been doing a lot with application repackaging and having to get a lot more creative with things than I had to at previous employers. I found myself needing to create a custom action for an MSI that ran a vbscript, and that vbscript needed to know what the installation directory was set to. Now, obviously most of the time you’re going to know what the installation directory is because you’re setting that already in the MSI and during a passive/silent install it’s obviously pre-determined, so needing to pull that into your vbscript is rare because you can just manually specify the directory. However, in my case end users could change the installation directory (which they would…) and that would royally screw up my custom action.

After some researching I found that it was actually really easy to pull in an MSI property into vbscript and then set it to the value of a variable, however then I found that you could not even read a ‘Public Property’ during the deferred execution phase.  I found a bunch of articles explaining ways that were suppose to allow you to get the property over, however none of them were just “working”. Finally, after about a day of looking at all these different solutions to the problem, I managed to get it working. So hopefully in an effort to save someone else a bunch of time, below are the steps for being able to read a public property during a deferred custom action.

  1. The first step to do is to create a deferred execution custom action within your MSI that will be running your vbscript. In this example, we’ll name the custom action “LabVBSCA”.
  2. The next step is to create an immediate execution custom action that creates a property. You can call the custom action whatever you would like, in this example though we’ll stick with calling it “LabCusProp”. Now, set the name of the property that it’s creating to be the SAME as the name of the custom action you created in step 1. In this case, you’re going to be creating a property called “LabVBSCA”. For the value of this new property, you can put in a single public property or multiple public properties, however in this example just put in “[INSTALLDIR] for the value of the new property.
  3. Back to the vbscript in custom action “LabVBSCA”, the following code can be used to pull the INSTALLDIR property into your script as a variable.Dim MSICustomAction
    MSICustomAction = Session.Property(“CustomActionData”)
    MsgBox(“”& MSICustomAction &””)

As for where the custom actions need to go in the event sequencing, the actions both need to live under “InstallExecuteSequence”, however where they go in the order items I don’t believe matters. I’m pretty sure the rule is “If it’s not working, lower the items in the list of events.” I do believe though that for best results, the custom action that creates the new property should placed before the custom action that uses the new property.

In the event that you’re wanting to pass multiple public properties over, you can simply put “[PROP1],[PROP2],[INSTALLDIR]” in for the property value that you create in step 2, and then in step 3 you’ll just need to split the array in your vbscript.

 

Hopefully this write up helps someone else save some time figuring it out…

Set default OU for Computer and User objects

You’ve likely noticed that every time a system is joined to the domain without a computer object being defined first, it ends up in the default “Computers” container. The same is true about user objects always ending up in the default Users container unless otherwise specified.  Generally an IT organization simply works around this behavior, however I think it’s better for an organization to customize their domain a bit by changing these default settings.

To change the default settings, all you have to do is run a simple command line on your DC for both user objects and computer objects. The command lines are below.

For user objects:

ReDirUsr “OU=User Accounts,DC=domain,DC=local”

For computer objects:

ReDirCmp “OU=Computer Accounts,DC=domain,DC=local”

Additionally, I would put GPO’s on the new default OU’s that would cripple user accounts and computer accounts on your domain while they’re in this default OU. If you think about it, you generally have a much more defined OU structure than just “User Accounts” and “Computer Accounts”. I would personally use those two default OU’s to catch user and computer objects that are created in your domain incorrectly. That will allow you to correct any configuration issues there might be with the objects before moving them to their proper OU, and possibly even track down someone in your organization that’s doing some incorrectly.

Controlling the Stationery fonts in Outlook 2010

You might find that you need to specify a particular font to be used in Outlook. This could be because you want to have a standard across the board, or because some users require a specific font.

The font settings in Outlook 2010 are located under File -> Options -> Mail -> Stationery Fonts. Once there you’ll see that you can adjust the front for New/Replying messages, as well as the font for plain text messages. Any change that you make for these fonts is stored under “HKCUSoftwareMicrosoftOffice14.0Commonmailsettings.

Once you identify the font settings you want, you have three ways of deploying. You can include the font settings with your Office MSP file, implement the registry modifications using a GPP, or deploy the registry modifications using a deployment tool like ConfigMgr. Obviously if you use the Office MSP file, the font change will only stay in affect as long as the end user doesn’t change it. If you use a GPP or ConfigMgr, you can configure the settings to be reapplied.

Configuring the “Compatibility” tab

This post discusses how to configure options on the Compatibility tab for a given executable by making modifications through the registry.

There are two different ways to go about doing it, making a change for an executable for all users on a system and making a change for an executable for a single user.

When you configure an executable to run in compatibility mode, Windows XP and 7 will store that configuration change either under HKCUSoftwareMicrosoftWindows NTCurrentVersionAppCompatFlagsLayers (If the change is only for a particular user.) or HKLMSoftwareMicrosoftWindows NTCurrentVersionAppCompatFlagsLayers (If making the change for all users.) Under the Layers key, the OS creates a String value for each executable and then assigned the compatibility properties to the value of that string. For example, if you had an executable living under C:Program FilesAdobeReaderAdbRd.exe and you wanted Windows 7 to run the executable in Windows XP SP3 compatility mode, you would create the following string.

Value Name: C:Program FilesAdobeReaderAdbRd.exe
Data: WINXPSP3

After that string is in place, depending on where you placed the string (System or User) the next time the executable is launched it will run under Windows XP SP3 compatibility.

In addition to just defining the OS compatibility, you can also specify all the additional options that you would see on the compatibility tab using that same string value. Below I’ve listed the available options and how you would call for that option to be enabled.

Windows XP Options

Windows 95 = WIN95
Windows 98/ME = WIN98
Windows NT 4.0 SP5 = NT4SP5
Windows 2000 = WIN2000

Run in 256 Colors = 256COLOR
Run in 640 x 480 screen resolution = 640X480
Disable visual themes = DISABLETHEMES
Turn off advanced text services for this program = DISABLECICERO

Windows 7 Options

Windows 95 = WIN95
Windows 98/ME = WIN98
Windows NT 4 SP5 = NT4SP5
Windows 2000 = WIN2000
Windows XP SP2 = WINXPSP2
Windows XP SP3 = WINXPSP3
Server 2003 SP1 = WINSRV03SP1
Server 2008 SP1 = WINSRV08SP1
Windows Vista = VISTARTM
Windows Vista SP1 = VISTASP1
Windows Vista SP2 = VISTASP2
Windows 7 = WIN7RTM

Run in 256 colors = 256COLOR
Run in 640×480 screen resolution = 640X480
Disable visual themes = DISABLETHEMES
Disable desktop composition = DISABLEDWM
Disable display scaling on high DPI settings = HIGHDPIAWARE
Run this program as an Administrator = RUNASADMIN

 

When wanting to use any of the additional options other than the OS mode, you simple need to add the option on to the value data. For example, if you wanted an executable to run under Windows XP SP3 mode and also run as an Administrator, the value would look like the following. “WINXPSP3 RUNASADMIN” Luckily, the order you provide these values in doesn’t matter. So even though on the compatibility tab the run as administrator option is always at the bottom, you can specify it first and then maybe specify the run in 256 colors option last.