Scripting – Installing Server Features on Multiple 2008 Servers

Sep 5, 2012 • Jonathan -

Installing server features on multiple servers using a text file and psexec. You can find psexec here.


Run the follwing psexec command:

Psexec.exe @Servers.txt ServerManagerCMD.exe -install FS-DFS

For a list of features that can be installed this way run:

ServerManagerCMD.exe -query

Scripting – ExpressMaint SQL Backups With Email Reports

Jul 17, 2012 • Jonathan -

This script takes full backups of SQL databases, stores the reports, and emails the results. This script makes use of ExpressMaint for backups and Bmail to send emails.

@echo off
:: set some stuff
SET utilBaseDir=C:\util
SET backupBaseDir=C:\db-backups
SET reportBaseDir=C:\db-reports
SET [email protected]
SET [email protected]
SET mailServerPort=25

:: backup the db
%utilBaseDir%\ExpressMaint.exe -S (local) -D ALL -B %backupBaseDir% -BU Days -BV 14 -V -C -RU Days -RV 14 -R %reportBaseDir% -T DB

:: get most recent report file
FOR /F "delims=|" %%I IN ('DIR "%reportBaseDir%\*.*" /B /O:D') DO SET NewestFile=%%I

:: get current date
FOR /F "TOKENS=1,2 eol=/ DELIMS=/ " %%A IN ('DATE/T') DO SET mm=%%B
FOR /F "TOKENS=1,2 DELIMS=/ eol=/" %%A IN ('echo %CDATE%') DO SET dd=%%B
FOR /F "TOKENS=2,3 DELIMS=/ " %%A IN ('echo %CDATE%') DO SET yyyy=%%B
SET dbReportDate=%mm%-%dd%-%yyyy%

:: email report
%utilBaseDir%\bmail.exe -s %useEmailServer% -p %mailServerPort% -t %reportEmailTo% -f %reportEmailFrom% -a "%dbReportDate% - Backup Report" -m %reportBaseDir%\%newestfile%

Exchange – Convert Mailbox Enabled User to Mail Enabled User

Jul 9, 2012 • Jonathan -

This powershell script will convert a mailbox enabled user into a mail enabled user. Please test before you use this script, it’s provided as is, I am in no way responsible if you break stuff, and there is a good chance you will if you don’t test.

    Convert mailbox enabled user into mail enabled user
	Automates converstion of mailbox enabled user account into a mail enabled user account
    Author: Jonathan - [email protected]
	Identity of mailbox enabled user being converted
.PARAMETER EmailAddress
	The users primary email address, this will be used as the external address on the new mail enabled user
.PARAMETER DomainController
	The domain controller to use
	.\Convert-MBUtoMEU.ps1 -Identity "Jon Q. User" -EmailAddress "[email protected]"

