Monday, November 15, 2010

Password change reminder script for all AD

If you have remote users in your domain, they are not notified by the DC when their password is about to expire, because they open their windows session before the VPN client can connect to the DC.

Here is a script that you can run daily on your DC to send an email to users from an OU, everyday for some days before it expires.
So they know they have to change it before it really expires.

Option Explicit


' Per environment constants - you should change these

Const SMTP_SERVER = "emailserv.mydomain.intra"               ' your mail server

Const STRFROM = "dcserv@mydomain.intra"               ' your DC

Const DAYS_FOR_EMAIL = 14                          'Send notification when pwd will expire in this number of days

Const GROUPDN = "CN=USERS_OU,OU=Groups,OU=Domain Users,DC=mydomain,DC=intra"     ' Recurse this user OU

Const LOGFILE = "C:\Scripts\PasswordExpiration\passwordexpiration.log"     ' Log file path


' System Constants - do not change

Const ONE_HUNDRED_NANOSECOND = .000000100 ' .000000100 is equal to 10^-7

Const SECONDS_IN_DAY = 86400

Const ADS_UF_DONT_EXPIRE_PASSWD = &h10000

Const E_ADS_PROPERTY_NOT_FOUND = &h8000500D


' Change to "True" for extensive debugging output

Const bDebug = False


Dim numDays, iResult

Dim strDomain

Dim objGroup, objMember, member

Dim objFSO, objFile, strOutput


Set objFSO = CreateObject("Scripting.FileSystemObject")

If objFSO.FileExists(LOGFILE) = True Then

     objFSO.DeleteFile(LOGFILE)

End If


Set objFile = objFSO.OpenTextFile(LOGFILE, 8, True)


Set objGroup = GetObject("LDAP://" & GROUPDN)

objFile.WriteLine "Executed at " & Now() & vbCRLF

objFile.WriteLine "Enumerating members of " & objGroup.distinguishedName & ":" & vbCRLF




Call GetSubMembers(objGroup)


objFile.WriteLine "Done. Finished at " & Now() & "."

objFile.Close


 


Function GetSubMembers (GroupObject)

Dim TmpMember

numDays = 0


If (TypeName(GroupObject.Member) = "Empty") Then

Exit Function

End If


If (TypeName(GroupObject.Member) = "String") Then

     TmpMember = GroupObject.Member

     Set objMember = GetObject("LDAP://" & GroupObject.Member)

     If (LCase(objMember.Class) = "user") then

      Wscript.Echo objMember.sAMAccountName

strDomain = Mid(objMember.distinguishedname, InStr(objMember.distinguishedname, "DC="))

      numdays = GetMaximumPasswordAge (strDomain)

objFile.WriteLine objMember.sAMAccountName & " " & TmpMember & " " & numdays & " " & objMember.Mail

Call ProcessUser (numDays)

     else

      Wscript.Echo "Group : " & objMember.CN

objFile.WriteLine "Group 1: " & objMember.CN

      Call GetSubMembers(objMember)

     End If



Else

For Each TmpMember In GroupObject.Member

      Set objMember = GetObject("LDAP://" & TmpMember)


If (LCase(objMember.Class) = "group") Then

      Wscript.Echo "Group : " & objMember.CN

objFile.WriteLine "Group 2: " & objMember.CN

Call GetSubMembers(objMember)

Else

      Wscript.Echo objMember.sAMAccountName

strDomain = Mid(objMember.distinguishedname, InStr(objMember.distinguishedname, "DC="))

      numdays = GetMaximumPasswordAge (strDomain)

objFile.WriteLine objMember.sAMAccountName & " " & TmpMember & " " & numdays & " " & objMember.Mail

Call ProcessUser (numDays)

End If

Next

End If

End Function




