Monday, April 23, 2007

Password Reminder updated!

I made some small (but significant) changes to the Password Reminder console application. First of all, it's useless to send disabled users a reminder to change their password eh? So I changed my code that only the 'not-disabled' users are notified. The property you need to query for this is : userAccountControl and it returns an integer. I used the following chart http://support.microsoft.com/kb/305144 to come up with the integer value of 544 to only get a non-disabled user.
The code below is the function that determines per user whether when his/her password will expire and if the user is enabled/disabled. If the password is about to expire within 20 days, an email will be sent to notify the user that their password must be changed.

public static void GetAccountExpiration(CUser user)

{

try

{

string LogUser = user.UserName;

DirectoryEntry entry = new DirectoryEntry("LDAP://DOMAINSERVER");

DirectorySearcher search = new DirectorySearcher(entry);

search.Filter = "(SAMAccountName=" + LogUser + ")";

SearchResult LDAPresult = search.FindOne();

entry = LDAPresult.GetDirectoryEntry();

//This int will tell us if the user is disabled yes or no

int disabled = Convert.ToInt32(entry.Properties["userAccountControl"].Value.ToString());

// Pulling the informtion on when the password was last changed and converting it to a LargeInteger.

LargeInteger liAcctPwdChange = entry.Properties["pwdLastSet"].Value as LargeInteger;

// Convert the highorder/loworder parts of the property pulled to a long.

long dateAcctPwdChange = (((long)(liAcctPwdChange.HighPart) << 32) + (long)liAcctPwdChange.LowPart);

// Convert FileTime to DateTime and get what today's date is.

DateTime dtNow = DateTime.Now;

// I added 90 days because I know what my password expiration is set to, if not you need to pull that information and add the number of days it is set for.

CultureInfo ci = new CultureInfo("nl-NL");

DateTime dtAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).AddDays(180);

string strAcctPwdChange = DateTime.FromFileTime(dateAcctPwdChange).ToString("d",ci);

string strAcctPwdExpires = DateTime.FromFileTime(dateAcctPwdChange).AddDays(180).ToString("d",ci);

// Calculate the difference between the date the pasword was changed, and what day it is now and display the # of days.

TimeSpan time;

time = dtAcctPwdChange - dtNow;

if (time.Days < 20 && time.Days >= 0)

{

if (disabled == 544)

{

Console.WriteLine(user.FirstName + " " + user.LastName + " " + user.EmailAddress + " " + "Password changed: " + strAcctPwdChange + " Password expires: " + strAcctPwdExpires + " There are " + time.Days.ToString()+ " days left");

WebMail mail = new WebMail();

mail.To = user.EmailAddress;

mail.From = "";

mail.Subject = "Password expiration";

mail.Body = "" +

"<style>table {margin: 20px; border: 2 inset #efefff; background-color: #efefff; } td {font-family: verdana; font-size: 10px; color: #444444; font-weight: normal} .label {width:200px; font-weight: bold;} .title {font-weight: bold; font-size:14px; align: center;}</style>" +

"<table cellspacing=10 cellpadding=0>" +

"<tr><td colspan=2 class=title>Password expiration</td></tr>" +

"<tr><td class=label>Dear "+user.FirstName + " "+user.LastName +" , <BR><BR>your password is about to expire. You've last changed your password on " + strAcctPwdChange + ". Your password will expire or is expired on " + strAcctPwdExpires + ".<br></td></tr></table>";

mail.SendMessage();

}

}

}

catch(Exception error)

{

Console.WriteLine(error.Message.ToString());

}

}


 

And there you have it! Btw if you are wondering why on earth I created this console app.. Well, in the Sharepoint2003 time we did not have the luxury of formsbased authentication for our internet users so we created an extranet domain which could be administrated via the web. And when an user logons to Sharepoint there was no easy task of telling the user that his or her password was about to expire, even if it was possible, not every user logged on every day/week so the idea came to notify the user by email.

Saturday, April 21, 2007

Sharepoint and databases

Well funny thing happened these week, I wanted to create a (sub)web programmatically using the OM using a webtemplate. Nothing fancy here eh? :) Just what I thought so I build it and I wanted to test it and everyhing went ok. So I deployed on production environment, tested it there and then the problems came. It continually keep getting errors like 'cannot complete this action'. Things that did work :
1. The ID could be read via the OM
2. The title of the web could be read via the OM
Things that didn't work :
1. Kept getting 404's when I navigated to the site
2. Kept getting 'cannot complete this action' errors using the weburl and adding the /layouts/settings.aspx (or any other .aspx) urls
3. The navigation in WSS was broken, all the subsites could not be displayed.
4. Could not be deleted using the OM
5. Could not be deleted using STSADM

So what to do? Yes.. the one thing you should never do. Modify the database. It's unsupported by MS (default.aspx-scid=kb;EN-US;841057) as my mate Daniel also pointed out and told me to call support of MS to solve this issue. Although during our IM session I managed to fix it by modifying the record in the WEBS table and then I could delete the web using STSADM. The tricky part here is that you'd never know what happens in the future after this modification (although the records were gone after the deletion with STSADM, so technically speaking the modifications were not there anymore)

