Few things to confirm:
I just created a test record and used the code below which worked as expected to hide "[Not Provided]" from the greeting. Note, I prefer to use exclusionary logic vs. inclusionary logic for things like this (i.e. they have to qualify your rules to get the custom name, instead of the custom name being the default value).
##Confirm First Name is not provided or is blank
#if ($lead.FirstName != '[Not Provided]' && $lead.FirstName != "")
Anyway, I don't hate it! ...
... but I don't like leaning on the type-jugglingand operator. They'll appear to work, until they don't because of mismatched object types. In contrast, and always work the same in any context, because they are typed. It's better to rely on those methods from the start, instead of getting bitten badly by an error and then switching to them.
It's also less confusing ifvalues don't match the first condition; even if you don't expect any s on the Lead object (only Strings) they're always possible on Custom Objects.
##Use First Name if not null, not blank, and not special placeholder string
#if( $lead.FirstName && !$lead.FirstName.isEmpty() && !$lead.FirstName.equals("[Not Provided]") )