Function GetMaximumPasswordAge (ByVal strDomainDN)

     Dim objDomain, objMaxPwdAge

     Dim dblMaxPwdNano, dblMaxPwdSecs, dblMaxPwdDays


     Set objDomain = GetObject("LDAP://" & strDomainDN)

     Set objMaxPWdAge = objDomain.maxPwdAge


     If objMaxPwdAge.LowPart = 0 And objMaxPwdAge.Highpart = 0 Then

          ' Maximum password age is set to 0 in the domain

          ' Therefore, passwords do not expire

          GetMaximumPasswordAge = 0

     Else

          dblMaxPwdNano = Abs (objMaxPwdAge.HighPart * 2^32 + objMaxPwdAge.LowPart)

          dblMaxPwdSecs = dblMaxPwdNano * ONE_HUNDRED_NANOSECOND

          dblMaxPwdDays = Int (dblMaxPwdSecs / SECONDS_IN_DAY)

          GetMaximumPasswordAge = dblMaxPwdDays

     End If

End Function




Function UserIsExpired (objMember, iMaxAge, iDaysForEmail, iRes)

     Dim intUserAccountControl, dtmValue, intTimeInterval

     Dim strName

     On Error Resume Next

     Err.Clear

     strName = Mid (objMember.Name, 4)

     intUserAccountControl = objMember.Get ("userAccountControl")


     If intUserAccountControl And ADS_UF_DONT_EXPIRE_PASSWD Then

          dp "The password for " & strName & " does not expire."

          UserIsExpired = False

     Else

          iRes = 0

          dtmValue = objMember.PasswordLastChanged

          If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then

               UserIsExpired = True

               dp "The password for " & strName & " has never been set."

          Else

               intTimeInterval = Int (Now - dtmValue)

               dp "The password for " & strName & " was last set on " & _

               DateValue(dtmValue) & " at " & TimeValue(dtmValue) & _

               " (" & intTimeInterval & " days ago)"

               If intTimeInterval >= iMaxAge Then

                    dp "The password for " & strName & " has expired."

                    UserIsExpired = True

               Else

                    iRes = Int ((dtmValue + iMaxAge) - Now)

                    dp "The password for " & strName & " will expire on " & _

                    DateValue(dtmValue + iMaxAge) & " (" & _

                    iRes & " days from today)."

                    If iRes <= iDaysForEmail Then

                         dp strName & " needs an email for password change"

                         UserIsExpired = True

                    Else

                         dp strName & " does not need an email for password change"

                         'Swap commented variable below to force email to be sent (for testing).

                         UserIsExpired = False

                    End If

               End If

          End If

     End If

End Function




Sub ProcessUser (iMaxPwdAge)

     Dim iResult, strExpire

     If Right (objMember.Name, 1) <> "$" Then

          If IsEmpty (objMember.Mail) or IsNull (objMember.Mail) Then

               dp Mid (objMember.Name, 4) & " has no mailbox"

          Else

               If UserIsExpired (objMember, iMaxPwdAge, DAYS_FOR_EMAIL, iResult) Then

                    objFile.WriteLine "Sending an email to " & objMember.givenName & " " & objMember.sn & _

                         " (" & objMember.Mail & "). Password expires in " & iResult & " days." & vbCRLF

                    Call SendEmail (iResult)

               Else

                    If iResult = "" Then

                         strExpire = "."

                    Else

                         strExpire = " for " & iResult & " days."

                    End If

                    objFile.WriteLine "Skipping " & objMember.givenName & " " & objMember.sn & _

                         ". Password does not expire" & strExpire & vbCRLF

               End If

          End If

     End If

End Sub




Sub SendEmail (iResult)

     Dim objMail

     Set objMail = CreateObject ("CDO.Message")

     objMail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/sendusing") = 2

     objMail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserver") = SMTP_SERVER

     objMail.Configuration.Fields.Item ("http://schemas.microsoft.com/cdo/configuration/smtpserverport") = 25

     objMail.Configuration.Fields.Update


     objMail.From = STRFROM

     objMail.To = objMember.Mail


     objMail.Subject = "[IMPORTANT] :: The Windows password of " & Mid (objMember.Name, 4) & " is going to expire"

     objMail.Textbody = "Hello, The Windows Active Directory password for user " & objMember.givenName & " " & objMember.sn & _

