O problema é que as aspas são interpretadas e removidas pelo shell local, não pelo remoto; você precisa de um nível extra:
ssh host sudo sh -c '"ls -hal /root/ > /root/test.out"'
O shell local consumirá um nível de cotação - as aspas simples serão "usadas" aqui, o ssh obterá os argumentos host , sudo , sh , -c e "ls -hal /root/ > /root/test.out" .
O shell remoto consome a próxima camada - as aspas duplas - e chama sudo com sh , -c e ls -hal /root/ > /root/test.out .
Por fim, a instância sh (em execução como raiz) é chamada com -c e ls -hal /root/ > /root/test.out - e analisa esse único argumento como uma linha de comando normal, avaliando o redirecionamento.
Para assistir a tudo isso, no sistema de destino, tente executar sudo strace -f -e execve -p $(cat /var/run/sshd.pid) .