SDServers.psm1

Function Set-SDIMCBootOrder {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [String]
        $imcip
    )
    
    $result = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body "<aaaLogin inName='admin' inPassword='12qwaszx!@QWASZX'></aaaLogin>"

    $cookie = $result.aaaLogin.outCookie

    $getstatus = '<configResolveClass cookie="' + $cookie + '" inHierarchical="false" classId="computeRackUnit"/>'
    $getStatusResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $getstatus

    # Remove any existing advanced boot order
    # Define clear text string for username and password
    [string]$userName = 'admin'
    [string]$userPassword = '12qwaszx!@QWASZX'

    # Convert to SecureString
    [securestring]$secStringPassword = ConvertTo-SecureString $userPassword -AsPlainText -Force
    [pscredential]$imccred = New-Object System.Management.Automation.PSCredential ($userName, $secStringPassword)


    Import-module Cisco.IMC
    Connect-IMC $imcip -Credential $imccred
    Get-ImcLsbootDevPrecision -Hierarchy | Where-Object { $_.order } | Remove-ImcManagedObject -force
    Disconnect-IMC

    #Get the MAC of the MLOM port 1
    $getLAN1Mac = '<configResolveClass cookie="' + $cookie + '" inHierarchical="true" classId="networkAdapterEthIf"/>'
    $getLAN1MacResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $getLAN1Mac

    $mac1 = $getLAN1MacResults.configResolveClass.outConfigs.networkAdapterEthIf |  Where-Object -Property Dn -Match "^sys/rack-unit-1/network-adapter-L/eth-1" | Select-Object -ExpandProperty Mac

    #SET new Boot order

    $request1 = '<configConfMo cookie="' + $cookie + '" inHierarchical="false" dn="sys/rack-unit-1/boot-precision/hdd-VMware_ESXi"> <inConfig> <lsbootHdd dn="sys/rack-unit-1/boot-precision/hdd-VMware_ESXi" name="VMware_ESXi" type="LOCALHDD" slot="MSTOR-RAID" order="1" state="Enabled"/> </inConfig> </configConfMo>'
    $request2 = '<configConfMo cookie="' + $cookie + '" inHierarchical="false" dn="sys/rack-unit-1/boot-precision/http-cobp1"> <inConfig> <lsbootHttp dn="sys/rack-unit-1/boot-precision/http-cobp1" type="HTTP" macAddress="' + $mac1 + '" iptype="IPv4" slot="L" port="1" order="2" state="Enabled" ipConfigType="DHCP"/> </inConfig> </configConfMo>'

    Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $request1
    Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $request2


    $getstatus = '<configResolveClass cookie="' + $cookie + '" inHierarchical="false" classId="computeRackUnit"/>'
    $getStatusResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $getstatus

    $powerState = $getStatusResults.configResolveClass.outConfigs.computeRackUnit.operPower
    if ($powerState -eq "off") {
        $poweron = '<configConfMo cookie="' + $cookie + '" inHierarchical="false" dn="sys/rack-unit-1" ><inConfig><computeRackUnit adminPower="up" dn="sys/rack-unit-1"/></inConfig></configConfMo>'
        Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $poweron
    }
    elseif ($powerState -eq "on") {
        $powerCycle = '<configConfMo cookie="' + $cookie + '" inHierarchical="false" dn="sys/rack-unit-1" ><inConfig><computeRackUnit adminPower="hard-reset-immediate" dn="sys/rack-unit-1"/></inConfig></configConfMo>'
        Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $powerCycle
    }
}
Function Set-SDIMCInterface {

    #Change the Cisco IMC from Dedicated to Shared_LOM and set redundancy to active active
    Get-ImcMgmtIf -Imc $imchandle | Set-ImcMgmtIf -NicMode shared_lom -NicRedundancy active-active -VlanEnable yes -VlanId 997 -Xml -Force
    Start-Sleep -Seconds 120
}
Function Set-SDIMCSetup {

    [CmdletBinding()]
    param (
        #ESXi IP
        [Parameter(Mandatory = $true)]
        [String]
        $imcip
    )
    Write-Host "Attempting to Access IMC API at $imcip"
    $result = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body "<aaaLogin inName='admin' inPassword='password'></aaaLogin>"

    if ($result.aaaLogin.response -eq "yes") {
        Write-Host "Login Sucessful at $imcip"
        $cookie = $result.aaaLogin.outCookie
    }

    #Changeing password
    Write-Host "Changing password"
    $passwordChange = "<configConfMo cookie='$cookie' inHierarchical='false' dn='sys/user-ext/user-1'><inConfig><aaaUser id='1' name='admin' priv='admin' pwd='12qwaszx!@QWASZX' dn='sys/user-ext/user-1'/></inConfig></configConfMo>"
    $passwordChangeResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $passwordChange

    Write-Host "Attempting to Access IMC API at $imcip with new password"
    $result = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body "<aaaLogin inName='admin' inPassword='12qwaszx!@QWASZX'></aaaLogin>"

    if ($result.aaaLogin.response -eq "yes") {
        Write-Host "Login Sucessful at $imcip"
        $cookie = $result.aaaLogin.outCookie
    }

    #Power on Server for Boot
    $getstatus = '<configResolveClass cookie="' + $cookie + '" inHierarchical="false" classId="computeRackUnit"/>'
    $getStatusResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $getstatus

    if ($getStatusResults.configResolveClass.outConfigs.computeRackUnit.operPower -eq "off") {
        Write-Host "Powering on $imcip"
        $poweron = '<configConfMo cookie="' + $cookie + '" inHierarchical="false" dn="sys/rack-unit-1" ><inConfig><computeRackUnit adminPower="up" dn="sys/rack-unit-1"/></inConfig></configConfMo>'
        $poweronResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $poweron

        if ($poweronResults.configConfMo.outConfig.computeRackUnit.status -eq "modified") {
            Write-Host "Powering on of server $imcip Sucessful"
        }

    }

    # Start loop to check if server is booted
    do {

        Write-Host "Waiting for server to complete BIOS Post"
        Write-Host "Sleeping for 30 seconds"
        Start-Sleep -Seconds 30
        $getStatusResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $getstatus
        $biosPostState = $getStatusResults.configResolveClass.outConfigs.computeRackUnit.biosPostState

    }until ($biosPostState -match "complete")

    Write-Host "BIOS Post complete"

    #Wait 30 Seconds
    Start-Sleep -Seconds 15

    Write-Host "Getting Local Drives through API for RAID Array"
    #Get Local Disks that are in the M2 Slot
    $getLocalHdd = '<configResolveClass cookie="' + $cookie + '" inHierarchical="false" classId="pidCatalogHdd"/>'
    $localHddResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $getLocalHdd
    $localHdd = $localHddResults.configResolveClass.outConfigs.pidCatalogHdd

    $localDisks = @()

    foreach ($hdd in $localHdd) {
        $localDisks += $hdd | Where-Object -Property "pid" -like "UCS-M2-240GB" | Select-Object -ExpandProperty disk
    }

    Write-Host "Creating Virtual Drive Group for Raid Array and creating Raid Array"
    #Set Var for Virtual Disk Creation
    $driveGroup = "[" + $localDisks[0] + "," + $localDisks[1] + "]"
    $driveCreate = '<configConfMo cookie="' + $cookie + '" inHierarchical="false" dn="sys/rack-unit-1/board/storage-MSTOR-RAID/virtual-drive-create"><inConfig><storageVirtualDriveCreatorUsingUnusedPhysicalDrive virtualDriveName="VD_BOOT" raidLevel="1" driveGroup="' + $driveGroup + '" stripSize="64k" adminState="trigger"/></inConfig></configConfMo>'

    #Create Raid array for the VMware ESXi
    $driveCreateResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $driveCreate

    if ( $driveCreateResults.configConfMo.outConfig.storageVirtualDriveCreatorUsingUnusedPhysicalDrive.status -eq "modified") {
        Write-Host "Sucessfully created RAID Array on $imcip"
    }


    Write-Host "Enableing Secure Boot on $imcip"
    #API Request for Enabling Secureboot
    $secureBootEnable = "<configConfMo cookie='$cookie' inHierarchical='true'><inConfig><lsbootBootSecurity dn='sys/rack-unit-1/boot-policy/boot-security' secureBoot='enable'/></inConfig></configConfMo>"
    $secureBootEnableResults = Invoke-RestMethod -Method Post -SkipCertificateCheck -Uri "https://$imcip/nuova" -Body $secureBootEnable

    if ($secureBootEnableResults.configConfMo.outConfig.lsbootBootSecurity.status -eq "modified") {
        Write-Host "Enableing Secure Boot on $imcip : Successful"
    }
}
Function Set-SDVCenterSettings {

    $site = $config.config.SiteNumber
    $siteNumberIP = (Set-SiteIPFormat -site $site)

    #Connect to vCenter Server for Site
    Connect-VIServer -Server "10.$siteNumberIP.4.200" -User 'administrator@vsphere.local' -Password '12qwaszx!@QWASZX' -Force

    #Get datacenter form vCenter
    $VMDataCenter = Get-Datacenter -Name "$site"

    #Create new Virtual Distributed Switch
    New-VDSwitch -Name "$site-VDS-001" -Location $VMDataCenter -LinkDiscoveryProtocol "LLDP" -LinkDiscoveryProtocolOperation "Both" -MaxPorts 256 -NumUplinkPorts 2 -Mtu 9000

    #Create VLANS on VDS-001 switch
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v30.$site`-usr-tr" -NumPorts 8 -VLanId 30
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v31.$site`-srv-tr" -NumPorts 8 -VLanId 31
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v32.$site`-net-mgt" -NumPorts 8 -VLanId 32
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v33.$site`-pawt0-tr" -NumPorts 8 -VLanId 33
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v34.$site`-pawt1-tr" -NumPorts 8 -VLanId 34
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v40.$site`-ia-tr" -NumPorts 8 -VLanId 40
    Get-VDSwitch -Name "$site-VDS-001" | New-VDPortgroup -Name "v998.$site`-net-mgt" -NumPorts 8 -VLanId 998
    Get-VDSwitch -Name "$site-VDS-002" | New-VDPortgroup -Name "v3001.$site`-vsan-tr" -NumPorts 8 -VLanId 3001
    Get-VDSwitch -Name "$site-VDS-002" | New-VDPortgroup -Name "v3002.$site`-vmotion-tr" -NumPorts 8 -VLanId 3002
}
Function Add-SDVMHost {
    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [String]
        $esxiip,
        [Parameter(Mandatory = $true)]
        [Bollean]
        $witnessHost
    )
    <#
        This Function connects to the vcenter server and then added the host to thew vSAN cluster if it is not a witness.
        Following this it then Adds the disks for vSAN into a disk group
    #>

    $site = $config.config.SiteNumber
    $siteNumberIP = (Set-SiteIPFormat -site $site)

    #Connect to vCenter Server for Site
    Connect-VIServer -Server "10.$siteNumberIP.4.200" -User 'administrator@vsphere.local' -Password '12qwaszx!@QWASZX' -Force
    if ($witnessHost -eq $false) {
        $vmcluster = Get-Cluster
        Add-VMHost -Location $vmcluster -Name $esxiip -User root -Password '12qwaszx!@QWASZX' -Force

        Disconnect-VIServer * -Confirm:$false
    
        Connect-VIServer -Server $esxiIP -Protocol https -User root -Password '12qwaszx!@QWASZX' -Force
    
        $capacityDisks = Get-VMHost | Get-ScsiLun | Where-Object -Property Model -EQ "INTEL SSDPF2KX03" | Select-Object -ExpandProperty CanonicalName
        $cacheDisks = Get-VMHost | Get-ScsiLun | Where-Object -Property Model -EQ "INTEL SSDPF2KX01" | Select-Object -ExpandProperty CanonicalName
    
        Disconnect-VIServer * -Confirm:$false
        Connect-VIServer -Server "10.$siteNumberIP.4.200" -Protocol https -User "Administrator@vsphere.local"-Password '12qwaszx!@QWASZX' -Force
    
        New-VsanDiskGroup -VMHost $esxiip -SsdCanonicalName $cacheDisks -DataDiskCanonicalName $capacityDisks
    
        Disconnect-VIServer * -Confirm:$false
    }
    elseif ($witnessHost -eq $true) {
        $dc = Get-Datacenter
        Add-VMHost -Location $dc -Name $esxiip -User root -Password '12qwaszx!@QWASZX' -Force
        Disconnect-VIServer * -Confirm:$false
    }
}
Function Set-SDVMHSettings {

    [CmdletBinding()]
    param (
        [Parameter(Mandatory = $true)]
        [String]
        $esxiip
    )

    $site = $config.config.SiteNumber
    $siteNumberIP = (Set-SiteIPFormat -site $site)

    #Connect to vCenter Server for Site
    Connect-VIServer -Server "10.$siteNumberIP.4.200" -User 'administrator@vsphere.local' -Password '12qwaszx!@QWASZX' -Force

    #Get NICs for VDS-001
    $vmhostNetworkAdapter1 = Get-VMHost $esxiip | Get-VMHostNetworkAdapter -Physical -Name vmnic2
    $vmhostNetworkAdapter2 = Get-VMHost $esxiip | Get-VMHostNetworkAdapter -Physical -Name vmnic3
    $vmhostNetworkAdapter3 = Get-VMHost $esxiip | Get-VMHostNetworkAdapter -Physical -Name vmnic4
    $vmhostNetworkAdapter4 = Get-VMHost $esxiip | Get-VMHostNetworkAdapter -Physical -Name vmnic5

    #Add Host to VDS-001
    Get-VDSwitch -Name "$site-VDS-001" | Add-VDSwitchVMHost -VMHost $esxiip -confirm:$False

    #Add Nics from the servers to the VDS-001
    Get-VDSwitch "$site-VDS-001" | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmhostNetworkAdapter1 -confirm:$False
    Get-VDSwitch "$site-VDS-001" | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmhostNetworkAdapter2 -confirm:$False
    Get-VDSwitch "$site-VDS-001" | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmhostNetworkAdapter3 -confirm:$False
    Get-VDSwitch "$site-VDS-001" | Add-VDSwitchPhysicalNetworkAdapter -VMHostPhysicalNic $vmhostNetworkAdapter4 -confirm:$False

    $esxiip -match ".\d+$"
    $esxiipLastOctect = $Matches[0]
    $esxiipLastOctect = $esxiipLastOctect.Replace(".", "")

    #Create VMDK for vmotion on VDS-001
    $vds = Get-VDSwitch -Name "$site-VDS-001"
    New-VMHostNetworkAdapter -VirtualSwitch $vds -PortGroup "v3002.$site`-vmotion-tr" -IP "10.$siteNumberIP.6.$esxiipLastOctect" -SubnetMask "255.255.255.0" -mtu 9000 -VMotionEnabled $true -vmhost $esxiip

    #Create VMDK for vSAN on VDS-001
    New-VMHostNetworkAdapter -VirtualSwitch $vds -PortGroup "v3001.$site`-vsan-tr" -IP "10.$siteNumberIP.5.$esxiipLastOctect" -SubnetMask "255.255.255.0" -mtu 9000 -VsanTrafficEnabled $true -VMHost $esxiip

    Disconnect-VIServer * -Confirm:$false

}
Function New-SDVMwareConfig {

    [CmdletBinding()]
    param (
        #VMware IP address
        [Parameter(Mandatory = $True)]
        [String]
        $vmwareIP,
        #Domain Name
        [Parameter(Mandatory = $True)]
        [String]
        $domainName,
        #Hostname for Virtual Machine Host
        [Parameter(Mandatory = $True)]
        [String]
        $hostname,
        #Site Number in IP Format
        [Parameter(Mandatory = $True)]
        [String]
        $siteNumberIP,
        #Root Password VMware
        [Parameter(Mandatory = $True)]
        [String]
        $rootPw,
        #On Board Port 1 MAC
        [Parameter(Mandatory = $True)]
        [String]
        $hypenMAC
    )

    $siteNumberIP = (Set-SiteIPFormat -site $siteNumberIP)

    [string[]]$vmkickstartconfig = Get-Content $PSScriptRoot\Templates\vmkickstart.txt

    $vmkickstartconfig[3] = $vmkickstartconfig[3].Replace('$vmwareIP', $vmwareIP)
    $vmkickstartconfig[3] = $vmkickstartconfig[3].Replace('$siteNumberIP', $siteNumberIP)
    $vmkickstartconfig[3] = $vmkickstartconfig[3].Replace('$hostname', $hostname)
    $vmkickstartconfig[3] = $vmkickstartconfig[3].Replace('$domainName', $domainName)
    $vmkickstartconfig[4] = $vmkickstartconfig[4].Replace('$rootpw', $rootpw)
    $vmkickstartconfig[23] = $vmkickstartconfig[23].Replace('$siteNumberIP', $siteNumberIP)

    $kickstart = "vmaccepteula
install --firstdisk --overwritevmfs
 
network --bootproto=static --ip=$vmwareIP --netmask=255.255.255.0 --gateway=10.$siteNumberIP.4.1 --hostname=$hostname.$domainName --nameserver=10.$siteNumberIP.8.82,10.$siteNumberIP.8.83 --vlanid=3000
rootpw $rootPw
keyboard 'US Default'
 
reboot
 
%firstboot --interpreter=busybox
 
# enable & start SSH
vim-cmd hostsvc/enable_ssh
vim-cmd hostsvc/start_ssh
 
# enable & start ESXi Shell
vim-cmd hostsvc/enable_esx_shell
vim-cmd hostsvc/start_esx_shell
 
# Suppress ESXi Shell warning
esxcli system settings advanced set -o /UserVars/SuppressShellWarning -i 1
 
# NTP
esxcli system ntp set -s 172.30.0.$siteNumberIP
esxcli system ntp set -e 1
"


    if (!(Test-Path C:\HTTP_Boot\esxi\01-$hypenMAC)) {
        New-Item -Name 01-$hypenMAC -Path C:\HTTP_Boot\esxi\ -ItemType Directory    
    }
    $kickstart | Out-File C:\HTTP_Boot\esxi\01-$hypenMAC\$hypenMAC-ks.cfg

    $ksPath = "http://$global:deployserverIP/esxi/01-$hypenMAC/$hypenMAC-ks.cfg"

    $bootCFG = "bootstate=0
title=Loading ESXi installer
timeout=5
prefix=http://$global:deployserverIP/esxi/7.0.3
kernel=b.b00
kernelopt=ks=$ksPath runweasel
modules=jumpstrt.gz --- useropts.gz --- features.gz --- k.b00 --- uc_intel.b00 --- uc_amd.b00 --- uc_hygon.b00 --- procfs.b00 --- vmx.v00 --- vim.v00 --- tpm.v00 --- sb.v00 --- s.v00 --- ucstoole.v00 --- nenicens.v00 --- nenic.v00 --- nfnic.v00 --- i40en.v00 --- igbn.v00 --- ixgben.v00 --- nmlx5cor.v00 --- nmlx5rdm.v00 --- qcnic.v00 --- qedentv.v00 --- qedf.v00 --- qedi.v00 --- qedrntv.v00 --- qfle3.v00 --- qfle3f.v00 --- qfle3i.v00 --- atlantic.v00 --- bnxtnet.v00 --- bnxtroce.v00 --- brcmfcoe.v00 --- elxiscsi.v00 --- elxnet.v00 --- iavmd.v00 --- icen.v00 --- ionic_en.v00 --- irdman.v00 --- iser.v00 --- lpfc.v00 --- lpnic.v00 --- lsi_mr3.v00 --- lsi_msgp.v00 --- lsi_msgp.v01 --- lsi_msgp.v02 --- mtip32xx.v00 --- ne1000.v00 --- nhpsa.v00 --- nmlx4_co.v00 --- nmlx4_en.v00 --- nmlx4_rd.v00 --- ntg3.v00 --- nvme_pci.v00 --- nvmerdma.v00 --- nvmetcp.v00 --- nvmxnet3.v00 --- nvmxnet3.v01 --- pvscsi.v00 --- qflge.v00 --- rste.v00 --- sfvmk.v00 --- smartpqi.v00 --- vmkata.v00 --- vmkfcoe.v00 --- vmkusb.v00 --- vmw_ahci.v00 --- bmcal.v00 --- crx.v00 --- elx_esx_.v00 --- btldr.v00 --- esx_dvfi.v00 --- esx_ui.v00 --- esxupdt.v00 --- tpmesxup.v00 --- weaselin.v00 --- esxio_co.v00 --- loadesx.v00 --- lsuv2_hp.v00 --- lsuv2_in.v00 --- lsuv2_ls.v00 --- lsuv2_nv.v00 --- lsuv2_oe.v00 --- lsuv2_oe.v01 --- lsuv2_oe.v02 --- lsuv2_sm.v00 --- native_m.v00 --- qlnative.v00 --- trx.v00 --- vdfs.v00 --- vmware_e.v00 --- vsan.v00 --- vsanheal.v00 --- vsanmgmt.v00 --- tools.t00 --- xorg.v00 --- gc.v00 --- imgdb.tgz --- basemisc.tgz --- resvibs.tgz --- imgpayld.tgz
build=7.0.3-0.20.19193900
updated=0"


    $BootCFG | Out-File C:\HTTP_Boot\esxi\01-$hypenMAC\boot.cfg

}
Function New-SDVsanStretchedClusterWitness {
    <#
    .SYNOPSIS
    This function will deploy a Witness for a 2 Node or Stretched vSAN Cluster
    .DESCRIPTION
    This function will deploy a Witness for a 2 Node or Stretched vSAN Cluster
 
    .PARAMETER Cluster
    Specifies the name of the Cluster you want to set the vSAN Witness Host for.
    .PARAMETER Datastore
    Specifies the name of the datastore to use.
    .PARAMETER OVAPath
    Full path and OVA filename for the vSAN Witness Appliance
    .PARAMETER Name
    The Virtual Machine Name of the vSAN Witness Appliance
    .PARAMETER Pass
    The root password of the vSAN Witness Appliance
    .PARAMETER Size
    The deployment size of the vSAN Witness Appliance
    .PARAMETER PG1
    The port group name for the vSAN Witness Appliance management network
    .PARAMETER PG2
    The port group name for the vSAN Witness Appliance WitnessPg network
 
    .EXAMPLE
    PS C:\> New-VsanStretchedClusterWitness -Cluster <Cluster Name> -Datastrre <Datastore name> -OVAPath <c:\path\witness-xxx.ova> -Name <Witness VM Name> -Pass <password for witness> -Size <tiny/normal/large> -PG1 <port group name for Management network> -PG2 <port group name for Witness Network>
     
    #>


    $site = $config.config.SiteNumber
    $siteNumberIP = (Set-SiteIPFormat -site $site)
    $Cluster = $site + "-vSAN"

    # Grab a random host in the cluster to deploy to
    $TargetHost = Get-Cluster $Cluster | Get-VMHost | Where-Object { $_.PowerState -eq "PoweredOn" -and $_.ConnectionState -eq "Connected" } | Get-Random

    # Grab a random datastore
    $TargetDatastore = Get-Datastore -Host $TargetHost | Where-Object -Property Name -Match "^datastore"

    # Grab the OVA properties from the vSAN Witness Appliance OVA
    $OVARoot = "C:\StackDeploy\"
    $OVAPath = Get-ChildItem C:\StackDeploy\ | Where-Object -Property Name -Match "^VMware-Virtual" | Select-Object -ExpandProperty Name
    $OVAFile = $OVARoot + $OVAPath

    $ovfConfig = Get-OvfConfiguration -Ovf $OVAFile

    # Set the Network Port Groups to use, the deployment size, and the root password for the vSAN Witness Appliance
    $ovfconfig.NetworkMapping.Management_Network.Value = "v3000." + $site + "-vmware-mgt"
    $ovfconfig.NetworkMapping.Secondary_Network.Value = "v3001." + $site + "-vsan-tr"
    $ovfconfig.DeploymentOption.Value = "normal"
    $ovfconfig.Common.guestinfo.passwd = "12qwaszx!@QWASZX"
    $ovfconfig.Common.guestinfo.ipaddress0 = "10.$siteNumberIP.4.201"
    $ovfconfig.Common.guestinfo.netmask0 = "255.255.255.0"
    $ovfconfig.Common.guestinfo.gateway0 = "10.$siteNumberIP.4.1"
    $ovfconfig.Common.guestinfo.dnsDomain = $config.config.DomainName
    $ovfconfig.Common.guestinfo.hostname = $site + "-VSANW-001v"
    $ovfconfig.Common.guestinfo.dns = "10.$siteNumberIP.8.82"
    $ovfconfig.Common.guestinfo.ipaddress1 = "10.$siteNumberIP.5.201"
    $ovfconfig.Common.guestinfo.netmask1 = "255.255.255.0"
    $ovfconfig.Common.guestinfo.gateway1 = "10.$siteNumberIP.5.1"

    # Import the vSAN Witness Appliance
    Import-VApp -Source $OVAFile -OvfConfiguration $ovfConfig -Name $ovfconfig.Common.guestinfo.hostname -VMHost $TargetHost -Datastore $TargetDatastore -DiskStorageFormat Thin

}
Function New-SDVsanStretchedClusterWitnessLarge {
    <#
    .SYNOPSIS
    This function will deploy a Witness for a 6 Node or Stretched vSAN Cluster
    .DESCRIPTION
    This function will deploy a Witness for a 6 Node or Stretched vSAN Cluster
 
    .PARAMETER Cluster
    Specifies the name of the Cluster you want to set the vSAN Witness Host for.
    .PARAMETER Datastore
    Specifies the name of the datastore to use.
    .PARAMETER OVAPath
    Full path and OVA filename for the vSAN Witness Appliance
    .PARAMETER Name
    The Virtual Machine Name of the vSAN Witness Appliance
    .PARAMETER Pass
    The root password of the vSAN Witness Appliance
    .PARAMETER Size
    The deployment size of the vSAN Witness Appliance
    .PARAMETER PG1
    The port group name for the vSAN Witness Appliance management network
    .PARAMETER PG2
    The port group name for the vSAN Witness Appliance WitnessPg network
 
    .EXAMPLE
    PS C:\> New-VsanStretchedClusterWitness -Cluster <Cluster Name> -Datastrre <Datastore name> -OVAPath <c:\path\witness-xxx.ova> -Name <Witness VM Name> -Pass <password for witness> -Size <tiny/normal/large> -PG1 <port group name for Management network> -PG2 <port group name for Witness Network>
     
    #>


    $site = $config.config.SiteNumber
    $siteNumberIP = (Set-SiteIPFormat -site $site)

    # Grab a random host in the cluster to deploy to
    $TargetHost = Get-VMHost -Name "10.$siteNumberIP.4.10"

    # Grab a random datastore
    $TargetDatastore = Get-Datastore -Host $TargetHost | Where-Object -Property Name -Match "^datastore"

    # Grab the OVA properties from the vSAN Witness Appliance OVA
    $OVARoot = "C:\StackDeploy\"
    $OVAPath = Get-ChildItem C:\StackDeploy\ | Where-Object -Property Name -Match "^VMware-Virtual" | Select-Object -ExpandProperty Name
    $OVAFile = $OVARoot + $OVAPath

    $ovfConfig = Get-OvfConfiguration -Ovf $OVAFile

    # Set the Network Port Groups to use, the deployment size, and the root password for the vSAN Witness Appliance
    $ovfconfig.NetworkMapping.Management_Network.Value = "v3000." + $site + "-vmware-mgt"
    $ovfconfig.NetworkMapping.Secondary_Network.Value = "v3001." + $site + "-vsan-tr"
    $ovfconfig.DeploymentOption.Value = "normal"
    $ovfconfig.Common.guestinfo.passwd = "12qwaszx!@QWASZX"
    $ovfconfig.Common.guestinfo.ipaddress0 = "10.$siteNumberIP.4.201"
    $ovfconfig.Common.guestinfo.netmask0 = "255.255.255.0"
    $ovfconfig.Common.guestinfo.gateway0 = "10.$siteNumberIP.4.1"
    $ovfconfig.Common.guestinfo.dnsDomain = $config.config.DomainName
    $ovfconfig.Common.guestinfo.hostname = $site + "-VSANW-001v"
    $ovfconfig.Common.guestinfo.dns = "10.$siteNumberIP.8.82"
    $ovfconfig.Common.guestinfo.ipaddress1 = "10.$siteNumberIP.5.201"
    $ovfconfig.Common.guestinfo.netmask1 = "255.255.255.0"
    $ovfconfig.Common.guestinfo.gateway1 = "10.$siteNumberIP.5.1"

    # Import the vSAN Witness Appliance
    Import-VApp -Source $OVAFile -OvfConfiguration $ovfConfig -Name $ovfconfig.Common.guestinfo.hostname -VMHost $TargetHost -Datastore $TargetDatastore -DiskStorageFormat Thin

}
Function New-SDVCenterConfig {

    [CmdletBinding()]
    param (
        #ESXi IP
        [Parameter(Mandatory = $true)]
        [String]
        $esxiIP
    )

    $site = $config.config.SiteNumber
    $siteNumberIP = (Set-SiteIPFormat -site $site)

    Connect-VIServer -Server $esxiIP -Protocol https -User root -Password '12qwaszx!@QWASZX' -Force

    $capacityDisks = Get-VMHost | Get-ScsiLun | Where-Object -Property Model -EQ "INTEL SSDPF2KX03" | Select-Object -ExpandProperty CanonicalName
    $cachDisks = Get-VMHost | Get-ScsiLun | Where-Object -Property Model -EQ "INTEL SSDPF2KX01" | Select-Object -ExpandProperty CanonicalName

    $vcenterTemplate = Get-content C:\StackDeploy\vCenter-Template.json -Raw | ConvertFrom-Json

    $vcenterTemplate.new_vcsa.esxi.hostname = $esxiIP
    $vcenterTemplate.new_vcsa.esxi.password = "12qwaszx!@QWASZX"
    $vcenterTemplate.new_vcsa.esxi.password = "12qwaszx!@QWASZX"
    $vcenterTemplate.new_vcsa.esxi.VCSA_Cluster.datacenter = $site
    $vcenterTemplate.new_vcsa.esxi.VCSA_Cluster.cluster = $site + "-vSAN"
    $vcenterTemplate.new_vcsa.esxi.VCSA_Cluster.deduplication_and_compression = $true
    $vcenterTemplate.new_vcsa.esxi.VCSA_cluster.disks_for_vsan.capacity_disk = @($capacitydisks)
    $vcenterTemplate.new_vcsa.esxi.VCSA_cluster.disks_for_vsan.cache_disk = @($cachDisks)
    $vcenterTemplate.new_vcsa.esxi.VCSA_cluster.enable_vlcm = $false

    $vcenterTemplate.new_vcsa.appliance.name = $site + "-VCSA-001v"

    $vcenterTemplate.new_vcsa.network.ip = "10." + $siteNumberIP + ".4.200"
    $vcenterTemplate.new_vcsa.network.prefix = "24"
    $vcenterTemplate.new_vcsa.network.gateway = "10." + $siteNumberIP + ".4.1"
    $vcenterTemplate.new_vcsa.network.system_name = "10." + $siteNumberIP + ".4.200"
    $vcenterTemplate.new_vcsa.network.dns_servers = @("10.$siteNumberIP.8.82", "10.$siteNumberIP.8.83")

    $vcenterTemplate.new_vcsa.os.password = "12qwaszx!@QWASZX"
    $vcenterTemplate.new_vcsa.os.ssh_enable = $true
    $vcenterTemplate.new_vcsa.os.time_tools_sync = $true

    $vcenterTemplate.new_vcsa.sso.password = "12qwaszx!@QWASZX"

    $vcenterTemplate | ConvertTo-Json -Depth 32 | Out-File C:\StackDeploy\vcenter-$site.json

    Disconnect-VIServer -Confirm:$false

}
Function Install-SDVCenterServer {

    if (!(Test-Path C:\StackDeploy\vcenter-logs)) {
        New-Item -Name vcenter-logs -ItemType Directory -Path C:\StackDeploy
    }
    #Get ISO for vCenter
    $vcsaiso = "C:\StackDeploy\" + (Get-ChildItem C:\StackDeploy | Where-Object -Property Name -Match "^VMware-VCSA" | Select-Object -ExpandProperty Name)

    $site = $config.config.SiteNumber
    
    $mountResult = Mount-DiskImage $vcsaiso -PassThru
    $mountResult | Get-Volume

    $driveLetter = (($mountResult | Get-Volume).DriveLetter)
    $process = (Start-Process "$driveLetter`:\vcsa-cli-installer\win32\vcsa-deploy.exe" -ArgumentList "install C:\StackDeploy\vcenter-$site.json --accept-eula --no-esx-ssl-verify --no-ssl-certificate-verification --verbose --log-dir C:\StackDeploy\vcenter-logs\" -Wait -PassThru)

    $process.ExitCode
    
    if ($process.ExitCode -eq 0) {
        Dismount-DiskImage -ImagePath $vcsaiso
        Write-Host "Sucessully deployed vCenter"

        return $process.ExitCode
    }
    elseif ($process.ExitCode -ne 0) {
        Write-Host $process.ExitCode
        Write-Host "An error has occured please consult the vcsa-cli-installer.log log files in C:\StackDeploy\vcenter-logs"
        return $process.ExitCode
    }

}
Function New-SDVsanStretchedCluster {
    <#
    .SYNOPSIS
        This function will create a 2 Node or Stretched vSAN Cluster
    .DESCRIPTION
        This function will create a 2 Node or Stretched vSAN Cluster
    .PARAMETER Witness
        Specifies the name of the new vSAN Witness Host want to use.
 
    .EXAMPLE
        PS C:\> New-VsanStretchedCluster -ClusterName <Cluster Name> -Witness <Witness>
 
    .NOTES
        Author : Jase McCarty
        Version : 0.1
        ==========Tested Against Environment==========
        VMware vSphere Hypervisor(ESXi) Version : 6.5
        VMware vCenter Server Version : 6.5
        PowerCLI Version : PowerCLI 6.5.4
        PowerShell Version : 3.0
 
    #>


    # Set our Parameters
    [CmdletBinding()]Param(
        [Parameter(Mandatory = $true)]
        [String]
        $Witness
    )

    $site = $global:config.config.SiteNumber

    # Check to see the cluster exists
    Try {
        # Check to make sure the New Witness Host has already been added to vCenter
        $Cluster = Get-Cluster -Name "$site-vSAN" -ErrorAction Stop
    }
    Catch [VMware.VimAutomation.Sdk.Types.V1.ErrorHandling.VimException.VimException] {
        Write-Host "The cluster, $ClusterName, was not found. " -foregroundcolor red -backgroundcolor white
        Write-Host "Please enter a valid cluster name and rerun this script."  -foregroundcolor black -backgroundcolor white
        Exit
    }        
        
    # Determine whether this is a 2 Node or Stretched Cluster
    $HostCount = $Cluster | Select-Object @{n = "count"; e = { ($_ | Get-VMHost).Count } }
    Switch ($HostCount.count) {
        "2" { $SCTYPE = "2 Node" }
        default { $SCTYPE = "Stretched" }
    }
            
    # Get the vSAN Cluster's Configuration
    $VsanConfig = Get-VsanClusterConfiguration -Cluster $Cluster

    # If we're dealing with a Stretched Cluster architecture, then we can proceed
    If (-Not $VsanConfig.StretchedClusterEnabled) {

        # Create Fault Domains for 2 Node vSAN
        $Cluster | Set-Cluster -VsanEnabled:$true -Confirm:$false -ErrorAction SilentlyContinue
        $VsanHosts = $Cluster | Get-VMHost
            
        $PFD = Get-VsanFaultDomain -Name "Preferred" -ErrorAction SilentlyContinue
        If (-Not $PFD) { $PFD = New-VsanFaultDomain -VMHost $VsanHosts[0] -Name "Preferred" -Confirm:$false }

        $SFD = Get-VsanFaultDomain -Name "Secondary" -ErrorAction SilentlyContinue
        If (-Not $SFD) { $SFD = New-VsanFaultDomain -VMHost $VsanHosts[1] -Name "Secondary" -Confirm:$false }
            
        # Get the Witness Host
        $WitnessHost = Get-VMHost -Name $Witness -ErrorAction Stop

        # See if it is the VMware vSAN Witness Appliance
        $IsVsanWitnessAppliance = Get-AdvancedSetting -Entity $WitnessHost -Name Misc.vsanWitnessVirtualAppliance

        # If it is the VMware vSAN Witness Appliance, then proceed
        If ($IsVsanWitnessAppliance.Value -eq "1") {
            Write-Host "$Witness is a vSAN Witness Appliance." -foregroundcolor black -backgroundcolor green
                    
            # Check to make sure a VMKernel port is tagged for vSAN Traffic, otherwise exit. Could possibly tag a VMkernel next time
            If ( Get-VMHost $Witness | Get-VMHostNetworkAdapter | Where-Object { $_.VsanTrafficEnabled }) {
                Write-Host "$Witness has a VMKernel port setup for vSAN Traffic. Proceeding."  -foregroundcolor black -backgroundcolor green
            }
            else {
                Write-Host "$Witness does not have a VMKernel port setup for vSAN Traffic. Exiting" -foregroundcolor red -backgroundcolor white
                Exit 
            }
        }
        else {
            # The Witness isn't a vSAN Witness Appliance, so exit
            Write-Host "$Witness is not a vSAN Witness Appliance, stopping" -foregroundcolor red -backgroundcolor white
            Write-Host "This script only supports using the vSAN Witness Appliance"  -foregroundcolor red -backgroundcolor white
            Exit
        }
        
        $VsanWitnessHostDisks = Get-VMHost -Name $Witness | Get-VMHostHba | Get-ScsiLun | Where-Object { $_.VsanStatus -eq "Eligible" }

        # There must be at least 2 disks
        # Need to add a check to make sure at least 1 flash and 1 capacity (flash or spinning)
        If ($VsanWitnessHostDisks.Count -gt 1) {
            $CacheDisks = @()
            $CapacityDisks = @()
    
            # Enumerate through each of the disks.
            
            Foreach ($VsanDisk in $VsanHostDisks) {
                # If the device is tagged as SSD and is less than the max size, denote it as a cache device
                If ($VsanDisk.IsSsd -eq $true -and $VsanDisk.CapacityGB -lt "80") {
                    $CacheDisks += $VsanDisk
                }
                else {
                    # Add the disk to the CapacityDisks array
                    $CapacityDisks += $VsanDisk
                }
            }
            # Set the cluster configuration to Stretched/2 Node, with the witness and the preferred fault domain
            Write-Host "Adding Witness $Witness and enabling the $SCTYPE Cluster" -foregroundcolor black -backgroundcolor white
            Set-VsanClusterConfiguration -Configuration $Cluster -StretchedClusterEnabled $True -PreferredFaultDomain $PFD -WitnessHost $Witness -WitnessHostCacheDisk $CacheDisks -WitnessHostCapacityDisk $CapacityDisks
        }

                
    } 
}

#Export Function Memembers
Export-ModuleMember -Function Set-SDIMCBootOrder
Export-ModuleMember -Function Set-SDIMCInterface
Export-ModuleMember -Function Set-SDIMCSetup
Export-ModuleMember -Function Set-SDVCenterSettings
Export-ModuleMember -Function Add-SDVMHost
Export-ModuleMember -Function Set-SDVMHSettings
Export-ModuleMember -Function New-SDVMwareConfig
Export-ModuleMember -Function New-SDVsanStretchedClusterWitness
Export-ModuleMember -Function New-SDVsanStretchedClusterWitnessLarge
Export-ModuleMember -Function New-SDVCenterConfig
Export-ModuleMember -Function Install-SDVCenterServer
Export-ModuleMember -Function New-SDVsanStretchedCluster