" (" & objMember.sAMAccountName & ")" & " will expire in " & iResult & " days. " & vbCRLF & vbCRLF & _

"Please change it before it expires (CTRL+ALT+DEL, then change password)." & vbCRLF & vbCRLF & _

"If you are a remote user, please connect with your VPN client and then change the password (so that DC server will be notified). The VPN peer will be automatically updated within 5 minutes." & vbCRLF & _

"You can also use Outlook Web Access with Internet Explorer (richer GUI than in Firefox) from outside to change it before it expires." & vbCRLF & vbCRLF & _

"If you have a phone with email capability, please change your password on it too." & vbCRLF & vbCRLF & _

"Thank you."

     objMail.Send

     Set objMail = Nothing

End Sub




Sub dp (str)

     If bDebug Then

          objFile.WriteLine str

     End If

End Sub

MBR / GPT partition style and Windows Server 2008 R2 system partition

GPT partition style has been introduced to expand the limitations of the MBR (2TB).

Today with disks of 2TB, you can have a raid system much larger than 2TB (eg : on a NAS, file server…)

If you wish to install a system on a 8TB partition for instance you need to create a partition on a GPT partition style of 8TB.

Windows can handle disks larger than 2TB, but not for the windows system installation…
Even Windows Server 2008R2 can only install on a MBR partition style, so up to a 2TB partition.

So you will have to split your raid into 2 and have Windows installed on the first and have data on the second.

For instance :

We have 5x 2TB HDD (initially a 8GB raid 5)

It can become :

2x 2TB HDD (raid 1) for Windows

3x 2TB HDD (raid 5) for data

So there is a lot of spare space on the first partition (system). Of course you can split into 2 partitions (system + data).

So you’d better have 2 small disks in raid 1 for the system and then have multiple large disks for data.

Be aware that NAS servers are usually sold with a bunch of large disks.

Thursday, November 4, 2010

SharePoint 2010 not crawling some sites

I recently came across an issue where SharePoint was not indexing some Site Collections and the crawl logs were showing the following with reference to the problematic Site Collection:

"The SharePoint item being crawled returned an error when attempting to download the item"

It turns out the start page of the root site contained a search result webpart which was causing the crawler to abort the rest of the crawl.

This issue has since been fixed in a hotfix. Install the latest CU to solve the issue.

Wednesday, November 3, 2010

Central Management of Content Types with SharePoint 2010

A new feature of SharePoint 2010 allows you to publish your content types from one central hub to Site Collections that choose to subscribe to them.

The first thing you need to do is to to define the location of your hub. You will find this in the properties of the managed metadata service at the bottom:

image

Then in the properties of the managed metadata service connection you need to tell it to “consume content types from the content type gallery”:

image

The site collections that are then supposed to use the content type hub will need to activate the site collection feature “Content Type Syndication Hub”.

In order for content types to be published you need to change the setting under “Manage Publishing for this Content Type”

Friday, October 22, 2010

IE9 Jumplists with SharePoint

I installed the new Beta of Internet Explorer 9 and really liked the idea of pinning an IE tab to the taskbar. To test it I pinned the Facebook homepage to the taskbar and noticed when I right-clicked it, I also had four “Tasks” in the jumplist.

I thought it would be cool to have something similar in a SharePoint portal where I could add links to a Document Center or a Search Center. It turns out it’s actually quite simple to do - add a Content Editor webpart to the site, open the HTML editor and add this to it:

<meta name="msapplication-task" content="name=Documents;action-uri=http://intranet/docs/;icon-uri=/_layouts/images/favicon.ico"/>

In the above example, the name that shows up in the jumplist is “Documents” and it links to “http://intranet/docs”. I used the standard SharePoint “favourite” icon but you can link to any you like.

Pretty cool!

Thursday, July 29, 2010

Profile Pictures in your SharePoint MySite

