On a number of sites now, including 5 main current ones, I've used HP Data Protector, one of HP's enterprise-level backup software packages ... depending on who you talk to.
Anyway, because Data Protector, originally called HP OmniBack, was ported over from the UNIX platform it means that most of the configuration can be done by editing plain text files. This includes the schedules, although the schedule text files can often get pretty messy once you've made a few changes. Below are a few backup schedules that have had all the fat trimmed out and don't have anything you don't need in them.
Daily & weekly full at 1830
This job runs a full backup every Monday-Friday at 1830 excluding the first Friday of each month. I usually choose to run a monthly backup on the first Friday of each month so this is a necessity for me.
-full
-every
-day Mon Tue Wed Thu
-at 18:30
-full
-day 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
-at 18:30
-full
-exclude
-day Sat Sun
-at 18:30
Daily differential at 1830, weekly full at 1830
This job runs a differential backup (incr1 in DP) every Monday-Thursday at 1830 and a full backup every Friday at 1830, excluding the first Friday of each month.
-incr 1
-every
-day Mon Tue Wed Thu
-at 18:30
-full
-day 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31
-at 18:30
-full
-exclude
-day Sat Sun
-at 18:30
Monthly full on the first Friday of each month at 1830
This job runs a full backup on the first Friday of every month at 1830. It fits in with the schedules above.
-full -every -day 1 2 3 4 5 6 7 -at 18:30 -full -exclude -day Sun Mon Tue Wed Thu Sat -at 18:30
Move ExpressionEngine to a different server
Why move ExpressionEngine?
Good question! I run a local development environment at home so that I can simulate the production environment at ICDSoft as much as possible. When I make significant changes, however, this means I have to up and move my ExpressionEngine instance from my development server to my production server.
What do I need to do before beginning?
The process is actually fairly simple. That said, always take the appropriate precautions before making any changes to a production environment, i.e. backup everything now including your existing file and the ExpressionEngine database. After that it is highly recommended that you check your backup to make sure it's recoverable later.
Ok, I've backed up. Now what?
You've backed everything up? Good. Here are the steps I followed to move my ExpressionEngine instance from my development server to my production server.
Prepare the database
- Clear all ExpressionEngine caches. DO THIS FIRST.
- On the new server, if it doesn't exist already, create the database ExpressionEngine will use.
- On the new server, if it doesn't exist already, create the database user that ExpressionEngine will use to connect to your database.
- Dump the existing database to a backup file. How you do this is up to you but I personally use phpMyAdmin to backup the database to a 'zipped' file.
- Upload your database backup to the new database.
- Confirm that your database user can connect to the ExpressionEngine database.
Prepare the ExpressionEngine files
- Compress your existing site, probably to a ZIP file.
- Upload the archived files to your production server.
- Uncompress the archived files into the appropriate directory. Please note that most people simply FTP the files to the new server but I choose to do it this way as it's much quicker to transfer a single ZIP archive than it is to transfer the thousands of files ExpressionEngine uses one at a time. I use a small PHP script to decompress the uploaded archive - you'll need to make sure your host allows this before it'll work for you. Anyway, here's the source.
<?php
echo "Unzipping ...";
system("unzip my-site-archive.zip");
echo "Done!";
?>
Obviously you'll have to change my-site-archive.zip to the name of your uploaded archive ...
Subscribe
Stay updated
On rare occasions I'll send out updates about what's happening over here at Digital Formula. These updates will be seriously minor and be things I find interesting that are relevant to Digital Formula.
I don't like getting SPAM. For that reason your email address will never be used for anything other than Digital Formula mailing lists.
If you're interested you should go ahead and throw your email address into the box below and hit the Go button. There's really no point in putting a fake address here as you'll be asked to confirm your subscription. :-)
Your details
{exp:mailinglist:form list="digitalformula"} {/exp:mailinglist:form}
Slow FTP running ProFTPD on Parallels for Mac
FTP slow? Noooo!
My current web development server is a Debian GNU/Linux 5.0.5 machine running under Parallels for Mac (which I'm trialling right now). It was all working great until I tried to access the FTP server running on it from my Macbook Pro over the Airport. It worked but maaaaan was it slow! The Debian server is running ProFTPD, one of the many free FTP server options out there.
Thankfully the solution to the slow FTP access is very simple. There isn't a DNS server running here as it's not something I need for local development (although it would've solved this problem, too). The problem was caused by reverse DNS lookups failing - this is something ProFTPD has enabled by default if you use apt-get install proftpd to install ProFTPD.
Turn off Reverse DNS lookups
Turning off reverse DNS lookups in ProFTPD is as simple as checking /etc/proftpd/proftpd.conf for the following lines.
- IdentLookups off
- UseReverseDNS off
The IdentLookups line may already be set to 'off' - that's fine and you can leave it that way. The UseReverseDNS value may not exist at all - if that's the case just added it to the proftpd.conf file and set the value to 'off' by following the format of the other configuration lines.
Restart ProFTPD
While logged in with appropriate privileges the following command (from the Terminal) should restart ProFTPD. Rebooting your Debian GNU/Linux server will also restart ProFTPD but the whole point of running Linux is so you hardly ever have to reboot … right?
/etc/init.d/proftpd restart
Obviously your own configuration may differ so only follow these instructions if it won't break everything - be warned!
Contact
Hi!
Tech
0100111001101001011000110110010100100001
A few semi-interesting things about the Digital Formula site. If they're not interesting to you ... well ... sorry. :)
If you're interested in finding out how things are done around here please head over to my article about which tools, software and applications I use.
About
What is Digital Formula?
This version of Digital Formula is an attempt at cleaning up all the stuff I had on the previous version of Digital Formula by trimming out info that wasn't getting many views. It's also a complete redesign from the ground up, using ExpressionEngine 2.1 instead of Wordpress (my blogging engine of choice since I started my first site years ago).
The content will be similar but I'm going to concentrate more, if possible, on how to do useful stuff in the web design arena instead of just loads of overly technical I.T. information. I used to separate this info into different sites but now I only want to manage 1 site, not 4. :)
All the old content from previous versions of Digital Formula can be found by visiting the Digital Formula Archives.
Thanks for visiting!
Another new Digital Formula? Say WHAT?
Let's get started ...
I’m bored of Wordpress. Don’t get me wrong - it’s probably considered the best web-based CMS available given its unbelievable growth and world-wide acceptance, even when compared to commercial ones. However, it’s so all-encompassing that I decided I wanted to have a go at getting a version of Digital Formula online that isn’t powered by Wordpress. There are a couple of reasons for this.
- Wordpress literally does everything for you. Ok, so I could make a theme for Wordpress but I’d still be somewhat tied into the Wordpress way of doing things. Yes, I know you can make a theme match pretty much any layout but that’s not what I wanted. Personal choice there, I guess.
- I wanted to see if I could make a complete site design from nothing to fully functional with only the bits I wanted. I’m not a designer by any means but I enjoy having a hack at it ... you can probably tell from the look of this site that hacking at design is really about as far as I can go ... haha.
- HTML5 and CSS3 have been calling to me for ages and the only real way I could create a site and have 100% control over the validity while using the latest web design techniques was to switch from Wordpress to a more open CMS like ExpressionEngine.
- For some reason I just really wanted to try ExpressionEngine (click the following link if you’re just after the techy bits).
ExpressionEngine
And here we are at the guts of what powers the new Digital Formula. ExpressionEngine. Didn’t quite get it the first 2 times? ExpressionEngine, an increasingly-popular web-based CMS that is aimed more at designers than coders since the choice of bolt-on themes is really something you can use to get a site running, in my opinion, not something you’d use to run a fully functional website.
So far I’m really enjoying EE. It’s powerful, fast, flexible and truly unlimited in terms of how you can make it look. It doesn’t have the raw option-based power of Wordpress but that didn’t concern me much, even though I knew before I started that I’d miss some of the Wordpress nice-to-have bits & pieces.
The end result
As a result, here we are. This is what I’m referring to as Digital Formula version 4. The first 2 versions were both Wordpress and, even though I customised the heck out of the themes I used, this one’s all mine. The design is unique in that I made it, I designed it, I created all the graphics, the layout ... everything. That’s the reason that there a couple of inconsistencies still visible on the site. Whether or not you spot them depends on how hard you’re looking - please accept my humble bended-knee apologies if you’re a hardcore designer and you’re sitting there clutching your sides trying to make sense of this attempt at design.
Meh, that’s enough. What ends up on this site is anyone’s guess but recently I decided to focus on upping the amount of fun stuff on here since I have a number of pretty true passions out of design and I.T - photography and cycling just to name 2 of them. They’ll be on here for sure.
If you want to get in touch please feel free to drop me a line if you like - I’m always up for a good ole’ pow-wow with other users of the intert00bs. Thanks and welcome!
How to host multiple websites on OS X Snow Leopard
Background
I've been doing a ton of web development lately and, since switching to Mac back in November 2009, it means all my local development is now done using the OS X implementation of Apache Webserver. Because there are a couple of different sites on the go right now I figured that simulating the production environment as much as possible would be a good idea. To me that means using actual hostnames e.g. http://digitalformula4.local/ rather than http://localhost/digitalformula4/ or, another alternative on OS X, http://localhost/~user/digitalformula4 (yuck).
<2>The Process2>Luckily, because OS X has access to pretty much all the Apache Webserver configuration options that are available on the full production install of Apache, setting this up is easy. For this example I'm going to assume you've got at least OS X 10.6 as that's what I'm using and I haven't tried it on anything older. At a guess, though, I can't see why this won't work on some older versions of OS X. Here are the steps I followed.
- Open System Preferences, go to Sharing and make sure Web Sharing is enabled. Without this option checked Apache won't work. If you want FTP access you can also enable that by clicking Options under 'File Sharing'. This isn't part of this article, though.
- Navigate to /Library/WebServer/Documents/ and make a folder that means something. For now I'll stick to the example above - 'digitalformula4.local''. You can either do this using Finder or by using the Terminal if you're comfortable doing it that way like me. The Terminal somehow makes you feel a bit more geeky, too. ;-)
- Edit /private//etc/apache2/extra/httpd-vhosts.conf. You'll need to do this as a user with appropriate permissions although using 'sudo' will also work. E.g. sudo nano /private/etc/apache2/extra/httpd-vhosts.conf from the Terminal should prompt you for your password and then allow you to edit the file. Here's a screenshot of what my digitalformul4.local section looks like in my httpd-vhosts.conf file. Don't forget to change the email address section to your email address!

- You then need to edit /private/etc/apache2/httpd.conf and uncomment (remove the leading #) from the line that reads Include /private/etc/apache2/extra/httpd-vhosts.conf. Why? If you don't, the changes you just finished making to httpd-vhosts.conf won't mean anything.
- Once you've modified and saved those files you'll need to restart Apache. The command for this, also requiring relevant privileges, is sudo apachectl restart.
- Edit /etc/hosts on the server and add the following line: 127.0.0.1 digitalformula4.local. Make sure you change digitalformula4.local to the name of YOUR host.
- On the machines you'll be browsing FROM you'll need to tell them how to find the new server. In my case I'm using a static IP address scheme - my server is configured on 192.168.0.3. On OS X this means editing /etc/hosts and adding the following line: 192.168.0.3 digitalformula4.local.
- On OS X you may need to clear your DNS cache before you can find the new hostname. Again from the Terminal, this command should work: sudo dscacheutil -flushcache.
Using those steps you should be able to then save files into /Library/WebServer/Documents/digitalformula4 (replaced with YOUR host name, of course) and have them show up in the browser. This is good for when you want to use 'real' paths e.g. /images/ instead of worrying about virtual paths when doing your development.
Hope that helps someone!
Allow EE code in Expression Engine with ‘Allow EE Code’
The Problem
One of the great features of ExpressionEngine is that you can change pretty much everything that affects layout. EE tags are a big part of this but I found that by default you can have EE tags inside templates, obviously, but not inside entries. Putting EE tags into entries will simply show the EE tags in the browser when viewing the entry - not good. So, how do we do this?
The first step is to download and install the 'Allow EE Code' plugin, a first-party plugin from the makers of ExpressionEngine. As always the best place to get info about the EE plugin manager is the EE documentation.
Without going into too much detail the remaining steps are as follows.
- Edit your custom fields, in particular the ones you'll be using EE tags in. Edit the list 'Default Text Formatting for This Field' and make sure the option 'Allow EeCode' is set to 'Yes'.
- Unless you set the default text formatting drop-down box on the previous screen to 'Allow Eecode" you'll also need to set 'Allow override on publish page?' to 'Yes'.
- Next time you edit or publish an entry you'll be able to have EE tags in your entries IF you set the default text formatting option to 'Allow Eecode'. If not you'll have to change the default text formatting from 'XHTML' to 'Allow Eecode'. See the previous setup if you don't have that option available.
I was trying to do this so that I could use the Freeform plugin by Solspace inside an entry instead of inside a separate template.
Hope that helps someone. :)
What tools, software & applications do I use? v3.0
Let's get started ...
This post is intended as a couple of things. Firstly, it’s the 2nd rewrite of a post I wrote a while ago that covered the same thing as this one covers but from when I was running Windows.
I’ve actually had a couple of people ask me what tools I use for various tasks so I’m going to compile a list of the various applications I use ‘every day’. That’s in quotes as obviously I don’t use all of these tools EVERY day but I consider them part of the list of tools I couldn’t do without. I don’t use anything particularly special but I’ll make this list for those that’ve asked anyway. Secondly, I keep meaning to make a list of tools I use for my own reference so it’ll double as that, too.
I’m not going to go into a whole load of detail about what the benefits of each one are – I’ll let you work that out for yourself if you want to try them (feel free to contact me if you want to discuss any of these though). I will include a couple of things which aren’t strictly applications too, e.g. hosting services. So, here we go – these details are correct as at July 18th, 2010.
Applications & Utilities
- » Operating system :: Mac OS X 10.6.4 (Snow Leopard) on a 27″ iMac and a 15" Core i7 Macbook Pro. I made the switch from PC to Mac towards the end of 2009 and am wishing I’d done it years ago (based strictly on what I use my machines for). Please keep comments about Mac vs PC to yourself as I’m not interested in comparing the two – they’re both great for different reasons.
- » Office Suite :: Microsoft Office 2008 for Mac … unfortunately I have to say that compared to the Window version this really is quite crap. Office 2011 for Mac promises to bridge the significant feature gap between Office for Windows and Office for Mac, though.
- » Email client :: Mozilla Thunderbird 3
- » App dev environment :: Xcode 3.2.1 when writing for OS X, Visual Studio Express (C#) when writing for Windows (Parallels Desktop)
- » Web dev environment :: Coda by Panic
- » FTP client :: Transmit by Panic
- » MySQL administrator :: Navicat Lite
- » Text editor :: Fraise
- » Primary browser: Mozilla Firefox 3.6
- » Other browsers: Opera 10.6, Google Chrome, Safari 5
- » Twitter client :: Kiwi for Mac
- » Password storage :: KeePassX – *highly* recommended on both OS X and Windows (the Windows version is called KeePass although KeePassX is available for Windows, too).
- » iPod manager :: iTunes – on OS X it’s actually really good and seems 100x more stable than the Windows version.
- » Photo processing :: Adobe Photoshop Lightroom 3 – I used to use Capture One 4.8 from Phase One but it started to fall WAY behind Lightroom in terms of post-processing options … a real shame.
- » Fitness management :: Rubitrack for Mac (my training device is a Garmin 310xt)
- » Instant messaging :: Windows Live Messenger>
- » Movie player :: VLC (everyone should use this although it struggles with the TSCC codec unfortunately).
- » Audio player :: iTunes
System Stuff
- » System management :: MacKeeper. The differences this thing can make to your Mac's performance (which is probably already pretty sweet) are astounding.
- » System hackery :: Tinker Tool. Purely for the Mac geeks out there.
One thing you might notice is they’re pretty much all free tools with the exception of Lightroom, Rubitrack, Coda, Transmit and MacKeeper, all of which I own licenses for (no they’re not pirated!).
Online Services
- » Website host :: ICDSoft – these guys are AMAZING. I wouldn’t use anyone else for Linux hosting.
- » Email service :: Gmail
- » Website CMS :: ExpressionEngine 2.1 and Wordpress 3.0
- » Online photo sharing :: Flickr (I own a ‘Pro’ account)
- » RSS feed management :: FeedBurner
- » Website statistics :: Google Analytics
- » Search engine :: Altavista … haha yeah right. :P
- » Bookmarks :: Delicious – I stopped using browser-based bookmarks many years ago. Ok, so bookmarks are considered a bit backward now but I’ve got stuff on Delicious that I refer back to all the time. Thankfully the functionality doesn't seem to have changed at all since its acquisition by Yahoo some time ago.
That’s about it really. As I said earlier I’m happy to discuss any of these if you like – just post a comment or use the Contact Me link at the top of the page.
Thanks!
Calculating distance and speed manually
Training Intro
I've been doing a reasonable amount of training on the road bike lately and given that the weather here in Melbourne is temperemental at best coming into winter I decided to get another indoor wind trainer. Because I didn't want to break the bank I didn't buy one that shows you your speed or distance. Apart from the fact that effective training should be based off heart rate and cadence anyway (or power output if you're REALLY serious) you're looking at AUD$800+ for that sort of thing, money I'm not prepared to spend on a trainer at the moment.
Anyway, I still wanted to know how far I'd gone and what my average speed was so I set about figuring out how to calculate these figures given the information I do have - cadence, time, wheel size and gear sizes.
Required Info
A bit of research came up with a few different ways of calculating the distance and average speed when you know the following:
- Wheel circumference
- Average cadence for the training session
- Chainring sizes (measured in number of teeth)
- Sprocket/cassette cog sizes (measured in number of teeth)
- Training session time
The method I found that worked best for me came from a Wikipedia page entitled Bicycle Gearing. It contains a whole load of useful information, including how to calculate what is referred to as "metres of development" i.e. the distance travelled for a single crank revolution. This, of course, is dependant on which gear you're in. Another thing to note before carrying on is that it's often recommended to train for certain intervals at certain levels of intensity and cadence. The only problem I can see with the calculations below is if you change gears a LOT during a trainer session you'd need to know how long you were in each gear for (in order to calculate the metres of development for each gear used). I'm not a doctor either so please be responsible and don't train before consulting a physician if you're not sure what you're doing. However, carrying on ...
When it rains in Wellington, it REALLY rains ...
Brrr ...
On June 27th 2010 the Wellington Harbour Marathon was held in ... yes, Wellington, New Zealand. :)
First up, the weather! The wind was an icy 40kph from the south (straight off Antarctica), the temperature was around 5 degrees and the rain was constant from start to finish. I was part of a team of photographers assigned with the difficult task of photographing each of the 6000 competitors at least once each.
The job was contracted to marathon-photos.com, a company who shoots sporting events so that the competitors can purchase photos of themselves after the event is over. It's a great idea!
Unfortunately the weather really stopped the event from being as fun as it could be but we got there in the end and some great shots were taken. If you want to see the photos or if you were there on the day, please check out marathon-photos.com. :)
Playing about with AppleScript…
Why AppleScript?
I’ve been playing about with AppleScript today as there are a couple of tasks I want to automate on my system (Snow Leopard 10.6.3 as I write this). My background in I.T. means that task automation is something I’m into for obvious reasons … why take ages to do something many times when you can automate the process and have it done in 1/10 of the time when it needs to be done next? :)
Anyway, I use KeePassX to store my passwords (it’s the OS X version of KeePass, in my opinion easily the world’s best open source password safe. Although I use Time Machine (it does a great job) I need to carry my passwords with me. I don’t use the same password all over the place which means I have a whole bunch of passwords – KeePassX means I don’t have to remember them all.
So, where does AppleScript fit in? I used to use a bash script to keep my USB key (a LaCie itsakey) and local hard drive password databases in sync and, while it worked fine, I decided to have a go at doing the same thing using AppleScript.
AppleScript is, for lack of a better expression, painfully close to being English. It’s stupidly easy to write although there are some advanced things you can do with it too (I’ll get to those in a future post).
Here’s my entire script – hope someone finds it useful. :) Please note that this version uses Growl to display notifications – I highly recommend installing it if you don’t have it installed already. Please also note that a production script would have much better error handling but this one does what I need it to. Comments welcome!
-- see if Growl is available on this system
tell application "System Events" to set GrowlAvailable to exists application process "GrowlHelperApp"
if GrowlAvailable then
-- enable the script to send Growl notifications
tell application "GrowlHelperApp"
set the allNotificationsList to {"Old KeePass versions removed.", "Old KeePass versions backed up.", "Master KeePass versions copied successfully."}
set the enabledNotificationsList to {"Old KeePass versions removed.", "Old KeePass versions backed up.", "Master KeePass versions copied successfully."}
register as application "Backup KeePass Database" all notifications allNotificationsList default notifications enabledNotificationsList icon of application "Script Editor"
end tell
end if
set diskName to "LaCie"
set folderName to "KeePass"
set databaseName to "passwords.kdb"
set databaseBackup to databaseName & ".bak"
set keyfileName to "passwords.key"
set keyfileBackup to keyfileName & ".bak"
-- get the username of the current logged in user
set userName to do shell script "whoami"
try
tell application "Finder"
if exists folder folderName of disk diskName then
-- set the locations of the original, destination and backup KeePass files
-- because we're using aliases, these files & folders MUST exist first or an exception will be thrown
set sourceDB to file databaseName of folder folderName of folder "Data" of folder userName of folder "Users" of disk " HD" as alias
set sourceKeyfile to file keyfileName of folder folderName of folder "Data" of folder userName of folder "Users" of disk " HD" as alias
set destDB to file databaseName of folder folderName of disk diskName as alias
set destKeyfile to file keyfileName of folder folderName of disk diskName as alias
set bakDB to file databaseBackup of folder folderName of disk diskName as alias
set bakKeyfile to file keyfileBackup of folder folderName of disk diskName as alias
-- set where the files will be copied to
set destFolder to folder folderName of disk diskName as alias
-- if exists file databaseBackup of folder folderName of disk diskName then
if exists file bakDB then
-- delete the existing backup files
delete file bakDB
delete file bakKeyfile
if GrowlAvailable then
tell application "GrowlHelperApp"
notify with name "Old KeePass versions removed." title "Backup KeePass Database" description "Old KeePass versions removed." application name "Backup KeePass Database"
end tell
end if
else
set continueResult to display dialog "Backup files are missing from " & folderName & " on disk " & diskName & ". Continue anyway?" buttons {"Yes", "No"} with icon caution with title "Backups missing"
if button returned of continueResult is "No" then
return
end if
end if
-- backup the existing files
if exists file destDB then
set name of destDB to databaseBackup
set name of destKeyfile to keyfileBackup
if GrowlAvailable then
tell application "GrowlHelperApp"
notify with name "Old KeePass versions backed up." title "Backup KeePass Database" description "Old KeePass versions backed up." application name "Backup KeePass Database"
end tell
end if
end if
-- copy the master files
copy file sourceDB to folder destFolder
copy file sourceKeyfile to folder destFolder
if GrowlAvailable then
tell application "GrowlHelperApp"
notify with name "Master KeePass versions copied successfully." title "Backup KeePass Database" description "Master KeePass versions copied successfully." application name "Backup KeePass Database"
end tell
end if
else
display dialog "Oops! The destination folder you selected, /" & diskName & "/" & folderName & "/, ain't there!. :( Please check it and try again." buttons {"Ok"} with icon stop with title "Oh no!"
end if
end tell
on error
-- an exception occurred
display dialog "An expected error has occurred while backing up your KeePass files. Have a look to see if all the required files are there and try again ... k? :)" buttons {"Ok"} with icon stop with title "Oh no!"
end try
Make the OS X Dock nice and tidy…
Tidy-ness ... nice.
I’m bit a of a tidy-freak when it comes to icons, desktops and overall system organisation … geeky? Yes. Easier to work with afterwards? Definitely.
So now that I’m using a Mac I’ve been slowly getting used to organising things better – including the Dock. I’ve got everything ordered how I want but still thought it was a bit of a mess (visually) so I tried to find a way of adding some space to the Dock, thereby creating ‘groups’ of Dock icons. Yes, I know about stacks but they didn’t do what I wanted.
All you need to do is run a pretty simple shell script to get it done. There are 2 scripts to use, one for the Applications side of the Dock and the other for the Documents side of the Dock. By ’side’ I mean the parts of the Dock on the relevant side of the existing resizer/splitter thingy.
Shell script I hear you say? Bad! Well … no, not as bad as you might think. Thankfully OS X has a built-in scripting language all of its own called … wait for it … AppleScript. From AppleScript you can run shell commands which you don’t even need to mess about in the shell if you don’t want to. For the Windows people out there think of this example as a batch file – the end result is the same.
Anyway, fire up the AppleScript Editor (it’s under Applications/Utilities if you haven’t moved it) and paste the following script into it. Note that this one is to add a spacer to the Application side of the Dock!
-- add a spacer to the Application side of the Dock
do shell script "defaults write com.apple.dock persistent-apps -array-add '{tile-data={}; tile-type=\"spacer-tile\";}'"
-- restart the Dock
-- process names are case-sensitive!
do shell script "killall Dock"
Unattended installation of SQL Server 2005 Express
* Article Removed *
To continue on with the theme of unattended installation-related posts lately, what if you want to install SQL Server 2005 Express Edition in unattended mode? SQL Server 2000 had the ability to save the installation into a file called setup.iss - how nice of Microsoft to remove this feature from SQL Server 2005 ... however, let's get rolling.
This post has been removed in favour of pushing readers towards installing SQL Server 2008 Express instead of SQL Server 2005 Express.
The benefits of using the 2008 version over 2005 are too numerous to list here and an article has been published on Digital Formula that goes into detail on how to perform an unattended installation of SQL Server 2008 Express. Please click the preceding link for full information.
Reloading hosts files in OS X
A changed way of thinking
Now that I’m using a Mac at home I’ve had to go through a bit of a mind switch when it comes to doing things I’ve been to doing for years.
Today’s mind bender came about because I needed to edit the hosts file to force Snow Leopard to find a URL on a different IP address to where it actually is. In Windows you just edit %SystemRoot%\system32\drivers\etc\hosts then run nbtstat -R to reload the hosts file but in OS X this obviously doesn’t work.
You still need to edit the hosts file, located at /etc/hosts, but obviously there's no nbtstat command to run afterwards. Depending on where you look on Google you'll find a number of answers, from running niload to lookupd but none of those worked for me. Thankfully I found the answer – here it is.
sudo dscacheutil -flushcache
Obviously you’ll need the sudo part unless you’re running your shell as root … let’s not get into that, though. :)
If you want to make an alias to this command so you don’t need to type the whole thing every time, do this:
alias flushcache=’sudo dscacheutil -flushcache’
Sorted!
Microsoft Excel - Count coloured cells
What backup?
Most companies have some sort of backup strategy in place and that strategy often involves documenting the success & failure rate of the backups on a daily basis. For obvious reasons all the companies I've worked with in the past have documented this using a variation of the well-known "backup matrix", created using Microsoft Excel.
I choose to create my backup matrix documents so that backup results are colour-coded. That way they're easily visible and it's easy to see what happened when and to get an overall idea of how good your backups have been. Green coloured cells are successful backups, red cells are failed backups etc.
The first thing I need to do when I create these documents is to make some 'reference cells'. These cells are coloured with the various colours that will be used in the matrix, e.g. green for successful etc, as listed above. So they don't look like reference cells I also use them as the key for the matrix so people know what the various colours mean.
How, then, do you work out how good the backups have been if there's no text in the cells to look for? You need a VBA function that looks for the cell's colour instead of its contents - easy. Below is the function I wrote for that purpose - you'll need to make sure you are using .XLSM documents if you are using Excel 2007 for Windows as .XLSX files are, by default, secured so that macros won't run.
Function countColours(colourReferenceCell As Range, cellRange As Range)
' countColours
' Chris Rasmussen, April 2010
'
' Count occurences of cells that are a certain background colour
' E.g. for use in a backup matrix
Dim currentCell As Range
Dim colourReference As Long
Dim vResult
colourReference = colourReferenceCell.Interior.ColorIndex
' reset the total count back to zero to prevent errors
vResult = 0
' go through all the cells in the specified range and look at the background colour
For Each currentCell In cellRange
If currentCell.Interior.ColorIndex = colourReference Then
vResult = vResult + 1
End If
Next currentCell
countColours = vResult
End Function
Once you've got this function in place, all you need to do is choose the cell that will show the total of successful backups (for example) and enter the following formula. We'll assume that cell A1 is the cell that is coloured green for reference. We'll also assume that the Excel cell range C1:C5 contains the results.
=countColours(A1,C1:C5)If you have 5 successful backups in your range and they're all coloured green, the cell containing that formula with contain the number 5. Easy. :)
Pay it forward ...
Helping a friend
For a few years now I’ve been dabbling in a bit of 3D design here and there. Purely as a hobby though and I’d never even dream of calling myself any good at it.
Anyway, I used to learn from a bunch of talented dudes over http://www.3dcaffeine.com, a site that unfortunately no longer exists (internal problems? I don’t know.) One of the members there was a Romanian guy by the name of Flavius, a very talented 3D designer with a pretty scary level of skill for someone his age, around 20 as I write this I think … no he’s not a Romanian scammer!
He’s in the unfortunate position where web hosting and all the bits that go with it are pretty hard to come by so I decided to do as the title of this post says – pay it forward. To do this I offered to pay for web hosting and domain registration for a website to be created, a site where Flavius could showcase his work, demonstrate his skills and get the word out there so that people know there are talented designers everywhere.
The site’s now live and, while it’s yet to have much content (it’s been live around an hour now but will undergoing plenty of changes over the next little while), is coming along nicely with a decent gallery to get started, backed up by a beautiful WordPress theme by Nick Roach over at Elegant Themes. Go there if you want themes – it’s the site I choose to use for all my WordPress themes.
Flavius’ new site can be found at http://flaviuscristea.com and will have more content added as time goes on. Please feel free to let me know if you find any problems there as I’ll be doing the back-end maintenance of the site even though Flavius will be maintaining the actual content.
Cool. :)
Wordpress ‘How To’ Guide
Efficient Wordpress
Please feel free to contact me through my contact page if you need clarification on or want to discuss any of the information in this post.
I apologise in advance for the length of this post ... I tend to go into a lot of detail when writing posts like this. I hope it all helps someone though. :)
Assumptions & requirements
To begin with, you'll need a few things before you even get started. Here's a brief, but not exhaustive, list of things you'll need.
- A domain name. The domain registrar you choose is up to you - it would be irresponsible of me to say that any particular registrar is better than any other.
- A web hosting account. I use ICDSoft - this is one situation where I'm happy to say they're better than any other Linux host I've ever used.
- A copy of the latest version of Wordpress. As of today, September 1st 2010, this is version 3.0.1 and can be downloaded from http://wordpress.org/.
- A theme. Wordpress has possibly the best theme support around so this is quite important. Personally I use theme from Elegant Themes. Pick one, download/purchase it and have the files ready for later steps.
- FTP credentials. You'll need to know the DNS address or IP address of the FTP site that supports the final, published URL, as well as the username and password to login there. I use the free FTP client, FileZilla - it's free and works on OS X (Mac), Linux and Windows.
- MySQL credentials. You'll need to know the connection address or IP address of the MySQL server that will support your Wordpress installation, as well as the username and password used to connect.
- An empty database ready for your Wordpress installation. You don't need to put anything in it - the Wordpress installation scripts will do that for you.
HDR photography intro for beginners
Brighter and more vivid colours
It's been a while since I put anything on this site that isn't of a technical nature so I thought I'd throw something photography-related up here. Today's non-technical article is about HDR photography, i.e. the practice of combining multiple exposures to create a single high dynamic range or HDR image. Here's what I came up with.
Before I start, I'll just say that this is just playing about with HDR - an actual attempt would probably produce much better results. :)
To make the images in this post I used a tripod-mounted Nikon D300 digital SLR camera w/ remote shutter release. Although you *can* take the exposures necessary for HDR by hand-holding your camera it's not recommended because all exposures must be of the same scene if you want to get the best results. A digital SLR camera or compact with the ability to control both shutter speed and aperture is required. The aperture must be set the same for all exposures to prevent parts of scene becoming 'blurred' due to depth-of-field changes. The ability to control shutter speed is necessary as HDR photography requires you to bracket your exposures, usually by +/- 2 stops. In case you don't want to read the Wikipedia article linked to just there, bracketing is taking a 'master' exposure and (usually) adjusting the shutter speed up and down a certain number of stops so that you have a set of shots of the same scene but with a range of varying shutter speeds.
A typical bracketing sequence with the shutter speed being adjusted by 1 stop each time might be like this (note that the aperture doesn't change). The ordering of these shots is irrelevant - it's the order my camera is set to though.
- 1/125 f/4.5 - the 'master' image, correctly exposed.
- 1/60 f/4.5 (-1 full stop)
- 1/80 f/4.5 (-2/3 stop)
- 1/100 f/4.5 (-1/3 stop)
- 1/160 f/4.5 (+1/3 stop)
- 1/200 f/4.5 (+2/3 stop)
- 1/250 f/4.5 (+1 stop)
With those shots taken it was a case of loading them into Photomatix Pro, a trial version of which can be downloaded from HDRsoft. The tone-mapping preferences are very much user- and image-specific so I won't list them here. The HDRsoft team has made a couple of good tutorials available to get you started if you've never used Photomatix Pro before.
Here is one of the exposures in my set without any post-processing being done. I shoot RAW and obviously this shot could be cleaned up and improved a lot by using ACR, Lightroom or whatever your RAW-processing software of choice happens to be. Personally I use Adobe Photoshop Lightroom.
And here is the same scene but as an HDR composite made up of 7 bracketed frames. The colour of the water and the detail in the clouds are pretty crazy I reckon ...
I've got the same 2 images combined into a single image so they can be seen side-by-side too - check it out.
it's available on Flickr for those interested in seeing it.
Obviously scene choice plays a big part in how well an HDR image comes out (the one above is just to demonstrate results, not photography) but it's still good fun. :)
Making the W3C Validator work with ASP.NET
Validation is important!
For as long as I can remember I've been making sure that the sites I play about with (published or not) produce markup that conforms with w3c specifications. The best-known way to do this is to run the markup generated by the web server through The W3C Markup Validation Service. Unfortunately it's been difficult to make ASP.NET applications produce 100% valid markup, something that always frustrated me. There may have been ways to make this work before that I'm not aware of but here's now to do it anyway.
It's worth noting that the DOCTYPE declarations used throughout this article aren't valid for HTML5.
I always write my sites to conform to XHTML 1.0 Strict specifications, despite currently making them HTML5-compliant wherever possible. If you're unsure what this means I would recommend heading over the W3C website about XHTML 1.0. The Strict DOCTYPE is actually the way HTML and XHTML were designed to be used so I'd recommend using them over the older/legacy Transitional DOCTYPE. Depending on where you look or what you read, the transitional DOCTYPE is intended for sites making the transition towards standards-compliant markup. To me that sounds like pretty good reason to stick to the strict DOCTYPE.
Anyway, when you're making your ASP.NET applications it's possible to make Visual Studio generate applications that conform to the W3C recommendations and therefore work with the W3C Markup Validation Service. There are 2 things you need to do for this to work properly. Note that this isn't specific to 'standard' ASP.NET applications - it will work with ASP.NET MVC applications, too.
Required steps
Step 1 isn't strictly (no pun intended) required but it's good practice. Edit Web.config and use the xhtmlConformance element to configure XHTML 1.0–conforming control rendering. Here's what is in my Web.config files - this must be placed inside the <system.web> section.
Microsoft's MSDN page about the xhtmlConformance element can be found by going to http://msdn.microsoft.com/en-us/library/ms228268.aspx.
C# Full-screen application - Complete Source
Update!
Yesterday I posted a quick update to an article I wrote back in 2007 entitled "How to make a full-screen Windows app using VB.NET". Aside from 1 or 2 people saying "Oh man why don't you be a man and write it using C#?" I reckon it's a good idea to do that anyway. Thanks Scott for the suggestion. ;) And thanks Phil for pointing me in the right direction with the DLL import stuff. :)
So, without any mucking about here's the exact same complete application example only this time in C#.
Please feel to ask any questions necessary. Thanks!
Form1's complete source:
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Runtime.InteropServices;
namespace Play
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
[DllImport ("user32.dll")]
private static extern bool SetWindowPos(IntPtr hWnd, IntPtr hWndIntertAfter, int X, int Y, int cx, int cy, int uFlags);
[DllImport("user32.dll")]
private static extern int GetSystemMetrics(int Which);
private const int SM_CXSCREEN = 0;
private const int SM_CYSCREEN = 1;
private IntPtr HWND_TOP = IntPtr.Zero;
private const int SWP_SHOWWINDOW = 64;
public int ScreenX
{
get
{
return GetSystemMetrics(SM_CXSCREEN);
}
}
public int ScreenY
{
get
{
return GetSystemMetrics(SM_CYSCREEN);
}
}
private void FullScreen()
{
this.WindowState = FormWindowState.Maximized;
this.FormBorderStyle = FormBorderStyle.None;
this.TopMost = true;
SetWindowPos(this.Handle, HWND_TOP, 0, 0, ScreenX, ScreenY, SWP_SHOWWINDOW);
}
private void Restore()
{
this.WindowState = FormWindowState.Normal;
this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
this.TopMost = false;
}
private void button1_Click(object sender, EventArgs e)
{
FullScreen();
}
private void cmdRestore_Click(object sender, EventArgs e)
{
Restore();
}
private void cmdExit_Click(object sender, EventArgs e)
{
Application.Exit();
}
}
}
How to use SQL Server CE with C# 3.5
The absolute basics
I'm writing this article because a small project I've been working on required me to look for information on using SQL Server CE with C# 3.5. I couldn't find very many useful articles on the topic so I've decided to write my own and summarise some of the useful bits I found.
For starters, why use SQL Server CE? I think it's an easy way of implementing a high supported and functional database solution for various types of applications although this article will focus on using SQL Server CE in a small Windows forms application. To begin with you'll need to download SQL Server CE from the Microsoft website.
In the past I think I've gone a bit overboard with the length of my posts so I'm going to attempt to keep this one short. The application I used this code in is pretty well split up and uses a number of different layers but you don't need to go this far to use SQL CE with your applications. The code below is a summary only and covers the key things I think you need to know - feel free to ask any questions you need to.
I'm also aware that the code below *will* need modification before you can just throw it into your own applications but, as mentioned above, please post questions on this post if there is anything you need clarification on.
Creating the database
string connStr = String.Format("Data Source = C:\temp\database.sdf");
using (SqlCeEngine engine = new SqlCeEngine(connStr))
{
engine.CreateDatabase();
}
SQL query with no result
Running a SQL command that doesn't return a result set (note that this is, in some cases, where you would execute SQL to create the database structure after using the code above to create the database file itself).using (SqlCeConnection conn = new SqlCeConnection(connStr))
{
using (SqlCeCommand cmd = new SqlCeCommand())
{
cmd.Connection = conn;
conn.Open();
cmd.CommandText = "SELECT * FROM table_name";
}
}
Getting a record from the database
using (var conn = new SqlCeConnection(connStr))
{
conn.Open();
string query = "SELECT * FROM Applications WHERE id = @Id";
using (var cmd = new SqlCeCommand(query, conn))
{
// appId is a variable passed to the method that uses this code sample
cmd.Parameters.AddWithValue("@Id", appId);
var reader = cmd.ExecuteResultSet(ResultSetOptions.Scrollable | ResultSetOptions.Updatable);
if (reader.HasRows)
{
while (reader.Read())
{
int Id = Convert.ToInt32(reader["Id"]);
// more code here to deal with other columns in the record that was selected from the database, if any
}
}
}
}
That's about as basic as it gets but I'm also in the process of writing another article about a basic application that uses this code in a "real-world" situation.
How to backup SQL Server 2005 Express
Backup IS important
A lot of my articles make use of or mention SQL Server Express, the light and cut-down and FREE version of Microsoft's flagship database product Microsoft SQL Server.
One of the features of the full and very expensive version of SQL Server 2005 is the ability to run scheduled backups using SQL Maintenance Plans. SQL Server requires SSIS (SQL Server Integration Services) for these to be available - unfortunately SQL Server Express doesn't include SSIS. There is a way to get scheduled backups for SQL Server Express though.
Before you begin you'll need to install SQL Server Management Studio Express.
Part 1 - Create a backup script
- Open SQL Server Management Studio Express and login as a user with sufficient permission to access the database(s) you want to backup. You can do this as 'sa' if you want.
- Expand the name of your server or instance, expand Databases and select the database you want to backup.
- Right-click the database name, select Tasks and then select Back Up.
- Set the options you require for the backup. For example you might want to change the location where the backup files get created, edit backup set retention period etc.
- Once you've set the options necessary click the Script drop-down option at the top of the backup window and select either 'Script Action to File', or, if you want to see/edit the contents of the script before saving it, select 'Script Action to New Query Window'. I find it's best to script the backup to a new query window because you can test it before saving.
- Save the created script when you're finished editing or enter an appropriate filename immediately if you selected 'Script Action to File'.
- If you saved the script, open it up - we're going to test it before making it 'live'.
- Once you have the script open click the checkmark/tick button just to make absolutely sure the script is valid (it's SQL Server-generated so it'd better be!).
- Click the 'Execute' button if you want to run a test. If you are backing up a very large database this can take a while and you won't get a whole lot of feedback while the backup is being run. When the backup finishes the results will be displayed in the Results pane, successful or not. If it fails, figure out why (e.g. check for sufficient disk space, permissions for the folder you're backing up to etc).
SQL Server 2008 Express Unattended Install
One-click goodness
On the previous version of Digital Formula I wrote an article called "How to perform an unattended installation of SQL Server 2005 Express". With the release of SQL Server 2008 it's time to write another one about how to do the same but for SQL Server 2008 Express. So, let's get started ...
Unattended installations of SQL Server can be as involved as you want - pretty much every option can be specified in the configuration file. For this example I’m going to perform a relatively basic installation with minimal customisation so you can see the process at work. The installation will specify most of what I think are the critical options you'll be interested in. Note that for this example I'm using the x86 (32-bit) version with advanced services.
Assumptions
- You've downloaded the x86 (32-bit) version of SQL Server 2008 Express from the Microsoft Microsoft SQL Server 2008 Express website
- Your system meets the requirements for installing SQL Server 2008
- You are installing from C:\Install\SQL2008 (you can change this as necessary but please make sure you update the paths in the examples below)
- You'll save your configuration file as C:\Install\sql-2008-express.ini
Required Files
- Run the executable you downloaded with the /x parameter (e.g. C:\Install\SQL2008\SQLEXPRADV_x86_ENU.exe
- Choose a location to extract the installation files to.
- Create a new text file that will become the unattended installation configuration file. Leave it empty for now.
Configuration Files
So, you can now create your own configuration file using Microsoft's documentation or you can use the version I've included in this article.
Be careful with the Microsoft documentation as there is an error on the page called How to: Install SQL Server 2008 from the Command Prompt. It mentions a parameter called /BROWSERSVRACCOUNT but this should be /BROWSERSVCACCOUNT. If you get this wrong the installation WILL fail.
You can download the configuration file I've made below. The changes I've made are as follows (you may need to change these to match your settings).
- Set the QUIETSIMPLE parameter to "True".
- Set the MEDIASOURCE parameter to the appropriate installation path.
- Added a parameter called SAPWD and set it to the strong 'sa' password.
- Set the INDICATEPROGRESS parameter to "True".
- Set the SQLSYSADMINACCOUNTS value to "MYPC\Administrator".
Once you have your answer file all nicely setup and ready to use you’ll need to tell the setup program how to use it.
Run the script
From a command prompt (or Start > Run if you’re into that) run the following command. Remember to change the file and path names to the ones that match your system.
C:\Install\SQL2008\setup.exe /CONFIGURATIONFILE=C:\Install\sql-2008-express.ini
If you’ve done everything right this will start the installation process and you’ll end up with a SQL Server 2008 instance called SQLExpress running on your system. Easy!
sqlcmd.exe on SQL 2008 fails - HResult 0x2, Level 16 etc
Error ... what?
I've built one of my test servers with SQL Server Express 2008 w/ Advanced Services. On a whole load of our servers I use SQL Express for local installations and SQLCMD.EXE works well as a good way to run scheduled backups. It's done this way because SQL Express doesn't support SSIS (SQL Server Integration Services), the component required for scheduled tasks. With SQL 2008, however, SQLCMD.EXE didn't work for me when I tried to setup scheduled backups. Here's how I fixed it ...
The instance in question has the default name of SQLEXPRESS. Obviously this means that to connect to the server you need to use SERVER\SQLEXPRESS - that works fine from Management Studio and from the Java application installed on this particular server.
When using SQLCMD.EXE from the command line the full error message looks like this:
Some Googling suggested that this problem could be caused by one of 2 things. Firstly, that the SQL Browser service isn't running - on my server it was running. Secondly, named pipes aren't enabled in the SQL Server Configuration Manager ... on mine they are. Hmmm.
I've had problems in the past with named instances of SQL Server so I had a look at the properties of the named pipes configuration and, sure enough, it said \\.\pipe\MSSQL$SQLEXPRESS\sql\query. That *looks* ok, right? Yes but it's the cause of the problem.
I changed the named pipe to the following.
Voila! SQLCMD.EXE now works from the command line meaning my scheduled backups now work too. Not being a full-time DBA I'd put this down to a bit of a fluke on my part although I then found an article by Jesse Johnston that confirmed the same steps worked in their situation too.
Problem solved!
Disable IEESC on Windows 2008
Blocked websites = bad
The default configuration for Windows Server 2008 still has Internet Explorer Enhanced Security Configuration enabled. Considering most administrators probably disable this I wonder why it's still there ... nonetheless here is a script to disable Internet Explorer Enhanced Security Configuration (IEESC) from a script.
:: If required, backup the registry keys
:: This is always a good idea before making registry changes
REG EXPORT "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" "%TEMP%.HKEY_LOCAL_MACHINE.SOFTWARE.Microsoft.Active Setup.Installed Components.A509B1A7-37EF-4b3f-8CFC-4F3A74704073.reg"
REG EXPORT "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" "%TEMP%.HKEY_LOCAL_MACHINE.SOFTWARE.Microsoft.Active Setup.Installed Components.A509B1A8-37EF-4b3f-8CFC-4F3A74704073.reg"
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" /v "IsInstalled" /t REG_DWORD /d 0 /f
REG ADD "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}" /v "IsInstalled" /t REG_DWORD /d 0 /f
Rundll32 iesetup.dll, IEHardenLMSettings
Rundll32 iesetup.dll, IEHardenUser
Rundll32 iesetup.dll, IEHardenAdmin
REG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A7-37EF-4b3f-8CFC-4F3A74704073}" /f /va
REG DELETE "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Active Setup\Installed Components\{A509B1A8-37EF-4b3f-8CFC-4F3A74704073}" /f /va
:: If you like you modify the registry to remove the warning that shows on first IE run
:: This registry change will also set the default home page to about:blank
REG DELETE "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main" /v "First Home Page" /f
REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main" /v "Default_Page_URL" /t REG_SZ /d "about:blank" /f
REG ADD "HKEY_CURRENT_USER\Software\Microsoft\Internet Explorer\Main" /v "Start Page" /t REG_SZ /d "about:blank" /f
Just another of those little Windows annoyances that can be removed easily if you like.
VB.NET – List active directory users – Re-write
Article rewrite
Please note: This is a rewrite of an article I wrote way back in 2007. The original article has been updated with a link to this one.
As per usual I had a situation where I had to do some Active Directory stuff with VB.NET. I had to grab a list of all the users in our AD so that people could select a user and perform functions on them from within a webpage. Another note: This article is VB.NET-specific. If you’d like to know how to do this using C# please see this post’s “partner” entitled "Follow Up – List active directory users – This time in C#"
Carrying on though, there are a number of ways you can do this but in the .NET Framework they all involve using the System.DirectoryServices namespace. A couple of quick things to be aware of before you try this yourself:
- Before messing with your Active Directory make sure you know what you’re doing and have the permissions of your AD Administrators (if it’s not you!)
- If you are going to use any of the following code from a .NET console application you’ll need to add a reference to System.DirectoryServices in addition to importing the namespace. I wrote a post a while ago about this entitled “Developer Dumbness” – it has the steps you need to add a reference to a .NET console application.
Anyway, the code below is a simple function that queries your Active Directory domain and retrieves all the user objects. This particular example filters out any user account whose “DisplayName” attribute meets the following criteria (the requirements for the app I had to write):
- Has an email address
- Does not contain the “$” symbol
- Does not contain the words “Admin” or “admin”
- Does not contain the words “Test” or “test”
- Does not contain the words “Service” or “service”
- Does not contain the word “System” or “system”
The example code below is a complete Windows console application that does all of the above. It’s important to note that if you’re using this in a production environment you’ll need to make sure the application containing the code has access to the Active Directory, usually using .NET impersonation – this is beyond the scope of this post.
Imports System
Imports System.Collections.Generic
Imports System.DirectoryServices
Module ListAdUsers
Sub Main(ByVal ParamArray Args() As String)
Console.Clear()
Dim userList As List(Of String) = New List(Of String)
Dim badEntries As Integer = 0
Dim domainName As String = String.Empty
If (Args.Length > 0) Then
domainName = Args(0)
Else
Console.Write(String.Format("{0}Please enter your Active Directory domain name: ", vbCrLf))
domainName = Console.ReadLine()
End If
Console.Write(String.Format("{0}Attempting to build user list for {1} ...{0}{0}", vbCrLf, domainName))
Try
If Not String.IsNullOrEmpty(domainName) Then
Dim myDirectoryEntry As DirectoryEntry = New DirectoryEntry(String.Format("LDAP://{0}", domainName))
Dim mySearcher As DirectorySearcher = New DirectorySearcher(myDirectoryEntry)
Dim mySort As SortOption = New SortOption("sn", SortDirection.Ascending)
mySearcher.Filter = ("(objectClass=user)")
mySearcher.Sort = mySort
For Each resEnt As SearchResult In mySearcher.FindAll()
Try
If Not String.IsNullOrEmpty(resEnt.Properties("Mail")(0).ToString()) _
AndAlso System.Text.RegularExpressions.Regex.IsMatch(resEnt.Properties("DisplayName")(0).ToString(), " |admin|test|service|system|[$]", System.Text.RegularExpressions.RegexOptions.IgnoreCase) Then
Dim space As Integer = resEnt.Properties("DisplayName")(0).ToString().IndexOf(" ")
Dim formattedName As String = String.Format("{0}{1}{2}", _
resEnt.Properties("DisplayName")(0).ToString().Substring(space).PadRight(25), _
resEnt.Properties("DisplayName")(0).ToString().Substring(0, space).PadRight(15), _
resEnt.Properties("Mail")(0).ToString() _
)
userList.Add(formattedName)
End If
Catch
badEntries = badEntries + 1
End Try
Next
If (userList.Count > 0) Then
Console.WriteLine(String.Format("=========== Listing of users in the {0} domain{1}", domainName, vbCrLf))
Console.WriteLine(String.Format("{0}{1}{2}{3}", "Surname".PadRight(25), "First Name".PadRight(15), "Email Address", vbCrLf))
For i = 0 To userList.Count - 1
Console.WriteLine(userList(i).ToString())
Next
Console.WriteLine(String.Format("{0}=========== {1} users found in the {2} domain", vbCrLf, userList.Count.ToString(), domainName))
Else
Console.WriteLine(String.Format("{0}=========== 0 users found in the {1} domain", vbCrLf, userList.Count.ToString()))
End If
Console.WriteLine(String.Format("=========== {0} objects could not be read", badEntries.ToString()))
Console.WriteLine("=========== End of Listing")
Else
Console.WriteLine("Please enter a domain name next time!")
End If
Catch ex As Exception
' in a production app you wouldn't show the user the exception details
Console.Write(String.Format("A critical error occurred.{0}Details: {1}", vbCrLf, ex.Message.ToString()))
End Try
End Sub
End Module
There are a HEAP of atttibutes you can use instead of “sn” in the sample above. Personally I use ADSIEDIT.MSC to look at all the possible attributes but you’ll need domain administrative access to run that. Here are a couple of useful ones though …
- company
- department
- description
- displayName
- manager
- name
- givenName
- sAMAccountName
Hope that helps someone! :)
Follow Up – List active directory users – This time in C#
From VB.NET to C#
In this article I’m going to carry on with the follow-ups to posts I wrote in the past about various topics. Today’s topic is still on the subject of using .NET to list the users in Active Directory although this time we’re going to do it in C#. I wrote the first post and sample application using VB.NET back when I (perhaps) didn’t know as much as I know now … hopefully y’all won’t be too harsh on my n00b code from back then. :)
So, what’s different? Apart from the language change here is a summary of what’s changed between this version and the original.
- All references that aren’t needed have been removed.
- The results are now added to a generic list of strings (the original was just an ArrayList).
- The domain name can now be passed as a parameter on the command line. If one isn’t provided the user will be prompted.
- Regular expressions are now used to filter out user accounts that don’t match certain criteria (the original did some horribly repetitive case-sensitive matching).
- The output is now formatted better (the original was just a plain list).
- The account’s email address is now shown too.
- A total count of the accounts that can’t be ‘read’ is shown at the end.
- The app’s exception handling is a whole heap better (the original, being a sample, didn’t have any).
- The app won’t run if a domain name isn’t provided at all – an error message is displayed.
Note that this version doesn’t do any validation of the domain name e.g. length, illegal characters etc although you could use regular expressions to validate it.
On the next page is the entire source for the application – it’s a single .cs file.
Error 29506 installing SQL 2005 Studio Express on Vista
Vista ... argh!
If you need to install SQL Server 2005 Management Studio Express on Windows Vista you might receive an error like the screenshot below.
This is due to the new Vista feature called UAC. The fix is simple & there are 2 ways of implementing it.
- Under 'Accessories' from 'All Programs', right-click the Command Prompt shortcut and select 'Run as Administrator'. Accept the UAC warning when prompted.
- From the command prompt change to the directory that holds the SSMSEE installation .MSI file.
- Enter the command .\SQLServer2005_SSMSEE_x64.msi if you're running Vista x64 (64-bit) or .\SQLServer2005_SSMSEE.msi if you're running Vista x86 (32-bit)
- Press enter and complete the installation as normal.
The second method is to disable UAC completely but I wouldn't recommend it.
Using XPathNavigator to query XML files
XML = useful
Have you ever needed to query a specific key value in an XML file? Depending on the format of your XML file, here's how to do it using XPathNavigator.
This is something I planned to write about ages ago but never got around to it.
Configuration
The System.Xml.XPath Namespace has some pretty useful stuff in it. This article is going to cover how to use both VB.NET and C# to extract a particular key value from an XML file. Let's say you have a simple XML file called C:\MyApplication\Configuration.xml that stores configuration for your application. Itlook like the sample below.
<?xml version="1.0" encoding="utf-8" standalone="yes"?>server01 server02.domain.local 25
The code - C#
First up, let's look at the C# code to read the value of the "BackupServer" key from the file above.
XPathDocument document = new XPathDocument("C:\\MyApplication\\Configuration.xml");
XPathNavigator navigator = document.CreateNavigator();
XPathNavigator currentNode = navigator.SelectSingleNode("//My.Application.Config/Settings/BackupServer");
String backupServer = currentNode.InnerXml.ToString();
The code - VB.NET
Dim document As XPathDocument = New XPathDocument("C:\MyApplication\Configuration.xml")
Dim navigator As XPathNavigator = document.CreateNavigator()
Dim currentNode As XPathNavigator =
navigator.SelectSingleNode("//My.Application.Config/Settings/BackupServer")
Dim backupServer As String = currentNode.InnerXml.ToString()
That's it! Pretty simple really. :)
C# - Self updating application ...
... without ClickOnce!
This one might be interesting for people who have wondered about how to distribute the latest version of their application without having to tell people when an update is released.
There are built-in options that you can use with the Microsoft .NET platform such as ClickOnce. We use ClickOnce here at Trade Me to deploy some of our in-house applications and it works really well.
Recently, though, I thought "Why not see if I can write my own method of updating my application?" It turned out to be quite an interesting litte project! The application I was working on at the time is written in C# although the learning curve to go from VB.NET to C# or vice-versa isn't too steep.
Where do we start?
To begin with I decided the update process should have the following steps.
- Check my website for a text file containing version information.
- Read the version information text file and compare the version information in it to the version of the application currently running.
- If the version in the text file is the same or less than the version currently being run, do nothing other than show a message to the user.
- If the version in the text file is greater than the version currently being run ask the user if they want to update to the later version.
- Do the actual update.
Components
There are 2 components to this particular solution. The first part is the actual application being updated and the updater application. If you are going to follow along with any of the stuff in this article you'll need to start a new solution with 2 projects. My main project is called "CountDown" and the updater application is called "AppStart" (for reasons not related to the updating stuff here). For the purposes of this article I'm going to assume you have a single project that needs the update functionality.
The main application
The first thing your main application will need to do is make use of the System.Net namespace by adding the following line to the top of the main namespace file.
using System.Net;
When the user runs the application they can click a button that runs a method to do most of the steps above. The first thing the method does is try to resolve the IP address of my website (http://www.digitalformula.net resolves to 203.194.159.161).
try
{
string RemoteDomain = "http://www.digitalformula.net";
IPHostEntry inetServer = Dns.GetHostEntry(RemoteDomain.Replace("http://", String.Empty));
}
catch (Exception ex)
{
...
}
Exchange 2003 - Errors restoring using Recovery Storage Group
Exchange recovery fun
Nasty. That's a good word to use when describing the process of restoring a Microsoft Exchange database. Sure, there are options provided that in theory make the process pretty easy but there are occasions when these options don't do the job by themselves.
I had a situation recently where I was asked to restore a user's mailbox that had been deleted. Their Active Directory account had also been deleted which means that the default restore options don't work properly (they require that the user still exists when the restore is done). I'll try and sum up what I had to do and the steps I took to get the mail back. Note that all this was done without the production copy of the database being taken down, changed or harmed in any way.
The backup software used for this was Symantec's Backup Exec 11d - these steps aren't specific this software and should work with any software capable of backing up and restoring an Exchange database. If you're not familiar with using Recovery Storage Groups (RSG) with Backup Exec, here is a link to an article that describes how to do it. That article describes most of the base-level restore process but in my situation it didn't work afterwards which meant some pretty in-depth troubleshooting.
The restore process completed successfully so I tried to mount the database I had configured within the RSG - no joy. The mount request spat out an error saying "An internal processing error has occurred", accompanied by messages in the Application Eventlog saying:
Information Store (1588) Recovery Storage Group: Attempted to attach database '<path>Mailbox Store.edb' but it is a database restored from a backup set on which hard recovery was not started or did not complete successfully.
andError 0xfffffde0 starting database "Recovery Storage Group\Mailbox Store" on the Microsoft Exchange Information Store.
and
Error 0xfffffde0 starting Storage Group /DC=local/DC=xxx/CN=Configuration/CN=Services/CN=Microsoft Exchange/CN=xxx/CN=Administrative Groups/CN=First Administrative Group/CN=Servers/CN=xxx/CN=InformationStore/CN=Recovery Storage Group on the Microsoft Exchange Information Store. MDB failed to start.
Some Google trawling turned up Microsoft article entitled What to Do When an Exchange Store Won't Mount. A quick read through there satisfied me that none of the conditions listed were causing the problem so I turned to the tried and sometimes trusted command-line program :: ESEUTIL (which is found in the C:\Program Files\Exchsrvr\bin folder of a default Exchange Server 2003 installation).
ESEUTIL has a ton of options, the relevant ones in this case being /r for Recovery, /g for InteGrity and /p for RePair. Note that a lot of articles reference a file called Restore.env. It contains information about the log files that relate to the backup you've just restored and can be used with the eseutil.exe option /cc - in this situation the Restore.env file was empty which meant I couldn't use this option.
Important : Run eseutil.exe from the directory that contains the RESTORED database files, not the production ones!
So, I tried to run an integrity check :
eseutil.exe /g "Mailbox Store.edb"
However, I was told the database was in an incomplete state due to some of the log files not being replayed into the database yet and that I needed to run a database recover first (even though I was given the option to skip this if I wanted to, it wasn't recommended). Note that r00 is site-specific and may need to be changed for your configuration. Run eseutil.exe from a command prompt to see the options.
eseutil.exe /r r00
The recover process failed too though. At this point I figured the database was simply in a state where it couldn't be recovered and couldn't be integrity-checked so I decided to run a repair :
eseutil.exe /p "Mailbox Store.edb"
This started and completed fine. Great! For completeness' sake I decided to run an integrity check before trying to mount the database again:
eseutil.exe /g "Mailbox Store.edb"
This time it worked fine, even though towards the end of the process the eseutil.exe process ended up taking up quite a lot of memory and saying "Deleting unicode fixup table". I wouldn't recommend doing a Google search for that because all the results appear to be stories of doom and gloom with one guy even saying I've never been able to repair a database that returned that error. I guess he didn't do enough research or try hard enough because I eventually got it working just fine.
Ok so by this point the RSG copy of the database was mounted within Exchange System Manager and seemed to be working just fine (the database must be mounted before data can be extracted from it). If you're paranoid about mounting an Exchange database with the same name as your production one, good - you should be. Mounting the database within the RSG, even though it has the same name as your production database, IS a safe process however.
After this it's usually a simple matter of using something like the Microsoft utility ExMerge to dive into the restored database and extract the desired mail into a PST file.
In this case however, running ExMerge highlighted a couple of problems. The list of mailboxes was complete, apart from the one I wanted to restore. This was due to the AD account being deleted as well. Assuming your backup is a complete database backup and also assuming the restore process worked ok, you should have a complete copy of the database available, including the deleted mailbox (as long as it was backed up prior to being deleted of course).
Looking through the ExMerge.log file I was able to find the GUID of the mailbox I wanted to restore and that ExMerge couldn't find a corresponding AD account for :: \BCz\D7\87\CAm\A0G\AF\DB\F3X\3E\A7e\DE - doesn't look like a normal mailbox GUID does it? That's ok, you can convert it into a valid GUID.
First, navigate to http://www.asciitable.com/ - you'll need it in a minute. Now, open up a text editor and paste the GUID into it (I just used Notepad).
\BCz\D7\87\CAm\A0G\AF\DB\F3X\3E\A7e\DE
A valid hex value or couplet is always 2 characters long with each part being 0-9 or a-f ... NOTHING else. You need to break out the couplets from the GUID value like the one above, find the ones that aren't valid hex and then convert them to valid hex values using http://www.asciitable.com. The one I was working with turned out as follows :
BC 7A D7 87 CA 6D A0 47 AF DB F3 58 3E A7 65 DE
Note that the ones I had to convert were 'z', 'm', 'X' and 'e' - you must make sure you separate the couplets properly by looking where the slashes appear. EVERYTHING HERE IS CASE-SENSITIVE!
I then used AD Users & Computers to create a temporary mailbox that I could change so that I wasn't messing with any production mailboxes - if you change the GUID for a mailbox that is being used, a new mailbox with the new GUID will be created the next time the mailbox is accessed. Not good because then you'll have to go through this whole restore process again. My temporary AD account was called "Restore Mailbox".
The next part involves using ADSIEdit to change the msExchMailboxGuid property for the "Restore Mailbox" account so that it matches the one I converted above. You can start ADSIEdit by running adsiedit.msc (it comes with the Windows Support Tools which you should download and install if you haven't already).
Using ADSIEdit, navigate to Domain, open your domain (e.g. DC=YourDomain,DC=com), expand the users container (CN=Users) and select the "Restore Mailbox" account from the list (CN=Restore Mailbox). Open the properties of this object and scroll through the list until you find msExchMailboxGuid. Change the value to the completed and valid hex string you converted earlier by clicking the "lEdit" button and pasting the new value into the box provided. There is no need to restart any services for this change to take effect.
Next time you run ExMerge, "Restore Mailbox" (or whatever name you chose) should be an available mailbox that you can export to a PST file.
This is a fairly long process, especially considering the time eseutil.exe can take to run but it's something you will probably have to do during your time as an Exchange Administrator.
Hope it helps someone!
How to make a full-screen Windows app using VB.NET
Who wants scrollbars?
Recently I had to write a Windows application that required the main form to run in full-screen mode. This means no title bar and with the window appearance above everything else, i.e. Start Button, taskbar, system tray and all other apps.
This requires an API call to the SetWindowPos function which you need to create an alias to before you can call it. The first part of the code, which should be placed in the declarations part of the form, looks like this :
Private Declare Function SetWindowPos Lib "user32.dll" Alias "SetWindowPos" (ByVal hWnd As IntPtr, ByVal hWndIntertAfter As IntPtr, ByVal X As Integer, ByVal Y As Integer, ByVal cx As Integer, ByVal cy As Integer, ByVal uFlags As Integer) As Boolean
You also need an alias to the API function called GetSystemMetrics, like this :
Private Declare Function GetSystemMetrics Lib "user32.dll" Alias "GetSystemMetrics" (ByVal Which As Integer) As Integer
Following this you need to declare 4 constants :
Private Const SM_CXSCREEN As Integer = 0 Private Const SM_CYSCREEN As Integer = 1 Private Shared HWND_TOP As IntPtr = IntPtr.Zero Private Const SWP_SHOWWINDOW As Integer = 64
Then 2 public properties :
Public ReadOnly Property ScreenX() As Integer
Get
Return GetSystemMetrics(SM_CXSCREEN)
End Get
End Property
-- and --
Public ReadOnly Property ScreenY() As Integer
Get
Return GetSystemMetrics(SM_CYSCREEN)
End Get
End Property
After this you need to write a simple sub routine to use the constants you declared above and that calls the SetWindowPos API function. The function's code looks like this :
Private Sub FullScreen()
Me.WindowState = FormWindowState.Maximized
Me.FormBorderStyle = FormBorderStyle.None
Me.TopMost = True
SetWindowPos(Me.Handle, HWND_TOP, 0, 0, ScreenX, ScreenY, SWP_SHOWWINDOW)
End Sub
Beyond that it's just a case of calling the FullScreen sub routine whenever you want the application to show in full-screen mode. Easy huh? :)