Lab Manager Configuration IP List: Difference between revisions

From vwiki
Jump to navigation Jump to search
(Initial creation)
 
(Updated to v2,0)
Line 1: Line 1:
<source lang="powershell">
<source lang="powershell">
<#
<#
=============================================================================================
=============================================================================================
Line 22: Line 21:
  -- Displays configs in yellow if they're not shared
  -- Displays configs in yellow if they're not shared
   
   
Version 1.4 - Apr 2011
Version 2.0 - Apr 2011
- Changed from single run to modular, continuous operation
  - Added RDP port test
  - Added RDP port test
   
   
=============================================================================================
=============================================================================================
#>
#>
$start = Get-Date


$UserFile = "User.fil"
$UserFile = "User.fil"
$PassFile = "Pass.fil"                          # Encrypted file to store password in
$PassFile = "Pass.fil"                          # Encrypted file to store password in
$LabMgrSvr = "LM-Server"                         # Lab Manager server hostname
$LabMgrSvr = "ukb-sr-lbmgr-10"
$ScriptName = ($MyInvocation.MyCommand.Name).Replace(".ps1", "")


Write-Host "Started script run at $start"
$host.UI.RawUI.WindowTitle = $ScriptName


# =============================================================================================
# =============================================================================================
Line 42: Line 41:
     Write-Host "Press any key to exit..."
     Write-Host "Press any key to exit..."
     $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
     $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    $labManager.Dispose()
     Exit
     Exit
}
}
Line 163: Line 163:
     if (!$failed) {
     if (!$failed) {
         Write-Host "Connection successful" -BackgroundColor DarkGreen
         Write-Host "Connection successful" -BackgroundColor DarkGreen
    }
}
# Bussiness functions ==========================================================================
function Select-Configuration {
    # Get list of configurations, query user which to do, and return selected config ID
   
    $ConfIDs = @()
    $confID = -99
    # Get list of config's and display deployed only
    Write-Host ("Deployed configurations...`n")
    $Configs = $labManager.ListConfigurations(1)
    $Configs = $Configs | Sort name
    foreach ($config in $Configs) {
        if ($config.isDeployed) {
            if ($FontColour -eq "Gray") {
                $FontColour = "White"
            } else {
                $FontColour = "Gray"
            }
            if ($config.isPublic) {
                Write-host -ForegroundColor $FontColour ("ID " + $config.id + " - " + $config.name + "  [" + $config.bucketName + "]")
               
            } else {
                Write-Host -ForegroundColor Yellow ("ID " + $config.id + " - " + $config.name + "  [" + $config.bucketName + "] - Not Shared !!")
            }
            $ConfIDs += $config.ID                          # List of config ID's (with which to validate user input)
        }
    }
    # Get config ID from user
    While (!($ConfIDs -contains $ConfID)) {  # Don't leave loop until user selected config ID is valid!
        $ConfID = Read-Host "`nSelect a configuration ID [0 to quit]"
        if (!$ConfID -or ($ConfID -eq 0)) {
            # Dump the Lab Manager connection
            $labManager.Dispose()
            exit
        } elseif (!($ConfIDs -contains $ConfID)) {
            Write-Host "Invalid, should be one of" ([string]::join(", ", $ConfIDs))
        }
    }
    Return $labManager.GetConfiguration($ConfID)
}
function Get-ConfigVMs {
    Param($objConfig)
   
    $VMs = @()
   
    # Get VM's for selected config
    $labManager.ListMachines($objConfig.id) | foreach {
        $vm = "" | Select VM_Name, VM_IntIP, VM_ExtIP, VM_State
        $vm.VM_Name = $_.name
        $vm.VM_IntIP = $_.internalIP
        $vm.VM_ExtIP = $_.externalIP
        $vm.VM_State = $_.status        # 1=Off, 2=On, 3=Suspended, 4=Stuck, 128=Invalid
        $VMs = $VMs + $vm
    }
    $VMs = $VMs | Sort VM_Name
    #$VMs | Select VM_Name, VM_IntIP, VM_ExtIP | Format-Table
    Return $VMs
}
function Send-ConfigIPs {
    Param($objConfig, $objConfVMs)
    # Email results to user
    $EmailTo = $env:username + "@michaelpage.com"
    $tmp = Read-Host "Email to [$EmailTo]"
    if ($tmp) {$EmailTo = $tmp}
    Write-Host "Emailing $EmailTo..." -nonewline
    # Create HTML for email
    [string]$msgHTML = "<!-- Genenerated by $ScriptName at " + (Get-Date).ToString() + " hrs -->`n"
    $msgHTML += "<html xmlns='http://www.w3.org/TR/REC-html40'>`n`n<head>`n<meta http-equiv=Content-Type content='text/html; charset=uk'`n>"
    $msgHTML += "<meta name=Generator content='Lab Manager NATs script'>`n<meta name=Author content='Simon Strutt'>`n</head>`n`n"
    $msgHTML += "<body style='font-family: arial; font-size: 10;'><table style='font-family: arial; font-size: 11';><tr><td>`nConfiguration:<td><b>" + $objConfig.name + "</b><tr><td>`nWorkspace:<td>" + $objConfig.bucketName
    $msgHTML += "<tr><td>`nDescription:<td>" + $objConfig.description + "<tr><td>Info correct at:<td>" + (Get-Date).ToString() + " hrs</table>`n"
    $msgHTML += "<br><br>`n`n"
    $msgHTML += "<table border=1 style='border-width: 1px; border-spacing: 0; border-color: black; background-color: #faf0e6; font-family: arial; font-size: 11; font-weight: bold'>`n"
    $msgHTML += "<tr style='border-width: 2px; background-color: #fcf7f8;'><th>VM Name<th>Internal IP<th>External IP`n"
    foreach ($vm in $objConfVMs) {
        $msgHTML += "<tr><td>" + $vm.VM_Name + "<td style='font-weight: normal'>" + $vm.VM_IntIP + "<td>" + $vm.VM_ExtIP
    }
    $msgHTML += "</table>`n`n<br><br>`n<table style='font-family: arial; font-size: 10; color: #888888'>`n<tr><td>Generated by script: <td>$ScriptName"
    $msgHTML += "`n</table>`n`n</body></html>"
    #Send via email
    $smtp = New-Object Net.Mail.SmtpClient -arg "mailrelay.uk.michaelpage.local"
    $msg = New-Object Net.Mail.MailMessage
       
    $msg.From = "VI-Mgmt@michaelpage.local"
    $msg.To.Add($EmailTo)
    $msg.Subject = "Lab Manager configuration: " + $objConfig.name
    $msg.IsBodyHTML = $true
    $msg.Body = $msgHTML
       
    try {
        $smtp.Send($msg)
    } catch {
        Write-Host "`n" $_
        Write-Host "`nCopy text above if you want to retain the info."
        PressAnyKeyToExit
    }
    Write-Host "sent !`n"
}
function Test-Access {
    Param($objConfVMs)
   
    # Check RDP access to powered-on VM's
    Write-Host -ForegroundColor white "`nTesting RDP (TCP port) access to powered on servers..."
    foreach ($vm in $objConfVMs) {
        if ($vm.VM_State -eq 2) {
            Write-Host ($vm.VM_Name).PadRight(16) ($vm.VM_ExtIP).PadRight(15) -nonewline
            Test-Port $vm.VM_ExtIP
        }
     }
     }
}
}
Line 191: Line 312:
# Get list of configurations, query user which to do, then get list of VM's and IP's
# Get list of configurations, query user which to do, then get list of VM's and IP's


$VMs = @()
$option = 1
$ConfIDs = @()
$confID = -99


# Get list of config's and display deployed only
$Config = Select-Configuration
Write-Host ("Deployed configurations...`n")
$host.UI.RawUI.WindowTitle = $ScriptName + " - " + $Config.name
$Configs = $labManager.ListConfigurations(1)
$Configs = $Configs | Sort name
foreach ($config in $Configs) {
    if ($config.isDeployed) {
        if ($FontColour -eq "Gray") {
            $FontColour = "White"
        } else {
            $FontColour = "Gray"
        }
        if ($config.isPublic) {
            Write-host -ForegroundColor $FontColour ("ID " + $config.id + " - " + $config.name + "  [" + $config.bucketName + "]")
           
        } else {
            Write-Host -ForegroundColor Yellow ("ID " + $config.id + " - " + $config.name + "  [" + $config.bucketName + "] - Not Shared !!")
        }
        $ConfIDs += $config.ID                          # List of config ID's (with which to validate user input)
    }
}


# Get config ID from user
While (1) {
While (!($ConfIDs -contains $ConfID)) {  # Don't leave loop until user selected config ID is valid!
    Write-Host -ForegroundColor white ("`n" + $Config.name + " (" + $Config.description + ")`n")
     $ConfID = Read-Host "`nSelect a configuration ID [0 to quit]"
    Write-Host "1 - Email IP addresses"
     if ($ConfID -eq 0) {
    Write-Host "2 - Check RDP access"
    Write-Host "3 - Change config"
    Write-Host "0 - Exit"
     $tmp = Read-Host "`nSelect an option [$option]"
     if ($tmp) {$option = $tmp}
   
    if ($option -notmatch "0|1|2|3") {
        Write-Host "$option is invalid"
        $option = 0
       
    } elseif ($option -eq 0) {
         # Dump the Lab Manager connection
         # Dump the Lab Manager connection
         $labManager.Dispose()
         $labManager.Dispose()
         exit
         exit
     } elseif (!($ConfIDs -contains $ConfID)) {
     } elseif ($option -eq 1) {
        Write-Host "Invalid, should be one of" ([string]::join(", ", $ConfIDs))
        $ConfVMs = Get-ConfigVMs $Config
    }
        Send-ConfigIPs $Config $ConfVMs
}
 
# Get VM's for selected config
$labManager.ListMachines($ConfID) | foreach {
    $vm = "" | Select ConfID, Config, Workspace, Description, VM_Name, VM_IntIP, VM_ExtIP, VM_State
    $vm.ConfID = $ConfID
    $vm.Config = $Configs |?{$_.id -eq $ConfID} | Select -ExpandProperty name
    $vm.Workspace = $Configs |?{$_.id -eq $ConfID} | Select -ExpandProperty bucketName
    $vm.Description = $Configs |?{$_.id -eq $ConfID} | Select -ExpandProperty description
    $vm.VM_Name = $_.name
    $vm.VM_IntIP = $_.internalIP
    $vm.VM_ExtIP = $_.externalIP
    $vm.VM_State = $_.status        # 1=Off, 2=On, 3=Suspended, 4=Stuck, 128=Invalid
    $VMs = $VMs + $vm
}
$VMs = $VMs | Sort VM_Name
$VMs | Select VM_Name, VM_IntIP, VM_ExtIP | Format-Table
 
# Dump the Lab Manager connection
$labManager.Dispose()
$end = Get-Date
 
# ==============================================================================================
# Email results to user
 
$EmailTo = $env:username + "@michaelpage.com"
$tmp = Read-Host "Email to [$EmailTo]"
if ($tmp) {$EmailTo = $tmp}
 
Write-Host "Emailing $EmailTo..." -nonewline
 
# Create HTML for email
[string]$msgHTML = "<!-- Genenerated by " + ($MyInvocation.MyCommand.Name) + " script at " + (Get-Date).ToString() + " hrs -->`n"
$msgHTML += "<html xmlns='http://www.w3.org/TR/REC-html40'>`n`n<head>`n<meta http-equiv=Content-Type content='text/html; charset=uk'`n>"
$msgHTML += "<meta name=Generator content='Lab Manager NATs script'>`n<meta name=Author content='Simon Strutt'>`n</head>`n`n"
$msgHTML += "<body style='font-family: arial; font-size: 10;'><table style='font-family: arial; font-size: 11';><tr><td>`nConfiguration:<td><b>" + $vm.Config + "</b><tr><td>`nWorkspace:<td>" + $vm.Workspace
$msgHTML += "<tr><td>`nDescription:<td>" + $vm.Description + "<tr><td>Info correct at:<td>" + $end.ToString() + " hrs</table>`n"
$msgHTML += "<br><br>`n`n"
$msgHTML += "<table border=1 style='border-width: 1px; border-spacing: 0; border-color: black; background-color: #faf0e6; font-family: arial; font-size: 11; font-weight: bold'>`n"
$msgHTML += "<tr style='border-width: 2px; background-color: #fcf7f8;'><th>VM Name<th>Internal IP<th>External IP`n"
foreach ($vm in $VMs) {
    $msgHTML += "<tr><td>" + $vm.VM_Name + "<td style='font-weight: normal'>" + $vm.VM_IntIP + "<td>" + $vm.VM_ExtIP
}
$msgHTML += "</table>`n`n<br><br>`n<table style='font-family: arial; font-size: 10; color: #888888'>`n<tr><td>Script started : <td>" + $start.ToString() + " hrs`n"
$msgHTML += "<tr><td>Script finished : <td>" + $end.ToString() + " hrs`n<tr><td>Generated by script: <td>" + ($MyInvocation.MyCommand.Name)
$msgHTML += "`n</table>`n`n</body></html>"
 
#Send via email
$smtp = New-Object Net.Mail.SmtpClient -arg "mailrelay.uk.michaelpage.local"
$msg = New-Object Net.Mail.MailMessage
      
      
$msg.From = "VI-Mgmt@michaelpage.local"
    } elseif ($option -eq 2) {
$msg.To.Add($EmailTo)
        $ConfVMs = Get-ConfigVMs $Config
$msg.Subject = "Lab Manager configuration: " + $vm.Config  
        Test-Access $ConfVMs
$msg.IsBodyHTML = $true
$msg.Body = $msgHTML
      
      
try {
     } elseif ($option -eq 3) {
     $smtp.Send($msg)
        $Config = Select-Configuration
} catch {
        $host.UI.RawUI.WindowTitle = $ScriptName + " - " + $Config.name
    Write-Host "`n" $_
       
    Write-Host "`nCopy text above if you want to retain the info."
     } else {
    PressAnyKeyToExit
         Write-Host "Unexpected error...!"
}
Write-Host "sent !`n"
 
# Check RDP access to powered-on VM's
$tmp = "N"
$tmp = Read-Host "Do you want test RDP port to powered on VMs? [$tmp]"
if ($tmp -match "Y") {
     foreach ($vm in $VMs) {
         if ($vm.VM_State -eq 2) {
            Write-Host ($vm.VM_Name).PadRight(16) ($vm.VM_ExtIP).PadRight(15) -nonewline
            Test-Port $vm.VM_ExtIP
        }
     }
     }
}      
}    
      
      
PressAnyKeyToExit
PressAnyKeyToExit
      
      