After migrating MySites from SharePoint 2007 to SharePoint 2010 it is possible that the profile pictures no longer display correctly. The picture is either cropped showing only the top corner (for example, in the Organisation Browser) or the aspect ratio is wrong, making it look very tall and narrow (for example, under the “In Common Between Us” section).

To solve this problem simply upload your picture again - go to your profile, click “Edit My Profile” and select “Choose Picture”. You can even use the same picture which should be stored under “Shared Pictures/Profile Pictures”.

Thursday, July 15, 2010

Force replication of AD partitions after tombstone lifetime exceeded / emails issues

If a server has exceed the tombstone lifetime (180 days on WS2008 by default), it will cause issues when brought back on the network.
New users, groups… are not synchronized anymore on this server, and it can cause issues with emails sent to these new users.
If the email server can check for the user in the AD against the bad server, emails won’t be delivered.

Run the following on a good dc :

Repadmin /showrepl

Get the GUI of a good DC :

DC=mydomain,DC=intra
Default-First-Site-Name\GOOD-DC1 via RPC
DSA object GUID: de7429ee-7637-45cb-bbf0-43d17b17831b
Last attempt @ 2010-07-15 12:17:30 was successful.

Then remove objects on the bad DC that not longer exist in the current AD (good DC) :

repadmin /removelingeringobjects bad-dc.mydomain.intra de7429ee-7637-45cb-bbf0-43d17b17831b "dc=mydomain, dc=intra"


Then :

repadmin /replicate bad-dc.mydomain.intra good-dc.mydomain.intra DC=mydomain,DC=intra /force

repadmin /replicate bad-dc.mydomain.intra good-dc.mydomain.intra CN=configuration,DC=mydomain,DC=intra /force

repadmin /replicate bad-dc.mydomain.intra good-dc.mydomain.intra CN=schema,CN=configuration,DC=mydomain,DC=intra /force

This will synchronize the servers for these partitions and you won’t have issues anymore with the accounts of the new users.

But, if the bad DC is planned for a removal I recommend to use the dcpromo /forceremoval method and a metadata cleanup as explained here :
Remove_ad_from_dc
Delete_failed_DC

Monday, July 12, 2010

Forefront Security for Exchange : release blocked emails

Forefont Security for Exchange (before v. 2010) may use a lot of CPU/RAM and almost hangs your transport server.

If you stop Forefront, some emails (*.eml) can remain blocked in the following folders (incoming and outgoing emails) :

C:\Program Files (x86)\Microsoft Forefront Security\Exchange Server\Data\Archive\in
C:\Program Files (x86)\Microsoft Forefront Security\Exchange Server\Data\Archive\out

In order to release them, just move them to the following folder and let Exchange process them :

C:\Program Files (x86)\Microsoft Forefront Security\Exchange Server\Pickup

Wednesday, May 19, 2010

Routing Sendmail SMTP messages to Exchange 2007 distribution lists

Relaying emails from an internal sendmail server to an Exchange 2007 transport server will work for AD users recipients, but not for AD distribution lists.
The error given by the Exchange server is :
550 5.7.1 RESOLVER.RST.AuthRequired; authentication required

In order to allow emails coming from an internal sendmail server, you can disable the authentication on this distribution list :

Edit the distribution list property in the Exchange Management Console, mail flow settings tab, Message Delivery restriction and then uncheck "Require that all senders are authenticated.


Send text messages (SMS) from Outlook/Exchange 2010

A cool new feature of Exchange 2010 allows you to send text messages from your OWA or Outlook 2010 client.

You will also need a Windows Mobile phone connected to your Exchange 2010 mailbox. WM 6.1 should download an update from the Exchange Server to enable this functionality (I haven’t tested this) whereas WM 6.5 can do this out of the box.

It basically works by syncing the SMS to your phone and your phone then sends it out.

When setting up the partnership between your Windows Mobile phone and Exchange you should see the option to also sync your text messages. Once you select this you will need to restart Outlook 2010 after which it will show you an additional item under “New Items” called “Test Message (SMS)”.

