windows-diskimage-builder/windows-diskimage-builder/diskimagebuilder.ps1

411 lines
12 KiB
PowerShell

# Copyright 2012 Hewlett-Packard Development Company, L.P.
#
# 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.
# Creates a Image file, Includes cloudbase-init package by default.
# User can create image by adding custom drivers, VirIO Drivers by providing suitable ISO or inf files. Enable Roles like Hyperv , TFTP etc., Use below formats to run script.
# Runs on Windows 7, 8, 8.1 and 2012 R2
# Requires Powershell 3.0 or above and wim file from ISO Source folder. ISO is not required. Only Wim file is enough to generate and apply wim to vhd.
# Basic Usage
#.\diskimagebuilder.ps1 -SourceFile <path>\install.wim -VHDFile <path>\VHDFilename -VHDSize <size of vhd>
# Enabling Feature like TFTP
#.\diskimagebuilder.ps1 -SourceFile <path>\install.wim -VHDFile <path>\VHDFilename -VHDSize <size of vhd> -feature TFTP
# Add Drivers to images. It auto adds all drivers present in the drivers folder
#.\diskimagebuilder.ps1 -SourceFile <path>\install.wim -VHDFile <path>\VHDFilename -VHDSize <size of vhd> -DriversPath <path to drivers folder>
#Add Unattend answer file
#.\diskimagebuilder.ps1 -SourceFile <path>\install.wim -VHDFile <path>\VHDFilename -VHDSize <size of vhd> -UnattendPath <path>\unattend.xml
#Add VirtIO Drivers
#.\diskimagebuilder.ps1 -SourceFile <path>\install.wim -VHDFile <path>\VHDFilename -VHDSize <size of vhd> -VirtIOPath <path>\virtio.iso
# All Commands Usage
#.\diskimagebuilder.ps1 -SourceFile <path>\install.wim -VHDFile <path>\VHDFilename -VHDSize <size of vhd> -feature <featuretoenable> -UnattendPath <path>\unattend.xml -DriversPath <path to drivers folder>
# Please download and install qemu binary for getting qcow2 format of image from the link --> http://qemu.weilnetz.de/w64/
Param(
[Parameter(mandatory=$True,HelpMessage="Name and path of Sourcefile (WIM).")]
[ValidateNotNullOrEmpty()]
[ValidateScript({ Test-Path $(Resolve-Path $_) })]
[String]$SourceFile,
[parameter(mandatory=$True,HelpMessage="Name and path of VHD or VHDx file.")]
[ValidateNotNullOrEmpty()]
[String]$VHDFile,
[parameter(mandatory=$True,HelpMessage="Size of VHD or VHDx file.")]
[ValidateNotNullOrEmpty()]
[String]$VHDSize,
[parameter(HelpMessage="feature to enable.")]
[ValidateNotNullOrEmpty()]
[String]$feature,
[parameter(HelpMessage="Index of the wim.")]
[ValidateNotNullOrEmpty()]
[String]$Index,
[parameter(HelpMessage="Unattended xml file path")]
[ValidateNotNullOrEmpty()]
[String]$UnattendPath,
[parameter(HelpMessage="cloudbaseinit msi url")]
[ValidateNotNullOrEmpty()]
[String]$CloudbaseInitMsiUrl,
[parameter(HelpMessage="Serial port baudrate")]
[ValidateNotNullOrEmpty()]
[String]$serialbaudrate,
[parameter(HelpMessage="Add Drivers Folder Path.")]
[ValidateNotNullOrEmpty()]
[String]$DriversPath,
[parameter(HelpMessage="Output format vhd\qcow2.")]
[ValidateNotNullOrEmpty()]
[String]$OutputFormat,
[parameter(HelpMessage="UEFI Disk layout")]
[ValidateNotNullOrEmpty()]
[String]$disklayout,
[parameter(HelpMessage="Add Drivers From Virtio ISO.")]
[ValidateNotNullOrEmpty()]
[String]$VirtIOPath
)
$name = "createimage"
$currdate = get-date -f yyyy-MM-dd
write-host $args
if(!$UnattendPath){
$UnattendPath = "unattend.xml"
}
if(!$CloudbaseInitMsiUrl){
$CloudbaseInitMsiUrl = "http://www.cloudbase.it/downloads/CloudbaseInitSetup_Beta.msi"
}
if(!$serialbaudrate){
$serialbaudrate = "9600"
}
if($OutputFormat){
$arrFormats = @("vhd", "qcow2")
$Found = 0
for ($i=0; $i -lt $arrFormats.length; $i++) {
if($arrFormats[$i] -eq $OutputFormat){
$Found = 1
}
}
if(!$Found){
Write-W2VInfo "Not a valid output format"
exit
}
}
$VHDVolume = 'v'
$Error = 0
if(!$Index){
$Index = 1
}
$VHDloc = Split-Path $VHDFile -Parent
$testpaths = @($SourceFile, $VirtIOPath, $DriversPath, $UnattendPath, $VHDloc)
function
Write-W2VError {
# Function to make the Write-Host (NOT Write-Error) output prettier in the case of an error.
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]
[ValidateNotNullOrEmpty()]
$text
)
Write-Host "ERROR : $($text)" -ForegroundColor green
}
function Write-W2VInfo {
# Function to make the Write-Host output a bit prettier.
[CmdletBinding()]
param(
[Parameter(Mandatory = $true, ValueFromPipeline = $true)]
[string]
[ValidateNotNullOrEmpty()]
$text
)
Write-Host "INFO : $($text)" -ForegroundColor Green
}
Function Createvhd{
Import-Module ..\Hyperv\HyperV.psd1
$GB = [System.UInt64] $VHDSize*1024*1024*1024
$ImageMgtService = get-wmiobject -class "Msvm_ImageManagementService" -namespace "root\virtualization" -computername "." 2
# Create the Dynamic VHD
$result = $ImageMgtService.CreateDynamicVirtualHardDisk($VHDFile,$GB)
if($result.ReturnValue -eq 4096){
# A Job was started, and can be tracked using its Msvm_Job instance
$job = [wmi]$result.Job
# Wait for job to finish
while($job.jobstate -lt 7){$job.get()}
# Return the Job's error code
return $job.ErrorCode
}
# Otherwise, the method completed
return $result.ReturnValue
}
Function PscreatePartition(){
#Mount-DiskImage
Mount-DiskImage -ImagePath $VHDFile -Verbose
Write-W2VInfo "image mounted"
$VHDDisk = Get-DiskImage -ImagePath $VHDFile | Get-Disk -Verbose
$VHDDiskNumber = [string]$VHDDisk.Number
#Initialize-Disk
Initialize-Disk -Number $VHDDiskNumber -PartitionStyle MBR -Verbose
#Format vhdfile
$VHDDrive = New-Partition -DiskNumber $VHDDiskNumber -UseMaximumSize -IsActive -Verbose
$VHDDrive | Format-Volume -FileSystem NTFS -NewFileSystemLabel OSDisk -Confirm:$false -Verbose
Add-PartitionAccessPath -DiskNumber $VHDDiskNumber -PartitionNumber $VHDDrive.PartitionNumber -AssignDriveLetter
$VHDDrive = Get-Partition -DiskNumber $VHDDiskNumber -PartitionNumber $VHDDrive.PartitionNumber
$VHDVolume = [string]$VHDDrive.DriveLetter+":"
. Logit "Driveletter is now = $VHDVolume"
dism.exe /apply-Image /ImageFile:$SourceFile /index:$Index /ApplyDir:$VHDVolume\
Write-W2VInfo "$VHDVolume\Windows"
Write-W2VInfo $VHDDrive.Offset
Write-W2VInfo $VHDDisk.Signature
}
function remove-vhd($vhdfile) {
$path = resolve-path $vhdfile
$script = "SELECT VDISK FILE=`"$path`"`r`nDETACH VDISK"
$script | diskpart
}
function CreateThrwDiskpart(){
$GB = [System.UInt64] $VHDSize*1024
$path = $vhdFile
$script = "create VDISK FILE=`"$path`" maximum=`"$GB`" type=expandable `r`nselect VDISK FILE=`"$path`"`r`nattach VDISK`r`ncreate partition primary`r`nassign letter=`"$VHDVolume`"`r`nformat fs=ntfs quick label=vhd`r`nactive`r`nexit"
$gptscript = "create VDISK FILE=`"$path`" maximum=`"$GB`" type=expandable `r`nselect VDISK FILE=`"$path`"`r`nattach VDISK`r`convert gpt`r`ncreate partition primary`r`nassign letter=`"$VHDVolume`"`r`nformat fs=ntfs quick label=vhd`r`nexit"
if($disklayout){
$gptscript | DISKPART
}else{
$script | DISKPART
}
$VHDVolume = [string]$VHDVolume + ":"
Write-W2VInfo " $VHDVolume is the drive letter"
dism.exe /apply-Image /ImageFile:$SourceFile /index:$Index /ApplyDir:$VHDVolume\
}
function MountDisk() {
$path = resolve-path $vhdFile
$script = "SELECT VDISK FILE=`"$path`"`r`attach VDISK"
$script | diskpart | Out-Null
}
function CreateBootfiles(){
$VHDVolume = [string]$VHDVolume + ":"
Write-W2VInfo $VHDVolume
cmd /c "$VHDVolume\Windows\System32\bcdboot.exe $VHDVolume\windows /s $VHDVolume"
bcdedit /store $VHDVolume\boot\BCD
}
function ApplyVirtIODrivers(){
$VHDVolume = $VHDVolume + ":"
$VirtIOMountPath = ''
if($VirtIOPath){
Write-W2VInfo "Mounting virio iso file."
$MountedISO = Mount-DiskImage $VirtIOPath -PassThru
$driveletter = ($MountedISO | Get-Volume).DriveLetter
$winstring = Get-WindowsImage -Imagepath $SourceFile | findstr "Name"
if($winstring -match "windows 7"){
$VirtIOMountPath = "$driveletter"+":\WIN7\AMD64"
}else{
$VirtIOMountPath = "$driveletter"+":\WIN8\AMD64"
}
Write-W2VInfo "Applying virtio drivers......"
Dism /image:$VHDVolume\ /Add-Driver /driver:$VirtIOMountPath /ForceUnsigned /recurse
Dismount-DiskImage $VirtIOPath
}
}
function ApplyDrivers(){
$VHDVolume = $VHDVolume + ":"
Write-W2VInfo "Applying Drivers...."
Dism /image:$VHDVolume\ /Add-Driver /driver:$DriversPath /ForceUnsigned /recurse
}
function ApplyUnattendxml(){
$VHDVolume = $VHDVolume + ":"
Write-W2VInfo "Copying Unattend xml file"
copy $UnattendPath $VHDVolume\Unattend.xml
}
function AddCloudbaseinit(){
$VHDVolume = $VHDVolume + ":"
#$CloudbaseInitMsiUrl = "http://www.cloudbase.it/downloads/CloudbaseInitSetup_Beta.msi"
$CloudbaseInitMsi = "$ENV:Temp\CloudbaseInitSetup_Beta.msi"
Write-W2VInfo "Downloading Cloudbase init msi ........."
(new-object System.Net.WebClient).DownloadFile($CloudbaseInitMsiUrl, $CloudbaseInitMsi)
New-Item -ItemType directory -Path $VHDVolume\Windows\Setup\Scripts
Copy-Item $pwd\SetupComplete.cmd $VHDVolume\Windows\Setup\Scripts
Copy-Item $CloudbaseInitMsi $VHDVolume\Windows\Setup\Scripts
}
function SerialPort(){
$VHDVolume = $VHDVolume + ":"
Write-W2VInfo "Adding Serial Port"
bcdedit /store $VHDVolume\boot\BCD /dbgsettings serial debugport:1 baudrate:$serialbaudrate
}
function convertoutputtoqcow2(){
try{
Write-W2VInfo "Converting to qcow2"
qemu-img.exe convert -f vpc -O qcow2 $VHDFile $VHDFile.Replace("vhd","qcow2")
Remove-Item $VHDFile
}catch{
Write-W2VInfo "qemu is not installed or its path is not set to system path. So ouput will be in vhd format"
exit
}
}
foreach($p in $testpaths){
if($p){
$valid = Test-Path -path $p
if(!$valid){
Write-W2VError "Not a valid Path please check the path specified --- $p"
exit
break
}
}
}
try {
if($disklayout){
$Errorvalue = 1
}else{
Createvhd
PscreatePartition
}
} catch{
Write-W2VInfo "Could not run through hyperv module will use diskpart..."
$Errorvalue = 1
}
if($Errorvalue){
CreateThrwDiskpart
}
CreateBootfiles
Addcloudbaseinit
Write-W2VInfo "---------------------Enabling features.-----------------------------------------------------"
if($feature){
Write-W2VInfo "----- Enabling Role -----"
Dism /online /enable-feature /featurename:$feature
}
if($UnattendPath){
ApplyUnattendxml
}
if($DriversPath){
ApplyDrivers
}
if($VirtIOPath){
ApplyVirtIODrivers
}
#serial port
SerialPort
#select and detach the vdisk created by the disk.
remove-vhd($VHDFile)
if($OutputFormat){
if($OutputFormat -eq "qcow2"){
convertoutputtoqcow2
}
}
Write-W2VInfo "================= Please check logs directory for Image creation log files. ===================="
Write-W2VInfo "================= Completed Image Creation and ready. ======================="