</source>
</source>

Revision as of 14:07, 19 April 2011

<#
=============================================================================================
 Lab Manager VM NAT Getter
=============================================================================================
 Simon Strutt  -  November 2010
=============================================================================================

Version 1
 - Initial creation!
 
Version 1.1 - Dec 2010
 - Added bucketName when displaying list of config's to better handle config's with same name in different workspaces
 
Version 1.2 - Jan 2011
 - Added sorting by VM name
 
Version 1.3 - Feb 2011
 - Configuration selection menu...
 -- Now sorted by name
 -- Displays configs in yellow if they're not shared
 
Version 2.0 - Apr 2011
 - Changed from single run to modular, continuous operation
 - Added RDP port test
 
=============================================================================================
#>

$UserFile = "User.fil"
$PassFile = "Pass.fil"                           # Encrypted file to store password in
$LabMgrSvr = "ukb-sr-lbmgr-10"
$ScriptName = ($MyInvocation.MyCommand.Name).Replace(".ps1", "")

$host.UI.RawUI.WindowTitle = $ScriptName

# =============================================================================================
# Basic helper functions

function PressAnyKeyToExit {
    Write-Host "Press any key to exit..."
    $x = $host.UI.RawUI.ReadKey("NoEcho,IncludeKeyDown")
    $labManager.Dispose()
    Exit
}

# =============================================================================================
# Lab Manager SOAP connection functions (adapted from POSH - http://poshcode.org/753)

function New-ObjectFromProxy {
	param($proxy, $proxyAttributeName, $typeName)

	# Locate the assembly for $proxy
	$attribute = $proxy | gm | where { $_.Name -eq $proxyAttributeName }
	$str = "`$assembly = [" + $attribute.TypeName + "].assembly"
	invoke-expression $str

	# Instantiate an AuthenticationHeaderValue object.
	$type = $assembly.getTypes() | where { $_.Name -eq $typeName }
	return $assembly.CreateInstance($type)
}

function Connect-LabManager {
	param($server, $credential)
    
    Write-Host "Connecting to $server..."

	# Log in to Lab Manager's web service.
	$server = "https://" + $server + "/"
	$endpoint = $server + "LabManager/SOAP/LabManager.asmx"
    try {
	   $proxy = new-webserviceproxy -uri $endpoint -cred $credential -ErrorAction:Stop
    } catch {
        Write-Host $_
        if ($_.ErrorDetails.Message -match "401: Unauthorized") {
            Remove-Item $UserFile
            Remove-Item $PassFile
            Write-Host "User/pass credential cache files have been deleted"
        } else {
             Write-Host $_.Exception.Message
             Write-Host $_.Exception.GetType().FullName
        }     
        PressAnyKeyToExit
    }

	# Before continuing we need to add an Authentication Header to $proxy.
	$authHeader = New-ObjectFromProxy -proxy $proxy -proxyAttributeName "AuthenticationHeaderValue" -typeName "AuthenticationHeader"
	$authHeader.username = $credential.GetNetworkCredential().UserName
	$authHeader.password = $credential.GetNetworkCredential().Password
	$proxy.AuthenticationHeaderValue = $authHeader
	return $proxy
}

function Ignore-SslErrors {
	# Create a compilation environment
	$Provider=New-Object Microsoft.CSharp.CSharpCodeProvider
	$Compiler=$Provider.CreateCompiler()
	$Params=New-Object System.CodeDom.Compiler.CompilerParameters
	$Params.GenerateExecutable=$False
	$Params.GenerateInMemory=$True
	$Params.IncludeDebugInformation=$False
	$Params.ReferencedAssemblies.Add("System.DLL") > $null
	$TASource=@'
	  namespace Local.ToolkitExtensions.Net.CertificatePolicy {
	    public class TrustAll : System.Net.ICertificatePolicy {
	      public TrustAll() { 
	      }
	      public bool CheckValidationResult(System.Net.ServicePoint sp,
	        System.Security.Cryptography.X509Certificates.X509Certificate cert, 
	        System.Net.WebRequest req, int problem) {
	        return true;
	      }
	    }
	  }
'@ 
	$TAResults=$Provider.CompileAssemblyFromSource($Params,$TASource)
	$TAAssembly=$TAResults.CompiledAssembly

	## We now create an instance of the TrustAll and attach it to the ServicePointManager
	$TrustAll=$TAAssembly.CreateInstance("Local.ToolkitExtensions.Net.CertificatePolicy.TrustAll")
	[System.Net.ServicePointManager]::CertificatePolicy=$TrustAll
}

# ===============================================================================================
# TCP Port test function (adapted from POSH - http://poshcode.org/85)
function Test-Port {
    Param([string]$srv,$port=3389,$timeout=3000)
     
    # Does a TCP connection on port 3389 (RDP), port and timeout can be overriden
     
    $ErrorActionPreference = "SilentlyContinue"
     
    # Create TCP Client
    $tcpclient = new-Object system.Net.Sockets.TcpClient
     
    # Tell TCP Client to connect to machine on Port
    $iar = $tcpclient.BeginConnect($srv,$port,$null,$null)
     
    # Set the wait time
    $wait = $iar.AsyncWaitHandle.WaitOne($timeout,$false)
     
    # Check to see if the connection is done
    if(!$wait)
    {
        # Close the connection and report timeout
        $tcpclient.Close()
        Write-Host "Connection Timeout" -BackgroundColor DarkRed
        Return
    }
    else
    {
        # Close the connection and report the error if there is one
        $error.Clear()
        $tcpclient.EndConnect($iar) | out-Null
        if (!$?) {
             write-host $error[0] -BackgroundColor DarkRed
             $failed = $true
        }
        $tcpclient.Close()
    }
     
    # Return $true if connection Establish else $False
    if (!$failed) {
        Write-Host "Connection successful" -BackgroundColor DarkGreen
    }
}

# Bussiness functions ==========================================================================

function Select-Configuration {
    # Get list of configurations, query user which to do, and return selected config ID
    
    $ConfIDs = @()
    $confID = -99

    # Get list of config's and display deployed only
    Write-Host ("Deployed configurations...`n")
    $Configs = $labManager.ListConfigurations(1) 
    $Configs = $Configs | Sort name
    foreach ($config in $Configs) {
        if ($config.isDeployed) {
            if ($FontColour -eq "Gray") {
                $FontColour = "White"
            } else {
                $FontColour = "Gray"
            }
            if ($config.isPublic) {
                Write-host -ForegroundColor $FontColour ("ID " + $config.id + " - " + $config.name + "  [" + $config.bucketName + "]")
                
            } else {
                Write-Host -ForegroundColor Yellow ("ID " + $config.id + " - " + $config.name + "  [" + $config.bucketName + "] - Not Shared !!")
            }
            $ConfIDs += $config.ID                           # List of config ID's (with which to validate user input)
        }
    }

    # Get config ID from user
    While (!($ConfIDs -contains $ConfID)) {   # Don't leave loop until user selected config ID is valid!
        $ConfID = Read-Host "`nSelect a configuration ID [0 to quit]"
        if (!$ConfID -or ($ConfID -eq 0)) {
            # Dump the Lab Manager connection
            $labManager.Dispose()
            exit
        } elseif (!($ConfIDs -contains $ConfID)) {
            Write-Host "Invalid, should be one of" ([string]::join(", ", $ConfIDs))
        }
    }
    Return $labManager.GetConfiguration($ConfID)
}


function Get-ConfigVMs {
    Param($objConfig)
    
    $VMs = @()
    
    # Get VM's for selected config
    $labManager.ListMachines($objConfig.id) | foreach {
        $vm = "" | Select VM_Name, VM_IntIP, VM_ExtIP, VM_State
        $vm.VM_Name = $_.name
        $vm.VM_IntIP = $_.internalIP
        $vm.VM_ExtIP = $_.externalIP
        $vm.VM_State = $_.status        # 1=Off, 2=On, 3=Suspended, 4=Stuck, 128=Invalid
        $VMs = $VMs + $vm
    }
    $VMs = $VMs | Sort VM_Name
    #$VMs | Select VM_Name, VM_IntIP, VM_ExtIP | Format-Table
    Return $VMs
}

function Send-ConfigIPs {
    Param($objConfig, $objConfVMs)

    # Email results to user
    $EmailTo = $env:username + "@michaelpage.com"
    $tmp = Read-Host "Email to [$EmailTo]"
    if ($tmp) {$EmailTo = $tmp}

    Write-Host "Emailing $EmailTo..." -nonewline

    # Create HTML for email
    [string]$msgHTML = "<!-- Genenerated by $ScriptName at " + (Get-Date).ToString() + " hrs -->`n"
    $msgHTML += "<html xmlns='http://www.w3.org/TR/REC-html40'>`n`n<head>`n<meta http-equiv=Content-Type content='text/html; charset=uk'`n>"
    $msgHTML += "<meta name=Generator content='Lab Manager NATs script'>`n<meta name=Author content='Simon Strutt'>`n</head>`n`n"
    $msgHTML += "<body style='font-family: arial; font-size: 10;'><table style='font-family: arial; font-size: 11';><tr><td>`nConfiguration:<td><b>" + $objConfig.name + "</b><tr><td>`nWorkspace:<td>" + $objConfig.bucketName
    $msgHTML += "<tr><td>`nDescription:<td>" + $objConfig.description + "<tr><td>Info correct at:<td>" + (Get-Date).ToString() + " hrs</table>`n"
    $msgHTML += "<br><br>`n`n"
    $msgHTML += "<table border=1 style='border-width: 1px; border-spacing: 0; border-color: black; background-color: #faf0e6; font-family: arial; font-size: 11; font-weight: bold'>`n"
    $msgHTML += "<tr style='border-width: 2px; background-color: #fcf7f8;'><th>VM Name<th>Internal IP<th>External IP`n"
    foreach ($vm in $objConfVMs) {
        $msgHTML += "<tr><td>" + $vm.VM_Name + "<td style='font-weight: normal'>" + $vm.VM_IntIP + "<td>" + $vm.VM_ExtIP
    }
    $msgHTML += "</table>`n`n<br><br>`n<table style='font-family: arial; font-size: 10; color: #888888'>`n<tr><td>Generated by script: <td>$ScriptName"
    $msgHTML += "`n</table>`n`n</body></html>"

    #Send via email
    $smtp = New-Object Net.Mail.SmtpClient -arg "mailrelay.uk.michaelpage.local"
    $msg = New-Object Net.Mail.MailMessage
        
    $msg.From = "VI-Mgmt@michaelpage.local"
    $msg.To.Add($EmailTo)
    $msg.Subject = "Lab Manager configuration: " + $objConfig.name 
    $msg.IsBodyHTML = $true
    $msg.Body = $msgHTML
        
    try {
        $smtp.Send($msg)
    } catch {
        Write-Host "`n" $_
        Write-Host "`nCopy text above if you want to retain the info."
        PressAnyKeyToExit
    }
    Write-Host "sent !`n"
}

function Test-Access {
    Param($objConfVMs)
    
    # Check RDP access to powered-on VM's
    Write-Host -ForegroundColor white "`nTesting RDP (TCP port) access to powered on servers..."
    foreach ($vm in $objConfVMs) {
        if ($vm.VM_State -eq 2) {
            Write-Host ($vm.VM_Name).PadRight(16) ($vm.VM_ExtIP).PadRight(15) -nonewline
            Test-Port $vm.VM_ExtIP
        }
    }
}

# ===============================================================================================
# Faff around with credentials and connect to Lab Manager server

# Check for credential files, create if required
if (!(Test-Path $UserFile) -or !(Test-Path $PassFile)) {
    Write-Host "Credential files not found"
    $cred = Get-Credential -Credential ($env:userdomain + "\" + $env:username)
    $cred.UserName | Set-Content $UserFile -Force
    $cred.Password | ConvertFrom-SecureString | Set-Content $PassFile -Force
    Write-Host "Credentials saved"
}
    
# Load password credential from encrypted file
$pass = Get-Content $PassFile | ConvertTo-SecureString
$user = Get-Content $UserFile
$cred = New-Object System.Management.Automation.PsCredential($user, $pass)

# Connect to Lab Mgr server
Ignore-SslErrors
$labManager = Connect-LabManager -server $LabMgrSvr -credential $cred
Write-Host "Sucessfully connected to Lab Manager web service!"

# ==============================================================================================
# Get list of configurations, query user which to do, then get list of VM's and IP's

$option = 1

$Config = Select-Configuration
$host.UI.RawUI.WindowTitle = $ScriptName + " - " + $Config.name

While (1) {
    Write-Host -ForegroundColor white ("`n" + $Config.name + " (" + $Config.description + ")`n")
    Write-Host "1 - Email IP addresses"
    Write-Host "2 - Check RDP access"
    Write-Host "3 - Change config"
    Write-Host "0 - Exit"
    $tmp = Read-Host "`nSelect an option [$option]"
    if ($tmp) {$option = $tmp}
    
    if ($option -notmatch "0|1|2|3") {
        Write-Host "$option is invalid"
        $option = 0
        
    } elseif ($option -eq 0) {
        # Dump the Lab Manager connection
        $labManager.Dispose()
        exit
    } elseif ($option -eq 1) {
        $ConfVMs = Get-ConfigVMs $Config
        Send-ConfigIPs $Config $ConfVMs
    
    } elseif ($option -eq 2) {
        $ConfVMs = Get-ConfigVMs $Config
        Test-Access $ConfVMs
    
    } elseif ($option -eq 3) {
        $Config = Select-Configuration
        $host.UI.RawUI.WindowTitle = $ScriptName + " - " + $Config.name
        
    } else {
        Write-Host "Unexpected error...!"
    }
}     
    
PressAnyKeyToExit