Incoming texts will also land in your Exchange mailbox.

It is worth noting that I wasn’t able to add the SMS syncing after I had created the partnership with Exchange – I had to remove the partnership and recreate it.

Tuesday, May 11, 2010

Add Traffic Light indicators to a Yes/No column in a custom SharePoint list

I needed to create a list which would show a Yes/No column as traffic lights. Since SharePoint already has the necessary images from KPI lists I decided to use them.

Unfortunately, this isn’t an option OOTB so I decided to generate the URL to the KPI gifs using a calculated column. The name of the Yes/No column was “Approved” so I created the following calculated column:

="<div><img src='/_layouts/images/KPIDefault-"&IF([Approved]=TRUE,0,2)&".gif'/></div>"

For those of you using various regional versions of SharePoint, be careful with the commas after “TRUE”. You might need to change them to semi-colons.

 

The problem with the result from the above calculated column is that it is simply displayed as text. While trying to get it to display as an image, I stumbled across this site, and in particular a script which does exactly that. The script can be downloaded from here. I have added it below for the sake of simplicity.

This script needs to be added to the bottom of the page using the Content Editor WebPart (add it by using the source editor not the Rich Text editor).

 

<script type="text/javascript">
/*
Text to HTML Lite - version 2.1.1
Questions and comments: Christophe@PathToSharePoint.com
*/

function TextToHTML(NodeSet, HTMLregexp) {
var CellContent = "";
var i=0;
while (i < NodeSet.length){
try {
CellContent = NodeSet[i].innerText || NodeSet[i].textContent;
if (HTMLregexp.test(CellContent)) {NodeSet[i].innerHTML = CellContent;}
}
catch(err){}
i=i+1;
}
}

// Calendar views
var regexpA = new RegExp("\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*");
TextToHTML(document.getElementsByTagName("a"),regexpA);

// List views
var regexpTD = new RegExp("^\\s*<([a-zA-Z]*)(.|\\s)*/\\1?>\\s*$");
TextToHTML(document.getElementsByTagName("TD"),regexpTD);

</script>

Tuesday, April 27, 2010

Map a drive letter to SkyDrive

Office 2010 has a very cool option to save files to the Windows Live SkyDrive. By choosing “Save and Send” from the File menu you can connect to your Windows Live SkyDrive as shown in the screenshot below.

 

image

 

After you click “Save As” you will get a normal Windows Explorer Save As dialog with the address in the address bar such as this one:

image

 

Copy this address, open the Windows Explorer, click on Computer and choose “Map network drive”

image

 

Now paste in the address you copied from above and choose the drive you would like to map it to

image

 

Done! ;)

Monday, April 12, 2010

Very Useful Tool: ADRecycleBin

The new Active Directory recycle bin feature in Windows Server 2008 R2 can be extremely useful. The problem, however, is that you need all your domain controllers to be running R2. The lack of a GUI can also make a restore a little hairy at best.

I recently came across a handy little (FREEWARE) tool from Overall Solutions called ADRecycleBin. The tool can work with the new recycle bin feature in Windows 2008 R2 but if you are running earlier versions of AD the tool will also work.

For some screenshots and to download the tool go here.

Monday, March 15, 2010

Showing active SharePoint connections

It can be very useful to see how many active connections you have on your SharePoint server. This can be easily done using PowerShell to look at the IIS performance counters.

As is mostly the case with scripting, somebody has already done a much better job than I ever could. Here is a script which creates a PowerShell function Get-WebServiceConnections.

I created a PowerShell script called CurrentConnections.ps1 with the following content and can now run it whenever needed:

function Get-WebServiceConnections()
{
  $results = @{}
  $perfmon = new-object System.Diagnostics.PerformanceCounter
  $perfmon.CategoryName = "Web Service"
  $perfmon.CounterName = "Current Connections"

  $cat = new-object System.Diagnostics.PerformanceCounterCategory("Web Service")
  $instances = $cat.GetInstanceNames()

  foreach ($instance in $instances)
  {
    $perfmon.InstanceName = $instance
    $results.Add($instance, $perfmon.NextValue())
  }
  write-output $results
}

