vSphere ESXi customize image のつくりかた（vSphere 7 が来た後の対応）

# カスタムイメージが必要な理由は
vSphere Hyprvisor (ESXi) のカスタムイメージ、これはハードウエアベンダーによって実装されているハードウエア構成が異なるために、その方言ともいえる違いを吸収するために必要なのですが、VMware で認定を受けているハードウエアであればそのベンダーがカスタムイメージを用意して提供してくれますが、家ラボのように VMware 認定機種ではない場合、自分でカスタムイメージを作らないとインストールすらできない場合もあります。特に NIC, SATA, USB あたりのドライバは大切で、NIC に対応したドライバーがないとそもそもインストーラーが先に進みませんし、PC にESXi をインストールする場合は SATA が無いとディスクが見えない、そして USB が無いと USB をブートデバイスにできないなどいろいろなことがあって、新しいバージョンの vSphere が出てくるたびにカスタムイメージを作っていたかと思います。
![ここに来るまでが大変](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/541683/0345ed1c-4b27-311d-4cc9-b6be2a9c4290.png)


# カスタムイメージを作るのに使うツールは（追記修正）
カスタムイメージを作るには VMware から提供されている PowerCLI をインストールした PowerShell から、[ESXi-Customizer-PS](https://www.v-front.de/p/esxi-customizer-ps.html) を使って作る方法を以前記事として書きました。

[vSphere ESXi customize image のつくりかた（vSphere 7 が来る前の準備）](https://qiita.com/inasato/items/62396114feeaffc7b3e2)

ただ、この時にはまだ vSphere 7 が登場していなかったため、この記事で紹介している [ESXi-Customizer-PS](https://www.v-front.de/p/esxi-customizer-ps.html) も vSphere 6.7 までしか対応しておらず、vSphere 7 のイメージを作ることができなくて、以下のサイトの記事を見ながら手作業でコマンドを入力して vSphere 7.0 のイメージを作成していたかと思います。

[ESXi on 10th Gen Intel NUC (Comet Lake - Frost Canyon)](https://www.virten.net/2020/03/esxi-on-10th-gen-intel-nuc-comet-lake-frost-canyon/)


ただ、やはり毎回コマンドを売ってやるのは大変ですし、[ESXi-Customizer-PS](https://www.v-front.de/p/esxi-customizer-ps.html) のように簡単にできればよいのになぁと思いました~~ので、本家の [ESXi-Customizer-PS](https://www.v-front.de/p/esxi-customizer-ps.html) から vSphere 7.0 対応版が出る前に、ちょっと本家の [ESXi-Customizer-PS](https://www.v-front.de/p/esxi-customizer-ps.html) を弄ったものを作ってみました。~~

そうしたら、GitHub に vSphere 7 版がありましたので、そちらを使ってください。
[VFrontDe/ESXi-Customizer-PS](https://github.com/VFrontDe/ESXi-Customizer-PS)

~~# オレオレ版 ESXi-Customizer-PS~~
~~オレオレ版と書いていますが詐欺的なものではなく、オリジナルに vSphere 7.0 の部分を追記しただけです。なので、使い方その他はオリジナルと同じ。異なるのは vSphere 7 だよということを教えるためのオプション、**-v70**ができただけです。 ESXi-Customizer-PS-v2.6.0.ps1  自体は PowerShell のテキストファイルなので、それを一部書き換えて ESXi-Customizer-PS-v2.6.0-vS7.ps1 にしてみました。中身は以下の通りです。~~

以降のソースはとりあえず残しておきます

```powershell:ESXi-Customizer-PS-v2.6.0-vS7.ps1
#############################################################################################################################
#
# ESXi-Customizer-PS.ps1 - a script to build a customized ESXi installation ISO using ImageBuilder
#
# Version:       2.6.0
# Author:        Andreas Peetz (ESXi-Customizer-PS@v-front.de)
# Info/Tutorial: https://esxi-customizer-ps.v-front.de/
#
# License:
#
# This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License
# as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.
#
# This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
# of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.
#
# A copy of the GNU General Public License is available at http://www.gnu.org/licenses/.
#
#############################################################################################################################

param(
    [string]$iZip = "",
    [string]$pkgDir = "",
    [string]$outDir = $(Split-Path $MyInvocation.MyCommand.Path),
    [string]$ipname = "",
    [string]$ipvendor = "",
    [string]$ipdesc = "",
    [switch]$vft = $false,
    [string[]]$dpt = @(),
    [string[]]$load = @(),
    [string[]]$remove = @(),
    [switch]$test = $false,
    [switch]$sip = $false,
    [switch]$nsc = $false,
    [switch]$help = $false,
    [switch]$ozip = $false,
    [switch]$v50 = $false,
    [switch]$v51 = $false,
    [switch]$v55 = $false,
    [switch]$v60 = $false,
    [switch]$v65 = $false,
    [switch]$v67 = $false,
    [switch]$v70 = $false,
    [switch]$update = $false,
    [string]$log = ($env:TEMP + "\ESXi-Customizer-PS-" + $PID + ".log")
)

# Constants
$ScriptName = "ESXi-Customizer-PS"
$ScriptVersion = "2.6.0"
$ScriptURL = "https://ESXi-Customizer-PS.v-front.de"

$AccLevel = @{"VMwareCertified" = 1; "VMwareAccepted" = 2; "PartnerSupported" = 3; "CommunitySupported" = 4}

# Online depot URLs
$vmwdepotURL = "https://hostupdate.vmware.com/software/VUM/PRODUCTION/main/vmw-depot-index.xml"
$vftdepotURL = "https://vibsdepot.v-front.de/"

# Function to update/add VIB package
function AddVIB2Profile($vib) {
    $AddVersion = $vib.Version
    $ExVersion = ($MyProfile.VibList | where { $_.Name -eq $vib.Name }).Version
    if ($AccLevel[$vib.AcceptanceLevel.ToString()] -gt $AccLevel[$MyProfile.AcceptanceLevel.ToString()]) {
        write-host -ForegroundColor Yellow -nonewline (" [New AcceptanceLevel: " + $vib.AcceptanceLevel + "]")
        $MyProfile.AcceptanceLevel = $vib.AcceptanceLevel
    }
    If ($MyProfile.VibList -contains $vib) {
        write-host -ForegroundColor Yellow " [IGNORED, already added]"
    } else {
        Add-EsxSoftwarePackage -SoftwarePackage $vib -Imageprofile $MyProfile -force -ErrorAction SilentlyContinue | Out-Null 
        if ($?) {
            if ($ExVersion -eq $null) {
                write-host -ForegroundColor Green " [OK, added]"
            } else {
                write-host -ForegroundColor Yellow (" [OK, replaced " + $ExVersion + "]")
            }
        } else {
            write-host -ForegroundColor Red " [FAILED, invalid package?]"
        }
    }
}

# Function to test if entered string is numeric
function isNumeric ($x) {
    $x2 = 0
    $isNum = [System.Int32]::TryParse($x, [ref]$x2)
    return $isNum
}

# Clean-up function
function cleanup() {
    Stop-Transcript | Out-Null
    if ($DefaultSoftwaredepots) { Remove-EsxSoftwaredepot $DefaultSoftwaredepots }
}

# Write info and help if requested
write-host ("`nThis is " + $ScriptName + " Version " + $ScriptVersion + " (visit " + $ScriptURL + " for more information!)")
if ($help) {
    write-host "`nUsage:"
    write-host "   ESXi-Customizer-PS [-help] | [-izip <bundle> [-update]] [-sip] [-v67|-v65|-v60|-v55|-v51|-v50]"
    write-host "                                [-ozip] [-pkgDir <dir>] [-outDir <dir>] [-vft] [-dpt depot1[,...]]"
    write-host "                                [-load vib1[,...]] [-remove vib1[,...]] [-log <file>] [-ipname <name>]"
	write-host "                                [-ipdesc <desc>] [-ipvendor <vendor>] [-nsc] [-test]"
    write-host "`nOptional parameters:"
    write-host "   -help              : display this help"
    write-host "   -izip <bundle>     : use the VMware Offline bundle <bundle> as input instead of the Online depot"
    write-host "   -update            : only with -izip, updates a local bundle with an ESXi patch from the VMware Online depot,"
    write-host "                        combine this with the matching ESXi version selection switch"
    write-host "   -pkgDir <dir>      : local directory of Offline bundles and/or VIB files to add (if any, no default)"
    write-host "   -ozip              : output an Offline bundle instead of an installation ISO"
    write-host "   -outDir <dir>      : directory to store the customized ISO or Offline bundle (the default is the"
    write-host "                        script directory. If specified the log file will also be moved here.)"
    write-host "   -vft               : connect the V-Front Online depot"
	write-host "   -dpt depot1[,...]  : connect additional Online depots by URL or local Offline bundles by file name"
    write-host "   -load vib1[,...]   : load additional packages from connected depots or Offline bundles"
    write-host "   -remove vib1[,...] : remove named VIB packages from the custom Imageprofile"
    write-host "   -sip               : select an Imageprofile from the current list"
    write-host "                        (default = auto-select latest available standard profile)"
    write-host "   -v70 |"
    write-host "   -v67 | -v65 | -v60 |"
    write-host "   -v55 | -v51 | -v50 : Use only ESXi 7.0/6.7/6.5/6.0/5.5/5.1/5.0 Imageprofiles as input, ignore other versions"
    write-host "   -nsc               : use -NoSignatureCheck with export"
    write-host "   -log <file>        : Use custom log file <file>"
    write-host "   -ipname <name>"
    write-host "   -ipdesc <desc>"
    write-host "   -ipvendor <vendor> : provide a name, description and/or vendor for the customized"
    write-host "                        Imageprofile (the default is derived from the cloned input Imageprofile)"
    write-host "   -test              : skip package download and image build (for testing)`n"
    exit
} else {
    write-host "(Call with -help for instructions)"
    if (!($PSBoundParameters.ContainsKey('log')) -and $PSBoundParameters.ContainsKey('outDir')) {
        write-host ("`nTemporarily logging to " + $log + " ...")
    } else {
        write-host ("`nLogging to " + $log + " ...")
    }
    # Stop active transcript
    try { Stop-Transcript | out-null } catch {}
    # Start own transcript
    try { Start-Transcript -Path $log -Force -Confirm:$false | Out-Null } catch {
        write-host -ForegroundColor Red "`nFATAL ERROR: Log file cannot be opened. Bad file path or missing permission?`n"
        exit
    }
}

# The main try ...

$isModule = @{}
try {

# Check for and load required modules/snapins
foreach ($comp in "VMware.VimAutomation.Core", "VMware.ImageBuilder") {
    if (Get-Module -ListAvailable -Name $comp -ErrorAction:SilentlyContinue) {
		$isModule[$comp] = $true
        if (!(Get-Module -Name $comp -ErrorAction:SilentlyContinue)) {
            if (!(Import-Module -PassThru -Name $comp -ErrorAction:SilentlyContinue)) {
                write-host -ForegroundColor Red "`nFATAL ERROR: Failed to import the $comp module!`n"
                exit
            }
        }
    } else {
		$isModule[$comp] = $false
        if (Get-PSSnapin -Registered -Name $comp -ErrorAction:SilentlyContinue) {
            if (!(Get-PSSnapin -Name $comp -ErrorAction:SilentlyContinue)) {
                if (!(Add-PSSnapin -PassThru -Name $comp -ErrorAction:SilentlyContinue)) {
                    write-host -ForegroundColor Red "`nFATAL ERROR: Failed to add the $comp snapin!`n"
                    exit
                }
            }
        } else {
            write-host -ForegroundColor Red "`nFATAL ERROR: $comp is not available as a module or snapin! It looks like there is no compatible version of PowerCLI installed!`n"
            exit
        }
    }
}

# Parameter sanity check
if ( ($v50 -and ($v51 -or $v55 -or $v60 -or $v65 -or $v67 -or $v70)) -or ($v51 -and ($v55 -or $v60 -or $v65 -or $v67 -or $v70)) -or ($v55 -and ($v60 -or $v65 -or $v67 -or $v70)) -or ($v60 -and ($v65 -or $v67 -or $v70)) -or ($v65 -and $v67 -or $v70) ) {
    write-host -ForegroundColor Yellow "`nWARNING: Multiple ESXi versions specified. Highest version will take precedence!"
}
if ($update -and ($izip -eq "")) {
    write-host -ForegroundColor Red "`nFATAL ERROR: -update requires -izip!`n"
    exit
}

# Check PowerShell and PowerCLI version
if (!(Test-Path variable:PSVersionTable)) {
    write-host -ForegroundColor Red "`nFATAL ERROR: This script requires at least PowerShell version 2.0!`n"
    exit
}
$psv = $PSVersionTable.PSVersion | select Major,Minor

if ($isModule["VMware.VimAutomation.Core"]) {
	$pcvm = (get-module "VMware.VimAutomation.Core").Version
	write-host ("`nRunning with PowerShell version " + $psv.Major + "." + $psv.Minor + " and VMware PowerCLI version " + $pcvm)
} else {
	$pcv = Get-PowerCLIVersion | select major,minor,UserFriendlyVersion
	write-host ("`nRunning with PowerShell version " + $psv.Major + "." + $psv.Minor + " and " + $pcv.UserFriendlyVersion)
	if ( ($pcv.major -lt 5) -or (($pcv.major -eq 5) -and ($pcv.minor -eq 0)) ) {
		write-host -ForegroundColor Red "`nFATAL ERROR: This script requires at least PowerCLI version 5.1 !`n"
		exit
	}
}

if ($update) {
    # Try to add Offline bundle specified by -izip
    write-host -nonewline "`nAdding Base Offline bundle $izip (to be updated)..."
    if ($upddepot = Add-EsxSoftwaredepot $izip) {
        write-host -ForegroundColor Green " [OK]"
    } else {
        write-host -ForegroundColor Red "`nFATAL ERROR: Cannot add Base Offline bundle!`n"
        exit
    }
    if (!($CloneIP = Get-EsxImageprofile -Softwaredepot $upddepot)) {
        write-host -ForegroundColor Red "`nFATAL ERROR: No Imageprofiles found in Base Offline bundle!`n"
        exit
    }
    if ($CloneIP -is [system.array]) {
        # Input Offline bundle includes multiple Imageprofiles. Pick only the latest standard profile:
        write-host -ForegroundColor Yellow "Warning: Input Offline Bundle contains multiple Imageprofiles. Will pick the latest standard profile!"
        $CloneIP = @( $CloneIP | Sort-Object -Descending -Property @{Expression={$_.Name.Substring(0,10)}},@{Expression={$_.CreationTime.Date}},Name )[0]
    }
}

if (($izip -eq "") -or $update) {
    # Connect the VMware ESXi base depot
    write-host -nonewline "`nConnecting the VMware ESXi Online depot ..."
    if ($basedepot = Add-EsxSoftwaredepot $vmwdepotURL) {
        write-host -ForegroundColor Green " [OK]"
    } else {
        write-host -ForegroundColor Red "`nFATAL ERROR: Cannot add VMware ESXi Online depot. Please check your Internet connectivity and/or proxy settings!`n"
        exit
    }
} else {
    # Try to add Offline bundle specified by -izip
    write-host -nonewline "`nAdding base Offline bundle $izip ..."
    if ($basedepot = Add-EsxSoftwaredepot $izip) {
        write-host -ForegroundColor Green " [OK]"
    } else {
        write-host -ForegroundColor Red "`nFATAL ERROR: Cannot add VMware base Offline bundle!`n"
        exit
    }
}

if ($vft) {
    # Connect the V-Front Online depot
    write-host -nonewline "`nConnecting the V-Front Online depot ..."
    if ($vftdepot = Add-EsxSoftwaredepot $vftdepotURL) {
        write-host -ForegroundColor Green " [OK]"
    } else {
        write-host -ForegroundColor Red "`nFATAL ERROR: Cannot add the V-Front Online depot. Please check your internet connectivity and/or proxy settings!`n"
        exit
    }
}

if ($dpt -ne @()) {
	# Connect additional depots (Online depot or Offline bundle)
	$AddDpt = @()
	for ($i=0; $i -lt $dpt.Length; $i++ ) {
		write-host -nonewline ("`nConnecting additional depot " + $dpt[$i] + " ...")
		if ($AddDpt += Add-EsxSoftwaredepot $dpt[$i]) {
			write-host -ForegroundColor Green " [OK]"
		} else {
			write-host -ForegroundColor Red "`nFATAL ERROR: Cannot add Online depot or Offline bundle. In case of Online depot check your Internet"
            write-host -ForegroundColor Red "connectivity and/or proxy settings! In case of Offline bundle check file name, format and permissions!`n"
			exit
		}
	}

}

write-host -NoNewLine "`nGetting Imageprofiles, please wait ..."
$iplist = @()
if ($iZip -and !($update)) {
    Get-EsxImageprofile -Softwaredepot $basedepot | foreach { $iplist += $_ }
} else {
	if ($v70) {
		Get-EsxImageprofile "ESXi-7.0*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
	} else {
	if ($v67) {
		Get-EsxImageprofile "ESXi-6.7*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
	} else {
		if ($v65) {
			Get-EsxImageprofile "ESXi-6.5*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
		} else {
			if ($v60) {
				Get-EsxImageprofile "ESXi-6.0*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
			} else {
				if ($v55) {
					Get-EsxImageprofile "ESXi-5.5*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
				} else {
					if ($v51) {
						Get-EsxImageprofile "ESXi-5.1*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
					} else {
						if ($v50) {
							Get-EsxImageprofile "ESXi-5.0*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
						} else {
							# Workaround for http://kb.vmware.com/kb/2089217
							Get-EsxImageprofile "ESXi-5.0*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
							Get-EsxImageprofile "ESXi-5.1*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
							Get-EsxImageprofile "ESXi-5.5*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
							Get-EsxImageprofile "ESXi-6.0*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
							Get-EsxImageprofile "ESXi-6.5*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
							Get-EsxImageprofile "ESXi-6.7*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
							Get-EsxImageprofile "ESXi-7.0*" -Softwaredepot $basedepot | foreach { $iplist += $_ }
						}
					}
				}
			}
		}
	}
}
}

if ($iplist.Length -eq 0) {
    write-host -ForegroundColor Red " [FAILED]`n`nFATAL ERROR: No valid Imageprofile(s) found!"
    if ($iZip) {
        write-host -ForegroundColor Red "The input file is probably not a full ESXi base bundle.`n"
    }
    exit
} else {
    write-host -ForegroundColor Green " [OK]"
    $iplist = @( $iplist | Sort-Object -Descending -Property @{Expression={$_.Name.Substring(0,10)}},@{Expression={$_.CreationTime.Date}},Name )
}

# if -sip then display menu of available image profiles ...
if ($sip) {
    if ($update) {
        write-host "`nSelect Imageprofile to use for update:"
    } else {
        write-host "`nSelect Base Imageprofile:"
    }
    write-host "-------------------------------------------"
    for ($i=0; $i -lt $iplist.Length; $i++ ) {
        write-host ($i+1): $iplist[$i].Name
    }
    write-host "-------------------------------------------"
    do {
        $sel = read-host "Enter selection"
        if (isNumeric $sel) {
            if (([int]$sel -lt 1) -or ([int]$sel -gt $iplist.Length)) { $sel = $null }
        } else {
            $sel = $null
        }
    } until ($sel)
    $idx = [int]$sel-1
} else {
    $idx = 0
}
if ($update) {
    $updIP = $iplist[$idx]
} else {
    $CloneIP = $iplist[$idx]
}

write-host ("`nUsing Imageprofile " + $CloneIP.Name + " ...")
write-host ("(dated " + $CloneIP.CreationTime + ", AcceptanceLevel: " + $CloneIP.AcceptanceLevel + ",")
write-host ($CloneIP.Description + ")")

# If customization is required ...
if ( ($pkgDir -ne "") -or $update -or ($load -ne @()) -or ($remove -ne @()) ) {

    # Create your own Imageprofile
    if ($ipname -eq "") { $ipname = $CloneIP.Name + "-customized" }
    if ($ipvendor -eq "") { $ipvendor = $CloneIP.Vendor }
    if ($ipdesc -eq "") { $ipdesc = $CloneIP.Description + " (customized)" }
    $MyProfile = New-EsxImageprofile -CloneProfile $CloneIP -Vendor $ipvendor -Name $ipname -Description $ipdesc

    # Update from Online depot profile
    if ($update) {
        write-host ("`nUpdating with the VMware Imageprofile " + $UpdIP.Name + " ...")
        write-host ("(dated " + $UpdIP.CreationTime + ", AcceptanceLevel: " + $UpdIP.AcceptanceLevel + ",")
        write-host ($UpdIP.Description + ")")
        $diff = Compare-EsxImageprofile $MyProfile $UpdIP
        $diff.UpgradeFromRef | foreach {
            $uguid = $_
            $uvib = Get-EsxSoftwarePackage | where { $_.Guid -eq $uguid }
            write-host -nonewline "   Add VIB" $uvib.Name $uvib.Version
            AddVIB2Profile $uvib
        }
    }

    # Loop over Offline bundles and VIB files
    if ($pkgDir -ne "") {
        write-host "`nLoading Offline bundles and VIB files from" $pkgDir ...
        foreach ($obundle in Get-Item $pkgDir\*.zip) {
            write-host -nonewline "   Loading" $obundle ...
            if ($ob = Add-EsxSoftwaredepot $obundle -ErrorAction SilentlyContinue) {
                write-host -ForegroundColor Green " [OK]"
                $ob | Get-EsxSoftwarePackage | foreach {
                    write-host -nonewline "      Add VIB" $_.Name $_.Version
                    AddVIB2Profile $_
                }
            } else {
                write-host -ForegroundColor Red " [FAILED]`n      Probably not a valid Offline bundle, ignoring."
            }
        }
        foreach ($vibFile in Get-Item $pkgDir\*.vib) {
            write-host -nonewline "   Loading" $vibFile ...
            try {
                $vib1 = Get-EsxSoftwarePackage -PackageUrl $vibFile -ErrorAction SilentlyContinue
                write-host -ForegroundColor Green " [OK]"
                write-host -nonewline "      Add VIB" $vib1.Name $vib1.Version
                AddVIB2Profile $vib1
            } catch {
                write-host -ForegroundColor Red " [FAILED]`n      Probably not a valid VIB file, ignoring."
            }
        }
    }
    # Load additional packages from Online depots or Offline bundles
    if ($load -ne @()) {
        write-host "`nLoad additional VIBs from Online depots ..."
        for ($i=0; $i -lt $load.Length; $i++ ) {
            if ($ovib = Get-ESXSoftwarePackage $load[$i] -Newest) {
                write-host -nonewline "   Add VIB" $ovib.Name $ovib.Version
                AddVIB2Profile $ovib
            } else {
                write-host -ForegroundColor Red "   [ERROR] Cannot find VIB named" $load[$i] "!"
            }
        }
    }
    # Remove selected VIBs
    if ($remove -ne @()) {
        write-host "`nRemove selected VIBs from Imageprofile ..."
        for ($i=0; $i -lt $remove.Length; $i++ ) {
            write-host -nonewline "      Remove VIB" $remove[$i]
            try {
                Remove-EsxSoftwarePackage -ImageProfile $MyProfile -SoftwarePackage $remove[$i] | Out-Null
                write-host -ForegroundColor Green " [OK]"
            } catch {
                write-host -ForegroundColor Red " [FAILED]`n      VIB does probably not exist or cannot be removed without breaking dependencies."
            }
        }
    }

} else {
    $MyProfile = $CloneIP
}


# Build the export command:
$cmd = "Export-EsxImageprofile -Imageprofile " + "`'" + $MyProfile.Name + "`'"

if ($ozip) {
    $outFile = "`'" + $outDir + "\" + $MyProfile.Name + ".zip" + "`'"
    $cmd = $cmd + " -ExportTobundle"
} else {
    $outFile = "`'" + $outDir + "\" + $MyProfile.Name + ".iso" + "`'"
    $cmd = $cmd + " -ExportToISO"
}
$cmd = $cmd + " -FilePath " + $outFile
if ($nsc) { $cmd = $cmd + " -NoSignatureCheck" }
$cmd = $cmd + " -Force"

# Run the export:
write-host -nonewline ("`nExporting the Imageprofile to " + $outFile + ". Please be patient ...")
if ($test) {
    write-host -ForegroundColor Yellow " [Skipped]"
} else {
    write-host "`n"
    Invoke-Expression $cmd
}

write-host -ForegroundColor Green "`nAll done.`n"

# The main catch ...
} catch {
    write-host -ForegroundColor Red ("`n`nAn unexpected error occured:`n" + $Error[0])
    write-host -ForegroundColor Red ("`nIf requesting support please be sure to include the log file`n   " + $log + "`n`n")

# The main cleanup
} finally {
    cleanup
    if (!($PSBoundParameters.ContainsKey('log')) -and $PSBoundParameters.ContainsKey('outDir')) {
        $finalLog = ($outDir + "\" + $MyProfile.Name + "-" + (get-date -Format yyyyMMddHHmm) + ".log")
        Move-Item $log $finalLog -force
        write-host ("(Log file moved to " + $finalLog + ")`n")
    }
}
```
~~とりあえずは vSPhere 7.0 U1b までは問題なく使えています。~~ESXi-Customizer-PS の使い方は、[vSphere ESXi customize image のつくりかた（vSphere 7 が来る前の準備）](https://qiita.com/inasato/items/62396114feeaffc7b3e2) を見てください。ここに記載してあるオプションの -v67 を -v70 にするだけで vSphere Hypervisor (ESXi) 7 のカスタムイメージができます。

# カスタムイメージを作る際の留意点
カスタムイメージを作る際に取り込むネイティブドライバによっては Customizer-PS-v2.6.0-vS7.ps1 で直接 ISO イメージを作成できない場合があります。この場合は -ozip を指定して一度 ZIP に書き出し、その後同じ Customizer-PS-v2.6.0-vS7.ps1 で -izip を指定して ZIP イメージを取り込んで ISO にします。このやり方も[vSphere ESXi customize image のつくりかた（vSphere 7 が来る前の準備）](https://qiita.com/inasato/items/62396114feeaffc7b3e2) に書いてあります。

# iso イメージを USB 媒体に書き込む
出来上がった iso イメージを イメージに書き出せない場合があります。CD に焼いて使うこともできますが、ここはスマートに USB メモリーに書き出して USB からインストールしたいですよね。それには Rufus というツールを使います。これも[vSphere ESXi customize image のつくりかた（vSphere 7 が来る前の準備）](https://qiita.com/inasato/items/62396114feeaffc7b3e2) に書きました。

# VMKLinux が消えた後に使えなくなっているデバイスは
VMKLinux を使って開発されている Realtek のオンボード NIC が全滅します。今の所 USB NIC の Realtek デバイスは、VMware の [flings](https://flings.vmware.com/) で提供されている [USB Network Native Driver for ESXi](https://flings.vmware.com/usb-network-native-driver-for-esxi)にあるネイティブドライバを使えば動作しますので、オンボードは諦めて、とりあえず USB NIC ｗ調達するのが速いです。
動作確認が取れているのは、
* [StarTech.com USB 3.0 -2ポートギガビットイーサネットLANアダプタ USBポート付き USB32000SPT](https://www.amazon.co.jp/gp/product/B00D8XTOD0/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
* [Anker アルミニウムユニボディハブ LANアダプター USB 3.0 RJ45 ギガビットイーサネットアダプタ 10/100/1000 Mbps](https://www.amazon.co.jp/gp/product/B013JDE2HG/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)
* [Anker PowerExpand+ 7-in-1 USB-C PD イーサネット ハブ](https://www.amazon.co.jp/gp/product/B07RRWZHL6/ref=ppx_yo_dt_b_asin_title_o02_s02?ie=UTF8&psc=1)
* [Anker PowerExpand 8-in-1 USB-C PD メディア ハブ ](https://www.amazon.co.jp/gp/product/B0874J3Y9T/ref=ppx_yo_dt_b_asin_title_o01_s00?ie=UTF8&psc=1)
あたりですが、個人的には安定していて 2ポートのLANが取れる[StarTech.com USB 3.0 -2ポートギガビットイーサネットLANアダプタ USBポート付き USB32000SPT](https://www.amazon.co.jp/gp/product/B00D8XTOD0/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1)がおすすめです。我が家の家ラボでは既に10個使っていますが、1台に2つ使っても安定して動いています。

我が家の家ラボでは Intel NUC 7i7 / 7i5(Intel Core i5 / i7)、ASUS ミニPC PN50-BBR026MD (AMD Ryzen R5 4500U)、謎メーカーの ACEPC CK2 (Core i5-7200U) で vSphere Hypervisor (ESXi) 7 を動かしています。NIC 増設はもちろん[StarTech.com の USB32000SPT](https://www.amazon.co.jp/gp/product/B00D8XTOD0/ref=ppx_yo_dt_b_search_asin_title?ie=UTF8&psc=1) を使っています。カスタムイメージを作ればこのくらい柔軟に vSphere 7 環境を作れるのでお勧めです。

# DDR4 の NUC の最大メモリー
我が家の家ラボは 第7世代の NUC で vSphere 環境を作っています。その前は DDR3L の第5世代と第6世代の NUC で環境を作っていたのですが、実際に搭載できるメモリー容量は NUC の仕様というより CPU 他の仕様で確認するのが大切です。
つまり、DDR3 / DDR3L メモリーのマシンであれば、最大 32GBのメモリーを搭載できます。そして、DDR4 メモリーのマシンであれば、仕様的には 128GB のメモリーを載せられるのですが、今市場に出回っているノート PC 用メモリーは 1枚 32GBが最大、ということで NUC は 64GB のメモリーを搭載して運用しています。もちろん Ryzen R5 のマシンも 64GB、QNAP TS-473 も 64GB メモリーを搭載して仮想環境を動かしています。メモリーが不足気味と感じているのであれば「どこまで載りそう？」を調べてチャレンジしてみるのもよいかもしれません。