HyperVClusteredEnvBuildout.psm1
#Function = 1 <# .SYNOPSIS Create a new virtual machine with the help of the Hyper-V module .DESCRIPTION This script will allow you to create a new VM, add a new math for your .VHDX, add memory, add storage, and add a, existing vSwitch. .EXAMPLE New-HyperVM -Name 'MYNEWVM' -VMSwitch 'MyVMSwitch' -MemoryStartup 2GB -NewVHDSize 50GB -Path C:\HyperV\MYNEWVM -NewVHDPath C:\HyperV\MYNEWVM\MYNEWVM.vhdx .NOTES Please Note: This is using the Hyper-V module to create a new VM. This just adds error handing, function, IF statements, and tests. #> Function New-HyperVM { [cmdletbinding(DefaultParameterSetName = 'NewVM', SupportsShouldProcess = $true, ConfirmImpact = 'Medium')] Param ( [Parameter(ParameterSetName = 'NewVM', Position = 0, Mandatory = $true, HelpMessage = 'Please type in a name for your Virtual Machine')] [ValidateNotNullOrEmpty()] [string]$Name, [Parameter(ParameterSetName = 'NewVM', Position = 1, HelpMessage = 'Please type in your vSwitch name')] [ValidateNotNullOrEmpty()] [string]$VMSwitch, [Parameter(ParameterSetName = 'NewVM', Position = 2, HelpMessage = 'Please type in specified memory startup size. For example: 2GB')] [ValidateNotNullOrEmpty()] [string]$MemoryStartup, [Parameter(ParameterSetName = 'NewVM', Position = 3, HelpMessage = 'Please type in new VHD size. Default is 50GB')] [ValidateNotNullOrEmpty()] [string]$NewVHDSize = 50GB, [Parameter(ParameterSetName = 'NewVM', Position = 4, HelpMessage = 'Please type in a path for your new VHD. Example: C:\hyperv\newvm.vhdx')] [ValidateNotNullOrEmpty()] [string]$NewVHDPath, [Parameter(ParameterSetName = 'NewVM', Position = 5, Mandatory = $true, HelpMessage = 'Please type a name for your NEW directory that will store your VM')] [ValidateNotNullOrEmpty()] [string]$Path ) Begin { $hosts = @() $hosts += $Name Write-Output "Starting: $MyInvocation.MyCommand" Write-Verbose 'Creating directory for new VM' Foreach ($VMName in $Name) { New-Item -Path $Path -Name "$VMName" -ItemType Directory } } Process { Try { IF ($PSBoundParameters.ContainsKey('NewVHDPath')) { $NewVHD = New-VHD -Path $NewVHDPath -SizeBytes $NewVHDSize $NewVHDOBJECT = [pscustomobject] @{ 'Hostname' = $NewVHD.ComputerName 'VHDFormat' = $NewVHD.VhdFormat 'VHDXSize' = $NewVHD.Size / 1GB } Write-Verbose 'Outputting results of new VHD' $NewVHDOBJECT }#IF IF (-Not($NewVHDPath)) { Write-Warning 'The VHDX path was not found. Please try again...' Pause } ELSE { $NewVMParams = @{ 'Name' = $Name 'Path' = "D:\hyperv\$Name" 'MemoryStartupBytes' = $MemoryStartup 'VHDPath' = $NewVHDPath 'SwitchName' = $VMSwitch 'Generation' = '2' } $NewVM = New-VM @NewVMParams $NewVMOBJECT = [pscustomobject] @{ 'VMName' = $NewVM.Name 'VMCurrentState' = $NewVM.State 'VMStatus' = $NewVM.Status 'VMGeneration' = $NewVM.Generation } $NewVMOBJECT }#Else }#Try Catch { $HyperVServer $TestHyperVServerConnection = Test-Connection $HyperVServer $IPregex = ‘(?<Address>((25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?))’ IF ($TestHyperVServerConnection.IPv4Address.IPAddressToString[0] -match $IPregex ) { Write-Output 'Connection to Hyper-V Server: Successful. Moving on...' } Else { Write-Warning 'Connection to Hyper-V Server: UNSUCCESSFUL' Pause Break } $TestVHDXPath = Test-Path $NewVHDPath IF ($TestVHDXPath -like 'true') { Write-Output 'Path to VHDX: Successful. Moving on...' } Else { Write-Warning 'Connection to VHDX: UNSUCCESSFUL' Pause Break } Write-Warning 'Please review the errors below' $PSCmdlet.ThrowTerminatingError($_) }#Catch }#Process End {} }#Function ########################################################################################################################################################################## #Function = 2 <# .SYNOPSIS Create a new iSCSI config utilizing the iSCSI initiator to connect to your iSCSI LUN .DESCRIPTION This function will allow you to connect your Hyper-V servers to an iSCSI LUN of your choosing utilizing the iSCSI initiator .EXAMPLE New-iSCSIConfig -ComputerName localhost -LogPath 'C:\Logs\LogName.txt' -iSCSITargetIPAddress 192.168.1.20 -NodeAddress iqn.1991-05.com.contoso:deepcore.contoso.com -ErroLog 'C:\Errors\Errorlog.txt' .NOTES Please Note: You must have an iSCSI LUN for the initiator to connect to prior to this function #> Function New-iSCSIConfig { [cmdletbinding(SupportsShouldProcess = $true, ConfirmImpact = 'High')] Param ( [Parameter(Position = 0, Mandatory=$true, ValueFromPipeline=$true)] [ValidateNotNullOrEmpty()] [psobject]$ComputerName = 'localhost', [Parameter(HelpMessage = 'Please specify a location for your logs')] [string]$LogPath, [Parameter(HelpMessage = 'Please specify an IP address for your iSCSI target')] [psobject]$iSCSITargetIPAddress, [string]$NodeAddress, [string]$ErrorLog ) Begin {Write-Output "Starting: $MyInvocation.MyCommand" $MyInvocation.BoundParameters} Process { TRY { $InstalliSCSIRolePARAMS = @{ 'ComputerName' = $ComputerName 'LogPath' = $LogPath 'Name' = 'FS-ISCSITARGET-Server' 'Verbose' = $true } Write-Verbose 'Installing iSCSI Server role' $InstalliSCSIController = Install-WindowsFeature @InstalliSCSIRolePARAMS $iSCSIControllerObject = [PSCustomObject] @{ 'Hostname' = $ComputerName 'Success' = $InstalliSCSIController.Success 'Restart?' = $InstalliSCSIController.RestartNeeded } $iSCSIControllerObject Write-Verbose 'Confirming iSCSI role was installed successfully' IF ($InstalliSCSIController.Success -like 'True') { Write-Output 'Installation of iSCSI Windows Feature was successful. We will now continue.' } ELSE { Write-Warning 'Configuration/Installation Error. Please review your parameters and try again. Exiting configuration' $Error[0] Pause Break } Write-Verbose 'Testing connection to iSCSI target' $TestConnection = Test-Connection $iSCSITargetIPAddress IF ($TestConnection.PSComputerName -notmatch "\w+") { Write-Warning 'The IP address was not reachable. Please try re-running your cmdlet and re-entering a new IP address into your parameter' Pause Break } ELSE { Write-Verbose 'Setting up switch for ShouldProcess to run' [switch]$Continue = $true } IF ($PSCmdlet.ShouldProcess($Continue)) { FOREACH ($Computer in $ComputerName) { Write-Verbose 'Starting iSCSI service' Start-Service -Name MSiSCSI Write-Verbose 'Confirming iSCSI start is started automatically' Set-Service -Name MSiSCSI -StartupType Automatic Write-Verbose 'Creating new iSCSI target portal' $NewiSCSITargetPortal = New-IscsiTargetPortal -TargetPortalAddress $iSCSITargetIPAddress Write-Verbose 'Connecting iSCSI target' $ConnectiISCSITargetPortal = Connect-IscsiTarget -NodeAddress $NodeAddress $ConnectiISCSITargetPortal $iSCSIConfig = [pscustomobject] @{ 'TargetPortalAddress' = $NewiSCSITargetPortal.TargetPortalAddress 'TargetPortalNumber' = $NewiSCSITargetPortal.TargetPortalPortNumber 'NodeAddress' = $NodeAddress } $iSCSIConfig | Format-Table }#FOREACH }#ShouldProcessIF }#TRY CATCH { Write-Warning 'An error has occured. Please check the error logs in your specific file share' $_ | Out-File $ErrorLog Throw }#CATCH }#Process End {} }#Function #################################################################################################################################################################### #Function = 3 <# .SYNOPSIS Create a new server cluster with your Hyper-V hosts .DESCRIPTION This function will allow you to connect your Hyper-V servers together to create a cluster .EXAMPLE New-ServerCluster -Node 'SERVER1','SERVER2' -ClusterName 'MyCluster1' .EXAMPLE 'SERVER1','SERVER2' | New-ServerCluster -ClusterName 'MyCluster1' .NOTES Please Note: You must have an iSCSI LUN for the initiator to connect to prior to this function #> #1, Cluster service cannot be started due to machines not currently being in a cluster. If the machines are in a cluster, then they can check the cluster available disks Function New-ServerCluster { [cmdletbinding(DefaultParameterSetName='ClusterConfig',SupportsShouldProcess = $true, ConfirmImpact = 'High')] Param ( [Parameter(ParameterSetName='ClusterConfig', Position = 0, Mandatory = $true, ValueFromPipeline = $true, ValueFromPipelineByPropertyName = $true, HelpMessage = 'Please enter your nodes that you are connecting to your new cluster')] [ValidateNotNull()] [Alias('ComputerName', 'NodeName')] [psobject[]]$Node, [Parameter(ParameterSetName='ClusterConfig', Position = 1, Mandatory = $true, HelpMessage = 'Please enter a name for your cluster')] [ValidateNotNull()] [Alias('Cluster', 'Name', 'HAClusterName')] [string]$ClusterName ) Begin { Write-Output 'We will now begin cluster testing to ensure network, storage, connection to AD, and roles are set up properly.' Write-Output 'Please Note: A cluster does not have to be set up prior. Only the role needs to be installed' Write-Output 'Please ensure you put all servers that you want to cluster and test in as comma-separated' $TestConnection = Test-Connection $Node IF (-Not($TestConnection)) { Write-Warning 'No connection was established to the specified nodes. Please try again...' Pause Exit } ELSE { Write-Output 'Connection to servers established. We will now proceed...' Pause } } Process { Try { IF ($PSBoundParameters.ContainsKey('Node')) { ## ** Run a test on the cluster after it's set up as well ** $TestCluster = Test-Cluster -Node $Node -Verbose $TestClusterOBJECTS = [pscustomobject] @{ 'LastWriteDateandTime' = $TestCluster.LastWriteTime 'NameOfReport' = $TestCluster.Name } $TestClusterOBJECTS $Input = Read-Host 'The test has completed. If passed, please press 1. If not, please press 2 to exit and fix issues' switch ($Input) { '1' { Write-Verbose 'Creating new cluster' $NewClusterPARAMS = @{ 'Name' = $ClusterName 'Node' = $Node 'Verbose' = $true } New-Cluster @NewClusterPARAMS }#1 '2' { Pause Exit }#2 }#Switch } ############################################################################### Storage Portion Below #################################################################### $NewClusterDiskQuestion = Read-Host 'Would you like to get your available disk clusters and add them to your cluster now? Y for yes or N to exit' IF ($NewClusterDiskQuestion -like 'y') { #Get available cluster disks Write-Output 'Please ensure you have your shared disk configured on BOTH clustered hosts.' Write-Verbose 'Setting Cluster Service to startup type: Automation' Set-Service -Name ClusSvc -StartupType Automatic Write-Verbose 'Starting Cluster Service' Start-Service -Name ClusSvc $GetDisk = Get-ClusterAvailableDisk FOREACH ($ClustDisk in $GetDisk) { $ClusterDiskObject = [pscustomobject] @{ 'Cluster' = $ClustDisk.Cluster 'Name' = $ClustDisk.Name 'Size' = $ClustDisk.Size } $ClusterDiskObject | Format-Table }#FOREACH #Connect clustered storage Pause Get-ClusterAvailableDisk | Add-ClusterDisk } ELSE { Pause Exit } #ELSE }#TRY CATCH { $ClusteredDisks = Get-ClusterAvailableDisk $ClusteredDisksObject = [pscustomobject] @{ 'Name' = $ClusteredDisks.Name } $ClusteredDisksObject Write-Warning 'An error has occursed. Please review the logs in your specified ErrorLog location' $_ | Out-File $ErrorLog #Throw error to host $_ Throw } }#Process End {Write-Verbose 'The function has completed'} }#Function |