Monday, December 7, 2009

Waar ben ik mee bezig?

Ja de laatste update is alweer een tijd geleden. De afgelopen maanden ben ik veel operationeel in het veld bezig geweest en natuurlijk weer een hoop ervaringen opgedaan, daarover later meer. Op dit moment ben ik bezig met de ontwikkeling van nieuwe oplossingen gebaseerd op UMRA, ik verwacht begin 2010 hierover meer te kunnen vertellen.

Monday, August 24, 2009

Performance tuning bij koppelingen

Bij veel klanten leveren we actieve koppelingen tussen HR-bron systemen en bijvoorbeeld een Active Directory. Een dergelijke koppeling bevat in de praktijk altijd een drietal scenario's:

  • Medewerker nieuw in dienst: aanmaken
  • Medewerker verandert van functie/afdeling: update met mogelijke wijzigingen in groepen
  • Medewerker gaat uit dienst: inactief maken, mogelijk na een aantal dagen/maanden definitief verwijderen
Bij een aantal van de bovenstaande scenario's is het denkbaar dat extra informatie nodig is uit het HR-systeem, en dat deze informatie meervoudig per werknemer is. Denk bijvoorbeeld aan lokaties, afdelingen, functies en kostenplaatsen. Een medewerker kan best aan meerdere van deze elementen gekoppeld zijn. De basisopzet van een koppeling is echter om met genormaliseerde gegevens te werken, dus 1 record met 1 waarde per werknemer.

Zodra in een koppeling gebruik wordt gemaakt van een groepsynchronisatie op basis van meedere elementen per werknemer zie je vaak dat het HR-systeem nogmaals wordt geraadpleegd, wat resulteert in een extra query voor elke werknemer. Deze extra queries zorgen niet alleen voor vertraging van de koppeling, maar ook voor extra netwerkbelasting en belasting van het HR-systeem.

De oplossing: werken met sessie variabelen.
In UMRA is er sinds versie 10 de mogelijkheid om variabelen in een sessie op te slaan. Een groot voordeel hiervan is dat je eenvoudig aan het begin van een koppeling een grote repository kunt opbouwen van alle gegevens die nodig zijn, en deze later kunt raadplegen uit memory in plaats van een extra query nodig te hebben.

Voorbeeld:
Stel je werkt met een HR-systeem met 5500 medewerkers. Elke medewerker heeft 1 of meer functies bij 1 of meer afdelingen. De koppeling loopt over een bron met 5500 records met genormaliseerde gegevens, dus 1 functie en 1 afdeling. Voordat de iteratie over de 5500 recors begint, wordt er eerst een grote gegevensset uit het HR systeem geladen met alle personeelsnummers, functies en afdelingen. Deze gegevensset wordt in de sessie opgeslagen.

Per iteratie voor de 5500 records kun je nu de gegevensset uit de sessie raadplegen, zoeken in de tabel in memory naar het personeelsnummer en zo alle functies en afdelingen ophalen per werknemer. Aangezien dit allemaal in memory plaatsvindt is de performance uitstekend en zijn subqueries naar externe systemen niet nodig.

Friday, August 21, 2009

SmartDocuments: Batch Import new accounts

SmartDocuments wordt bij een aantal klanten gebruikt als huisstijl-applicatie bovenop Microsoft Office Word. Deze applicatie draait bovenop een SQL database die eigen user accounts bijhoudt. Dat zorgt er weer voor dat je dus zelf het userbeheer van een dergelijke applicatie zou moeten bijhouden. Je kunt dit echter integreren in een UMRA omgeving en dit aan bijvoorbeeld je helpdesk delegeren via e-formulieren.


De SQL database van SmartDocuments heeft een tabel genaamd SDUsers, hierin wordt de status van de user accounts bijgehouden die SmartDocuments mogen gebruiken. Het probleem is echter dat een property van deze database gevuld moet worden via een zogenoemde XML PropertyBag, waarin de werkelijke properties van de user zijn opgenomen. Dit dient vooraf correct geformatteerd te worden voordat het in de database verwerkt kan worden. Met UMRA kun je gelukkig eenvoudig XML formatteren en deze PropertyBag voorbereiden voor een database insert.

