diff --git a/vCenter Tools/CreatedvSwitchPorts.ps1 b/vCenter Tools/CreatedvSwitchPorts.ps1 new file mode 100644 index 0000000..444f961 --- /dev/null +++ b/vCenter Tools/CreatedvSwitchPorts.ps1 @@ -0,0 +1,226 @@ +param ( + [string]$vCenter = "", + [string]$dvSwitch = "", + [string]$CSVFile = "", + [switch]$SaveCred = $false, + [switch]$Help = $false +) + +# Variables +$fileVersion = "1.0.0" +$fileDate = "2026-01-28" + +# Display Script Banner +Write-Host "--------------------------------------------------" -ForegroundColor White +Write-Host "dvSwitch Port Group Creation Script" -ForegroundColor Green +Write-Host "Version $($FileVersion) ($($FileDate))" -ForegroundColor Green +Write-Host "Written by Charlie Silverman" -ForegroundColor Green +Write-Host "--------------------------------------------------" -ForegroundColor White + +if ($Help) { + Write-Host + Write-Host "Purpose: Create dvSwitch Port Groups en masse." + Write-Host "Command Syntax:" + Write-Host " CreatedvSwitchPortGroups.ps1 (-vcenter [vcenter host name]) (-dvSwitch ""[dvswitch]"") (-CSVFile ""[csvfile]"")" + Write-Host " (-savecred) (-help)`n" -foregroundcolor green + Write-Host "Command Line Options:" + Write-Host + Write-Host -NoNewLine " -vCenter " -foregroundcolor Green + Write-Host "- The FQDN or IP address of a vCenter server." + Write-Host -NoNewLine " -dvSwitch " -foregroundcolor Green + Write-Host "- The name of the distributed virtual switch in vCenter." + Write-Host -NoNewLine " -CSVfile " -foregroundcolor Green + Write-Host "- The path to the CSV file. See note below for format." + Write-Host -NoNewLine " -savecred " -foregroundcolor Green + Write-Host "- Configure and store vCenter server credentials. This will only store the credentials under" + Write-Host " the current logged in user." + Write-Host -NoNewLine " -help " -foregroundcolor Green + Write-Host "- Display command help." + Write-Host + Write-Host "If any of the information is not provided, you will be prompted. If a credential has been previously stored, it will" + Write-Host "be used again unless the -savecred option is specified." + Write-Host + Write-Host "The CSV file must follow the format listed below. The only field required is PortGroup. Fields can be in any order." + Write-Host " PortGroup, VLAN, PortBinding, NumPorts, ActiveUplink, DisabledUplink, StandbyUplink, Notes" + Write-Host "Where:" + Write-Host " Portgroup " -ForegroundColor Green -NoNewLine + Write-Host " - The name of the port group." + Write-Host " VLAN " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] The VLAN tag for the port group." + Write-Host " PortBinding " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] The type of port binding for the port group. This can be either Static or Dynamic." + Write-Host " Defaults to Static if not specified." + Write-Host " NumPorts " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] The number of ports for the port group. This is ignored for a dynamic port group." + Write-Host " Defaults to 254 if not specified." + Write-Host " ActiveUplink " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] A comma delimited list of switch uplinks to be set as active for the port group." + Write-Host " StandbyUplink " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] A comma delimited list of switch uplinks to be set as standby for the port group." + Write-Host " UnusedUplink " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] A comma delimited list of switch uplinks to be set as unused for the port group." + Write-Host " Notes " -ForegroundColor Green -NoNewLine + Write-Host " - [Optional] Notes to add to the port group." + + exit +} + +$quiet = Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false + +if ($vCenter -eq "") { + $vCenter = Read-Host "Enter name of vCenter Server" +} + +if ($SaveCred) { + $credential = Get-Credential -Message "Enter credentials for vCenter server $vCenter" + $credential | Export-Clixml -path $env:USERPROFILE\kistools-$vcenter.cred + Write-Host "Saving credentials." +} + +if (Test-Path -path $env:USERPROFILE\kistools-$vcenter.cred -PathType Leaf) { + $credentials = Import-Clixml -path $env:USERPROFILE\kistools-$vcenter.cred + Write-Host "Using stored credentials" +} else { + $credentials = Get-Credential -Message "Enter credentials for vCenter server $vCenter" + if (!$credentials) { + Write-Host "ERROR: No credentials were entered" -foregroundcolor yellow + } +} + +try { + Write-Host -NoNewLine "Connecting to vCenter $vcenter..." + $vcconn = Connect-VIServer $vcenter -Credential $credentials -ErrorAction Stop + Write-Host " Success" -ForegroundColor green +} catch { + Write-Host " Failure" -ForegroundColor Yellow -BackgroundColor Red + exit +} + +try { + if ($dvSwitch -ne "") { + get-VDswitch $dvSwitch -ErrorAction Stop + } +} catch { + Write-Host "ERROR: dvSwitch ""$dvSwitch"" is not found." -ForegroundColor Red + $dvSwitch = "" +} + +if ($dvSwitch -eq "") { + $dvSwitchlist = Get-VDSwitch | Sort-Object + While (($dvSwitch -eq "") -or (-not $dvSwitch)) { + Write-Host "`ndvSwitch Selection:`n" + for ($x = 0; $x -lt $dvSwitchlist.length; $x++) { + Write-Host "$(([string]($x+1)).PadLeft(3,' '))" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "$($DVSwitchlist[$x].name)" -ForegroundColor Yellow + } + $dvSwitchNum = [int](Read-Host "`nSelect dvSwitch Number") - 1 + $dvSwitch = $dvSwitchlist[$dvSwitchNum] + } + $mySwitch = get-VDSwitch $dvSwitch +} else { + $mySwitch = get-VDSwitch $dvSwitch +} + +$csvdata = Import-CSV $csvfile + +Write-Host "Processing Port Group List" + +for ($x = 0; $x -lt $csvdata.length; $x++) { + $pgname = $csvdata[$x].PortGroup + if ($pgname -eq "") { continue } + if (-not ($pgvlan = $csvdata[$x].VLAN)) { + $pgvlan = 0 + } + if (-not ($pgbinding = $csvdata[$x].PortBinding)) { + $pgbinding = "Static" + } + if (-not ($pgports = $csvdata[$x].NumPorts)) { + $pgports = 254 + } + if ($pgactive -and (($pgactive = ($csvdata[$x].ActiveUplink).split(",")).count -eq 0)) { + $pgactive = @() + } + if ($pgstandby -and (($pgstandby = ($csvdata[$x].StandbyUplink).split(",")).count -eq 0)) { + $pgstandby = @() + } + if ($pgunused -and (($pgunused = ($csvdata[$x].UnusedUplink).split(",")).count -eq 0)) { + $pgunused = @() + } + Write-Host "$pgname... " -NoNewLine + if ($temp = Get-VdPortGroup $pgname -erroraction silentlycontinue) { + Write-Host " Already Exists - Skipping" -ForegroundColor Yellow + continue + } + try { + $newpg = New-VdPortGroup -name "$pgname" -vlanid $pgvlan -PortBinding $pgbinding -VdSwitch "$dvSwitch" -erroraction stop + Write-Host "Created Successfully" -ForegroundColor Green + } catch { + Write-Host " ERROR - Unable to Create Port Group $pgname on dvSwitch $dvSwitch." -ForegroundColor Red + Write-Host "$($_.Exception.Message)" -ForegroundColor Gray + continue + } + + $myuplinks = @() + foreach($uplink in $pgactive) { + if ($uplink -eq "") { continue } + if (($mySwitch.ExtensionData.Config.UplinkPortPolicy.UplinkPortName | Where-Object {$_ -eq $uplink}).Count -eq 0) { + Write-Host "Warning: Uplink ""$uplink"" for Active is not found on switch $dvSwitch" -ForegroundColor Yellow + continue + } + $myuplinks += $uplink + } + + if ($myuplinks.Count -gt 0) { + Write-Host " Assigning active uplink ports... " -NoNewLine + try { + $temp = $newpg | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -ActiveUplinkPort $myuplinks -ErrorAction Stop + Write-Host "Success" -ForegroundColor Green + } catch { + Write-Host "ERROR assigning uplinks to $pgname" -ForegroundColor Red + Write-Host "$($_.Exception.Message)" -ForegroundColor Gray + } + } + + $myuplinks = @() + foreach($uplink in $pgstandby) { + if ($uplink -eq "") { continue } + if (($mySwitch.ExtensionData.Config.UplinkPortPolicy.UplinkPortName | Where-Object {$_ -eq $uplink}).Count -eq 0) { + Write-Host "Warning: Uplink ""$uplink"" for STANDBY is not found on switch $dvSwitch" -ForegroundColor Yellow + continue + } + $myuplinks += $uplink + } + + if ($myuplinks.Count -gt 0) { + Write-Host " Assigning standby uplink ports... " -NoNewLine + try { + $temp = $newpg | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -StandbyUplinkPort $myuplinks -ErrorAction Stop + Write-Host "Success" -ForegroundColor Green + } catch { + Write-Host "ERROR assigning standby uplinks to $pgname" -ForegroundColor Red + Write-Host "$($_.Exception.Message)" -ForegroundColor Gray + } + } + + $myuplinks = @() + foreach($uplink in $pgunused) { + if ($uplink -eq "") { continue } + if (($mySwitch.ExtensionData.Config.UplinkPortPolicy.UplinkPortName | Where-Object {$_ -eq $uplink}).Count -eq 0) { + Write-Host "Warning: Uplink ""$uplink"" for UNUSED is not found on switch $dvSwitch" -ForegroundColor Yellow + continue + } + $myuplinks += $uplink + } + + if ($myuplinks.Count -gt 0) { + Write-Host " Assigning unused uplink ports... " -NoNewLine + try { + $temp = $newpg | Get-VDUplinkTeamingPolicy | Set-VDUplinkTeamingPolicy -UnusedUplinkPort $myuplinks -ErrorAction Stop + Write-Host "Success" -ForegroundColor Green + } catch { + Write-Host "ERROR assigning unused uplinks to $pgname" -ForegroundColor Red + Write-Host "$($_.Exception.Message)" -ForegroundColor Gray + } + } +} \ No newline at end of file diff --git a/vCenter Tools/DRSGroupFunctions.ps1 b/vCenter Tools/DRSGroupFunctions.ps1 new file mode 100644 index 0000000..14298ef --- /dev/null +++ b/vCenter Tools/DRSGroupFunctions.ps1 @@ -0,0 +1,118 @@ +Function Get-DrsGroup { +<# +.SYNOPSIS +Retrieves DRS groups from a cluster. + +.DESCRIPTION +Retrieves DRS groups from a cluster. + +.PARAMETER Cluster +Specify the cluster for which you want to retrieve the DRS groups + +.PARAMETER Name +Specify the name of the DRS group you want to retrieve. + +.EXAMPLE +Get-DrsGroup -Cluster $Cluster -Name "VMs DRS Group" +Retrieves the DRS group "Vms DRS Group" from cluster $Cluster. + +.EXAMPLE +Get-Cluster | Get-DrsGroup +Retrieves all the DRS groups for all clusters. + +.INPUTS +ClusterImpl + +.OUTPUTS +ClusterVmGroup +ClusterHostGroup + +.COMPONENT +VMware vSphere PowerCLI +#> + + param([parameter(Mandatory=$true, ValueFromPipeline=$true)]$Cluster, + [string] $Name="*") + + process { + $Cluster = Get-Cluster -Name $Cluster + if($Cluster) { + $Cluster.ExtensionData.ConfigurationEx.Group | ` + Where-Object {$_.Name -like $Name} + } + } +} + +Function Add-VMToDrsGroup { +<# +.SYNOPSIS +Adds a virtual machine to a cluster VM DRS group. + +.DESCRIPTION +Adds a virtual machine to a cluster VM DRS group. + +.PARAMETER Cluster +Specify the cluster for which you want to retrieve the DRS groups + +.PARAMETER DrsGroup +Specify the DRS group you want to retrieve. + +.PARAMETER VM +Specify the virtual machine you want to add to the DRS Group. + +.EXAMPLE +Add-VMToDrsGroup -Cluster $Cluster -DrsGroup "VM DRS Group" -VM $VM +Adds virtual machine $VM to the DRS group "VM DRS Group" of cluster $Cluster. + +.EXAMPLE +Get-Cluster MyCluster | Get-VM "A*" | Add-VMToDrsGroup -Cluster MyCluster -DrsGroup $DrsGroup +Adds all virtual machines with a name starting with "A" in cluster MyCluster to the DRS group $DrsGroup of cluster MyCluster. + +.INPUTS +VirtualMachineImpl + +.OUTPUTS +Task + +.COMPONENT +VMware vSphere PowerCLI +#> + + param([parameter(Mandatory=$true)] $Cluster, + [parameter(Mandatory=$true)] $DrsGroup, + [parameter(Mandatory=$true, ValueFromPipeline=$true)] $VM) + + begin { + $Cluster = Get-Cluster -Name $Cluster + } + + process { + if ($Cluster) { + if ($DrsGroup.GetType().Name -eq "string") { + $DrsGroupName = $DrsGroup + $DrsGroup = Get-DrsGroup -Cluster $Cluster -Name $DrsGroup + } + if (-not $DrsGroup) { + Write-Error "The DrsGroup $DrsGroupName was not found on cluster $($Cluster.name)." + } + else { + if ($DrsGroup.GetType().Name -ne "ClusterVmGroup") { + Write-Error "The DrsGroup $DrsGroupName on cluster $($Cluster.Name) doesn't have the required type ClusterVmGroup." + } + else { + $VM = $Cluster | Get-VM -Name $VM + If ($VM) { + $spec = New-Object VMware.Vim.ClusterConfigSpecEx + $spec.groupSpec = New-Object VMware.Vim.ClusterGroupSpec[] (1) + $spec.groupSpec[0] = New-Object VMware.Vim.ClusterGroupSpec + $spec.groupSpec[0].operation = "edit" + $spec.groupSpec[0].info = $DrsGroup + $spec.groupSpec[0].info.vm += $VM.ExtensionData.MoRef + + $Cluster.ExtensionData.ReconfigureComputeResource_Task($spec, $true) + } + } + } + } + } +} diff --git a/vCenter Tools/DeployTestingVMs.ps1 b/vCenter Tools/DeployTestingVMs.ps1 new file mode 100644 index 0000000..9b9b1d9 --- /dev/null +++ b/vCenter Tools/DeployTestingVMs.ps1 @@ -0,0 +1,675 @@ +param ( + [string]$vCenter = "", + [string]$Cluster = "", + [string]$dvSwitch = "", + [string]$Datastore = "", + [string]$SourceVMName = "", + [string]$Folder = "", + [string]$CSVFile = "", + [switch]$SaveCred = $false, + [switch]$Help = $false +) + +Import-Module .\DRSGroupFunctions.ps1 + +function GetFolderFromPath($folder) { + $parts = $folder.Split("\") + if ($parts.length -eq 0) { return $folder } + for ($x = 0; $x -lt $parts.length; ++$x) { + $thispart = $parts[$x] + if ($x -gt 0) { + $thisfolder = Get-Folder $parts[$x] | Where-Object {$_.Parent.Id -eq $parent.Id} + } else { + $thisfolder = Get-Folder $parts[$x] | Where-Object {$_.Parent.Name -eq "vm"} + } + $parent = $thisfolder + } + return $thisfolder +} + +# Variables +$fileVersion = "1.2.0" +$fileDate = "2026-06-03" + +# Display Script Banner +Write-Host "--------------------------------------------------" -ForegroundColor White +Write-Host "vSphere Testing VM Deployment Script" -ForegroundColor Green +Write-Host "Version $($FileVersion) ($($FileDate))" -ForegroundColor Green +Write-Host "Written by Charlie Silverman" -ForegroundColor Green +Write-Host "--------------------------------------------------" -ForegroundColor White + +if ($Help) { + Write-Host + Write-Host "Purpose: Deploy testing VMs for a set of port groups." + Write-Host "Command Syntax:" + Write-Host " DeployTestingVMs.ps1 (-vcenter [vCenter]) (-Cluster ""[Cluster]"") (-dvSwitch ""[dvswitch]"")" -ForegroundColor green + Write-Host " (-SourceVMName ""[SourceVMName]"") (-CSVFile ""[csvfile]"")" -ForegroundColor green + Write-Host "Command Line Options:" + Write-Host + Write-Host -NoNewLine " -vCenter " -ForegroundColor Green + Write-Host "- The FQDN or IP address of a vCenter server." + Write-Host -NoNewLine " -Cluster " -ForegroundColor Green + Write-Host "- The name of the Cluster in vCenter." + Write-Host -NoNewLine " -dvSwitch " -ForegroundColor Green + Write-Host "- The name of the distributed virtual switch in vCenter." + Write-Host -NoNewLine " -SourceVMName " -ForegroundColor Green + Write-Host "- The name of the distributed virtual switch in vCenter." + Write-Host -NoNewLine " -CSVfile " -ForegroundColor Green + Write-Host "- The path to the CSV file. See note below for format." + Write-Host -NoNewLine " -savecred " -ForegroundColor Green + Write-Host "- Configure and store vCenter server credentials. This will only store the credentials under" + Write-Host " the current logged in user." + Write-Host -NoNewLine " -help " -ForegroundColor Green + Write-Host "- Display command help." + Write-Host + Write-Host "If any of the information is not provided, you will be prompted. If a credential has been previously stored, it will" + Write-Host "be used again unless the -savecred option is specified." + Write-Host + Write-Host "The CSV file must follow the format listed below. The only field required is PortGroup. Fields can be in any order." + Write-Host " VLAN, Description, IPAddress, Netmask, Gateway, Site" + Write-Host "Where:" + Write-Host " VLAN " -ForegroundColor Green -NoNewLine + Write-Host " - The VLAN tag for the port group." + Write-Host " Description " -ForegroundColor Green -NoNewLine + Write-Host " - The Description for the port group." + Write-Host " IPAddress " -ForegroundColor Green -NoNewLine + Write-Host " - IP address for the VM." + Write-Host " Netmask " -ForegroundColor Green -NoNewLine + Write-Host " - Netmask for the network." + Write-Host " Gateway " -ForegroundColor Green -NoNewLine + Write-Host " - Default gateway for the network." + Write-Host " Site " -ForegroundColor Green -NoNewLine + Write-Host " - The site prefix to be used for DRS group configuration." + Write-Host "" + Write-Host "The port group name will be assumed to be in the following format: ""[Description] - VLAN[VLAN]""" + Write-Host "If the VLAN tag is 12 and the description is ""Big Servers"", the port group name will be ""Big Servers - VLAN12""" + Write-Host "" + Write-Host "The DRS group name will be assumed to be in the following format: ""[Site] Only VMs""" + Write-Host "If the Site is Primary, the DRS group name will be ""Primary Only VMs""" + Write-Host "" + Write-Host "Additionally, the new VM names will be in the format ""KISStress - VLAN[VLAN]""" + exit +} + +try { + $data = import-csv $CSVFile +} catch { + Write-Host "ERROR: Input file is not in a valid format." -ForegroundColor Yellow -BackgroundColor Red + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + exit +} + +if (!($data | Where-Object {$_.PSObject.Properties.Name -contains "VLAN"}) -or (!($data | Where-Object {$_.PSObject.Properties.Name -contains "Description"}))) { + Write-Host "ERROR: Input file is not in a valid format." -ForegroundColor Yellow -BackgroundColor Red + exit +} + +$setip = $false + +if ($data | Where-Object {$_.PSObject.Properties.Name -contains "IPAddress"}) { + if ($data | Where-Object {$_.PSObject.Properties.Name -contains "Netmask"}) { + if ($data | Where-Object {$_.PSObject.Properties.Name -contains "Gateway"}) { + $setip = $true + } + } +} + +if ($vCenter -eq "") { + $vCenter = Read-Host "Enter name of vCenter Server" +} + +if ($SaveCred) { + $credential = Get-Credential -Message "Enter credentials for vCenter server $vCenter" + $credential | Export-Clixml -path $env:USERPROFILE\kistools-$vcenter.cred + Write-Host "Saving credentials." +} + +if (Test-Path -path $env:USERPROFILE\kistools-$vcenter.cred -PathType Leaf) { + $credentials = Import-Clixml -path $env:USERPROFILE\kistools-$vcenter.cred + Write-Host "Using stored credentials" +} else { + $credentials = Get-Credential -Message "Enter credentials for vCenter server $vCenter" + if (!$credentials) { + Write-Host "ERROR: No credentials were entered" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit + } +} + +try { + Write-Host -NoNewLine "Connecting to vCenter $vcenter... " + $vcconn = Connect-VIServer $vcenter -Credential $credentials -ErrorAction Stop + Write-Host "Success" -ForegroundColor green +} catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +if ($Cluster -eq "") { + $Clusterlist = Get-Cluster | Sort-Object + $startpos = 0 + $step = 10 + While (($Cluster -eq "") -or (-not $Cluster)) { + $endpos = $startpos + 10; + if ($endpos -gt $Clusterlist.length) { $endpos = $Clusterlist.length } + $page = $startpos / $step + 1 + $maxpage = [math]::Ceiling($Clusterlist.length / $step) + Write-Host "`nCluster Selection (Page $page of $maxpage):`n" + if ($startpos -gt 0) { + Write-Host " 0" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "<< Previous Page" -ForegroundColor White + } + for ($x = $startpos; $x -lt $endpos; $x++) { + Write-Host "$(([string]($x+1-$startpos)).PadLeft(3,' '))" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "$($Clusterlist[$x].name)" -ForegroundColor Yellow + } + if ($endpos -lt $Clusterlist.length) { + Write-Host " $($step+1)" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host ">> Next Page" -ForegroundColor White + } + $Clusternum = Read-Host "`nSelect Cluster Number" + $Clusternum = [int]$Clusternum - 1 + if ($Clusternum -eq -1) { + $startpos -= $step + continue + } + if ($Clusternum -eq $step) { + $startpos += $step + continue + } + $Cluster = $Clusterlist[$Clusternum + $startpos].Name + } +} + +try { + Write-Host "Validating cluster ""$Cluster""... " -NoNewLine + $mycluster = get-cluster $Cluster + Write-Host "Success" -ForegroundColor Green +} catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Unable to locate cluster ""$Cluster"" in $vCenter" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +if ($dvSwitch -eq "") { + $myhost = $mycluster | Get-VMHost | Select-Object -First 1 + $SwitchList = Get-VdSwitch -VMHost $myhost + $startpos = 0 + $step = 10 + While (($dvSwitch -eq "") -or (-not $dvSwitch)) { + $endpos = $startpos + 10; + if ($endpos -gt $SwitchList.length) { $endpos = $SwitchList.length } + $page = $startpos / $step + 1 + $maxpage = [math]::Ceiling($SwitchList.length / $step) + Write-Host "`ndvSwitch Selection (Page $page of $maxpage):`n" + if ($startpos -gt 0) { + Write-Host " 0" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "<< Previous Page" -ForegroundColor White + } + for ($x = $startpos; $x -lt $endpos; $x++) { + Write-Host "$(([string]($x+1-$startpos)).PadLeft(3,' '))" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "$($SwitchList[$x].name)" -ForegroundColor Yellow + } + if ($endpos -lt $SwitchList.length) { + Write-Host " $($step+1)" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host ">> Next Page" -ForegroundColor White + } + $dvSwitchnum = Read-Host "`nSelect dvSwitch Number" + $dvSwitchnum = [int]$dvSwitchnum - 1 + if ($dvSwitchnum -eq -1) { + $startpos -= $step + continue + } + if ($dvSwitchnum -eq $step) { + $startpos += $step + continue + } + $dvSwitch = $SwitchList[$dvSwitchnum + $startpos].Name + } +} + +try { + Write-Host "Validating dvSwitch ""$dvSwitch""... " -NoNewLine + $mydvSwitch = Get-VdSwitch $dvSwitch + Write-Host "Success" -ForegroundColor Green +} catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Unable to locate dvSwitch $dvSwitch in $vCenter" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + exit +} + +if ($SourceVMName -eq "") { + $VMList = $mycluster | Get-VM + $startpos = 0 + $step = 10 + While (($SourceVMName -eq "") -or (-not $SourceVMName)) { + $endpos = $startpos + 10; + if ($endpos -gt $VMList.length) { $endpos = $VMList.length } + $page = $startpos / $step + 1 + $maxpage = [math]::Ceiling($VMList.length / $step) + Write-Host "`nSource VM Selection (Page $page of $maxpage):`n" + if ($startpos -gt 0) { + Write-Host " 0" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "<< Previous Page" -ForegroundColor White + } + for ($x = $startpos; $x -lt $endpos; $x++) { + Write-Host "$(([string]($x+1-$startpos)).PadLeft(3,' '))" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "$($VMlist[$x].name)" -ForegroundColor Yellow + } + if ($endpos -lt $VMList.length) { + Write-Host " $($step+1)" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host ">> Next Page" -ForegroundColor White + } + $VMnum = Read-Host "`nSelect VM Number" + $VMnum = [int]$VMnum - 1 + if ($VMnum -eq -1) { + $startpos -= $step + continue + } + if ($VMnum -eq $step) { + $startpos += $step + continue + } + $SourceVMName = $VMlist[$VMnum + $startpos].Name + } +} + +try { + Write-Host "Locating source VM ""$SourceVMName""... " -NoNewLine + if ($abyss = Get-VM $SourceVMName -ErrorAction Stop) { + Write-Host "Success" -ForegroundColor Green + } else { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Aborted" -ForegroundColor Yellow + } +} catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Error locating VM $SourceVMName in $vCenter" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +if ($Datastore -eq "") { + $DSList = $mycluster | Get-Datastore | Where-Object {$_.ExtensionData.Host.Count -gt 1} + $startpos = 0 + $step = 10 + While (($Datastore -eq "") -or (-not $Datastore)) { + $endpos = $startpos + 10; + if ($endpos -gt $DSList.length) { $endpos = $DSList.length } + $page = $startpos / $step + 1 + $maxpage = [math]::Ceiling($DSList.length / $step) + Write-Host "`nDatastore Selection (Page $page of $maxpage):`n" + if ($startpos -gt 0) { + Write-Host " 0" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "<< Previous Page" -ForegroundColor White + } + for ($x = $startpos; $x -lt $endpos; $x++) { + Write-Host "$(([string]($x+1-$startpos)).PadLeft(3,' '))" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "$($DSlist[$x].name)" -ForegroundColor Yellow + } + if ($endpos -lt $DSList.length) { + Write-Host " $($step+1)" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host ">> Next Page" -ForegroundColor White + } + $dvSwitchnum = Read-Host "`nSelect Datastore Number" + $dvSwitchnum = [int]$dvSwitchnum - 1 + if ($dvSwitchnum -eq -1) { + $startpos -= $step + continue + } + if ($dvSwitchnum -eq $step) { + $startpos += $step + continue + } + $Datastore = $DSlist[$dvSwitchnum + $startpos].Name + } +} + +try { + Write-Host "Locating Datastore ""$Datastore""... " -NoNewLine + $mydatastore = Get-Datastore $Datastore -ErrorAction Stop + if ($mydatastore) { + Write-Host "Success" -ForegroundColor Green + } else { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Unable to locate datastore $Datastore in $Cluster" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + } +} catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Error locating Datastore $Datastore in $vCenter" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +if ($Folder -eq "") { + Write-Host "Inventorying VM Folder Structure..." -NoNewLine + $FolderList = Get-Folder | Where-Object {$_.Parent.Name -eq "vm"} | Sort-Object -Property @{Expression={$_.Name}; Descending=$false} + $FolderList += Get-Folder | Where-Object {($_.Parent.Name -ne "vm") -and ($_.Type -eq "VM") -and $($_.Name -ne "vm")} | Sort-Object -Property @{Expression={$_.Parent.Name}; Descending=$false},@{Expression={$_.Name}; Descending=$false} + Write-Host " Success" -ForegroundColor Green + for($x = 0; $x -lt $FolderList.length; ++$x) { + $thisfolder = $FolderList[$x] + $path = "" + if ($thisfolder.Parent.Name -ne "vm") { + $searchcount = 0 + While ($searchcount -lt 10) { + $nextfolder = $thisfolder.Parent + $path = "$($nextfolder.Name)\$($path)" + if ($nextfolder.Parent.Name -ne "vm") { + $thisfolder = $nextfolder + ++$searchcount + } else { + $searchcount = 11 + } + } + } + if ($path -ne "") { + $path = "$($path)$($Folderlist[$x].Name)" + } else { + $path = $Folderlist[$x].Name + } + + $FolderList[$x] | Add-Member -NotePropertyName "FullPath" -NotePropertyValue $path + } + $startpos = 0 + $step = 10 + + While (-not $myfolder) { + $endpos = $startpos + 10; + if ($endpos -gt $FolderList.length) { $endpos = $FolderList.length } + $page = $startpos / $step + 1 + $maxpage = [math]::Ceiling($FolderList.length / $step) + Write-Host "`nFolder Selection (Page $page of $maxpage):`n" + if ($startpos -gt 0) { + Write-Host " 0" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "<< Previous Page" -ForegroundColor White + } + for ($x = $startpos; $x -lt $endpos; $x++) { + $path = $Folderlist[$x].FullPath + Write-Host "$(([string]($x+1-$startpos)).PadLeft(3,' '))" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host "$path" -ForegroundColor Yellow + } + if ($endpos -lt $FolderList.length) { + Write-Host " $($step+1)" -NoNewLine -ForegroundColor Green + Write-Host ": " -NoNewLine -ForegroundColor Gray + Write-Host ">> Next Page" -ForegroundColor White + } + $Foldernum = Read-Host "`nSelect Folder Number" + $Foldernum = [int]$Foldernum - 1 + if ($Foldernum -eq -1) { + $startpos -= $step + continue + } + if ($Foldernum -eq $step) { + $startpos += $step + continue + } + + $Folder = $FolderList[$Foldernum].FullPath + $myfolder = $FolderList[$Foldernum].Name + } +} + +try { + Write-Host "Locating Folder ""$Folder""... " -NoNewLine + $myfolder = GetFolderFromPath($Folder) + if ($myfolder) { + Write-Host "Success" -ForegroundColor Green + } else { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + } +} catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Error locating Folder $Folder in $vCenter" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +## Validate that the proper DRS groups exist for each site in the format "[site] Only VMs" +Write-Host "Verifying that the necessary DRS groups exist..." +$sites = $data.Site | Select-Object -Unique -CaseInsensitive + +$siteerror = $false +foreach ($site in $sites) { + $sitegroup = "$site Only VMs" + Write-Host " - $sitegroup... " -NoNewLine + try { + $drsg = Get-DrsGroup -Cluster $Cluster -Name $sitegroup + if ($drsg) { + Write-Host "Success" -ForegroundColor Green + } else { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + $siteerror = $true + } + } catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "ERROR: Unable to locate DRS group $sitegroup." -ForegroundColor Yellow -BackgroundColor Red -NoNewLine + Write-Host "" + $siteerror = $true + } +} + +if ($siteerror) { + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +## Validate that the necessary network port groups exist in the format "[Description] - VLAN[VLAN]" +Write-Host "Verifying that the necessary port groups exist..." +$pgerror = $false +foreach ($row in $data) { + $vlan = [int]$row.VLAN + $description = $row.Description + $myportgroupname = "$description - VLAN$vlan" + Write-Host " - $myportgroupname... " -NoNewLine + try { + $pg = Get-VDPortGroup -Name $myportgroupname + if ($pg) { + Write-Host "Success" -ForegroundColor Green + } else { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + $pgerror = $true + } + } catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + $pgerror = $true + } +} + +if ($pgerror) { + Write-Host "Operation Terminated" -ForegroundColor Yellow + exit +} + +exit + +foreach($row in $data) { + try { + $abyss = [int]$row.VLAN + } catch { + continue + } + $vlan = [int]$row.VLAN + $description = $row.Description + + $myportgroupname = "$description - VLAN$vlan" + $myvmname = "KISStress - VLAN$vlan" + + Write-Host + + try { + if (Get-VM $myvmname -ErrorAction Silent) { + Write-Host "WARNING: VM ""$myvmname"" already exists. Skipping." -ForegroundColor Yellow + continue + } + } catch { + Write-Host "ERROR: Unable to determine if ""$myvmname"" exists. Skipping." -ForegroundColor Red + continue + } + + try { + $myportgroup = Get-VdPortGroup -Name $myportgroupname -VDSwitch $dvswitch + } catch { + Write-Host "ERROR: Could not locate port group ""$myportgroupname""" + continue + } + + Write-Host "Cloning ""$SourceVMName"" to VM ""$myvmname""... " -NoNewLine + try { + $task = New-VM -Name $myvmname -VM $SourceVMName -ResourcePool $mycluster -Datastore $Datastore -Location $myfolder -DiskStorageFormat Thin -ErrorAction Silent -RunAsync + } catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + continue + } + + $created = $false + while (($task = Get-Task -iD $task.Id).State -eq "Running") { + Start-Sleep -Seconds 5 + Write-Host "." -NoNewLine + } + switch(($task = Get-Task -iD $task.Id).State) { + "Success" { + Write-Host "Success" -ForegroundColor Green + } + "Error" { + if ($task.ExtensionData.Info.Cancelled) { + Write-Host "Failure - Task Cancelled" -ForegroundColor Yellow -BackgroundColor Red + continue + } else { + Write-Host "Failure - Unknown Error" -ForegroundColor Yellow -BackgroundColor Red + continue + } + } + } + $nic = Get-VM $myvmname | Get-NetworkAdapter + try { + Write-Host "Changing NIC on VM ""$myvmname"" to port group ""$myportgroupname""... " -NoNewLine + $task = $nic | Set-NetworkAdapter -Portgroup $myportgroup -Confirm:$false -ErrorAction Stop -RunAsync + while (($task = Get-Task -iD $task.Id).State -eq "Running") { + Start-Sleep -Seconds 1 + Write-Host "." -NoNewLine + } + switch(($task = Get-Task -iD $task.Id).State) { + "Success" { + Write-Host "Success" -ForegroundColor Green + } + "Error" { + if ($task.ExtensionData.Info.Cancelled) { + Write-Host "Failure - Task Cancelled" -ForegroundColor Yellow -BackgroundColor Red + } else { + Write-Host "Failure - Unknown Error" -ForegroundColor Yellow -BackgroundColor Red + } + } + } + } catch { + Write-Host " Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + } + + if ($row.Site) { + Write-Host "Adding VM ""$myvmname"" to DRS Group ""$($row.Site) Only VMs"" in cluster $Cluster... " -NoNewLine + try { + $task = Add-VMToDrsGroup -Cluster $Cluster -DrsGroup "$($row.Site) Only VMs" -VM $myvmname + $task | Add-Member -NotePropertyName "Id" -NotePropertyValue "Task-$($task.Value)" + } catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "ERROR: Error adding VM ""$myvmname"" to DRS Group ""$($row.Site) Only VMs""" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + continue + } + + while (($task = Get-Task -iD $task.Id).State -eq "Running") { + Start-Sleep -Seconds 1 + Write-Host "." -NoNewLine + } + switch(($task = Get-Task -iD $task.Id).State) { + "Success" { + Write-Host "Success" -ForegroundColor Green + } + "Error" { + if ($task.ExtensionData.Info.Cancelled) { + Write-Host "Failure - Task Cancelled" -ForegroundColor Yellow -BackgroundColor Red + } else { + Write-Host "Failure - Unknown Error" -ForegroundColor Yellow -BackgroundColor Red + } + } + } + } + + try { + Write-Host "Powering on VM ""$myvmname""... " -NoNewLine + $task = Start-VM $myvmname -ErrorAction Stop -RunAsync + } catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + } + + $booted = $false + while (!$booted) { + if ((Get-VM $myvmname).ExtensionData.Guest.ToolsStatus -eq "toolsOk") { + $booted = $true + continue + } + Start-Sleep 5 + Write-Host "." -NoNewLine + } + Write-Host "Success" -ForegroundColor Green + +# Update Network Information If Provided + if ($setip) { + $ipaddress = $row.IPAddress + $netmask = $row.netmask + $gateway = $row.Gateway + + if (!$ipaddress -or !$netmask -or !$gateway) { continue } + Write-Host "Updating network configuration for vm ""$myvmname""... " -NoNewLine + + $ifcfg = "sudo echo 'STARTMODE=auto' > /etc/sysconfig/network/ifcfg-eth0 +sudo echo 'BOOTPROTO=static' >> /etc/sysconfig/network/ifcfg-eth0 +sudo echo 'IPADDR=$ipaddress' >> /etc/sysconfig/network/ifcfg-eth0 +sudo echo 'NETMASK=$netmask' >> /etc/sysconfig/network/ifcfg-eth0 +sudo echo 'default $gateway - -' > /etc/sysconfig/network/routes +sudo /etc/init.d/network restart +" + $UserName = "stress" + $Password = ConvertTo-SecureString -String "stress" -AsPlainText -Force + $Credential = New-Object System.Management.Automation.PSCredential -ArgumentList $UserName, $Password + try { + $abyss = Invoke-VMScript $myvmname -ScriptText $ifcfg -GuestCredential $Credential -ScriptType Bash + Write-Host "Success" -ForegroundColor Green + } catch { + Write-Host "Failure" -ForegroundColor Yellow -BackgroundColor Red + Write-Host "Message: $($_.Exception.Message)" -ForegroundColor yellow + } + } +} \ No newline at end of file diff --git a/vCenter Tools/GetKeys.ps1 b/vCenter Tools/GetKeys.ps1 new file mode 100644 index 0000000..f62e9e9 --- /dev/null +++ b/vCenter Tools/GetKeys.ps1 @@ -0,0 +1,150 @@ +param ( + [string]$vCenter = "", + [switch]$SaveCred = $false, + [switch]$Help = $false +) + +# Variables +$fileVersion = "1.1.0" +$fileDate = "2025-04-02" + +# Display Script Banner +Write-Host "--------------------------------------------------" -ForegroundColor White +Write-Host "vSphere TPM Key Inventory" -ForegroundColor Green +Write-Host "Version $($FileVersion) ($($FileDate))" -ForegroundColor Green +Write-Host "Written by Charlie Silverman" -ForegroundColor Green +Write-Host "--------------------------------------------------" -ForegroundColor White + +if ($Help) { + Write-Host + Write-Host "Purpose: Collect TPM encryption keys for all ESXi hosts." + Write-Host "Command Syntax:" + Write-Host " GetKeys.ps1 (-vcenter [vcenter host name]) (-savecred) (-help)" + Write-Host "Command Line Options:" + Write-Host + Write-Host -NoNewLine " -vCenter " -foregroundcolor Green + Write-Host "- The FQDN or IP address of a vCenter server." + Write-Host -NoNewLine " -savecred " -foregroundcolor Green + Write-Host "- Configure and store vCenter server credentials. This will only store the credentials under" + Write-Host " the current logged in user." + Write-Host -NoNewLine " -help " -foregroundcolor Green + Write-Host "- Display command help." + Write-Host + Write-Host "If no any of the information is not provided, you will be prompted. If a credential has been previously stored, it will be used again unless the -savecred option is specified." + Write-Host + exit +} + +if (-not (Get-Module -ListAvailable -Name VMware.PowerCLI*)) { + Write-Host "ERROR: VMware PowerCLI is not installed!" -foregroundcolor yellow + exit +} + +$hideresult = Set-PowerCLIConfiguration -InvalidCertificateAction Ignore -Confirm:$false + +if ($vCenter -eq "") { + $vCenter = Read-Host "Enter name of vCenter Server" +} + +if ($savecred) { + $credential = Get-Credential -Message "Enter credentials for vCenter server $vcenter" + $credential | Export-Clixml -path $env:USERPROFILE\kis-getkeys-$vcenter.cred + Write-Host "Saving credentials." +} + +if (Test-Path -path $env:USERPROFILE\kis-getkeys-$vcenter.cred -PathType Leaf) { + $credentials = Import-Clixml -path $env:USERPROFILE\kis-getkeys-$vcenter.cred + Write-Host "Using stored credentials" +} else { + $credentials = Get-Credential -Message "Enter credentials for vCenter server $vcenter" + if (!$credentials) { + Write-Host "ERROR: No credentials were entered" -foregroundcolor yellow + } +} + +try { + Write-Host -NoNewLine "Connecting to vCenter $vcenter..." + $vcconn = Connect-VIServer $vcenter -Credential $credentials -ErrorAction SilentlyContinue + Write-Host " Success" -ForegroundColor green +} catch { + Write-Host " Failure" -ForegroundColor Yellow -BackgroundColor Red + exit +} + +$now = (Get-Date).ToString("yyyyMMdd_hhmm") +$exportfile = "TPMKeys-$vCenter-$now.csv" + +$VMHosts = Get-VMHost | Sort-Object +$VMHostKeys = @() +foreach ($VMHost in $VMHosts) { + $esxcli = Get-EsxCli -VMHost $VMHost -V2 + try { + $encryption = $esxcli.system.settings.encryption.get.Invoke() + if ($encryption.Mode -eq "TPM") + { + $key = $esxcli.system.settings.encryption.recovery.list.Invoke() + $hostKey = [pscustomobject]@{ + Host = $VMHost.Name + EncryptionMode = $encryption.Mode + RequireExecutablesOnlyFromInstalledVIBs = $encryption.RequireExecutablesOnlyFromInstalledVIBs + RequireSecureBoot = $encryption.RequireSecureBoot + RecoveryID = $key.RecoveryID + RecoveryKey = $key.Key + } + $VMHostKeys += $hostKey + } + else + { + $hostKey = [pscustomobject]@{ + Host = $VMHost.Name + EncryptionMode = $encryption.Mode + RequireExecutablesOnlyFromInstalledVIBs = $encryption.RequireExecutablesOnlyFromInstalledVIBs + RequireSecureBoot = $encryption.RequireSecureBoot + RecoveryID = $null + RecoveryKey = $null + } + $VMHostKeys += $hostKey + } + } + catch { + $VMHost.Name + $_ + } +} +Write-Host "Exporting TPM keys for all hosts in $vcenter`n to $exportfile..." -NoNewLine +try { + $VMHostKeys | Export-Csv $exportfile + Write-Host " Complete" -ForegroundColor Green +} catch { + Write-Host " Failed" -ForegroundColor Red + exit +} + +Write-Host "Attempting to reset all TPM Encryption Recovery Key Backup Alarms..." +# Locate TPM Encrytpion Recovery Key Backup Alarm ID +$alarm = Get-AlarmDefinition "TPM Encryption Recovery Key Backup Alarm" +$alarmID = $alarm.Id -split '-', 2 | select-object -last 1 +$alarmMgr = Get-View AlarmManager + +foreach ($VMHost in $VMHosts) { + try { + $decalarm = $VMHost.ExtensionData.TriggeredAlarmState | where-object {$_.Alarm.Value -eq $alarmID} | Select-Object -first 1 + if ([string]::IsNullorEmpty($decalarm)) { + continue + } + } catch { + Write-Host "Error retrieving alarms for host $VMHost" + continue + } +} + +Write-Host "Clearing all yellow alarms from ESXi hosts..." +try { + $filter = New-Object VMware.Vim.AlarmFilterSpec + $filter.Status += [VMware.Vim.ManagedEntityStatus]::yellow + $filter.TypeEntity = [VMware.Vim.AlarmFilterSpecAlarmTypeByEntity]::entityTypeHost + $filter.TypeTrigger = [vmware.vim.AlarmFilterSpecAlarmTypeByTrigger]::triggerTypeAll + $alarmMgr.ClearTriggeredAlarms($filter) + Write-Host " Success" -ForegroundColor Green +} catch { + Write-Host " Failed" -ForegroundColor Red +} diff --git a/vCenter Tools/GetSnaps.ps1 b/vCenter Tools/GetSnaps.ps1 new file mode 100644 index 0000000..194b9e3 --- /dev/null +++ b/vCenter Tools/GetSnaps.ps1 @@ -0,0 +1,114 @@ +param ( + [string]$vcenter = "", + [switch]$allvms = $false, + [switch]$SaveCred = $false, + [switch]$Help = $false +) + +# Variables +$fileVersion = "1.0.0" +$fileDate = "2024-12-11" +$savecred = $false + +# Display Script Banner +Write-Host "--------------------------------------------------" -ForegroundColor White +Write-Host "vCenter Snapshot Report" -ForegroundColor Green +Write-Host "Version $($FileVersion) ($($FileDate))" -ForegroundColor Green +Write-Host "Written by Charlie Silverman" -ForegroundColor Green +Write-Host "--------------------------------------------------" -ForegroundColor White + +if ($Help) { + Write-Host "Command Syntax:" -ForegroundColor Green + Write-Host 'GetSnaps.ps1 -vcenter="VCURI" [-help] [-savecred]' -ForegroundColor Green + Write-Host "" + Write-Host "Command line options:" -ForegroundColor Green + Write-Host "---------------------" -ForegroundColor Green + Write-Host "-vcenter - Specify the FQDN for the vCenter server" -ForegroundColor Green + Write-Host "-allvms - Get snapshots for all VMs. Omitting this option will only check powered on VMs." -ForegroundColor Green + Write-Host "-savecred - Save Credentials. If credentials were previously saved and this option is not selected," -ForegroundColor Green + Write-Host " they will be used." -ForegroundColor Green + Write-Host "-help - Show this help information." -ForegroundColor Green + exit +} + +if ($vcenter -eq "") { + $vcenter = Read-Host "Enter name of vCenter Server" +} + +try { + if (Test-Path -Path "$env:USERPROFILE\GetSnaps-${vcenter}.cred" -PathType Leaf) { + Write-Host "Using stored credentials for $vcenter." + $cred = Import-CliXML -path "$env:USERPROFILE\GetSnaps-${vcenter}.cred" + } else { + $cred = Get-Credential -Message "Enter credentials for vCenter $vcenter" + } + $vcenterConnection = connect-viserver $vcenter -credential $cred -ErrorAction Stop +} catch { + Write-Host "ERROR: Invalid credentials or incorrect vCenter FQDN" + Write-Host $_ + exit +} +if ($savecred) { + Write-Host "Storing credentials for $vcenter." + $cred | Export-CliXML -Path "$env:USERPROFILE\GetSnaps-${vcenter}.cred" +} + +$DesktopPath = [Environment]::GetFolderPath("Desktop") +$now = (Get-Date).ToString("yyyyMMdd_hhmm") +$outputFileName = "$DesktopPath\VMSnapshotList-$now.html" + +# Get all VMs +if ($allvms) { + $VMs = Get-VM +} else { + $VMs = Get-VM | Where {$_.PowerState -eq "PoweredOn"} +} + +# Create empty array to hold snapshot information +$SnapshotInfo = @() + +# Loop through each VM and get snapshot information +foreach ($VM in $VMs) { + $Snapshots = Get-Snapshot -VM $VM + + # Loop through each snapshot and add information to array + foreach ($Snapshot in $Snapshots) { + $SnapshotInfo += [PSCustomObject]@{ + VMName = $VM.Name + SnapshotName = [System.Uri]::UnescapeDataString($Snapshot.Name) + Created = $Snapshot.Created + Description = $Snapshot.Description + SizeGB = [math]::Round(($Snapshot.SizeGB),2) + } + } +} + +# Create HTML output +$HTML = @" + +
+