Todas as outras respostas estão corretas: use call. Por exemplo:
call "msbuild.bat"
História
Nas versões antigas do DOS, não era possível executar recursivamente arquivos em lote. Em seguida, foi introduzido o comando de chamada que chamou outro shell do cmd para executar o arquivo em lotes e retornou a execução de volta ao shell do cmd quando terminar.
Obviamente, em versões posteriores, nenhum outro shell cmd era mais necessário.
Nos primeiros dias, muitos arquivos em lotes dependiam do fato de que a chamada de um arquivo em lotes não retornaria ao arquivo em lotes de chamada. Alterar esse comportamento sem sintaxe adicional teria quebrado muitos sistemas, como sistemas de menus em lotes (usando arquivos em lotes para estruturas de menus).
Como em muitos casos com a Microsoft, a compatibilidade com versões anteriores, portanto, é a razão desse comportamento.
Dicas
Se seus arquivos em lotes tiverem espaços em seus nomes, use aspas ao redor do nome:
call "unit tests.bat"
A propósito: se você não tiver todos os nomes dos arquivos em lote, também poderá usá-lo (isso não garante a ordem correta das chamadas de arquivos em lote; segue a ordem do sistema de arquivos):
FOR %x IN (*.bat) DO call "%x"
Você também pode reagir aos níveis de erro após uma chamada. Usar:
exit /B 1 # Or any other integer value in 0..255
para retornar um nível de erro. 0 indica execução correta. No arquivo em lotes de chamada, você pode reagir usando
if errorlevel neq 0 <batch command>
Use if errorlevel 1
se você tiver um Windows mais antigo que o NT4 / 2000 / XP para capturar todos os níveis de erro 1 e superior.
Para controlar o fluxo de um arquivo em lotes, existe o seguinte :-(
if errorlevel 2 goto label2
if errorlevel 1 goto label1
...
:label1
...
:label2
...
Como outros apontaram: dê uma olhada nos sistemas de compilação para substituir arquivos em lote.