De code om een nieuwe entry in de SDUsers tabel aan te maken via een SQL insert werkt als volgt:

INSERT INTO SDUsers
(ID,
IsAdmin,
Login,
Password,
ItemData)
VALUES
(replace(convert(varchar(255), newid()), '-', ''),
0,
'%AD_username%',
'',
'%PropertyBag%')

De %AD_username% is de sAMAccountName waarde uit Active Directory welke door UMRA wordt doorgegeven, en de %PropertyBag% is een door UMRA in XML formatteerde string.

Het opvragen van de status of iemand SmartDocuments kan gebruiken is natuurlijk simpel, via het volgende commando kun je opvragen of een username voorkomt in de SDUsers tabel:

SELECT ID
FROM SDUsers
WHERE Login = '%AD_username%'

Neem contact op met Tools4ever om meer te weten te komen over de integratie met SmartDocuments en hoe de XML database import specifiek voor jouw omgeving kan worden ingericht.

Thursday, July 16, 2009

VBScript to read Exchange 2003 mailbox store total size

In Exchange 2007, you have PowerShell to perform powerful queries on mailbox stores, which make it easy to get the total size of a mailbox store by calculating all mailbox contents in bytes. In Exchange 2003 however, you need to do this with WMI which doesn't know about mailbox stores but only allows you to query mailboxes.


The script below does 2 loops through all mailboxes. The first one is to get a unique list of all the mailbox stores from each mailbox, and the second one is to calculate the total size of each unique mailbox store from all the mailboxes. In my tests it takes about 30 seconds for an environment of 3 mailbox stores with over 9000 mailboxes.

The script takes 2 parameters, Exchange server and output file. The output file will contain the following data:
mailbox store 1|5262342
mailbox store 2|23489
mailbox store 3|60930235

==========================================
dim fso, StoreArray, StoreName_cache
set fso = CreateObject("Scripting.FileSystemObject")

strComputerName = wscript.arguments(0)
strOutput = wscript.arguments(1)

set output = fso.CreateTextFile(strOutput, True)
strE2K3WMIQuery = "winmgmts://" & strComputerName & "/root/MicrosoftExchangeV2"
Set mboxList = GetObject(strE2K3WMIQuery).InstancesOf("Exchange_Mailbox")

StoreName_cache = ""

For each mailbox in mboxList
if InStr(StoreName_cache, mailbox.StoreName) = 0 then
StoreName_cache = StoreName_cache & ";" & mailbox.StoreName & "|0"
end if
Next
StoreName_cache = Mid(StoreName_cache, 2, Len(StoreName_cache))
StoreArray = Split(StoreName_cache, ";")

For each mailbox in mboxList
For currentIndex = 0 to UBound(StoreArray)
tmpArray = Split(StoreArray(currentIndex), "|")
if tmpArray(0) = mailbox.StoreName then
tmpSize = CLng(tmpArray(1)) + CLng(mailbox.Size)
StoreArray(currentIndex) = mailbox.StoreName & "|" & tmpSize
end if
Next
Next

For currentIndex = 0 to UBound(StoreArray)
output.WriteLine StoreArray(currentIndex)
Next

Monday, July 13, 2009

Use DFSCMD.EXE for scripted DFS mappings

When using DFS, you might want to consider adding DFS links for user home and profile directories to a DFS root. If you want to integrate this into a script, try the following command-line:

"%SystemRoot%\dfscmd.exe" /map "%DFSHomeRoot%\%AD_username%" "\\%HomeServer%\%HomeShare%\%AD_username%"

Variable explanation:
  1. %SystemRoot% = C:\WINDOWS\System32
  2. %DFSHomeRoot% = the DFS root you want the folder linked to
  3. %AD_username% = the sAMAccountName attribute for the user, in this case the name of the folder
  4. \\%HomeServer%\%HomeShare%\%AD_username% = UNC path to the folder which needs the link

Vasco Digipass with UMRA and Active Directory

Several clients are using digipass systems from Vasco as their main security token system for both VPN and building access. Since this system is Active Directory integrated and features an API, we can easily integrate it within the UMRA identity management framework for automatic token provisioning on new user accounts, and token profile management on existing user accounts.


