A good build script should be self-contained, self-booting and portable. You should be able to check it out of source control and run it. No buts. Period. The rules (or tips) that follow should be self-evident and applied everywhere. Unfortunately, they are not. The following "rules" are based on issues I've encountered in existing real-world build scripts.
Rule 1 - No hard-coded paths. Hard-coded paths are the bane of the portable build script. Just say no.
Rule 2 - avoid OS-specific scripts. Avoid scripts in general for lifecycle-related tasks. If you must use scripts, make them portable (see Rule 1), for example by writing them in Groovy. But be careful: arbitrary scripts in build processes are things that have a high risk of becoming maintenance liabilities later on down the track.Rule 3 - don't rely on custom tool installations. If you must install your own versions of tools for the build job, do it in a portable manner. Personnally, I'd rather make this declarative - the Maven Enforcer Plugin, for example, lets you do this. Or a Ant script that tests the version of Ant being run. I don't mind ensuring that Maven, Ant or Groovy are installed on a new build server - I'll even install multiple versions if you really need this. But don't use your own home-rolled tool installation scripts that don't work anywere other than the original machine they were written on!
Rule 4 - Don't home-role your dependency management solution. I've seen many places that use shared directories, or even just an arbitrary local directory, to store libraries. There are good existing solutions for this, such as Maven, Maven Ant Tasks and Ivy. Don't force newcomers to learn your home-rolled version from scatch when they join the maintenance team!
Rule 5- keep it simple and easy to understand. That's what I dislike about Ant build scripts - they can so easily degenerate into uncontrollable monsters. But I've also seen build scripts that put layer upon layer of shell scripts before they get round to calling an Ant script! Build scripts are like code - if you want to be able to maintain it later on, you need to keep it tidy, find the simplest possible solution that works, and refactor from time to time.
Also, make it clear how it works and what it does. With Maven, the standard lifecycle makes it pretty clear how to compile, how to test, and how to package a project. This is generally not the case with other build scripts, where you need to study the script itself to understand how to compile the code. This should not be so. Ant, for example, supports target documentation - it's just that not a lot of people use it.
These are just a few rules that can help make your builds more portable and generally easier to maintain. There are of course plenty of others, and applying these rules does not mean you don't have to use your brain as well ;-).