Get-WebServiceConnections

Thursday, March 4, 2010

Customizing Forefront Server Security Notification messages

As an administrator, you would like to know more information when a virus is detected on your Exchange organization than the default message.



Here you will find the list of keywords that can be added to your message template.
In my case, I wanted to add the recipient details, and sender address :

Sender: "%ISName%%ESName%%ESAddress%"
Recipient: "%IRName%%ERNames%"

Wednesday, March 3, 2010

Large XML file editor useful for displaying BackupExec logs

When using BackupExec to save all your data, the xml logfile can be huge, hundreds of MB or more.
Then BackupExec cannot display the result and it is really hard to find the reason of any issue encountered.
I found this freeware : XML Marker which works pretty good with a 700MB file (you can start searching the file even if not finished loading).

Exchange 2010 Public Folder Replication

After installing the first Exchange 2010 Server in an Exchange 2007 environment, I noticed the public folders weren’t replicating. Even after adding a number of replicas the hierarchy wasn’t even showing up.

After much searching I found this comment in a blog entry with the solution. Basically, it was due to an object still remaining in Active Directory from Exchange 2003 days.

Using ADSIEdit open “Configuration-Services-Microsoft Exchange-<Organization Name>-Administrative Groups-<Name of your Admin Group>

In this container delete the object “Servers”.

(Before doing this you should probably back up your AD ;) )

 

After a little waiting, all was back to normal.

Wednesday, February 10, 2010

Changing the polling interval for the Exchange FDS

The Exchange 2007 File Distribution Service is responsible for keeping the OAB on the CAS in sync with the mailbox server. The default setting only polls the OAB every 8 hours. This could mean that a change you make doesn’t make it to the Outlook clients until well over a day (if you leave the OAB creation to the default once a day)!

To change this setting to e.g. every hour (60 minutes) use this command:

Get-OabVirtualDirectory| Set-OabVirtualDirectory -pollinterval 60

Wednesday, February 3, 2010

Exchange organization reboot issue : blocked emails

When your exchange 2007 organization have multiple servers, since roles should be splitted on different machines, and you need to reboot them, it appears that sometimes emails are blocked.
This can come from the Hub transport server and even if the MS Exchange transport service is set on automatic, is appears not started after reboot.
Just start the Microsoft Exchange Transport service, and all emails will be released.

Unmanaged SAN storage processor (SP)

It could happen that one of the storage processor of your SAN displays as unmanaged in GUI.
This can happen after a SAN reboot and is usually related to the UPS powering this SP.
Since the communication between the UPS and the SAN is broken (not available), the SP goes on unmanaged and disable the cache.
In order to solve this, you'll need to stop the SAN (and everything running on before), stop the UPs, restart the UPS and let it do the check opreations (< 1 minute), and finally start the SAN.
Everything should be ok.

Tuesday, February 2, 2010

Viewing the Dell Service Tag from Windows

If you ever need to check the Dell Service Tag on a machine from within Windows, run the following command:

wmic bios get serialnumber

To do this remotely you need to add the /node: switch. For example:

wmic /node:<servername> bios get serialnumber

Thursday, January 21, 2010

Displaying the Quick Launch in Web Part Pages

If you create a web part page in MOSS 2007 it won’t show the Quick Launch on the left side of the page.

To work around this open the page in SPD and remove the following code:

<asp:Content ContentPlaceHolderId="PlaceHolderLeftNavBar" runat="server"></asp:Content>

 

Unfortunately, the Quick Launch won’t be the correct width so in order for that to be displayed correctly you need to remove these additional lines of code:

<asp:Content ContentPlaceHolderId="PlaceHolderPageImage" runat="server"></asp:Content>
<asp:Content ContentPlaceHolderId="PlaceHolderNavSpacer" runat="server"></asp:Content>