This brings me to the next thing I wanted to get of my chest and that is: Sharepoint developers/consultants must know what is going on in the databases. Having read the following blogpost SharePoint Database Growth Rates by Dave Wollerman about truncate the logfiles if the recovery model of the database is set to Full. By default the databases that are created by Sharepoint have the recovery model on Full. And why is that? I can't imagine why anyone wants to recover his/her Sharepoint database using the transactional logs since the database backup is probably the last backup/restore method you should use.
Therefore I always recommend setting the recovery model to Simple so you don't have to think about the transaction logfiles. Another benefit you get with this is better perfomance since the DMBS doesn't have to worry about creating logfiles. But to know all of this, just to let the DBA guys know how to configure, you have to get knowledge of SQL Server.

So to conclude this post: do some SQL Server training or even better get certified as MS SQL DBA (like I'm planning to be ;))

MOSS Extension :Interactive Media Manager

Well here is the first add-on for MOSS (if you don't count Excel- and Forms Services or the BDC as seperate add-ons). So what does this add-on do? Basically it's a nice solution for companies that want to use digital images as their primary content to collaborate with each other. Here is a snippet of the features :

Interactive Media Manager includes components of existing Microsoft solutions such as Windows Workflow Foundation, Windows Communication Foundation, InfoPath® XML forms and the newly announced Microsoft Silverlight™, previously called Windows Presentation Foundation Everywhere (WPF/E). Building on the capabilities of Office SharePoint Server 2007, Interactive Media Manager provides the following customizable Web parts that target specific processes within the content production life cycle:

• Media Library serves as a front end in which media content items in the digital asset management system are displayed as thumbnails.

• Media Viewer displays information such as annotations and time codes in Society of Motion Picture and Television Engineers format and offers sophisticated, built-in playback controls.

• Media Annotator allows groups of people to collaborate on media assets through video annotations, digital inking and discussions.

• Media Import facilitates the upload of media files and automatically launches associated workflows, such as information-gathering processes.

• Media Cart provides an individualized area for storing media assets that people want to edit themselves or push out to appropriate editors.

 

(really nice theme they use eh? ;)

What really interests me is the following sentence "..Interactive Media Manager easily integrates with Microsoft business intelligence tools, giving management insight into production details...". Does anybody have thoughts about this? Here is more info from the whitepaper that answers my question :)

Business Intelligence

Interactive Media Manager offers first-class reporting capabilities with customizable dashboards and easy integration with reporting tools such as Microsoft Office PerformancePoint™ Server 2007, Microsoft SQL Server™ 2005 Reporting Services and Excel® Services. (Excel Services is a new, shared service in SharePoint Server 2007 that makes it easy to display and calculate Microsoft Office Excel 2007 workbooks on SharePoint Server portals and dashboards.) Media and management companies will want to take advantage of the built-in workflow reporting functions that show the status, time spent, and steps included in ongoing workflows.

Unlike standalone DAM systems, the Interactive Media Manager solution offers a convenient way of incorporating business information into content production. The Report Center offers a central place for collecting and publishing reports, spreadsheets, and key performance indicators common to a group, including SQL Server 2005 Reporting Services reports and data from business management systems. Also, with Excel Services, people can securely share live, interactive Excel workbooks.

Check http://www.microsoft.com/resources/mediaandentertainment/solutions_imm.mspx and Microsoft Introduces Interactive Media Manager - extension of MOSS 2007 for more details!

Tuesday, April 17, 2007

MOSS : Keeping metadata while copying/moving items

From the Sharepoint Helpdesk comes this post about how to keep your metadata while you want to copy or move items/documents across your sites/lists. The keyfactor here is the use Manage Content Structure link in the site adminstration page! In short, this is the Explorer view but then webbased ;)

So thanks Stephen! I had some difficulty with moving items around when a list became corrupted and I wanted to move all the items while the metadata was preserved, this is just what I needed back then ;)

Friday, April 13, 2007

SQL 2k > SQL 2k5 > SQL 2k = NoGo

Right you're probably wondering why on earth you would want to migrate a database from SQL2k to SQL2k5 and then back to SQL2k heh?
Well let me explain the context; a request to migrate an existing Sharepoint 2003 environment into another existing Sharepoint 2003 environment was made by a customer. No problem eh? Well it is when one environment is only RTM and the other is SP2. Luckily the to-be-migrated environment wasn't that big so I could restore the environment onto a development machine using the RTM version then apply SP2 and backup the environment again and restore that servicepackked environment to the destination environment.
So what was the problem you think.. well the 'from' environment was SQL2K, the 'upgrade-to-sp2' environment was SQL2K5 and the 'destination' environment was SQL2K. And while doing the whole process of installing Sharepoint on the 'upgrade-to-sp2' environment I had forgotten that SQL2K5 was running as primary database server.
When I wanted to restore the sp2'ed environment I immediatly received errors in the SPSBackup/Restore tool (ofcourse without a proper error-code). The next thing I tried was to restore the backup files straight into SQL where I was faced with some very weird errors like 'only 64 backup devices are allowed'.. Then it struck me! So I opened up the development machine, opened up SQL Management Studio and there were my SQL2K databases, upgraded to SQL2k5.. although they had SQL2000 compatablility level, it was not downgradable to be restored/attached to a SQL2k database server.

Thus long story short : it's not possible to restore (migrated) sql2k5 databases to sql2k databaseservers.