Script para Criação de Pendrive bootavel do Windows


  JG-Tux

Eu sei que existem diversas ferramentas, como Ventoy, WoeUSB, Unetbootin, GParted e outras, que facilitam a criação de um pendrive inicializável de forma eficiente. No entanto, estou aprendendo Bash e decidi criar meu próprio script com essa finalidade.

Antes do lançamento do Windows 11, eu costumava usar a biblioteca wimlib para comprimir ao máximo o arquivo install.wim, garantindo que ele tivesse menos de 4 GB. Isso permitia que ele fosse armazenado em um pendrive formatado em FAT32. No entanto, com o Windows 11, o tamanho do arquivo install.wim aumentou consideravelmente, e mesmo após a compressão, ele pode ultrapassar os 4 GB. Isso inviabiliza a utilização de sistemas de arquivos FAT32.

Recentemente, encontrei uma solução utilizando o ntfs-3g para formatar o pendrive como NTFS. Essa abordagem me permite simplesmente extrair a ISO do Windows para o pendrive, tornando todo o processo mais rápido e eficiente. No entanto, vale ressaltar que, se o script for interrompido durante a instalação, será necessário reiniciar a máquina para que o sistema reconheça o pendrive novamente.

Este script suporta distros derivadas do Debian, Arch Linux e Fedora. No entanto, o último teste foi realizado somente no Arch Linux. Aceito sugestões/pr de como melhorar o script.

Como Usar

Siga estas etapas:

  1. Baixe a ISO do Windows diretamente do site oficial da Microsoft.

  2. Abra o terminal e navegue até o diretório onde você baixou a ISO.

  3. Execute o seguinte comando no terminal:

    curl -o windusb.sh https://raw.githubusercontent.com/Broly1/Windusb/master/windusb.sh && chmod +x windusb.sh && ./windusb.sh
    

Isso baixará automaticamente o script Windusb, tornará o script executável e o executará. O script guiará você pelo processo de criação do pendrive inicializável.

GitHub

6 curtidas

Bacana! Scripts são bem úteis embora seja uma linguagem bem difícil por ter vários jeitos de fazer as mesmas coisas, não ter tipos fortes, e também regras estranhas de conversão de tipos.

A parte mais difícil da programação na maioria das vezes nem é fazer o que precisa ser feito, mas sim verificar que você tem todos os ingredientes antes de começar. Um script pra fritar um ovo seria bastante simples se for “Quebre o ovo na frigideira com um pouco de óleo e fogo baixo, aguarde 2 minutos, desligue o fogo, coma o ovo”. Nesse ponto o script funciona perfeitamente para você pois vc já conhece o seu fogão, sua geladeira e sua despensa. Porém o script para fritar um ovo em qualquer lugar não pode ser assim, pois alguém na Finlândia que pega a frigideira, coloca óleo, começa a esquentar, pega o ovo, IHHH não tem ovo, terminou o script mas a panela ficou no fogo ligado! A receita para fritar um ovo pode virar uma receita para estragar uma panela…

Pessoalmente eu uso bastante scripts feitos por mim, e quando procuro ou vejo o script de alguém, pego as partes interessantes para fazer meu próprio. Scripts para divulgação geral são inseguros para um usuário comum (não programador) executar, especialmente quando precisa ser executado em modo de administrador. Uma vez que seja dada a senha, pode acontecer qualquer coisa, inclusive o que a pessoa espera que aconteça! Eu jamais recomendo que pessoas saiam executando código de terceiros (que não são de programas oficiais da distribuição).

Isso posto, e imaginando que esse script seria incluído em um programa oficial nas distribuições, algumas considerações minhas seriam:

Verificar todas as dependências antes de iniciar o programa.

Severidade alta. Pensei em um array de comandos usados e comandos de verificação. Incluiria todos eles para verificação em loop. Ao não achar um programa (ou melhor ainda se uma versão antiga incompatível for encontrada), o script se encerra com uma mensagem. No caso de você querer adicionar suporte a várias distribuições, daí sim usar o comando para instalar o pacote que provê o referido programa, e reinicia a verificação. Você pensou nisso e verificou o ntfs-3g e p7zip, mas o script também usa sudo, sgdisk, wipefs. Isso evita do seu programa acabar no meio com “XXXX not found”.

Comentários são legais, mas não abuse

Severidade baixa. A princípio o nome das funções e variáveis devem ser auto explicativos, de modo que os comentários devem conter informações adicionais relevantes, mas evitar a explicação do código em si, que deve ser legível. Evite especialmente comentar linha a linha, a menos que seja um exercício de aprendizado. Comentar cada linha também é comportamento padrão dos geradores automáticos de código por inteligência artificial, então dá um jeitão de código pré-fabricado ao seu programa.

Seleção da iso

Severidade: baixa. O programa está bem legal nas seleções, mas pegar simplesmente a primeira iso não ficou bom. O ideal seria uma nova seleção com todos os arquivos iso que foram achados no diretório para o usuário escolher qual será escrita.

Funções são específicas

Severidade alta. Uma das piores práticas (e das mais fáceis de fazer) é começar a inchar funções simples com outras tarefas. Veja que a função format_drive está também selecionando a ISO e verificando dependências. Não faz sentido estar ali, mesmo que comentado. Crie funções específicas na parte principal do script. Eu acho que nem precisaria essa função, uma vez a função partformat faz essas tarefas mas com outro nome.

Nomes de variáveis e funções

Severidade: terrível (isso pode acabar com um projeto). Geralmente um programa segue regras sobre os nomes, as duas principais são a capitalização ou o símbolo sublinhado. Se o programa é seu, vc que escolhe, mas mantenha a coerência. Veja que a função format_drive está com sublinhado, mas partformat está da pior forma possível: abreviada e sem diferenciação. Esse é o verdadeiro terror até para você mesmo no futuro. Em um outro programa sem coerência isso poderia ser abreviação de ‘packed real-time formatter’.

Parâmetros

Severidade média. Embora o seu script não necessite nenhum parâmetro para funcionamento, a função principal está usando, e passando isso para as sub funções que também não necessitam. Embora deixar não cause problema no script, ele causa confusão para quem tenta entendê-lo pois imagina que será usado em algum momento.

2 curtidas

Opa valeu pelas dicas, estou procurando uma forma melhor de checagem de software usando o package manager,
no caso do sgdisk ele já vem preinstalado nas distros que testei mas tb quero adicioná-lo a essa checagem,
E no caso de seleção da ISO vou criar uma função que se tiver somente uma ISO o script continua sem prompt se tiver duas ou mais ele coloca em um menu de escolha como a do pendrive, e também tem o problema de arquivos com nomes parecidos e auto complete, outra maneira q pensei foi fazer o drop da ISO no terminal para pegar o Path, porém pelo que pesquisei os terminais funcionam diferente em desktops diferentes e isso pode não funcionar em algumas distros então abandonei essa ideia.
No caso dos nomes de variáveis esse é o mais fácil de resolver assim como os comentários :grinning:.
já no caso do parâmetro não entendi bem o q quiz dizer, paço augumas funções pelo loop para mostrar o prompt para o usuário escolher o pendrive e se aceita continuar o script e tal, se quiser elaborar um pouco mais manda bala.

Fixed! :+1:

Mané usar WoeUSB. Parabéns pelo projeto, fera

2 curtidas

Na linha 129 troque “$iso_file” por “${iso_file[@]}”

1 curtida

Pronto resolvido esse bo

get_the_iso() {
	iso_files=(Win*.iso)

	if [ ${#iso_files[@]} -eq 0 ]; then
		clear
		printf "No Windows ISO files found in the current directory.\n"
		exit 1
	fi

	if [ ${#iso_files[@]} -eq 1 ]; then
		iso_path="${iso_files[0]}"
		printf "Windows ISO found: %s\n" "$iso_path"
	else
		clear
		printf "Multiple Windows ISO files found:\n"

		select iso_path in "${iso_files[@]}"; do
			if [ -n "$iso_path" ]; then
				printf "Selected Windows ISO: %s\n" "$iso_path"
				break
			else
				printf "Invalid selection. Please choose a valid option.\n"
			fi
		done
	fi
}

Virou um espaguete mas tb resolveu.

# Search the system  if the packages we need is already installed
install_apt_package() {
    local package_name="$1"
    if ! dpkg -l "$package_name" > /dev/null 2>&1; then
        apt update
        apt install -y "$package_name"
    else
        printf "Package %s '$package_name' is already installed (APT).\n"
    fi
}

install_dnf_package() {
    local package_name="$1"
    if ! rpm -q "$package_name" > /dev/null 2>&1; then
        dnf install -y "$package_name"
    else
        printf "Package %s '$package_name' is already installed (DNF).\n"
    fi
}

install_pacman_package() {
    local package_name="$1"
    if ! pacman -Q "$package_name" > /dev/null 2>&1; then
        pacman -Sy --noconfirm --needed "$package_name"
    else
        printf "Package %s '$package_name' is already installed (Pacman).\n"
    fi
}

# Install the missing packages if we dont have them
install_missing_packages() {
	clear
	cat <<"EOF"
#############################
#  Installing Dependencies  #
#############################
EOF
debian_packages=("ntfs-3g" "p7zip-full" "gdisk")
fedora_packages=("ntfs-3g" "p7zip-plugins" "gdisk")
arch_packages=("ntfs-3g" "p7zip" "gptfdisk")

# Check for the distribution type and call the appropriate function
if [[ -f /etc/debian_version ]]; then
    for package in "${debian_packages[@]}"; do
        install_apt_package "$package"
    done
elif [[ -f /etc/fedora-release ]]; then
    for package in "${fedora_packages[@]}"; do
        install_dnf_package "$package"
    done
elif [[ -f /etc/arch-release ]]; then
    for package in "${arch_packages[@]}"; do
        install_pacman_package "$package"
    done
else
    printf "Your distro is not supported!\n"
    exit 1
fi
}

GitHub