É como a maioria dos recursos de dbms, se você usá-lo na situação certa, ele faz seu trabalho bem, na situação errada, ele faz mal.
Prós: Algumas coisas simplesmente não podem ser feitas sem ele. Normalmente, descobri que isso é apenas para trabalho administrativo, e não para o código do aplicativo. Alguns comandos do sistema não permitem que parâmetros sejam usados como entrada. Por exemplo, se eu precisar executar algo através de um sproc em todos os bancos de dados, em muitas instâncias com bancos de dados desconhecidos, e o comando não aceitar parâmetros, geralmente resolvo isso através do SQL dinâmico. No entanto, isso é mais importante no Sybase ASE do que no MSSQL.
Contras: não vou me interessar muito, pois acho que todos já sabemos, mas pode haver algum risco de injeção de SQL se usada incorretamente. O maior para mim é que a consulta será tratada como ela é, uma consulta adhoc exclusiva e não parte do plano de consulta compilado. Para algo que é executado ocasionalmente, não é grande coisa. Para algo que é executado centenas de vezes por minuto e que possui muitos sql exclusivos, isso geraria muitos planos de consulta novos, potencialmente desnecessários, que consumiam ciclos e diminuíam o tempo válido do cache do plano.