# This script is hosted at https://bypassnro.sougen.dev
# Fork of https://w1.zawa-lab.net/w - adds an optional Computer name prompt.
# Upstream article: https://w1.zawa-lab.net/p/20260728_oobe_bypass/
# License: CC BY-NC-SA 4.0 by zawa-lab (https://w1.zawa-lab.net/)
# Usage: powershell -c "irm bypassnro.sougen.dev|iex"
<#
  oobe-localaccount.ps1  (ASCII only)

  Fork of https://w1.zawa-lab.net/w  (CC BY-NC-SA 4.0 by zawa-lab)
  adds an optional Computer name prompt (blank -> Windows default).

  At OOBE, press Shift+F10, then run:
      powershell -c "irm bypassnro.sougen.dev|iex"

  Prompts for a local account name, password, and computer name,
  generates unattend.xml, and re-runs OOBE through sysprep.

  Set DRYRUN=1 beforehand to stop just before sysprep:
      set DRYRUN=1
#>

$ErrorActionPreference = 'Stop'

$sysprep = "$env:SystemRoot\System32\Sysprep\sysprep.exe"
if (-not (Test-Path $sysprep)) {
    throw 'sysprep.exe not found. Run this inside OOBE.'
}

# ---- settings (edit to taste) ----
$TimeZone     = 'Tokyo Standard Time'
$InputLocale  = '0411:00000411'
$SystemLocale = 'ja-JP'
$UILanguage   = 'ja-JP'
$UserLocale   = 'ja-JP'
# ----------------------------------

Write-Host ''
Write-Host '=== Create local account ===' -ForegroundColor Cyan
Write-Host ''

# --- account name ---
while ($true) {
    $name = Read-Host 'User name'
    if ($name -notmatch '^[A-Za-z0-9][A-Za-z0-9_.-]{0,19}$') {
        Write-Host '  Letters, digits, _ . - only. Max 20 chars.' -ForegroundColor Yellow
        continue
    }
    if ($name -eq $env:COMPUTERNAME) {
        Write-Host '  Must not match the current computer name.' -ForegroundColor Yellow
        continue
    }
    break
}

# --- password ---
function ConvertFrom-Secure([Security.SecureString]$s) {
    $b = [Runtime.InteropServices.Marshal]::SecureStringToBSTR($s)
    try   { [Runtime.InteropServices.Marshal]::PtrToStringUni($b) }
    finally { [Runtime.InteropServices.Marshal]::ZeroFreeBSTR($b) }
}

while ($true) {
    $p1 = ConvertFrom-Secure (Read-Host 'Password (blank allowed)' -AsSecureString)
    $p2 = ConvertFrom-Secure (Read-Host 'Password (confirm)'       -AsSecureString)
    if ($p1 -ne $p2) {
        Write-Host '  Mismatch. Try again.' -ForegroundColor Yellow
        continue
    }
    break
}

# --- computer name (optional) ---
while ($true) {
    $cn = (Read-Host 'Computer name (blank = Windows default)').Trim()
    if ($cn -eq '') { break }
    if ($cn.Length -gt 15) {
        Write-Host '  Max 15 chars.' -ForegroundColor Yellow
        continue
    }
    if ($cn -notmatch '^[A-Za-z0-9-]+$') {
        Write-Host '  Letters, digits, hyphen only. No spaces.' -ForegroundColor Yellow
        continue
    }
    if ($cn -match '^[0-9]+$') {
        Write-Host '  Must not be all digits.' -ForegroundColor Yellow
        continue
    }
    if ($cn -match '^-|-$') {
        Write-Host '  Must not start or end with a hyphen.' -ForegroundColor Yellow
        continue
    }
    if ($cn -ieq $name) {
        Write-Host '  Must not match the user name.' -ForegroundColor Yellow
        continue
    }
    break
}

# unattend expects Base64 of UTF-16LE (plaintext + 'Password')
$pwNode = if ([string]::IsNullOrEmpty($p1)) {
    ''
} else {
    $b64 = [Convert]::ToBase64String([Text.Encoding]::Unicode.GetBytes($p1 + 'Password'))
    @"

            
              $b64
              false</PlainText>
            </Password>
"@
}

$specializeNode = if ([string]::IsNullOrEmpty($cn)) {
    ''
} else {
    @"

  <settings pass="specialize">
    <component name="Microsoft-Windows-Shell-Setup"
               processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
               language="neutral" versionScope="nonSxS">
      <ComputerName>$cn</ComputerName>
    </component>
  </settings>
"@
}

$xml = @"
<?xml version="1.0" encoding="utf-8"?>
<unattend xmlns="urn:schemas-microsoft-com:unattend">$specializeNode
  <settings pass="oobeSystem">
    <component name="Microsoft-Windows-International-Core"
               processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
               language="neutral" versionScope="nonSxS">
      <InputLocale>$InputLocale</InputLocale>
      <SystemLocale>$SystemLocale</SystemLocale>
      <UILanguage>$UILanguage</UILanguage>
      <UserLocale>$UserLocale</UserLocale>
    </component>

    <component name="Microsoft-Windows-Shell-Setup"
               processorArchitecture="amd64" publicKeyToken="31bf3856ad364e35"
               language="neutral" versionScope="nonSxS"
               xmlns:wcm="http://schemas.microsoft.com/WMIConfig/2002/State">
      <TimeZone>$TimeZone</TimeZone>

      <UserAccounts>
        <LocalAccounts>
          <LocalAccount wcm:action="add">
            <Name>$name</Name>
            <DisplayName>$name</DisplayName>
            <Group>Administrators</Group>$pwNode
          </LocalAccount>
        </LocalAccounts>
      </UserAccounts>

      <OOBE>
        <HideEULAPage>true</HideEULAPage>
        <HideOEMRegistrationScreen>true</HideOEMRegistrationScreen>
        <HideOnlineAccountScreens>true</HideOnlineAccountScreens>
        <HideWirelessSetupInOOBE>true</HideWirelessSetupInOOBE>
        <ProtectYourPC>3</ProtectYourPC>
      </OOBE>

      <FirstLogonCommands>
        <SynchronousCommand wcm:action="add">
          <Order>1</Order>
          <Description>Remove answer files</Description>
          <CommandLine>cmd /c del /f /q "%SystemRoot%\Panther\unattend.xml" "%SystemRoot%\System32\Sysprep\unattend.xml"</CommandLine>
        </SynchronousCommand>
      </FirstLogonCommands>
    </component>
  </settings>
</unattend>
"@

$panther = "$env:SystemRoot\Panther"
$target  = "$panther\unattend.xml"

New-Item -ItemType Directory -Force -Path $panther | Out-Null
[IO.File]::WriteAllText($target, $xml, (New-Object Text.UTF8Encoding $false))
Copy-Item $target "$env:SystemRoot\System32\Sysprep\unattend.xml" -Force

# sanity check
[xml]$check = Get-Content $target
if (-not $check.unattend) { throw 'Generated XML is invalid.' }

Write-Host ''
Write-Host "Account '$name' defined. Answer file written to:" -ForegroundColor Green
Write-Host "  $target"
if (-not [string]::IsNullOrEmpty($cn)) {
    Write-Host "Computer name will be set to '$cn'." -ForegroundColor Green
}
Write-Host ''

if ($env:DRYRUN -eq '1') {
    Write-Host 'DRYRUN=1 -- sysprep skipped. Nothing was rebooted.' -ForegroundColor Yellow
    exit 0
}

Write-Host 'Running sysprep. The machine will reboot shortly.' -ForegroundColor Green
Start-Sleep -Seconds 3

& $sysprep /oobe /reboot /unattend:$target