The process of assigning a token to a user account is fairly simple and involves some basic steps:
  1. Locate a token from the digipass-pool. This is a root OU created by the Vasco software when installed in your environment.
  2. Retrieve the vasco-SerialNumber attribute from the located token.
  3. Supply the sAMAccountName attribute, domain name, vasco-SerialNumber and grace period # of days to the TCL script
  4. The Vasco software moves the digipass object from the digipass-pool to the user OU and applies all kinds of vasco related attributes on both the user object and the digipass object. Vasco extends the Active Directory schema to support these attributes.
  5. The user in Active Directory gets extra tabs in their property dialog when using the AD Users and Computers MMC snap-in.
The challenging part when integrating Vasco into Active Directory account provisioning is to write TCL scripts. The documentation provided by Vasco is unfortunately very basic and didn't offer much help. Some of the operations, like adding authorization profiles and grace periods are not documented at all. Also, be careful that the Vasco connection to the Active Directory appears to be not bound to a specific domain controller, so integrating it with batch jobs may cause replication issues. I've determined that for most clients a delay of 5-10 seconds before executing a TCL script is sufficient to let the AD replicate to its domain controllers.

When moving user accounts to another OU, make sure you also move the digipass object to the same OU, otherwise it won't work. Also, update the vasco-linkUserToDPToken attribute on the user object and the vasco-linkDPTokenToUser attribute on the token object in your script, otherwise the link between the user and the digipass object will be broken.

Vasco uses TCL scripting for all unattended scripted operations, which can be executed using the command line tool DPAMINCMD.EXE, which is installed by default with the Vasco software inside the BIN folder.

Example TCL script to create a user account with digipass association:
set userid [lindex $argv 0]
set domain [lindex $argv 1]
set serial_no [lindex $argv 2]
set grace_period_end [lindex $argv 3]
set grace_period_minus [lindex $argv 4]
set password [lindex $argv 5]

puts $userid
puts $domain
puts $serial_no
puts $grace_period_end
puts $grace_period_minus
puts $password

if [catch "user create {userid $userid domain $domain password $password}" result] {
puts "Create: $result"
} else {
puts "Create: $result"
}

if [string equal $grace_period_minus yes] {
if [catch "digipass assign {userid $userid serial_no $serial_no search_up_ou 1 grace_period_end -$grace_period_end}" result] {
puts "Assign-minus: $result"
} else {
puts "Assign-minus: $result"
}
} else {
if [catch "digipass assign {userid $userid serial_no $serial_no search_up_ou 1 grace_period_end $grace_period_end}" result] {
puts "Assign: $result"
} else {
puts "Assign: $result"
}
}

A similar TCL script to delete the digipass association from a user account:
set userid [lindex $argv 0]
set domain [lindex $argv 1]
set serial_no [lindex $argv 2]
puts $userid
puts $domain
puts $serial_no

if [catch "user delete {userid $userid domain $domain}" result] {
puts "Create: $result"
} else {
puts "Create: $result"
}

if [catch "digipass unassign {userid $userid serial_no $serial_no}" result] {
puts "Assign: $result"
} else {
puts "Assign: $result"
}

Monday, June 29, 2009

ASP: dynamic checkbox generation

UMRA features quite easy integration with IIS through the use of a COM object, which makes it very easy to send request to and receive information from UMRA. The only thing we need to do when creating a web interface for UMRA is to feed the correct information to an UMRA project.

Code samples:
Set Umra = Server.CreateObject("UmraCom.Umra")
RetVal = Umra.Connect("SRV01", 56814)
RetVal = Umra.SetVariableText("%input%", input)
RetVal = Umra.ExecuteProjectScript("my-project")
RetVal = Umra.GetVariableText("%my-status%", status)

The above code snippet creates an UMRA object, connects to the UMRA service, then feeds some information, executes an UMRA project and then gets the status back from the service.

Challenge on creating dynamic ASP pages:
Ever had trouble creating an ASP page with a variable amount of checkboxes, depending on a database or an Active Directory query? There are easy ways to generate the checkboxes on the page and to dynamically handle the user interaction results. The trick is to generate numbered checkboxes and set the value to the data you want to be processed. The only thing you have to do to handle the submit is query all checkboxes and their values to get the data you need.


ASP page with checkboxes in form:

ASP page to handle the submit: