diff --git a/Vester/Private/Template/VesterTemplate.Tests.ps1 b/Vester/Private/Template/VesterTemplate.Tests.ps1 index 079a2da..0ef5ade 100644 --- a/Vester/Private/Template/VesterTemplate.Tests.ps1 +++ b/Vester/Private/Template/VesterTemplate.Tests.ps1 @@ -22,6 +22,99 @@ Param( [switch]$Remediate ) +function ConvertPSObjectToHashtable { + param ( + [Parameter(ValueFromPipeline)] + $InputObject + ) + + process { + if ($InputObject -is [psobject]){ + $hash = @{} + foreach ($property in $InputObject.PSObject.Properties){ + $hash[$property.Name] = ConvertPSObjectToHashtable $property.Value + } + $hash + } + else{ + $InputObject + } + } +} + +function Compare-Hashtable { +<# +.SYNOPSIS +Compare two Hashtable and returns an array of differences. + +.DESCRIPTION +The Compare-Hashtable function computes differences between two Hashtables. Results are returned as +an array of objects with the properties: "key" (the name of the key that caused a difference), +"side" (one of "<=", "!=" or "=>"), "lvalue" an "rvalue" (resp. the left and right value +associated with the key). + +.PARAMETER left +The left hand side Hashtable to compare. + +.PARAMETER right +The right hand side Hashtable to compare. + +.EXAMPLE + +Returns a difference for ("3 <="), c (3 "!=" 4) and e ("=>" 5). + +Compare-Hashtable @{ a = 1; b = 2; c = 3 } @{ b = 2; c = 4; e = 5} + +.EXAMPLE + +Returns a difference for a ("3 <="), c (3 "!=" 4), e ("=>" 5) and g (6 "<="). + +$left = @{ a = 1; b = 2; c = 3; f = $Null; g = 6 } +$right = @{ b = 2; c = 4; e = 5; f = $Null; g = $Null } + +Compare-Hashtable $left $right + +#> +[CmdletBinding()] + param ( + [Parameter(Mandatory = $true)] + [Hashtable]$Left, + + [Parameter(Mandatory = $true)] + [Hashtable]$Right + ) + + function New-Result($Key, $LValue, $Side, $RValue) { + New-Object -Type PSObject -Property @{ + key = $Key + lvalue = $LValue + rvalue = $RValue + side = $Side + } + } + [Object[]]$Results = $Left.Keys | % { + if ($Left.ContainsKey($_) -and !$Right.ContainsKey($_)) { + New-Result $_ $Left[$_] "<=" $Null + } else { + if ($Left[$_] -is [hashtable] -and $Right[$_] -is [hashtable] ) { + Compare-Hashtable $Left[$_] $Right[$_] + } + else { + $LValue, $RValue = $Left[$_], $Right[$_] + if ($LValue -ne $RValue) { + New-Result $_ $LValue "!=" $RValue + } + } + } + } + $Results += $Right.Keys | % { + if (!$Left.ContainsKey($_) -and $Right.ContainsKey($_)) { + New-Result $_ $Null "=>" $Right[$_] + } + } + if ($Results -ne $null) { $Results } +} + # Gets the scope, the objects for the scope and their requested test files $Scopes = Split-Path (Split-Path $TestFiles -Parent) -Leaf | Select -Unique $Final = @() @@ -74,60 +167,97 @@ foreach($Scope in $Final.Scope) # Runs through each test file on the below objects in the current scope foreach($Test in $Tests) { - Write-Verbose "Processing test file $Test" - $TestName = Split-Path $Test -Leaf - - Describe -Name "$Scope Configuration: $TestName" -Fixture { - # Pull in $Title/$Description/$Desired/$Type/$Actual/$Fix from the test file - . $Test - - # Pump the brakes if the config value is $null - If ($Desired -eq $null) { - Write-Verbose "Due to null config value, skipping test $TestName" - # Use continue to skip this test and go to the next loop iteration - continue - } - # Loops through each object in the inventory list for the specific scope. - # It runs one test at a time against each $Object and moves onto the next test. - foreach($Object in $Inventory) - { - It -Name "$Scope $($Object.Name) - $Title" -Test { - Try { - # "& $Actual" is running the first script block to compare to $Desired - # The comparison should be empty - # (meaning everything is the same, as expected) - $Result = (& $Actual -as $Type) - #allow for $Desired to be a scriptblock vs simple value - if ($Desired.GetType().name -eq 'scriptblock') { - $Desired = (& $Desired -As $Type) - } - Compare-Object -ReferenceObject $Desired -DifferenceObject $Result | - Should BeNullOrEmpty - } Catch { - # If the comparison found something different, - # Then check if we're going to fix it - If ($Remediate) { - Write-Warning -Message $_ - # -WhatIf support wraps the command that would change values - If ($PSCmdlet.ShouldProcess("vCenter '$($cfg.vcenter.vc)' - $Scope '$Object'", "Set '$Title' value to '$Desired'")) { - Write-Warning -Message "Remediating $Object" - # Execute the $Fix script block - & $Fix - } - } Else { - # -Remediate is not active, so just report the error - $Message = @( - "Desired: [$($Desired.gettype())] $Desired" - "Actual: [$($Result.gettype())] $Result" - "Synopsis: $Description" - "Link: https://wahlnetwork.github.io/Vester/reference/tests/$Scope/$($Title.replace(' ','-').replace(':','')).html" - "Test File: $Test" - ) -join "`n" - Throw $Message - } - } #Try/Catch - } #It + # Loops through each object in the inventory list for the specific scope. + # It runs one test at a time against each $Object and moves onto the next test. + ForEach($Object in $Inventory) + { + Write-Verbose "Processing test file $Test" + $TestName = Split-Path $Test -Leaf + + Describe -Name "$Scope Configuration: $TestName" -Fixture { + # Pull in $Title/$Description/$Desired/$Type/$Actual/$Fix from the test file + . $Test + + # If multiple tests + # Added in a check for $NULL and "" as you can't run a method (gettype()) on a $Null valued expression + # This is checking for an object that is a PSCustomobject, which shouldnt be null. + If(($Desired -ne $NULL) -and ($Desired -ne "") -and ($Desired.GetType().Name -eq "PSCustomObject")) { + # Gathers the the actual and desired values + # Formats the hashtable as a PSCustomObject + # As a side note: The ActualObjects Type is always the correct object type + # ConvertFrom-Json does not preserve things like 'int64' + # Converts to hashtable + $Results = (& $Actual) + + # Converts $Desired to a hashtable as it needs to be a hashtable to be compared + # $ht2 = @{} + # $Desired.psobject.properties | Foreach { $ht2[$_.Name] = $_.Value } + # $Desired = $ht2 + $Desired = $Desired | ConvertPSObjectToHashtable + + It -Name "$Scope $($Object.Name) - $Title" -Test { + Try { + $Mishaps = Compare-HashTable -Left $Desired -Right $Results + $Mishaps | Should BeNullOrEmpty + } Catch { + # If the comparison found something different, + # Then check if we're going to fix it + If($Remediate) { + Write-Warning -Message $_ + # -WhatIf support wraps the command that would change values + If($PSCmdlet.ShouldProcess("vCenter '$($cfg.vcenter.vc)' - $Scope '$Object'", "Set '$Title' value to '$Desired'")) + { + Write-Warning -Message "Remediating $Object" + # Execute the $Fix script block + & $Fix + } + } Else { + # -Remediate is not active, so just report the error + ### Changed it to write-error so it didnt terminate the above foreach loop + #Write-Error "$($_.Exception.Message)" -ErrorAction Stop + Write-Error "$($_.Exception.Message)`n$($Mishaps | Convertto-json)" -ErrorAction "Stop" + } + } # Try/Catch + } # It + } # If $Desired -eq PSCustomobject + # Else it is a normal single value test + Else + { + It -Name "$Scope $($Object.Name) - $Title" -Test { + Try { + # Checks for $NULLs + If($Desired -eq $NULL) { + Write-Verbose "Making sure `$Null is still `$Null" + ($Desired -eq (& $Actual -as $Type)) -or ("" -eq (& $Actual -as $Type)) | Should Be $TRUE + } Else { + Compare-Object -ReferenceObject $Desired -DifferenceObject (& $Actual -as $Type) | Should BeNullOrEmpty + } + } Catch { + # If the comparison found something different, + # Then check if we're going to fix it + If ($Remediate) { + Write-Warning -Message $_ + # -WhatIf support wraps the command that would change values + If ($PSCmdlet.ShouldProcess("vCenter '$($cfg.vcenter.vc)' - $Scope '$Object'", "Set '$Title' value to '$Desired'")) { + Write-Warning -Message "Remediating $Object" + # Execute the $Fix script block + & $Fix + } + } Else { + # -Remediate is not active, so just report the error + $Message = @( + "Desired: [$($Desired.gettype())] $Desired" + "Actual: [$($Result.gettype())] $Result" + "Synopsis: $Description" + "Link: https://wahlnetwork.github.io/Vester/reference/tests/$Scope/$($Title.replace(' ','-').replace(':','')).html" + "Test File: $Test" + ) -join "`n" + Throw $Message + } + } #Try/Catch + } #It + } #If/Else $Desired.GetType().Name -eq "PSCustomObject" } #Foreach Inventory }#Describe }#Foreach Tests diff --git a/Vester/Tests/Host/AD-JoinDomain.Vester.ps1 b/Vester/Tests/Host/AD-JoinDomain.Vester.ps1 new file mode 100644 index 0000000..e940452 --- /dev/null +++ b/Vester/Tests/Host/AD-JoinDomain.Vester.ps1 @@ -0,0 +1,29 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'Join Domain' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Join ESXi hosts to an Active Directory (AD) domain to eliminate the need to create and maintain multiple local user accounts.' + +# The config entry stating the desired values +$Desired = $cfg.host.joindomain + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-VMHostAuthentication).Domain +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + if (($Object | Get-VMHostAuthentication).Domain -ne $null){ + $Object | Get-VMHostAuthentication | Set-VMHostAuthentication -LeaveDomain -Force -Confirm:$false + } + $Object | Get-VMHostAuthentication | Set-VMHostAuthentication -JoinDomain -Domain $Desired -Credential (Get-Credential -Message "Please enter privileged credential for join domain $Desired") -Confirm:$false +} diff --git a/Vester/Tests/Host/DCUI-Service-Policy.Vester.ps1 b/Vester/Tests/Host/DCUI-Service-Policy.Vester.ps1 new file mode 100644 index 0000000..2f0e857 --- /dev/null +++ b/Vester/Tests/Host/DCUI-Service-Policy.Vester.ps1 @@ -0,0 +1,32 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'DCUI Service Policy' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Policy for DCUI service (on,off,automatic)' + +# The config entry stating the desired values +$Desired = $cfg.host.dcuiservicepolicy + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-VMHostService | Where-Object -FilterScript { + $_.Key -eq 'DCUI' + }).Policy +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + Set-VMHostService -HostService ($Object | + Get-VMHostService | + Where-Object -FilterScript { + $_.Key -eq 'DCUI' + }) -Policy $Desired -ErrorAction Stop +} diff --git a/Vester/Tests/Host/DCUI-Service.Vester.ps1 b/Vester/Tests/Host/DCUI-Service.Vester.ps1 new file mode 100644 index 0000000..a2d06b6 --- /dev/null +++ b/Vester/Tests/Host/DCUI-Service.Vester.ps1 @@ -0,0 +1,43 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'DCUI Service State' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Checks state of DCUI service (running or stopped)' + +# The config entry stating the desired values +$Desired = $cfg.host.dcuiservicerunning + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'bool' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-VMHostService | Where-Object -FilterScript { + $_.Key -eq 'DCUI' + }).Running +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + if ($Desired -eq $true) + { + Start-VMHostService -HostService ($Object | + Get-VMHostService | + Where-Object -FilterScript { + $_.Key -eq 'DCUI' + }) -ErrorAction Stop -Confirm:$false + } + if ($Desired -eq $false) + { + Stop-VMHostService -HostService ($Object | + Get-VMHostService | + Where-Object -FilterScript { + $_.Key -eq 'DCUI' + }) -ErrorAction Stop -Confirm:$false + } +} diff --git a/Vester/Tests/Host/ISCSI-CHAP.Vester.ps1 b/Vester/Tests/Host/ISCSI-CHAP.Vester.ps1 new file mode 100644 index 0000000..79e7950 --- /dev/null +++ b/Vester/Tests/Host/ISCSI-CHAP.Vester.ps1 @@ -0,0 +1,41 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'ISCSI CHAP Settings' + +# Test description: How New-VesterConfig explains this value to the user +$Description = "Specifies the ISCSI CHAP settings for the host" + +# The config entry stating the desired values +$Desired = $cfg.host.iscsichap + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'hashtable' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + $ht2 = @{} + ($Object | Get-VMHostHba | Where {$_.Type -eq "Iscsi"} | Select -ExpandProperty AuthenticationProperties).psobject.properties | Foreach { $ht2[$_.Name] = $_.Value } + $ht2 +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + if ($Desired.ChapType -ne 'Prohibited') { + $CHAPpass = Read-Host "Enter a password for outgoing CHAP Credential" -AsSecureString + $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($CHAPpass) + $CHAPpasstext = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) + if ($Desired.MutualChapEnabled) { + $MutualChapPass = Read-Host "Enter a password for incoming CHAP Credential" -AsSecureString + $BSTR = [System.Runtime.InteropServices.Marshal]::SecureStringToBSTR($MutualChapPass) + $MutualChapPasstext = [System.Runtime.InteropServices.Marshal]::PtrToStringAuto($BSTR) + $Object | Get-VMHostHba | Where {$_.Type -eq "Iscsi"} | Set-VMHostHba -ChapType $Desired.ChapType -ChapName $Desired.ChapName -ChapPassword $CHAPpasstext -MutualChapName $Desired.MutualChapName -MutualChapPassword $MutualChapPasstext -Confirm:$false + } + else{ + $Object | Get-VMHostHba | Where {$_.Type -eq "Iscsi"} | Set-VMHostHba -ChapType $Desired.ChapType -ChapName $Desired.ChapName -ChapPassword $CHAPpasstext -Confirm:$false + } + } +} \ No newline at end of file diff --git a/Vester/Tests/Host/Kernel-DisableMOB.Vester.ps1 b/Vester/Tests/Host/Kernel-DisableMOB.Vester.ps1 new file mode 100644 index 0000000..9cec005 --- /dev/null +++ b/Vester/Tests/Host/Kernel-DisableMOB.Vester.ps1 @@ -0,0 +1,26 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'Disable Managed Object Browser (MOB)' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Disables (or enables) The managed object browser (MOB)' + +# The config entry stating the desired values +$Desired = $cfg.host.disablemob + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-AdvancedSetting -Name Config.HostAgent.plugins.solo.enableMob).Value +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $Object | Get-AdvancedSetting -Name Config.HostAgent.plugins.solo.enableMob |Set-AdvancedSetting -value $Desired -Confirm:$false -ErrorAction Stop +} diff --git a/Vester/Tests/Host/Lockdown-Mode.Vester.ps1 b/Vester/Tests/Host/Lockdown-Mode.Vester.ps1 new file mode 100644 index 0000000..ce0760e --- /dev/null +++ b/Vester/Tests/Host/Lockdown-Mode.Vester.ps1 @@ -0,0 +1,32 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'Lockdown Mode' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Enable lockdown mode to restrict remote access.' + +# The config entry stating the desired values +$Desired = $cfg.host.lockdown + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + $myhost = $Object | Get-View + $lockdown = Get-View $myhost.ConfigManager.HostAccessManager + $lockdown.UpdateViewData() + $lockdown.LockdownMode +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $myhost = $Object | Get-View + $lockdown = Get-View $myhost.ConfigManager.HostAccessManager + $lockdown.ChangeLockdownMode($Desired) + $lockdown.UpdateViewData() +} diff --git a/Vester/Tests/Host/SNMP-Settings.Vester.ps1 b/Vester/Tests/Host/SNMP-Settings.Vester.ps1 new file mode 100644 index 0000000..06deb2c --- /dev/null +++ b/Vester/Tests/Host/SNMP-Settings.Vester.ps1 @@ -0,0 +1,35 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'Ensure proper SNMP configuration' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'If SNMP is not being used, it should remain disabled. If it is being used, the proper trap destination should be configured.' + +# The config entry stating the desired values +$Desired = $cfg.host.configsnmp + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'hashtable' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + $ht2 = @{} + ((Get-ESXCli -v2 -VMHost $Object).system.snmp.get.invoke()).psobject.properties | Foreach { $ht2[$_.Name] = $_.Value } + $ht2 +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $EsxCli = (Get-EsxCli -v2 -VMhost $Object) + $Arguments = $EsxCli.system.snmp.set.CreateArgs() + ForEach ($key in $Desired.Keys){ + if($Desired."$key" -ne $null -and $Desired."$key" -ne ''){ + $Arguments."$key"=$Desired."$key" + } + } + $EsxCli.system.snmp.set.Invoke($Arguments) +} \ No newline at end of file diff --git a/Vester/Tests/Host/Syslog-LogDir.Vester.ps1 b/Vester/Tests/Host/Syslog-LogDir.Vester.ps1 new file mode 100644 index 0000000..d95afc1 --- /dev/null +++ b/Vester/Tests/Host/Syslog-LogDir.Vester.ps1 @@ -0,0 +1,26 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'Syslog Dir' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'ESXi can be configured to store log files on an in-memory file system.' + +# The config entry stating the desired values +$Desired = $cfg.host.syslogdir + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-AdvancedSetting -Name Syslog.global.logDir).Value +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $Object | Get-AdvancedSetting -Name Syslog.global.logDir | Set-AdvancedSetting -Value $Desired -Confirm:$false -ErrorAction Stop +} diff --git a/Vester/Tests/Host/TSM-Service-Policy.Vester.ps1 b/Vester/Tests/Host/TSM-Service-Policy.Vester.ps1 new file mode 100644 index 0000000..db9a9e4 --- /dev/null +++ b/Vester/Tests/Host/TSM-Service-Policy.Vester.ps1 @@ -0,0 +1,32 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'TSM Service Policy' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Policy for TSM service (on,off,automatic)' + +# The config entry stating the desired values +$Desired = $cfg.host.tsmservicepolicy + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-VMHostService | Where-Object -FilterScript { + $_.Key -eq 'TSM' + }).Policy +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + Set-VMHostService -HostService ($Object | + Get-VMHostService | + Where-Object -FilterScript { + $_.Key -eq 'TSM' + }) -Policy $Desired -ErrorAction Stop +} diff --git a/Vester/Tests/Host/TSM-Service.Vester.ps1 b/Vester/Tests/Host/TSM-Service.Vester.ps1 new file mode 100644 index 0000000..f620c6a --- /dev/null +++ b/Vester/Tests/Host/TSM-Service.Vester.ps1 @@ -0,0 +1,43 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'TSM Service State' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'Checks state of TSM service (running or stopped)' + +# The config entry stating the desired values +$Desired = $cfg.host.tsmservicerunning + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'bool' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-VMHostService | Where-Object -FilterScript { + $_.Key -eq 'TSM' + }).Running +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + if ($Desired -eq $true) + { + Start-VMHostService -HostService ($Object | + Get-VMHostService | + Where-Object -FilterScript { + $_.Key -eq 'TSM' + }) -ErrorAction Stop -Confirm:$false + } + if ($Desired -eq $false) + { + Stop-VMHostService -HostService ($Object | + Get-VMHostService | + Where-Object -FilterScript { + $_.Key -eq 'TSM' + }) -ErrorAction Stop -Confirm:$false + } +} diff --git a/Vester/Tests/Host/vNetwork-SecurityPolicy.Vester.ps1 b/Vester/Tests/Host/vNetwork-SecurityPolicy.Vester.ps1 new file mode 100644 index 0000000..f50e42a --- /dev/null +++ b/Vester/Tests/Host/vNetwork-SecurityPolicy.Vester.ps1 @@ -0,0 +1,78 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'vNetwork Security Policy' + +# Test description: How New-VesterConfig explains this value to the user +$Description = "Specifies vswitch and portgroup security policy settings" + +# The config entry stating the desired values +$Desired = $cfg.host.vnetworksecuritypolicy + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'hashtable' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + $ht2 = @{} + $Object | Get-VirtualSwitch | Get-SecurityPolicy | Foreach { + $ht3=@{} + $_.psobject.properties | Foreach { + if( @("ForgedTransmits","AllowPromiscuous","MacChanges","AllowPromiscuousInherited","ForgedTransmitsInherited","MacChangesInherited") -contains $_.Name ) { + $ht3[$_.Name]=$_.Value + } + } + $ht2[$_.VirtualSwitch.Name] = $ht3 + } + $Object | Get-VirtualPortGroup | Get-SecurityPolicy | Foreach { + $ht3=@{} + $_.psobject.properties | Foreach { + if( @("ForgedTransmits","AllowPromiscuous","MacChanges","AllowPromiscuousInherited","ForgedTransmitsInherited","MacChangesInherited") -contains $_.Name ) { + $ht3[$_.Name]=$_.Value + } + } + $ht2[$_.VirtualPortGroup.Name] = $ht3 + } + $ht2 +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $Desired.keys | Foreach { + if ( $Desired[$_]["ForgedTransmitsInherited"] -ne $null -and $Desired[$_]["MacChangesInherited"] -ne $null -and $Desired[$_]["AllowPromiscuousInherited"] -ne $null ){ + $VirtualPortGroupName = $_ + if ($Desired[$_]["ForgedTransmitsInherited"]) { + $Object | Get-VirtualPortGroup | Where {$_.name -eq $VirtualPortGroupName} | Get-SecurityPolicy | + Set-SecurityPolicy -ForgedTransmitsInherited $Desired[$_]["ForgedTransmitsInherited"] + } + else{ + $Object | Get-VirtualPortGroup | Where {$_.name -eq $VirtualPortGroupName} | Get-SecurityPolicy | + Set-SecurityPolicy -ForgedTransmits $Desired[$_]["ForgedTransmits"] + } + if ($Desired[$_]["MacChangesInherited"]) { + $Object | Get-VirtualPortGroup | Where {$_.name -eq $VirtualPortGroupName} | Get-SecurityPolicy | + Set-SecurityPolicy -MacChangesInherited $Desired[$_]["MacChangesInherited"] + } + else{ + $Object | Get-VirtualPortGroup | Where {$_.name -eq $VirtualPortGroupName} | Get-SecurityPolicy | + Set-SecurityPolicy -MacChanges $Desired[$_]["MacChanges"] + } + if ($Desired[$_]["AllowPromiscuousInherited"]) { + $Object | Get-VirtualPortGroup | Where {$_.name -eq $VirtualPortGroupName} | Get-SecurityPolicy | + Set-SecurityPolicy -AllowPromiscuousInherited $Desired[$_]["AllowPromiscuousInherited"] + } + else{ + $Object | Get-VirtualPortGroup | Where {$_.name -eq $VirtualPortGroupName} | Get-SecurityPolicy | + Set-SecurityPolicy -AllowPromiscuous $Desired[$_]["AllowPromiscuous"] + } + } + else{ + $VirtualSwitchName = $_ + $Object | Get-VirtualSwitch | Where {$_.name -eq $VirtualSwitchName} | Get-SecurityPolicy | + Set-SecurityPolicy -ForgedTransmits $Desired[$_]["ForgedTransmits"] -MacChanges $Desired[$_]["MacChanges"] -AllowPromiscuous $Desired[$_]["AllowPromiscuous"] + } + } +} diff --git a/Vester/Tests/Host/vNetwork-VLanId.Vester.ps1 b/Vester/Tests/Host/vNetwork-VLanId.Vester.ps1 new file mode 100644 index 0000000..3031ba2 --- /dev/null +++ b/Vester/Tests/Host/vNetwork-VLanId.Vester.ps1 @@ -0,0 +1,31 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'vNetwork VLAN ID' + +# Test description: How New-VesterConfig explains this value to the user +$Description = "Specifies portgroup VLAN ID" + +# The config entry stating the desired values +$Desired = $cfg.host.vnetworkvlanid + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'hashtable' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + $ht2 = @{} + $Object | Get-VirtualPortGroup -Standard | Foreach { $ht2[$_.Name] = $_.VLanId } + $ht2 +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $Desired.keys| Foreach { + $VirtualPortGroup=$_ + $vmhost | Get-VirtualPortGroup -Standard -Name $VirtualPortGroup | Set-VirtualPortGroup -VLanId $Desired[$_] + } +} diff --git a/Vester/Tests/Host/vNetwork-dvfilterBind.Vester.ps1 b/Vester/Tests/Host/vNetwork-dvfilterBind.Vester.ps1 new file mode 100644 index 0000000..c3b23b7 --- /dev/null +++ b/Vester/Tests/Host/vNetwork-dvfilterBind.Vester.ps1 @@ -0,0 +1,26 @@ +# Test file for the Vester module - https://github.com/WahlNetwork/Vester +# Called via Invoke-Pester VesterTemplate.Tests.ps1 + +# Test title, e.g. 'DNS Servers' +$Title = 'Audit use of dvfilter network APIs' + +# Test description: How New-VesterConfig explains this value to the user +$Description = 'If you are using a product that makes use of this API then verify that the host has been configured correctly.' + +# The config entry stating the desired values +$Desired = $cfg.host.verifydvfilterbind + +# The test value's data type, to help with conversion: bool/string/int +$Type = 'string' + +# The command(s) to pull the actual value for comparison +# $Object will scope to the folder this test is in (Cluster, Host, etc.) +[ScriptBlock]$Actual = { + ($Object | Get-AdvancedSetting -Name Net.DVFilterBindIpAddress).Value +} + +# The command(s) to match the environment to the config +# Use $Object to help filter, and $Desired to set the correct value +[ScriptBlock]$Fix = { + $Object | Get-AdvancedSetting -Name Net.DVFilterBindIpAddress | Set-AdvancedSetting -Value $Desired -Confirm:$false -ErrorAction Stop +}