Artigos
De Autounattend.xml a uma Pipeline de Provisionamento Windows com Segurança em Primeiro Plano
Como separei código público, mídia sensível de implantação, Domain Join delegado, Hybrid Microsoft Entra Join, limpeza e validação
Pronto para ler este conteúdo em voz alta.
Automatizar a instalação do Windows é simples de descrever e difícil de operar com segurança.
Um Autounattend.xml funcional pode selecionar a edição, criar contas, aplicar configurações, executar scripts e concluir o setup do sistema operacional com pouca interação. Porém, quando o arquivo inclui material de Wi-Fi, senhas administrativas ou credenciais de ingresso no domínio, ele deixa de ser apenas configuração. Ele passa a ser mídia sensível de implantação.
Essa distinção orientou o desenvolvimento do Windows Unattended Provisioning.
O projeto começou com um arquivo de resposta funcional usado em uma implantação real do Windows. O objetivo não era publicar esse arquivo operacional. O objetivo era transformar o comportamento validado em uma pipeline pública e reutilizável, mantendo os segredos específicos do ambiente fora do repositório.
O resultado é um fluxo PowerShell de build e execução no endpoint que gera um arquivo de resposta específico por implantação, executa Domain Join delegado no Active Directory, conclui o Hybrid Microsoft Entra Join após a reinicialização, registra estado, remove artefatos que contêm credenciais e valida o XML gerado com credenciais não produtivas no GitHub Actions.
Instalação autônoma não é o mesmo que provisionamento gerenciado
Um arquivo de resposta pode tornar a instalação silenciosa, mas um endpoint gerenciado exige mais do que um Windows Setup concluído.
Para que o dispositivo se torne operacional em um ambiente Microsoft híbrido, várias transições independentes precisam ocorrer:
- O Windows Setup precisa terminar.
- O endpoint precisa obter conectividade de rede.
- A descoberta DNS do Active Directory precisa funcionar.
- A conta do computador precisa ser criada ou reutilizada na OU correta.
- O dispositivo precisa reiniciar como membro do domínio.
- O Hybrid Microsoft Entra Join precisa ser concluído.
- O auto-enrollment no Intune e o processamento de políticas precisam ocorrer quando configurados.
- O Windows LAPS precisa rotacionar a senha temporária do administrador local.
- Os artefatos de setup e o material de autologon precisam ser removidos.
Essas transições não são concluídas ao mesmo tempo, e o sucesso em uma camada não comprova o sucesso da próxima.
Por exemplo, uma operação Add-Computer bem-sucedida comprova que o ingresso no domínio foi aceito. Ela não comprova que AzureAdJoined já está como YES, que o dispositivo apareceu no Intune ou que o Windows LAPS já rotacionou a senha local.
A arquitetura de provisionamento, portanto, precisava de fases explícitas, comportamento de repetição, estado e critérios de aceite em vez de um único resultado de “instalação concluída”.
A primeira decisão de segurança: não publicar o arquivo operacional
O repositório público não contém um Autounattend.xml pronto para implantação.
Em vez disso, ele contém:
- um template sanitizado e compactado;
- uma configuração de exemplo sem segredos;
- um script local de build;
- scripts de endpoint para primeiro logon, Hybrid Join e limpeza;
- validação estrutural;
- documentação em inglês e português;
- política de segurança e orientações de teste.
O build local solicita os valores que não podem existir com segurança no controle de versão:
- usuário e senha da conta delegada de Domain Join;
- senha do Wi-Fi de provisionamento;
- opcionalmente, a senha temporária do Administrator.
Quando a senha temporária não é fornecida, o build gera uma nova com RandomNumberGenerator, garante caracteres de diferentes classes, embaralha o resultado e a apresenta uma única vez para recuperação controlada durante o piloto.
O output/Autounattend.xml resultante contém segredos reais porque o Windows Setup e o fluxo atual com Add-Computer precisam deles. Ele é ignorado pelo Git, mas apenas ignorar o arquivo não é suficiente. O XML e o pendrive precisam ser tratados como credenciais de curta duração.
Essa é uma fronteira importante: o repositório foi projetado para ser público; o artefato gerado não.
Tratando o build como um compilador
O script de build se comporta mais como um pequeno compilador do que como uma operação de cópia de arquivo.
Ele executa quatro classes de trabalho.
Validação de configuração
O script exige valores explícitos para versão do projeto, domínio, OU de destino, perfil Wi-Fi, timeout, comportamento do Hybrid Join, opções de limpeza e comportamentos legados selecionados.
Senhas não pertencem ao arquivo PSD1. Elas são coletadas separadamente como entradas seguras.
Escape conforme o contexto
Os valores são inseridos em diferentes contextos sintáticos:
- texto XML;
- XML embutido em outro valor XML;
- strings PowerShell delimitadas por aspas simples;
- scripts embutidos em CDATA.
Um valor seguro em um contexto pode quebrar outro. Por isso, o build aplica funções de escape separadas e rejeita a sequência ]]> dentro dos scripts, pois ela encerraria o CDATA de forma inesperada.
Resolução de placeholders e parsing do XML
Após as substituições, o build rejeita placeholders não resolvidos e faz o parsing do conteúdo final como XML. Um arquivo de resposta inválido é interrompido antes de chegar à mídia de instalação.
Identidade do artefato
O arquivo gerado recebe um hash SHA-256. O hash não torna o arquivo com segredos seguro, mas fornece uma identidade precisa para o artefato testado e copiado para a mídia.
Essa fronteira de build mantém o template público revisável e torna cada artefato de implantação explícito e rastreável.
O Domain Join começa com validação de rede e DNS
O fluxo executado no endpoint não chama Add-Computer imediatamente.
No primeiro logon, ele:
- inicia o serviço de Wi-Fi do Windows;
- solicita conexão ao perfil de provisionamento configurado;
- consulta registros DNS SRV
_ldap._tcp.dc._msdcs.<domínio>; - seleciona um candidato a controlador de domínio;
- valida disponibilidade LDAP na porta TCP 389;
- repete até o limite configurado.
Somente após encontrar um controlador de domínio acessível o script reconstrói a credencial delegada e chama Add-Computer com o domínio, a OU de destino e o servidor selecionado.
Isso não elimina todas as falhas ambientais, mas substitui uma tentativa cega de ingresso por verificações observáveis de pré-requisitos.
A identidade usada no Domain Join também é restringida por política, não apenas por código. O modelo de segurança exige uma conta dedicada, com permissão somente para criar ou reutilizar objetos de computador na OU de destino. Ela não deve ser Domain Admin, conta interativa, conta de RDP ou identidade de serviço genérica.
O comportamento de falha importa mais do que o caminho feliz
Um script de provisionamento que funciona apenas quando tudo está disponível não está operacionalmente completo.
Quando o Domain Join falha, o fluxo:
- registra a exceção no log de ingresso;
- grava
domainJoin: Failedno documento de estado; - registra que o Hybrid Join não foi iniciado;
- remove os valores de autologon;
- agenda a limpeza;
- evita a reinicialização automática;
- encerra com código de falha.
Evitar o restart é deliberado. Uma reinicialização silenciosa após falha no ingresso dificultaria a investigação e poderia deixar o endpoint em estado ambíguo.
A documentação de testes também exige cenários negativos para:
- controlador de domínio indisponível;
- credencial delegada inválida;
- segredo de Wi-Fi incorreto;
- endpoint já ingressado em domínio;
- Hybrid Join desabilitado;
- limpeza interrompida.
O validador automatizado atual é estrutural, portanto esses casos ambientais ainda exigem um piloto representativo. Essa limitação é documentada, não escondida.
O Hybrid Microsoft Entra Join é uma fase adiada
Domain Join e Hybrid Join são separados intencionalmente.
Após o ingresso bem-sucedido no domínio, o script de primeiro logon registra uma tarefa agendada executada como SYSTEM. Ela pode iniciar no boot e repetir após um pequeno intervalo. Sua responsabilidade é processar políticas e acionar o fluxo nativo Automatic-Device-Join até que o estado de identidade esperado seja alcançado.
Essa separação resolve dois problemas de timing:
- o dispositivo precisa reiniciar como membro do domínio antes que o caminho de identidade híbrida seja confiável;
- Política de Grupo, sincronização, registro e visibilidade na nuvem podem não ser imediatos.
O projeto registra o Hybrid Join de forma independente usando estados como Pending, WaitingForDomain, Succeeded ou Disabled.
Ele também mantém o Microsoft Intune e o Windows LAPS fora da sua fronteira de confiança. O script consegue observar e documentar suas próprias ações, mas um Hybrid Join bem-sucedido não comprova que a política do Intune ou a rotação de senha foram concluídas.
Esses controles precisam ser validados nos portais administrativos apropriados da Microsoft.
Limpeza é uma etapa do provisionamento, não manutenção secundária
As partes mais sensíveis do fluxo existem apenas temporariamente:
- arquivos de resposta copiados para locais do Windows Setup;
- XML do Wi-Fi de provisionamento;
- script de primeiro logon contendo a credencial delegada;
- valores de autologon no Registro;
- arquivo gerado na mídia removível.
A limpeza, portanto, faz parte da arquitetura.
O script de primeiro logon copia a lógica de limpeza para um local controlado e a agenda após a reinicialização, permitindo que o próprio script em execução também seja removido. Conforme a configuração, a limpeza pode remover o perfil de Wi-Fi de provisionamento.
Isso reduz a persistência no endpoint, mas não protege retroativamente uma mídia perdida ou copiada. Quando a custódia do pendrive é incerta, a credencial delegada precisa ser rotacionada.
Essa regra operacional é tão importante quanto o código de limpeza.
Estado legível por máquina torna o processo suportável
O projeto grava um arquivo JSON não sensível em:
C:\ProgramData\WindowsDomainProvisioning\state.json
O estado contém:
- versão do projeto;
- domínio de destino;
- status do Domain Join;
- status do Hybrid Join;
- status da limpeza;
- expectativa de gerenciamento pelo LAPS;
- timestamp de atualização;
- último erro, quando presente.
Os logs são separados por fase sob o mesmo diretório base.
Isso fornece uma interface prática de suporte. O administrador consegue inspecionar o endpoint sem reconstruir todo o histórico apenas pelos logs do Windows Setup.
Também evita um erro comum de observabilidade: tratar a ausência de uma mensagem de erro como prova de que todas as etapas posteriores de enrollment foram concluídas.
O CI valida o artefato sem usar segredos de produção
O workflow do GitHub Actions roda em Windows e cria uma configuração local a partir do exemplo público.
Depois, ele fornece credenciais fictícias ao script de build, gera o arquivo de resposta, executa a validação estrutural e confirma que nem o XML gerado nem a configuração local estão rastreados pelo Git.
O validador verifica:
- parsing do XML;
- placeholders não resolvidos;
- presença dos scripts embutidos obrigatórios;
- marcadores esperados de Domain Join e limpeza;
- avisos conhecidos herdados do template validado.
Isso não é um teste end-to-end de domínio ou Entra. É um teste determinístico de integridade do build, que comprova que o código público continua capaz de gerar o artefato esperado sem depender de credenciais produtivas.
O que a versão 1.0.0 deliberadamente não resolve
A primeira versão preserva comportamentos opinativos da base validada, incluindo remoção de aplicativos, bypass de requisitos de hardware, habilitação de Remote Desktop, uma conta local padrão temporária e alterações de ACL na unidade do sistema.
Essas opções podem ser inadequadas em outro ambiente. Elas exigem revisão conforme a baseline de segurança, a versão do Windows, a política de hardware e os requisitos de software da organização.
A maior questão arquitetural remanescente é a credencial reutilizável de Domain Join temporariamente embutida no arquivo gerado.
As mitigações atuais são:
- delegação de privilégio mínimo na OU;
- estação de build controlada;
- mídia fisicamente controlada;
- lotes curtos de implantação;
- rotação de credencial;
- limpeza do endpoint;
- Windows LAPS após o enrollment.
A direção futura preferida é Offline Domain Join, que pode reduzir a dependência de uma credencial reutilizável dentro do arquivo de resposta.
Lições ao transformar um arquivo de setup em projeto
A principal lição foi que um projeto de provisionamento não é definido pela quantidade de etapas de setup que automatiza.
Ele é definido pela clareza com que trata as fronteiras:
- código público versus saída sensível;
- estação de build versus endpoint;
- Domain Join versus registro na nuvem;
- automação versus sistemas externos de política;
- sucesso versus sucesso parcial;
- limpeza versus revogação de credenciais;
- validação estrutural versus aceite em ambiente real.
Quando essas fronteiras ficaram explícitas, o arquivo de resposta original pôde se tornar um projeto público sustentável, em vez de permanecer como um artefato operacional isolado.
O Windows Unattended Provisioning v1.0.0 não é um sistema universal de implantação zero-touch. Ele é uma base documentada, testável e validada em piloto para provisionamento controlado de Windows — e uma fundação clara para a próxima melhoria de segurança.