Skip to content

Instantly share code, notes, and snippets.

@midacts
Created December 24, 2017 03:59
Show Gist options
  • Save midacts/6f66e3b9617b81863588ce4c9c64ddc3 to your computer and use it in GitHub Desktop.
Save midacts/6f66e3b9617b81863588ce4c9c64ddc3 to your computer and use it in GitHub Desktop.
function New-VesterConfig {
<#
.SYNOPSIS
Generates a Vester config file from settings in your existing VMware environment.
.DESCRIPTION
New-VesterConfig is designed to be a quick way to get started with Vester.
Vester needs one config file for each vCenter server it interacts with. To
help speed up this one-time creation process, New-VesterConfig uses PowerCLI
to pull current values from your environment to store in the config file.
You'll be prompted with the list of Clusters/Hosts/VMs/etc. discovered, and
asked to choose one of each type to use as a baseline; i.e. "all my other
hosts should be configured like this one." Those values are displayed
interactively, and you can manually edit them as desired.
Optionally, advanced users can use the -Quiet parameter. This suppresses
all host output and prompts. Instead, values are pulled from the first
Cluster/Host/VM/etc. found alphabetically. Manual review afterward of the
config file is strongly encouraged if using the -Quiet parameter.
It outputs a single Config.json file at \Vester\Configs, which may require
admin rights. Optionally, you can use the -OutputFolder parameter to
specify a different folder to store the Config.json file.
.EXAMPLE
New-VesterConfig
Ensures that you are connected to only one vCenter server.
Based on all Vester test files found in '\Vester\Tests', the command
discovers values from your environment and displays them, occasionally
prompting for a selection of which cluster/host/etc. to use.
Outputs a new Vester config file to '\Vester\Configs\Config.json',
which may require admin rights.
.EXAMPLE
New-VesterConfig -Quiet -OutputFolder "$env:USERPROFILE\Desktop"
-Quiet suppresses all host output and prompts, instead pulling values
from the first cluster/host/etc. found alphabetically.
Upon completion, Config.json will be created on your Desktop.
.NOTES
This command relies on the Pester and PowerCLI modules for testing.
"Get-Help about_Vester" for more information.
.LINK
https://wahlnetwork.github.io/Vester
.LINK
https://github.com/WahlNetwork/Vester
#>
[CmdletBinding()]
param (
# Select a folder to create a new Config.json file inside
[Parameter(Mandatory = $False)]
[ValidateScript({Test-Path $_ -PathType Container})]
[object]$OutputFolder = "$(Split-Path -Parent $PSScriptRoot)\Configs",
[Parameter(Mandatory = $False)]
[string]$Datacenter = '*',
[Parameter(Mandatory = $False)]
[string]$Cluster = '*',
[Parameter(Mandatory = $False)]
[string]$DatastoreCluster = '*',
[Parameter(Mandatory = $False)]
[string]$VMHost = '*',
[Parameter(Mandatory = $False)]
[string]$VM = '*',
[Parameter(Mandatory = $False)]
[string]$VDS = '*'
)
# Must have only one vCenter connection open
# Potential future work: loop through all vCenter connections
If ($DefaultVIServers.Count -lt 1) {
Write-Warning 'Please connect to vCenter before running this command.'
throw 'A single connection with Connect-VIServer is required.'
} ElseIf ($DefaultVIServers.Count -gt 1) {
Write-Warning 'Vester config files are designed to be unique to each vCenter server.'
Write-Warning 'Please connect to only one vCenter before running this command.'
Write-Warning "Current connections: $($DefaultVIServers -join ' / ')"
throw 'A single connection with Connect-VIServer is required.'
}
Write-Verbose "vCenter: $($DefaultVIServers.Name)"
# TODO: Make this a param? Or keep hardcoded?
Write-Verbose "Assembling Vester files within $(Split-Path -Parent $PSScriptRoot)\Tests\"
$GetVesterTest = "$(Split-Path -Parent $PSScriptRoot)\Tests\" | Get-VesterTest -Simple
# Appending to a list is faster than rebuilding an array
$VesterTestSuite = New-Object 'System.Collections.Generic.List[PSCustomObject]'
# For each *.Vester.ps1 file found
$GetVesterTest | ForEach-Object {
# Do the necessary Split-Path calls once and save them for later
$TestObj = [PSCustomObject]@{
Full = $_
Parent = Split-Path (Split-Path $_ -Parent) -Leaf
Leaf = Split-Path $_ -Leaf
}
$VesterTestSuite.Add($TestObj)
}
# Grabs the high level test scopes.
# Under Vester\Test the folders named: Cluster, DSCluster, Host, etc
$ScopeList = ($VesterTestSuite | Select-Object -Property Parent -Unique).Parent
Write-Verbose "Scopes supplied by test files: $($ScopeList -join ' | ')"
# Builds out the config
$config = [ordered]@{}
$config.vcenter = @{vc = $DefaultVIServers.Name}
$config.scope = [ordered]@{
datacenter = $Datacenter
cluster = $Cluster
dscluster = $DatastoreCluster
host = $VMHost
vm = $VM
vds = $VDS
}
# Gathers the supplied inventory items
Write-Verbose "Gathering inventory objects from $($DefaultVIServers.Name)"
$vCenter = $DefaultVIServers.Name
$DatacenterObject = Get-Datacenter -Name $config.scope.datacenter -Server $vCenter
$ClusterObject = Get-Cluster -Location $DatacenterObject -Name $config.scope.cluster
$DSClusterObject = $DatacenterObject | Get-DatastoreCluster -Name $config.scope.dscluster
$VMHostObject = $ClusterObject | Get-VMHost -Name $config.scope.host
$VMObject = $ClusterObject | Get-VM -Name $config.scope.vm
$NetworkObject = $DatacenterObject | Get-VDSwitch -Name $config.scope.vds -ErrorAction Stop
# Group tests by their scope
ForEach ($Scope in $ScopeList) {
Write-Verbose "Processing all tests for scope $Scope"
# Loop through each test file applicable in the current scope
# Couldn't resist calling each file a Vest. Sorry, everyone
ForEach ($Vest in $VesterTestSuite | Where-Object Parent -eq $Scope) {
Write-Verbose "Processing test file $($Vest.Leaf)"
# Import all variables from the current .Vester.ps1 file
. $Vest.Full
$Object = switch ($Scope) {
'vCenter' {$vCenter}
'Datacenter' {$DatacenterObject}
'Cluster' {$ClusterObject}
'DSCluster' {$DSClusterObject}
'Host' {$VMHostObject}
'VM' {$VMObject}
'Network' {$NetworkObject}
# If not scoped properly, don't know what object to check
Default {$null}
}
# TODO: Should probably offload this to a private function
$CfgLine = (Select-String -Path $Vest.Full -Pattern '\$cfg') -replace '.*\:[0-9]+\:',''
$CfgLine -match '.*\$cfg\.([a-z]+)\.([a-z]+)$' | Out-Null
# Run the $Actual script block, storing the result in $Result
If ($Object -and ($Result = & $Actual) -ne $null) {
# Call module private function Set-VesterConfigValue to add the entry
Set-VesterConfigValue -Value ($Result -as $Type)
} Else {
# Inventory $Object doesn't exist, or $Actual returned nothing
# Populate with null value; Invoke-Vester will skip this test
Set-VesterConfigValue -Value $null
} #if $Object and $Result
} #foreach $Vest
# Formats the results for this scope in an ordered hashtable
Write-Host ''
Write-Host ' # Config values for scope ' -NoNewline
Write-Host "$Scope" -ForegroundColor Green
# Only gets the enumerator if values exist
$Sorted = If($config.$Scope){ $config.$Scope.GetEnumerator() | Sort-Object Name }
$Sorted
$config.$Scope = [ordered]@{}
$Sorted | Foreach-Object { $config.$Scope.Add($_.Name, $_.Value) }
} #foreach $Scope
Write-Verbose "Creating config file at $OutputFolder\Config.json"
Try {
$config | ConvertTo-Json | Out-File $OutputFolder\Config.json -ErrorAction Stop
Write-Host "`nConfig file created at " -ForegroundColor Green -NoNewline
Write-Host "$OutputFolder\Config.json"
Write-Host 'Edit the file manually to change any displayed values.'
} Catch {
Write-Warning "`nFailed to create config file at $OutputFolder\Config.json"
Write-Warning 'Have you tried running PowerShell as an administrator?'
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment