1) mapping a source pattern to an output pattern
2) managing dependencies between rules
To be fair it's good at those, and often the sorts of things you can do with a rule are quite complex (being basically shell scripts).
However, the problem is that 1) it's an obscure DSL and 2) that it is really rubbish at doing more complicated things.
For example, grunt-contrib-clean lets you: delete any files that match a regex, not leave alone any files that match a different regex. Grunt also has a built in templating language that can be used to expand configuration files from submodule into local build scripts without copying the entire gruntfile. grunt-open launches a browser to a dev url cross platform. The list goes on and on and on.
Make is terribly terribly bad at complex tasks like this, that's the problem.
You can write a custom shell-script / ruby-script / python-script for these tasks, but why would you? Someone else already has. Dont repeat all the things every time with your own code.
If all you need to do is map .c to .o, or .scss to .css and .coffee to .js, use make, totally. It's good at that.
Otherwise, stay away.