Monday, August 30, 2010

VSS: Exclude Files and Folders from Shadow Copy

This very simple little hint can help greatly when dealing with older servers while limited drive space and demanding restore retention. This will only work on Vista upwards (Server 2008 for example)

Quite simply, open the registry key HKLM\System\CurrentControlSet\Control\BackupRestore\FilesNotToSnapshot – there will be a few default entries in there.
Add a new Multi-String Value and name it with a description for the set of files to exclude – for example My Custom Application. Now for the data, add a file or folder path to add to the exclusion list.

A folder can also include all sub-folders with the recursive switch /s, with the example below…

String Name Data
My Application %ProgramData%\MyApp\*
c:\MyApp\database.mdf
c:\MyApp\Sundry\* /s
My Application 2 %ProgramData%\MyApp2\scratch.bin

Thursday, August 19, 2010

VBScript: Deploy Outlook Stationery and Signature

Today I was tasked with scripting a custom and uniform stationery and signature for each user in the domain.  After thinking about this for a little while, I decided the best way to tackle this was to leave the stationery and signature HTML files in tact with a few alterations…

For the HTML files, simply pop them open in an editor (notepad for example – certainly not word!)  and find the variables.  In my example, i used the Full Name, Email Address and Mobile Number as the variables in the stationery and replaced them with %FULLNAME%, %EMAIL% and %MOBILE%.

To distribute the file, choose your preferred method mine is a simple Group Policy with a logon script that copies these files, then calls the VBScript.

The Script

Below is the script, it is fairly easy to understand, shoot me a message if not and I’ll go into more detail afterwards.

'Set Variables (LOOOOOOOTS of Variables)
dim objShell, objSysInfo, strUser, objUser, strName, strMobile, _
strEmail, appdata, strStationery, strSignature, objWord, _
strComputer, strKeyPath, strRegValueName, strRegValue, _
strValue, signature, stationery

set objShell = CreateObject("WScript.Shell")
set objSysInfo = CreateObject("ADSystemInfo")
strUser = objSysInfo.UserName
set objUser = GetObject("LDAP://" & strUser)
strName = objUser.FullName
strMobile = objUser.Mobile
strEmail = objUser.emailAddress
appdata = objShell.ExpandEnvironmentStrings("%appdata%")
strStationery = appdata & "\Microsoft\Stationery\Stationery.html"
strSignature = appdata & "\Microsoft\Signatures\Signature-Reply.htm"
set objWord = CreateObject("Word.Application")
strKeyPath = "SOFTWARE\Microsoft\Office\" & objWord.Version _
& "\Common\MailSettings"
strRegValueName = "NewStationery"
strValue = "Stationery"
objWord.EmailOptions.EmailSignature.NewMessageSignature = ""
objWord.EmailOptions.EmailSignature.ReplyMessageSignature = "Signature-Reply"
'Set Registry to selected stationery
objShell.RegWrite strKeyPath & strRegValueName, strRegValue, "REG_SZ"

'Read source stationery and signature
stationery = GetFile(strStationery)
signature = GetFile(strSignature)

'Write the modified files
WriteFile strStationery, ReplaceTemplate(stationery)
WriteFile strSignature, ReplaceTemplate(signature)

'Read file function
function GetFile(FileName)
If FileName<>"" Then
Dim FS, FileStream
Set FS = CreateObject("Scripting.FileSystemObject")
on error resume Next
Set FileStream = FS.OpenTextFile(FileName)
GetFile = FileStream.ReadAll
End If
End Function

'Write modified files
function WriteFile(FileName, Contents)
Dim OutStream, FS

on error resume Next
Set FS = CreateObject("Scripting.FileSystemObject")
Set OutStream = FS.OpenTextFile(FileName, 2, True)
OutStream.Write Contents
End Function

'Replace blocks in template with user data.
function ReplaceTemplate(TempFile)
TempFile = replace(TempFile, "%FULLNAME%", strName)
TempFile = replace(TempFile, "%EMAIL%", strEmail)

If strMobile = "" Then
TempFile = replace(TempFile, "%MOBILE%", "")
Else TempFile = replace(TempFile, "%MOBILE%", "Mob:" & strMobile)
End If

ReplaceTemplate = TempFile
End Function

Monday, August 16, 2010

Powershell: Force AD Users to Reset Password

There are times when going into ADUC and modifying a bunch of users to have their password change on next logon is either a) too much hassle or b) needs to be a specific time.  By using powershell and Quests ActiveRoles modules, we can create a fairly simple script to do so.

When running this script, there are a few things that can go wrong – for example a user might be set to ‘can not change password’.  So there are a few ways to catch this, my personal favourite is by raising an event log error and having our management software pick up on the event id.

Setting the Variables
First thing we need to do is to set some variables, this script assuming we want to force the reset for all users in a specified OU – this does propagate down to child OU’s as well.

#------- Assign Variables -------#
Add-PSSnapin Quest.ActiveRoles.ADManagement
$OUvar = $args[0]
$OU = Get-QADObject | ? { ($_.Type -eq "organizationalUnit") -and ($_.Name -eq $OUvar) }
if (!$OU) {
write-host "No Organizational Unit with the name of "+$OUvar+" could be found."
break
}else {
$Users = Get-QADUser -SearchRoot $OU.DN
if (!$Users) { write-host "No users found in OU "+$OU.DN+"."
else { write.host "Successfully harvested the following users from OU "+$OU.DN+" `n "+$Users
}
#------- ######## -------#



So basically here we are accepting a command line variable as the OU to find the users in. There is a little error checking here as well to make sure we have some users to apply this too.




Forcing the Change
Here is the real meat and potatoes of this script, it also includes some basic error checking and makes sure that all users that were told to flag were indeed flagged.

#------- Force Password Change On Next Logon -------#
ForEach ($User in $Users) {
Set-QADUser $User -PasswordNeverExpires $false -UserMustChangePassword $true
$UsersVerified = Get-QADUser -SearchRoot $OU.DN | ? { $_.UserMustChangePassword }
}
if ($Users.count -ne $UsersVerified.count) {
$UsersDif = compare $Users $UsersVerified
write-host "Not all users were modified, the following users were not affected. `n "
+$UsersDif.inputobject.logonname
}else { write-host "Users were successfuly set to change password on next logon" }
}
#------- ######## -------#

Friday, August 13, 2010

Powershell: Unlocking an AD User Account

Once again cutting the time for basic administrative tasks, Powershell comes to the rescue!  This below script requires Quests ActiveRoles AD Management script pack which can be freely downloaded from Their Website

The Script

#------- Assign Variables -------#
Add-PSSnapin Quest.ActiveRoles.ADManagement
$UserArg = $args[0]
$User = Get-QADUser | ? {$_.LogonName -eq $UserArg}
#------- ######## -------#


#------- Unlock the User -------#
if (!$User){ write-host "Uh Oh! That user can not be found!" }
else {
Set-QADUser $User -ObjectAttributes @{lockouttime='0'}
if (!$User.AccountIsLockedOut){
write-host "Successfully unlocked user account "+$User.LogonName
}else {
write-host "There was an error resetting the account for "+$User.LogonName+ `
". Account still has lockout period set."
}
}
#------- ######## -------#

Special Notes


This script is designed to run with a command line variable as the username (hence the $args[0]) – so remember to call it correctly.


My production script has some event log functions that raise an event at each stage, and if an error happens (normally human error mis-typing the username!) it can raise an error with a custom Source and EventID which our monitoring software picks up and creates a service ticket.