param (
	[parameter(Mandatory=$true, HelpMessage="Enter the Identity of the user to convert")][string]$Identity,
	[parameter(Mandatory=$true, HelpMessage="Enter the users primary email address")][string]$EmailAddress,
	[parameter(Mandatory=$true, HelpMessage="Enter the domain controller to use")][string]$DomainController

# get the user
$user = Get-Mailbox -DomainController $DomainController -Identity $Identity

# get curret email addresses
$currAddresses = $user.EmailAddresses

# get the X500 address
$legDn = $user.LegacyExchangeDn

# add the legacy DN to the list

# disable the old mailbox
Disable-Mailbox -DomainController $DomainController -Identity $user

# Mail enable the user account
Enable-MailUser -Identity $thisUser -DomainController $DomainController -ExternalEmailAddress $EmailAddress

# get the new user
$newUser = Get-MailUser -DomainController $DomainController -Identity $Identity

# set the new addresses
Set-MailUser -DomainController $DomainController -Identity $newUser -EmailAddressPolicyEnabled $false -ExternalEmailAddress $EmailAddress -EmailAddresses $currAddresses

Powershell – Email Password Expiration Reminders

Jun 27, 2012 • Jonathan -

Combination of scripts to send HTML formatted reminder emails to users whos passwords are about to expire. These scripts are shamelessly stolen from a few places on the web, with minor modifications. I’ve got this running daily as a scheduled task to send email reminders to users. This helps when users don’t logout of their computers, which means they don’t get the expiring password notification.

Make sure you modify the XSL template to meet your requirements, you will also need to add a valid path to a logo image to Send-HTMLFormattedEmail.ps1.


# Requires Active Directory Module for Windows Powershell
# Found in Windows Features-->Remote Server Admin tools-->Role Administration Tools--> AD DS and AD LDS Tools
# Uses HTML email script found at:
Import-Module ActiveDirectory
Import-Module c:\scripts\pw-expired\Send-HTMLFormattedEmail.ps1

# Debug mode.  Use $debugemail to send all emails to a test address
$debug = $false
$debugemail = "[email protected]"

# set the domain controller to user
$dc = ""

# SMTP Server address
$smtp = ''

#Sender details
$fromemail = "[email protected]"
$fromdisplay = "Contoso IT Department"

# Path to the XSL template for email
$xsltemplate = "c:\scripts\pw-expired\pw-expired.xsl"

# Get all *enabled* users in domain who have a password expiration, a passwordlastset timestamp, who are allowed to change password and have an email address to send the notice to.
Get-ADUser -Server $dc -filter * -properties PasswordNeverExpires,PasswordLastSet,EmailAddress,CannotChangePassword,Enabled | ?{($_.PasswordLastSet) -and ($_.EmailAddress) -and ($_.CannotChangePassword -eq $False) -and ($_.Enabled -eq $true) -and ($_.PasswordNeverExpires -ne $true)} |foreach {

	# Get your current password policy how many days old
	$PasswordPolicy = Get-ADDefaultDomainPasswordPolicy

	# Get the last time they changed password

	# Get Today for something to compare against

	# Find out when password is supposed to expire
	$ExpireDate=$PasswordLastSetDate + $PasswordPolicy.MaxPasswordAge

	# How many days left before expires.  We can use .days to get a round number for email usage, .totaldays for computational purposes.

	# Get a friendly name string, because it doesn't work inside the quotes when passed through as $_.givenName for some reason that's above my skill level 😛

	# Call html email function (seperate module) depending on number of days left, adjusting subject etc.  Below sends email at 14 days, and then at 5 days onwards with a specific one for less then 24 hours left.
	# can add -CC or -BCC parameters as required.

	# debug is false, send mail to the users
	if ($debug -ne $true) {
		if ($PasswordAgeLeft.TotalDays -le 15 -and $PasswordAgeLeft.TotalDays -ge 13){
			Write-Host "Sending email to $FriendlyName ..."
			Send-HTMLFormattedEmail -To $_.EmailAddress -ToDisName $_.givenName -From $Fromemail -FromDisName $Fromdisplay -Subject "Your Password is due to expire soon, $FriendlyName" -Content $PasswordAgeLeft.days -XSLPath $xsltemplate -Relay $smtp 
		elseif ($PasswordAgeLeft.Totaldays -le 1 -and $PasswordAgeLeft.TotalDays -ge 0) {
			Write-Host "Sending email to $FriendlyName ..."
			Send-HTMLFormattedEmail -To $_.EmailAddress -ToDisName $_.givenName -From $Fromemail -FromDisName $Fromdisplay -Subject "Your Password expires today, $FriendlyName . Read this to be able to continue to work" -Content $PasswordAgeLeft.days -XSLPath $xsltemplate -Relay $smtp 
		elseif ($PasswordAgeLeft.Totaldays -le 5 -and $PasswordAgeLeft.TotalDays -ge 1) {
			Write-Host "Sending email to $FriendlyName ..."
			Send-HTMLFormattedEmail -To $_.EmailAddress -ToDisName $_.givenName -From $Fromemail -FromDisName $Fromdisplay -Subject "Your Password is due to expire very soon, $FriendlyName" -Content $PasswordAgeLeft.days -XSLPath $xsltemplate -Relay $smtp
		else {}
	# debug is true, send all emails to a test address
	else { 
		if ($PasswordAgeLeft.TotalDays -le 15 -and $PasswordAgeLeft.TotalDays -ge 0) { 
			Send-HTMLFormattedEmail -To $debugemail -ToDisName $_.givenName -From $Fromemail -FromDisName $Fromdisplay -Subject "Your Password is due to expire soon, $FriendlyName" -Content $PasswordAgeLeft.days -XSLPath $xsltemplate -Relay $smtp


# Based on code by tysonkopczynski (
# Added Inline attachments by Simon Henderson
# Send-HTMLFormattedEmail
# Usage:	Send-HTMLFormattedEmail -?
function Send-HTMLFormattedEmail {
    	Used to send an HTML Formatted Email.
    	Used to send an HTML Formatted Email that is based on an XSLT template.
	.Parameter To
		Email address or addresses for whom the message is being sent to.
		Addresses should be seperated using ;.
	.Parameter ToDisName
		Display name for whom the message is being sent to.
	.Parameter CC
		Email address if you want CC a recipient.
		Addresses should be seperated using ;.
	.Parameter BCC
		Email address if you want BCC a recipient.
		Addresses should be seperated using ;.
	.Parameter From
		Email address for whom the message comes from.
	.Parameter FromDisName
		Display name for whom the message comes from.
	.Parameter Subject
		The subject of the email address.
	.Parameter Content
		The content of the message (to be inserted into the XSL Template).
	.Parameter Relay
		FQDN or IP of the SMTP relay to send the message to.
		The full path to the XSL template that is to be used.
    try {
		#logo used in signature
		$Logopic = "c:\\scripts\\pw-expired\\logo.png"
        $Message = New-Object System.Net.Mail.MailMessage
		# add the attachment, and set it to inline.
		$Attachment = New-Object Net.Mail.Attachment("c:\\scripts\\pw-expired\\logo.png")
		$Attachment.ContentDisposition.Inline = $True
		$Attachment.ContentDisposition.DispositionType = "Inline"
		$Attachment.ContentType.MediaType = "image/jpg"
		$Logo = "cid:logo" 
        # Load XSL Argument List
        $XSLArg = New-Object System.Xml.Xsl.XsltArgumentList
        $XSLArg.AddParam("To", $Null, $ToDisName)
        $XSLArg.AddParam("Content", $Null, $Content)
		$XSLArg.AddParam("Logo", $Null, $Logo)

        # Load Documents
        $BaseXMLDoc = New-Object System.Xml.XmlDocument

        $XSLTrans = New-Object System.Xml.Xsl.XslCompiledTransform

        #Perform XSL Transform
        $FinalXMLDoc = New-Object System.Xml.XmlDocument
        $MemStream = New-Object System.IO.MemoryStream
        $XMLWriter = [System.Xml.XmlWriter]::Create($MemStream)
        $XSLTrans.Transform($BaseXMLDoc, $XSLArg, $XMLWriter)

        $MemStream.Position = 0
        # Load the results
        $Body = $FinalXMLDoc.Get_OuterXML()

		# Populate the Message.
		$html = [System.Net.Mail.AlternateView]::CreateAlternateViewFromString($body, $null, "text/html")
		$imageToSend = new-object$Logopic,"image/jpg")
		$imageToSend.ContentID = "logo"
        $Message.Subject = $Subject
        $Message.IsBodyHTML = $True
		# Add From
        $MessFrom = New-Object System.Net.Mail.MailAddress $From, $FromDisName
		$Message.From = $MessFrom

		# Add To
		$To = $To.Split(";") # Make an array of addresses.
		$To | foreach {$Message.To.Add((New-Object System.Net.Mail.Mailaddress $_.Trim()))} # Add them to the message object.
		# Add CC
		if ($CC){
			$CC = $CC.Split(";") # Make an array of addresses.
			$CC | foreach {$Message.CC.Add((New-Object System.Net.Mail.Mailaddress $_.Trim()))} # Add them to the message object.

		# Add BCC
		if ($BCC){
			$BCC = $BCC.Split(";") # Make an array of addresses.
			$BCC | foreach {$Message.BCC.Add((New-Object System.Net.Mail.Mailaddress $_.Trim()))} # Add them to the message object.
        # Create SMTP Client
        $Client = New-Object System.Net.Mail.SmtpClient $Relay

        # Send The Message
    catch {
		throw $_
		$attachment.Dispose() #dispose or it'll lock the file


<?xml version="1.0"?>

<xsl:stylesheet version="1.0" xmlns:xsl="">
<xsl:output media-type="xml" omit-xml-declaration="yes" />
    <xsl:param name="To"/>
    <xsl:param name="Content"/>
	<xsl:param name="Logo"/>

<xsl:attribute-set name="image-style">
  <xsl:attribute name="style">float:left; margin-right:0px; margin-bottom:0px</xsl:attribute>
  <xsl:attribute name="alt">green</xsl:attribute>
  <xsl:attribute name="src"><xsl:value-of select="$Logo" /></xsl:attribute>
  <xsl:attribute name="title">SP logo</xsl:attribute>

    <xsl:template match="/">
                <title>Your Password is due to Expire!</title>
            <div width="400px">
                <p>Hello <xsl:value-of select="$To" />,</p>
                <p>Your windows password will expire in <xsl:value-of select="$Content" /> days.</p>
				<p>This password is used log in to Contoso PCs  and access email, VPN, and various intranet sites.</p>
				<p>If you are working on an Office computer, please press CTRL-ALT-DELETE and choose change password. Follow the instructions to set your new password. </p>
				<p>If you use web based Outlook, please visit <a href=""></a>, login and follow the steps outlined below.
						<li>Log into your e-mail account.</li>
						<li>Click Options and then 'See all options' in the top right of the window.</li>
						<li>Click 'Change your password' on the right column.</li>
						<li>Enter your current password, and provide a new password in the required fields.</li>
						<li>Click Save.</li>
					<strong>PASSWORD REQUIREMENTS</strong>
					Your Password...
						<li>must be at least 8 characters long</li>
						<li>must contain any 3 of the following:
								<li>upper case letter</li>
								<li>lower case letter</li>
								<li>special character (like [email protected]#$%^)</li>
						<li>must not be the same as your previous passwords</li>
						<li>must not contain any part of your name</li>
					<strong>If you do not change your password it will expire and you will be unable to work until it is changed!</strong><br />
					If any point you have any questions or concerns please open a help desk ticket by replying to this email, or contact the Helpdesk at 1-877-997-8715
			Many thanks,<br />	
            Contoso IT Team<br />
			<xsl:element name="img" use-attribute-sets="image-style"></xsl:element>

Exchange 2010 – Watch PST Import Request Progress

Jun 26, 2012 • Jonathan -

Quick Powershell script to watch the status of import requests in Exchange 2010.

    Detailed stats on a single PST import request
	Watch the status of a single PST import request
    Author: Jonathan
	Identity of Mailbox Import Request
	.\Watch-ImportRequest.ps1 -Identity "Jon Q. User"
param (
	[parameter(Mandatory=$true, HelpMessage="Enter the Identity of the active move request.")][string]$Identity

do { 
	$mbMove = Get-MailboxImportRequestStatistics -Identity $Identity
	$stat = "Importing PST | $Identity"
	$act = "Duration: " + [string]$mbMove.OverallDuration + " | " + $mbMove.PercentComplete + "% complete"
	Write-Progress -activity $act -Status $stat -percentComplete $mbMove.PercentComplete
Until ( $mbMove.Status -eq "Completed" )

Exchange – Find All Disabled User Accounts NOT Hidden From The Address Book

Jun 22, 2012 • Jonathan -

Quick Powershell one-liner to find disabled accounts that are not hidden from the GAL.

Get-Mailbox -Filter{(HiddenFromAddressListsEnabled -eq $false) -AND (UserAccountControl -eq "AccountDisabled, NormalAccount")}

Powershell – Backup Multiple DHCP Databases to SMB Share

Jun 21, 2012 • Jonathan -

Quick script to backup DHCP databases from various Windows 2008R2 site servers to a central file share.

# server site codes
$siteCodes = @('PDX','NYC','LAX')

# set backup path
$backupRoot = "\\\some-share\backups\dhcp"

# copy the DHCP backups over to MY-FPS
ForEach ($x in $siteCodes) {
	$path = "\\$\c$\windows\system32\dhcp\backup"
	Copy-Item $path -Destination $backupRoot\$x -Recurse -Force -ErrorAction SilentlyContinue

Hyperion – SmartView Connection Screen Box is Blank in Excel on Windows 64 bit

Jun 11, 2012 • Jonathan -

Using Office 2007 or Office 2010, the SmartView Connection Manager is blank on the right pane of the connection box. This is due to 64-bit Windows not supporting multiple nested child windows as far as resizing is concerned due to the kernel stack overflow.

The cause of this problem has been identified and verified as an Oracle unpublished Bug 9451307 – SMARTVIEW INSTALLED ON 64 BIT SHOWS ONLY BLANK ON RIGHT PANE IN CONNECTION BOX.

This issue has been fixed in the SmartView v11. Patch Release, Patch:9779433 – Oracle’s Hyperion Smart View for Office Service Fix. This patch can be obtained from My Oracle Support.


Exchange 2010 – Add Calendar Permissions to Members of AD Group

May 31, 2012 • Jonathan -

I was recently tasked with adding calendar permissions for the members of an AD group to a specific users mailbox. The following Powershell snippet will grant “Editor” permissions on the “someuser” calendar for the members of the AD group named “Some Group”.

This snippet makes use of the Get-ADGroupMember and the Get-Mailbox cmdlets.

Get-ADGroupMember -Identity "Some Group" | ForEach-Object { 
	$mb = Get-Mailbox -Identity $_.distinguishedName
	Add-MailboxFolderPermission -Identity "someuser:\Calendar" -User $mb.Alias -AccessRights Editor

Exchange 2010 – Monitoring The Progress of Mailbox Move Requests

Apr 27, 2012 • Jonathan -

In Exchange 2010 mailbox moves are asynchronous and are performed by the Microsoft Exchange Mailbox Replication service (MRS). Unfortunately there is no built in way to watch the mailbox move complete with a progress bar. Below is a Powershell script that will present a status bar for the mailbox move.

    Detailed stats on a single mailbox move 
	Watch the status of a single mailbox move
	Identity of Mailbox Move Request
	.\Watch-MailboxMove.ps1 -Identity "John Q. User"
param (
	[parameter(Mandatory=$true, HelpMessage="Enter the Identity of the active move request.")][string]$Identity,
	[parameter(Mandatory=$false, HelpMessage="Which Domain Controller are we using?")][string]$DomainController

do { 
	$mbMove = Get-MoveRequestStatistics -Identity $Identity -DomainController $DomainController
	$stat = [string]$mbMove.BytesTransferred + " - " + [string]$mbMove.ItemsTransferred + " of " + [string]$mbMove.TotalMailboxItemCount + " items."
	$act = "Moving " + $mbMove.DisplayName + "'s mailbox | " + [string]$mbMove.OverallDuration + " | " + $mbMove.PercentComplete + "% complete"
	Write-Progress -activity $act -Status $stat -percentComplete $mbMove.PercentComplete
Until ( $mbMove.Status -eq "Completed" )

subscribe via RSS