├── .gitignore ├── README.md ├── Vagrantfile ├── copy-winpe.cmd ├── make-winpe-iso.cmd ├── provision-adk.ps1 ├── provision-base.ps1 ├── provision-winpe-virtio.ps1 ├── provision-winpe.ps1 ├── ps.ps1 ├── startup.ps1 ├── winpe.jpg ├── winpe.xcf └── winpeshl.ini /.gitignore: -------------------------------------------------------------------------------- 1 | .vagrant/ 2 | tmp/ 3 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | An example [Windows PE (WinPE)](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-intro) iso built in a vagrant environment. 2 | 3 | # Usage 4 | 5 | Install the [Windows 2022 Base Box](https://github.com/rgl/windows-vagrant). 6 | 7 | Build the ISO with: 8 | 9 | ```bash 10 | vagrant up --no-destroy-on-error --no-tty build 11 | ``` 12 | 13 | When it finishes, you should have the ISO in the `tmp/winpe-amd64.iso` file. 14 | 15 | The ISO file can be written to an usb disk or [pxe booted](https://github.com/rgl/pxe-vagrant). 16 | 17 | You can also try it with: 18 | 19 | ```bash 20 | vagrant up --no-destroy-on-error --no-tty bios 21 | vagrant up --no-destroy-on-error --no-tty uefi 22 | ``` 23 | 24 | # Reference 25 | 26 | * [Windows PE (WinPE)](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-intro) 27 | * [WinPE: Mount and Customize](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-mount-and-customize) 28 | * [WinPE: Create Apps](https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpe-create-apps) 29 | -------------------------------------------------------------------------------- /Vagrantfile: -------------------------------------------------------------------------------- 1 | ENV['VAGRANT_NO_PARALLEL'] = 'yes' 2 | 3 | Vagrant.configure('2') do |config| 4 | config.vm.box = 'windows-2022-amd64' 5 | 6 | config.vm.provider :libvirt do |lv, config| 7 | lv.memory = 4*1024 8 | lv.cpus = 4 9 | lv.cpu_mode = 'host-passthrough' 10 | #lv.nested = true 11 | lv.keymap = 'pt' 12 | config.vm.synced_folder '.', '/vagrant', type: 'smb', smb_username: ENV['USER'], smb_password: ENV['VAGRANT_SMB_PASSWORD'] 13 | end 14 | 15 | config.vm.define :build do |config| 16 | config.vm.provision :shell, inline: "$env:chocolateyVersion='2.3.0'; Invoke-Expression ((New-Object System.Net.WebClient).DownloadString('https://community.chocolatey.org/install.ps1'))", name: "Install Chocolatey" 17 | config.vm.provision :shell, path: 'ps.ps1', args: 'provision-base.ps1' 18 | config.vm.provision :shell, path: 'ps.ps1', args: 'provision-adk.ps1' 19 | config.vm.provision :shell, path: 'ps.ps1', args: 'provision-winpe.ps1' 20 | end 21 | 22 | [ 23 | 'bios', 24 | 'uefi', 25 | ].each do |firmware| 26 | config.vm.define firmware do |config| 27 | config.vm.box = nil 28 | config.vm.provider :libvirt do |lv, config| 29 | lv.loader = '/usr/share/ovmf/OVMF.fd' if firmware == 'uefi' 30 | lv.boot 'hd' 31 | lv.boot 'cdrom' 32 | lv.storage :file, :size => '40G' 33 | lv.storage :file, :device => :cdrom, :bus => 'sata', :path => "#{Dir.getwd}/tmp/winpe-amd64.iso" 34 | lv.mgmt_attach = false 35 | lv.machine_type = 'q35' 36 | lv.cpu_mode = 'host-passthrough' 37 | lv.graphics_type = 'spice' 38 | lv.video_type = 'qxl' 39 | lv.input :type => 'tablet', :bus => 'virtio' 40 | lv.channel :type => 'unix', :target_name => 'org.qemu.guest_agent.0', :target_type => 'virtio' 41 | lv.channel :type => 'spicevmc', :target_name => 'com.redhat.spice.0', :target_type => 'virtio' 42 | config.vm.synced_folder '.', '/vagrant', disabled: true 43 | end 44 | config.vm.network :private_network, ip: '10.9.9.0', auto_config: false, libvirt__forward_mode: 'nat', libvirt__dhcp_enabled: true 45 | end 46 | end 47 | end 48 | -------------------------------------------------------------------------------- /copy-winpe.cmd: -------------------------------------------------------------------------------- 1 | call "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat" 2 | 3 | @echo Copying WinPE files... 4 | if exist c:\winpe-amd64 (rmdir /s /q c:\winpe-amd64) 5 | call copype amd64 c:\winpe-amd64 6 | -------------------------------------------------------------------------------- /make-winpe-iso.cmd: -------------------------------------------------------------------------------- 1 | call "C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\DandISetEnv.bat" 2 | 3 | @echo Making winpe-amd64.iso... 4 | call MakeWinPEMedia /iso /f c:\winpe-amd64 c:\vagrant\tmp\winpe-amd64.iso 2>&1 | findstr /v "% complete" 5 | -------------------------------------------------------------------------------- /provision-adk.ps1: -------------------------------------------------------------------------------- 1 | Import-Module C:\ProgramData\chocolatey\helpers\chocolateyInstaller.psm1 2 | 3 | # Install the Windows 2022 Assessment and Deployment Kit (ADK) 10.1.22000.1. 4 | # see https://docs.microsoft.com/en-us/windows-hardware/get-started/adk-install 5 | $adkUrl = 'https://software-download.microsoft.com/download/sg/20348.1.210507-1500.fe_release_amd64fre_ADK.iso' 6 | $winpeAdkAddonUrl = 'https://software-download.microsoft.com/download/sg/20348.1.210507-1500.fe_release_amd64fre_ADKWINPEADDONS.iso' 7 | 8 | function Install-Adk($title, $url) { 9 | $artifactPath = "C:\vagrant\tmp\$(Split-Path -Leaf $url)" 10 | if (!(Test-Path $artifactPath)) { 11 | mkdir -Force (Split-Path -Parent $artifactPath) | Out-Null 12 | Write-Host "Downloading $title..." 13 | (New-Object System.Net.WebClient).DownloadFile($url, "$artifactPath.tmp") 14 | Move-Item "$artifactPath.tmp" $artifactPath 15 | } 16 | $mountedImage = $null 17 | if ($artifactPath -like '*.iso') { 18 | Write-Host 'Mounting image...' 19 | $mountedImage = Mount-DiskImage -Passthru $artifactPath 20 | $mountedVolume = $mountedImage | Get-Volume 21 | $setupPath = Resolve-Path "$($mountedVolume.DriveLetter):\*.exe" 22 | } else { 23 | $setupPath = $artifactPath 24 | } 25 | try { 26 | Write-Host "Installing $title..." 27 | &$setupPath @args | Out-String -Stream 28 | } finally { 29 | if ($mountedImage) { 30 | Write-Host 'Dismounting image...' 31 | Dismount-DiskImage $artifactPath | Out-Null 32 | } 33 | } 34 | } 35 | 36 | Install-Adk ` 37 | 'Windows Assessment and Deployment Kit (ADK)' ` 38 | $adkUrl ` 39 | /quiet /features OptionId.DeploymentTools 40 | 41 | Install-Adk ` 42 | 'WinPE add-on for the Windows Assessment and Deployment Kit (ADK)' ` 43 | $winpeAdkAddonUrl ` 44 | /quiet 45 | 46 | Write-Host 'Creating the Windows System Image Manager shortcut in the Desktop...' 47 | Install-ChocolateyShortcut ` 48 | -ShortcutFilePath "$env:USERPROFILE\Desktop\Windows System Image Manager.lnk" ` 49 | -TargetPath 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit\Deployment Tools\WSIM\imgmgr.exe' 50 | -------------------------------------------------------------------------------- /provision-base.ps1: -------------------------------------------------------------------------------- 1 | # define the Install-Application function that downloads and unzips an application. 2 | Add-Type -AssemblyName System.IO.Compression.FileSystem 3 | function Install-Application($name, $url, $expectedHash, $expectedHashAlgorithm = 'SHA256') { 4 | $localZipPath = "$env:TEMP\$name.zip" 5 | (New-Object Net.WebClient).DownloadFile($url, $localZipPath) 6 | $actualHash = (Get-FileHash $localZipPath -Algorithm $expectedHashAlgorithm).Hash 7 | if ($actualHash -ne $expectedHash) { 8 | throw "$name downloaded from $url to $localZipPath has $actualHash hash that does not match the expected $expectedHash" 9 | } 10 | $destinationPath = Join-Path $env:ProgramFiles $name 11 | [IO.Compression.ZipFile]::ExtractToDirectory($localZipPath, $destinationPath) 12 | } 13 | 14 | # disable cortana and web search. 15 | New-Item -Path 'HKLM:\SOFTWARE\Policies\Microsoft\Windows\Windows Search' -Force ` 16 | | New-ItemProperty -Name AllowCortana -Value 0 ` 17 | | New-ItemProperty -Name ConnectedSearchUseWeb -Value 0 ` 18 | | Out-Null 19 | 20 | # set keyboard layout. 21 | # NB you can get the name from the list: 22 | # [Globalization.CultureInfo]::GetCultures('InstalledWin32Cultures') | Out-GridView 23 | Set-WinUserLanguageList pt-PT -Force 24 | 25 | # set the date format, number format, etc. 26 | Set-Culture pt-PT 27 | 28 | # set the welcome screen culture and keyboard layout. 29 | # NB the .DEFAULT key is for the local SYSTEM account (S-1-5-18). 30 | New-PSDrive HKU -PSProvider Registry -Root HKEY_USERS | Out-Null 31 | 'Control Panel\International','Keyboard Layout' | ForEach-Object { 32 | Remove-Item -Path "HKU:\.DEFAULT\$_" -Recurse -Force 33 | Copy-Item -Path "HKCU:\$_" -Destination "HKU:\.DEFAULT\$_" -Recurse -Force 34 | } 35 | Remove-PSDrive HKU 36 | 37 | # set the timezone. 38 | # use Get-TimeZone -ListAvailable to list the available timezone ids. 39 | Set-TimeZone -Id 'GMT Standard Time' 40 | 41 | # show window content while dragging. 42 | Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name DragFullWindows -Value 1 43 | 44 | # show hidden files. 45 | Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name Hidden -Value 1 46 | 47 | # show protected operating system files. 48 | Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name ShowSuperHidden -Value 1 49 | 50 | # show file extensions. 51 | Set-ItemProperty -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\Advanced -Name HideFileExt -Value 0 52 | 53 | # display full path in the title bar. 54 | New-Item -Path HKCU:\Software\Microsoft\Windows\CurrentVersion\Explorer\CabinetState -Force ` 55 | | New-ItemProperty -Name FullPath -Value 1 -PropertyType DWORD ` 56 | | Out-Null 57 | 58 | # set desktop background. 59 | Copy-Item C:\vagrant\winpe.jpg C:\Windows\Web\Wallpaper\Windows 60 | Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name Wallpaper -Value C:\Windows\Web\Wallpaper\Windows\winpe.jpg 61 | Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name WallpaperStyle -Value 0 62 | Set-ItemProperty -Path 'HKCU:\Control Panel\Desktop' -Name TileWallpaper -Value 0 63 | Set-ItemProperty -Path 'HKCU:\Control Panel\Colors' -Name Background -Value '1 0 171' 64 | 65 | # install tooling. 66 | choco install -y 7zip 67 | choco install -y carbon 68 | -------------------------------------------------------------------------------- /provision-winpe-virtio.ps1: -------------------------------------------------------------------------------- 1 | # see https://docs.fedoraproject.org/en-US/quick-docs/creating-windows-virtual-machines-using-virtio-drivers/index.html 2 | # see https://github.com/virtio-win/virtio-win-guest-tools-installer 3 | # see https://github.com/virtio-win/virtio-win-pkg-scripts 4 | Write-Output 'Adding the virtio drivers...' 5 | $qemuDriversIsoUrl = 'https://fedorapeople.org/groups/virt/virtio-win/direct-downloads/archive-virtio/virtio-win-0.1.248-1/virtio-win-0.1.248.iso' 6 | $qemuDriversIsoPath = "C:\vagrant\tmp\$(Split-Path -Leaf $qemuDriversIsoUrl)" 7 | $qemuDriversPath = "$env:TEMP\$([IO.Path]::GetFileNameWithoutExtension($qemuDriversIsoUrl))" 8 | if (!(Test-Path $qemuDriversIsoPath)) { 9 | mkdir -Force (Split-Path -Parent $qemuDriversIsoPath) | Out-Null 10 | (New-Object System.Net.WebClient).DownloadFile($qemuDriversIsoUrl, $qemuDriversIsoPath) 11 | } 12 | if (!(Test-Path $qemuDriversPath)) { 13 | 7z x "-o$qemuDriversPath" $qemuDriversIsoPath 14 | } 15 | Get-ChildItem $qemuDriversPath -Include 2k22 -Recurse ` 16 | | Where-Object { Test-Path "$_\amd64" } ` 17 | | ForEach-Object { 18 | Get-ChildItem "$_\amd64\*.inf" | ForEach-Object { 19 | $driverPath = $_.FullName 20 | Write-Output "Adding the $driverPath driver..." 21 | try { 22 | Add-WindowsDriver -Path $env:WINDOWS_PE_MOUNT_PATH -Driver $driverPath 23 | } catch { 24 | # NB as-of virtio-win 0.1.248, the following drivers fail to be added: 25 | # pvpanic-pci.inf 26 | # smbus.inf 27 | # see https://github.com/virtio-win/kvm-guest-drivers-windows/issues/1107 28 | if ("$_" -match 'The request is not supported') { 29 | Write-Host "WARNING The driver was not added. Ignoring the known error: $_" 30 | return 31 | } 32 | throw 33 | } 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /provision-winpe.ps1: -------------------------------------------------------------------------------- 1 | Import-Module Carbon 2 | 3 | $adkPath = 'C:\Program Files (x86)\Windows Kits\10\Assessment and Deployment Kit' 4 | $mountPath = 'C:\winpe-amd64\mount' 5 | $env:WINDOWS_PE_MOUNT_PATH = $mountPath 6 | 7 | if (Test-Path "$mountPath\Windows") { 8 | Write-Output 'Discarding and unmounting the existing Windows PE image...' 9 | Dismount-WindowsImage -Path $mountPath -Discard 10 | Remove-Item -Recurse $mountPath 11 | } 12 | 13 | cmd /c copy-winpe.cmd 14 | 15 | Write-Output 'Mounting the Windows PE image...' 16 | Mount-WindowsImage ` 17 | -ImagePath C:\winpe-amd64\media\sources\boot.wim ` 18 | -Index 1 ` 19 | -Path $mountPath ` 20 | | Out-Null 21 | 22 | $windowsOptionalComponentsPath = "$adkPath\Windows Preinstallation Environment\amd64\WinPE_OCs" 23 | @( 24 | 'WinPE-WMI' 25 | 'WinPE-NetFx' 26 | 'WinPE-Scripting' 27 | 'WinPE-PowerShell' 28 | 'WinPE-StorageWMI' 29 | 'WinPE-DismCmdlets' 30 | 'WinPE-SecureStartup' 31 | 'WinPE-SecureBootCmdlets' 32 | ) | ForEach-Object { 33 | Write-Output "Adding the $_ Windows Package..." 34 | Add-WindowsPackage ` 35 | -Path $mountPath ` 36 | -PackagePath "$windowsOptionalComponentsPath\$_.cab" ` 37 | | Out-Null 38 | } 39 | 40 | Write-Output 'Adding the startup files...' 41 | Copy-Item startup.ps1 $mountPath 42 | Copy-Item winpeshl.ini "$mountPath\Windows\System32" 43 | Grant-CPermission "$mountPath\Windows\System32\winpe.jpg" Administrators FullControl 44 | Copy-Item winpe.jpg "$mountPath\Windows\System32" 45 | <# 46 | # this is commented because changing the background color does not seem to be supported on winpe. 47 | # see the registry hive supporting files at https://msdn.microsoft.com/en-us/library/windows/desktop/ms724877(v=vs.85).aspx 48 | reg load HKLM\WINPE_DEFAULT "$mountPath\Windows\System32\config\DEFAULT" | Out-Null 49 | New-PSDrive -PSProvider Registry -Name WINPE_DEFAULT -Root HKEY_LOCAL_MACHINE\WINPE_DEFAULT | Out-Null 50 | Set-ItemProperty -Path 'WINPE_DEFAULT:\Control Panel\Desktop' -Name WallpaperStyle -Value 0 51 | Set-ItemProperty -Path 'WINPE_DEFAULT:\Control Panel\Desktop' -Name TileWallpaper -Value 0 52 | Set-ItemProperty -Path 'WINPE_DEFAULT:\Control Panel\Colors' -Name Background -Value '1 30 171' 53 | Remove-PSDrive WINPE_DEFAULT 54 | reg unload HKLM\WINPE_DEFAULT | Out-Null 55 | #> 56 | 57 | Write-Output 'Customizing the image...' 58 | Get-ChildItem provision-winpe-*.ps1 | Sort-Object FullName | ForEach-Object { 59 | PowerShell -File ps.ps1 $_ 60 | if ($LASTEXITCODE) { 61 | throw "Failed with Exit Code $LASTEXITCODE" 62 | } 63 | } 64 | 65 | Write-Output 'Cleaning up the image...' 66 | dism.exe /Quiet /Cleanup-Image "/Image=$mountPath" /StartComponentCleanup /ResetBase 67 | if ($LASTEXITCODE) { 68 | throw "Failed with Exit Code $LASTEXITCODE" 69 | } 70 | 71 | Write-Output 'Saving and unmounting the Windows PE image...' 72 | Dismount-WindowsImage -Path $mountPath -Save 73 | 74 | # NB this removes the "Press any key to boot from CD or DVD" prompt 75 | # that appears when running in UEFI with the default efisys.bin. 76 | Write-Output 'Replacing fwfiles\efisys.bin with efisys_noprompt.bin...' 77 | Copy-Item ` 78 | "$adkPath\Deployment Tools\amd64\Oscdimg\efisys_noprompt.bin" ` 79 | "$mountPath\..\fwfiles\efisys.bin" 80 | 81 | Write-Output 'Creating the Windows PE iso file...' 82 | cmd /c make-winpe-iso.cmd 83 | -------------------------------------------------------------------------------- /ps.ps1: -------------------------------------------------------------------------------- 1 | param( 2 | [Parameter(Mandatory=$true)] 3 | [string]$script, 4 | 5 | [Parameter(Mandatory=$false, ValueFromRemainingArguments=$true)] 6 | [string[]]$scriptArguments 7 | ) 8 | 9 | Set-StrictMode -Version Latest 10 | $ErrorActionPreference = 'Stop' 11 | $ProgressPreference = 'SilentlyContinue' 12 | trap { 13 | Write-Host "ERROR: $_" 14 | ($_.ScriptStackTrace -split '\r?\n') -replace '^(.*)$','ERROR: $1' | Write-Host 15 | ($_.Exception.ToString() -split '\r?\n') -replace '^(.*)$','ERROR EXCEPTION: $1' | Write-Host 16 | Exit 1 17 | } 18 | 19 | # enable TLS 1.1 and 1.2. 20 | [Net.ServicePointManager]::SecurityProtocol = [Net.ServicePointManager]::SecurityProtocol ` 21 | -bor [Net.SecurityProtocolType]::Tls11 ` 22 | -bor [Net.SecurityProtocolType]::Tls12 23 | 24 | # wrap the choco command (to make sure this script aborts when it fails). 25 | function Start-Choco([string[]]$Arguments, [int[]]$SuccessExitCodes=@(0)) { 26 | $command, $commandArguments = $Arguments 27 | if ($command -eq 'install') { 28 | $Arguments = @($command, '--no-progress') + $commandArguments 29 | } 30 | for ($n = 0; $n -lt 10; ++$n) { 31 | if ($n) { 32 | # NB sometimes choco fails with "The package was not found with the source(s) listed." 33 | # but normally its just really a transient "network" error. 34 | Write-Host "Retrying choco install..." 35 | Start-Sleep -Seconds 3 36 | } 37 | &C:\ProgramData\chocolatey\bin\choco.exe @Arguments 38 | if ($SuccessExitCodes -Contains $LASTEXITCODE) { 39 | return 40 | } 41 | } 42 | throw "$(@('choco')+$Arguments | ConvertTo-Json -Compress) failed with exit code $LASTEXITCODE" 43 | } 44 | function choco { 45 | Start-Choco $Args 46 | } 47 | 48 | Set-Location c:\vagrant 49 | $script = Resolve-Path $script 50 | Set-Location (Split-Path -Parent $script) 51 | Write-Host "Running $script..." 52 | . ".\$(Split-Path -Leaf $script)" @scriptArguments 53 | -------------------------------------------------------------------------------- /startup.ps1: -------------------------------------------------------------------------------- 1 | $Host.UI.RawUI.WindowTitle = "PowerShell v$($PSVersionTable.PSVersion) :: Windows PE v$([Environment]::OSVersion.Version)" 2 | cls 3 | 4 | # NB this was rendered by http://patorjk.com/software/taag/#p=display&f=Standard&t=Windows%20PE 5 | @' 6 | __ ___ _ ____ _____ 7 | \ \ / (_)_ __ __| | _____ _____ | _ \| ____| 8 | \ \ /\ / /| | '_ \ / _` |/ _ \ \ /\ / / __| | |_) | _| 9 | \ V V / | | | | | (_| | (_) \ V V /\__ \ | __/| |___ 10 | \_/\_/ |_|_| |_|\__,_|\___/ \_/\_/ |___/ |_| |_____| {0} 11 | 12 | '@ -f @((Get-ItemProperty 'HKLM:\SOFTWARE\Microsoft\Windows NT\CurrentVersion').ReleaseId) 13 | 14 | Write-Output "#`n# SMBIOS`n#" 15 | $info = Get-WmiObject Win32_ComputerSystemProduct 16 | New-Object PSObject -Property @{ 17 | DmiSystemVendor = $info.Vendor 18 | DmiSystemProduct = $info.Name 19 | DmiSystemVersion = $info.Version 20 | DmiSystemSerial = $info.IdentifyingNumber 21 | DmiSystemUuid = $info.UUID 22 | } 23 | -------------------------------------------------------------------------------- /winpe.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rgl/windows-pe-vagrant/a7a0baf73eccd1da40d4963ff1ddc6646c67a100/winpe.jpg -------------------------------------------------------------------------------- /winpe.xcf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/rgl/windows-pe-vagrant/a7a0baf73eccd1da40d4963ff1ddc6646c67a100/winpe.xcf -------------------------------------------------------------------------------- /winpeshl.ini: -------------------------------------------------------------------------------- 1 | ; see https://docs.microsoft.com/en-us/windows-hardware/manufacture/desktop/winpeshlini-reference-launching-an-app-when-winpe-starts 2 | ; NB The apps listed in [LaunchApp] and [LaunchApps] run in order of appearance, 3 | ; and don't start until the previous app has terminated. 4 | ; NB The system is rebooted after the last app has terminated. 5 | 6 | ;[LaunchApp] 7 | ;AppPath = powershell 8 | 9 | [LaunchApps] 10 | ;wpeutil, SetKeyboardLayout 0409:00000409 ; English (en-US) 11 | wpeutil, SetKeyboardLayout 0816:00000816 ; Portuguese (pt-PT) 12 | wpeutil, SetUserLocale pt-PT 13 | wpeutil, InitializeNetwork 14 | powershell, -NoLogo -NoExit -ExecutionPolicy Bypass \startup.ps1 15 | --------------------------------------------------------------------------------