Created
December 12, 2016 19:25
-
-
Save riverar/dc634b58683a78d0a682dc765544b413 to your computer and use it in GitHub Desktop.
Xbox One disk partitioning script
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# Copyright (c) Rafael Rivera | |
# | |
# Licensed under the Apache License, Version 2.0 (the "License"); | |
# you may not use this file except in compliance with the License. | |
# You may obtain a copy of the License at | |
# | |
# http://www.apache.org/licenses/LICENSE-2.0 | |
# | |
# Unless required by applicable law or agreed to in writing, software | |
# distributed under the License is distributed on an "AS IS" BASIS, | |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
# See the License for the specific language governing permissions and | |
# limitations under the License. | |
Add-Type -TypeDefinition @" | |
// Copyright (c) Damien Guard. All rights reserved. | |
// Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. | |
// You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 | |
// Originally published at http://damieng.com/blog/2006/08/08/calculating_crc32_in_c_and_net | |
using System; | |
using System.Collections.Generic; | |
using System.Security.Cryptography; | |
public sealed class Crc32 : HashAlgorithm | |
{ | |
public const UInt32 DefaultPolynomial = 0xedb88320u; | |
public const UInt32 DefaultSeed = 0xffffffffu; | |
static UInt32[] defaultTable; | |
readonly UInt32 seed; | |
readonly UInt32[] table; | |
UInt32 hash; | |
public Crc32() | |
: this(DefaultPolynomial, DefaultSeed) | |
{ | |
} | |
public Crc32(UInt32 polynomial, UInt32 seed) | |
{ | |
table = InitializeTable(polynomial); | |
this.seed = hash = seed; | |
} | |
public override void Initialize() | |
{ | |
hash = seed; | |
} | |
protected override void HashCore(byte[] array, int ibStart, int cbSize) | |
{ | |
hash = CalculateHash(table, hash, array, ibStart, cbSize); | |
} | |
protected override byte[] HashFinal() | |
{ | |
var hashBuffer = UInt32ToBigEndianBytes(~hash); | |
HashValue = hashBuffer; | |
return hashBuffer; | |
} | |
public override int HashSize { get { return 32; } } | |
public static UInt32 Compute(byte[] buffer) | |
{ | |
return Compute(DefaultSeed, buffer); | |
} | |
public static UInt32 Compute(UInt32 seed, byte[] buffer) | |
{ | |
return Compute(DefaultPolynomial, seed, buffer); | |
} | |
public static UInt32 Compute(UInt32 polynomial, UInt32 seed, byte[] buffer) | |
{ | |
return ~CalculateHash(InitializeTable(polynomial), seed, buffer, 0, buffer.Length); | |
} | |
static UInt32[] InitializeTable(UInt32 polynomial) | |
{ | |
if (polynomial == DefaultPolynomial && defaultTable != null) | |
return defaultTable; | |
var createTable = new UInt32[256]; | |
for (var i = 0; i < 256; i++) | |
{ | |
var entry = (UInt32)i; | |
for (var j = 0; j < 8; j++) | |
if ((entry & 1) == 1) | |
entry = (entry >> 1) ^ polynomial; | |
else | |
entry = entry >> 1; | |
createTable[i] = entry; | |
} | |
if (polynomial == DefaultPolynomial) | |
defaultTable = createTable; | |
return createTable; | |
} | |
static UInt32 CalculateHash(UInt32[] table, UInt32 seed, IList<byte> buffer, int start, int size) | |
{ | |
var crc = seed; | |
for (var i = start; i < size - start; i++) | |
crc = (crc >> 8) ^ table[buffer[i] ^ crc & 0xff]; | |
return crc; | |
} | |
static byte[] UInt32ToBigEndianBytes(UInt32 uint32) | |
{ | |
var result = BitConverter.GetBytes(uint32); | |
if (BitConverter.IsLittleEndian) | |
Array.Reverse(result); | |
return result; | |
} | |
} | |
"@ -PassThru | Out-Null | |
function Get-Crc32 | |
{ | |
Param ( | |
[Parameter(ValueFromPipeline)] | |
[byte[]]$buffer | |
) | |
$crc32 = New-Object Crc32 | |
return $crc32.ComputeHash($buffer) | |
} | |
function Set-XboxPartitionAttributes() | |
{ | |
Param ( | |
[parameter(ValueFromPipeline)] | |
$disk | |
) | |
# Read enough sector data to cover the GPT header and partition entries | |
$reader = New-Object System.IO.BinaryReader([IO.File]::Open($disk.Path, "Open", "Read", "ReadWrite")) | |
$reader.BaseStream.Position = 0 | |
$sectorData = $reader.ReadBytes(32768) | |
$reader.Close() | |
$reader.Dispose() | |
# Zero out CRCs | |
[Array]::Copy([byte[]]@(0) * 4, 0, $sectorData, 512 + 16, 4) # Header | |
[Array]::Copy([byte[]]@(0) * 4, 0, $sectorData, 512 + 88, 4) # Partition array | |
# Set Disk GUID | |
$guidBytes = ([Guid]::Parse($XboxDisk.Guid)).ToByteArray() | |
[Array]::Copy($guidBytes, 0, $sectorData, 512 + 56, $guidBytes.Length) | |
# Adjust partition attributes | |
for($i = 0; $i -lt $XboxDisk.Partitions.Count; $i++) { | |
$partition = $XboxDisk.Partitions[$i] | |
# Adjust partition GUID | |
$guidBytes = ([Guid]::Parse($partition.Guid)).ToByteArray() | |
[Array]::Copy($guidBytes, 0, $sectorData, 1024 + (128 * $i) + 16, $guidBytes.Length) | |
# Adjust partition name (36 UTF16 LE units) | |
$stringBytes = [Text.Encoding]::Unicode.GetBytes($partition.Name.PadRight(36, "`0")) | |
[Array]::Copy($stringBytes, 0, $sectorData, 1024 + (128 * $i) + 56, $stringBytes.Length) | |
} | |
# Compute partition array CRC | |
$partitionArrayCrc = Get-Crc32 $sectorData[1024..17407] | |
[array]::Reverse($partitionArrayCrc) | |
# Write-Host "Part. CRC: " ([BitConverter]::ToString($partitionArrayCrc)) | |
[Array]::Copy($partitionArrayCrc, 0, $sectorData, 512 + 88, $partitionArrayCrc.Length) | |
$headerCrc = Get-Crc32 $sectorData[512..603] | |
[array]::Reverse($headerCrc) | |
# Write-Host "Header CRC: " ([BitConverter]::ToString($headerCrc)) | |
[Array]::Copy($headerCrc, 0, $sectorData, 512 + 16, $headerCrc.Length) | |
# Write it all out to disk | |
$writer = New-Object System.IO.BinaryWriter([IO.File]::Open($disk.Path, "Open", "Write", "ReadWrite")) | |
$writer.Write($sectorData) | |
# Write the backup GPT header, with LBAs swapped, to the last sector too | |
$primaryLba = $sectorData[536..543] | |
$backupLba = $sectorData[544..551] | |
[Array]::Copy($backupLba, 0, $sectorData, 536, $primaryLba.Length) | |
[Array]::Copy($primaryLba, 0, $sectorData, 544, $backupLba.Length) | |
$writer.BaseStream.Seek($disk.Size - $disk.PhysicalSectorSize, "Begin") | |
$writer.Write($sectorData[512..1024], 0, 512) | |
$writer.Close() | |
$writer.Dispose() | |
} | |
$XboxDisk = @" | |
{ | |
"Partitions": [ | |
{ | |
Name: "Temp Content", | |
Guid: "{b3727da5-a3ac-4b3d-9fd6-2ea54441011b}", | |
Size: 44023414784 | |
}, | |
{ | |
Name: "User Content", | |
Guid: "{869bb5e0-3356-4be6-85f7-29323a675cc7}", | |
Size: 0 | |
}, | |
{ | |
Name: "System Support", | |
Guid: "{c90d7a47-ccb9-4cba-8c66-0459f6b85724}", | |
Size: 42949672960 | |
}, | |
{ | |
Name: "System Update", | |
Guid: "{9a056ad7-32ed-4141-aeb1-afb9bd5565dc}", | |
Size: 12884901888 | |
}, | |
{ | |
Name: "System Update 2", | |
Guid: "{24b2197c-9d01-45f9-a8e1-dbbcfa161eb2}", | |
Size: 7516192768 | |
} | |
], | |
Guid: "{a2344bdb-d6de-4766-9eb5-4109a12228e5}" | |
} | |
"@ | ConvertFrom-Json | |
# Change to match desired disk. | |
# There will be no data loss warnings so choose wisely. | |
$diskId = -42 | |
If($diskId -lt 0) | |
{ | |
Write-Error "`$diskId must be changed to match the correct disk number (see below)." | |
Get-Disk | |
return | |
} | |
$disk = Get-Disk $diskId | |
$disk | Clear-Disk -RemoveData -Confirm:$False | |
$disk | Initialize-Disk -PartitionStyle GPT -Confirm:$False | |
# Remove the unwanted MSR partition | |
$disk | Get-Partition | Remove-Partition -Confirm:$False | |
$XboxDisk.Partitions[1].Size = [Math]::Truncate( | |
$disk.LargestFreeExtent - ($XboxDisk.Partitions | Select -ExpandProperty Size | Measure-Object -Sum | Select -ExpandProperty Sum)) | |
foreach($partition in $XboxDisk.Partitions) { | |
$disk | New-Partition -Size $partition.Size -AssignDriveLetter | | |
Format-Volume -FileSystem NTFS -NewFileSystemLabel $partition.Name -Force | |
} | |
$disk | Set-XboxPartitionAttributes |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment