Lab Manager Config IP List and RDP Test

From vwiki
Jump to navigation Jump to search
The printable version is no longer supported and may have rendering errors. Please update your browser bookmarks and please use the default browser print function instead.
<#
=============================================================================================
 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 = "lab-manager"                       # Hostname of your lab Manager server
$smtpSvr = "smtp"                                # Hostname of your SMTP server
$EmailFrom = "me@domain.com"                     # Email address to send from
$EmailDomain = "domain.com"                      # Email domain (used to guess email to send to)
$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)
    
    # Include VM Power State
    $tmp = Read-Host "Include VM power state (on/off) [N]"
    if ($tmp -and ($tmp -match "y")) {
        $IncPowerState = 1
    } else { 
        $IncPowerState = 0
    }

    # Email results to user
    $EmailTo = $env:username + "@" + $EmailDomain
    $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"
    if ($IncPowerState) {
        $msgHTML += "<th>Power"
    }
    $msgHTML += "<th>Internal IP<th>External IP`n"
    foreach ($vm in $objConfVMs) {
        $msgHTML += "<tr><td>" + $vm.VM_Name
        if ($IncPowerState) {
            Switch ($vm.VM_State) {
                1   {$msgHTML += "<td style='font-weight: normal; text-align: center'>Off"}
                2   {$msgHTML += "<td style='text-align: center'>On"}
                3   {$msgHTML += "<td style='font-weight: normal; text-align: center'>Suspended"}
                4   {$msgHTML += "<td style='font-weight: normal; text-align: center'>Stuck"}
                128 {$msgHTML += "<td style='font-weight: normal; text-align: center'>Invalid"}
                default {$msgHTML += "<td style='font-weight: normal; text-align: center'>Unknown"}
            }
        }
        $msgHTML += "<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 $smtpSvr
    $msg = New-Object Net.Mail.MailMessage
        
    $msg.From = $EmailFrom
    $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