functions/Add-DbrServerToInventory.ps1

Function Add-DbrServerToInventory
{
<#
.SYNOPSIS
Adds an instance or an array of instances to the dbareports database using the config file

.DESCRIPTION
This command will add a SQL Instance or an array of instances to the dbareports database using the config file generated at install or via the dbrclient command

.PARAMETER SqlInstance
The instance or array of instances to add

.PARAMETER SqlInstanceCredential
The credential to connect to the dbareports database

.PARAMETER Port
The Port of the Instance to be added (if not specified then this is gathered)

.PARAMETER Environment
The terminology that you and your users use to define the environment the instance is in. Suggested examples are Prod or Production, Test, UAT, QA, PreProd, ProductionSupport,Development, etc

.PARAMETER Location
The terminology that you and your users use to define the location of the instance. It could be the town or city that the data centre is in or the name of the office etc

.NOTES
dbareports PowerShell module (https://dbareports.io, SQLDBAWithABeard.com)
Copyright (C) 2016 Rob Sewell

This program is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version.

This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details.

You should have received a copy of the GNU General Public License along with this program. If not, see <http://www.gnu.org/licenses/>.

.LINK
https://dbareports.io/functions/Add-DbrServerToInventory

.EXAMPLE
Add-DbrServerToInventory sql2016
    
Adds the SQL Server instance "sql2016" to the inventory then takes additional steps determined by the content of the config file.

.EXAMPLE
Add-DbrServerToInventory sql2016, sql2014
    
Adds the SQL Server instances sql2016 and sql2014 to the inventory then takes additional steps determined by the content of the config file.
#>

    [CmdletBinding()]
    Param (
        [parameter(ValueFromPipeline = $true, Mandatory = $true)]
        [Alias("SqlServer", "ServerInstance")]
        [string[]]$SqlInstance,
        [object]$SqlInstanceCredential,
        [int]$Port,
        [string]$Environment,
        [string]$Location
    )
    
    BEGIN
    {
        Get-Config
        $SqlServer = $script:SqlServer
        $InstallDatabase = $script:InstallDatabase
        $SqlCredential = $script:SqlCredential
        
        if ($SqlServer.length -eq 0)
        {
            throw "No config file found. Have you installed dbareports? Please run Install-DbaReports or Install-DbaReportsClient"
        }
        
        $sourceserver = Connect-SqlServer -SqlServer $sqlserver -SqlCredential $SqlCredential
        
        # Get columns automatically from the table on the SQL Server
        # and creates the necessary $script:datatable with it
        $table = "dbo.InstanceList"
        $schema = $table.Split(".")[0]
        $tablename = $table.Split(".")[1]
        Initialize-DataTable
        
        # Go get list of instances
        try
        {
            $sql = "SELECT * FROM [dbo].[InstanceList]"
            $allservers = $sourceserver.Databases[$InstallDatabase].ExecuteWithResults($sql).Tables
        }
        catch
        {
            Write-Exception $_
            throw "Can't get InstanceList in the $InstallDatabase database on $($sourceserver.name)."
        }
        
        # Go get a list of SERVERS :-)
        try
        {
            $sql = "SELECT ServerID,ServerName FROM [info].[ServerInfo]"
            $TheServers = $sourceserver.Databases[$InstallDatabase].ExecuteWithResults($sql).Tables
        }
        catch
        {
            Write-Exception $_
            throw "Can't get ServerName in the $InstallDatabase database on $($sourceserver.name)."
        }
    }
    
    PROCESS
    {
        foreach ($server in $SqlInstance)
        {
            try
            {
                try
                {
                    $smoserver = Connect-SqlServer -SqlServer "TCP:$Server" -SqlCredential $SqlInstanceCredential 
                }
                catch
                {
                    Write-Output "TCP connection failed for $Server trying again without"
                    $smoserver = Connect-SqlServer -SqlServer "$Server" -SqlCredential $SqlInstanceCredential
                }
                $ComputerName = $smoserver.ComputerNamePhysicalNetBIOS
                $ServerName = $smoserver.NetName
                $isclustered = $smoserver.IsClustered
                $InstanceName = $smoserver.InstanceName
                $name = $smoserver.Name.Replace("TCP:","")
                $NotContactable = $False
                
                if ($InstanceName.length -eq 0)
                {
                    $InstanceName = "MSSQLSERVER"
                }
            }
            catch
            {
                Write-Warning "Couldn't contact $Server. Marked as NotContactable."
                $NotContactable = $true
                $Name = $server
            }
            
            $row = $allservers.Rows | Where-Object { $_.InstanceName -eq $InstanceName -and $_.ComputerName -eq $ComputerName }
            $key = $row.InstanceId
                                    
            if ($key -eq $null)
            {
                $update = $false
            }
            else
            {
                Write-Output "$Server already exists in database. Updating information."
                $update = $true
            }
            
            $row = $TheServers.Rows | Where-Object {$_.ServerName -eq $ComputerName }
            $Serverkey = $row.ServerId
            $Exists = $false
            if($datatable.rows.count -gt 0)
            {
            $exists = $datatable.Rows.ComputerName.Contains($ComputerName)
            }
            else
            {
            $exists = $false
            }    
            Write-output "Exists = $Exists for $Server"        ## trouble shooting
            if ($Serverkey -eq $null)
            {
                if($exists -eq $false)
                {
                    $update = $false
                try
                    {
                        $sql = "INSERT INTO [info].[ServerInfo] ([ServerName]) VALUES ('$ComputerName')"
                        $sourceserver.Databases[$InstallDatabase].ExecuteNonQuery($sql)
                        Write-Output "Added $ComputerName to ServerInfo Table"
                    }
                catch
                    {
                        Write-Exception $_
                        return "Server insert failed Quitting"
                    }
                }
                else
                {
                    Write-Output "$ComputerName already exists in datatable. Moving On."
                    break
                }
            }
            else
            {
                Write-Output "$ComputerName already exists in database. Updating information."
            }


            try
                {
                    $sql = "SELECT [ServerId] FROM [info].[ServerInfo] WHERE Servername = '$ComputerName'"
                    $serverid = $sourceserver.Databases[$InstallDatabase].ExecuteWithResults($sql).Tables.ServerId
                }
            catch
                {
                    Write-Exception $_
                    return "Failed to Get ServerId from Serverinfo Table"
                }
            
            
            if ($Port -eq 0 -and $NotContactable -eq $false)
            {
                try
                {
                    # WmiComputer is unreliable :( Use T-SQL
                    $sql = "SELECT local_tcp_port FROM sys.dm_exec_connections WHERE session_id = @@SPID"
                    $Port = $smoserver.ConnectionContext.ExecuteScalar($sql)
                }
                catch
                {
                    Write-Warning "Port could not be determined for $ServerName. Skipping."
                    Continue
                }
            }
            
            if ($isclustered -eq $true)
            {
                $sql = "Select NodeName FROM sys.dm_os_cluster_nodes"
                $nodes = $smoserver.ConnectionContext.ExecuteWithResults($sql).Tables.NodeName
                
                foreach ($node in $nodes)
                {
                    if ($SqlInstance -notcontains $node -and $computername -ne $node)
                    {
                        $row = $allservers.Rows | Where-Object { $_.ComputerName -eq $node }
                        $nodekey = $row.InstanceId
                                                
                        if ($nodekey -eq $null)
                        {
                            $nodeupdate = $false
                        }
                        else
                        {
                            $nodeupdate = $true
                        }
                        
                        Write-Warning "Added clustered node $node to server collection."
                        
                        # Populate the datatable
                        $datatable.rows.Add(
                            $nodekey,
                            $serverid,
                            $name,
                            $node,
                            $servername,
                            $InstanceName,
                            $isclustered,
                            $port,
                            0,
                            $Environment,
                            $Location,
                            $NotContactable,
                            $nodeupdate
                        )
                    }
                }
            }
            
            # Populate the datatable
            $datatable.rows.Add(
                $key,
                $serverid,
                $name,
                $computername,
                $servername,
                $InstanceName,
                $isclustered,
                $port,
                0,
                $Environment,
                $Location,
                $NotContactable,
                $Update
            )
        }
        
        $rowcount = $datatable.Rows.Count
        
        if ($rowcount -eq 0)
        {
            Write-Output "No rows returned. No update required."
            continue
        }
        
        
        if ($Update -eq $true)
        {
            Write-Output "Updating $rowcount row(s)"
        }
        else
        {
            Write-Output "Adding $rowcount row(s)"
        }
        try
        {
            Write-Tvp
            
        }
        catch
        {
            Write-Exception $_
            return "Bulk insert failed. Recording exception and quitting."
        }
        
        $execaccount = $sourceserver.JobServer.ServiceAccount
        $testjob = $sourceserver.JobServer.Jobs | Where-Object { $_.Name -like "*dbareports - Test*" } | Select-Object -First 1
        $proxy = $testjob.JobSteps[0].ProxyName
        
        if ($proxy.length -gt 0)
        {
            $proxydetails = $sourceserver.JobServer.ProxyAccounts[$proxy]
            $proxycredential = $proxydetails.CredentialIdentity
            $execaccount = "$proxy ($proxycredential)"
        }
        
        $successful = $SqlInstance -join ", "
        Write-Output "Checking to see if $execaccount has access to $successful."
        
        try
        {
            $agentserverjob = $sourceserver.JobServer.Jobs | Where-Object { $_.Name -like "*dbareports - Test Access to Servers and Log Directory" }
            if ($agentserverjob.CurrentRunStatus -eq "Idle")
            {
                $agentserverjob.Start()
            }
            do
            {
                Start-Sleep -Milliseconds 200
            }
            until ($agentserverjob.CurrentRunStatus -eq "Idle" -or ++$i -eq 20)
            
            
            if ($agentserverjob.LastRunOutcome -eq "Failed")
            {
                Write-Warning "$execaccount cannot access one of the instances in InstanceList. Check dat."
            }
            else
            {
                Write-Output "Lookin' good! $execaccount successfully logged in to $successful."
            }
            
            if ($update -ne $true)
            {
                Write-Output "Populating a few other tables with the info for $successful while we're at it."
                
                try
                {
                    Write-Output "Starting Agent Job Server job"
                    $agentserverjob = $sourceserver.JobServer.Jobs | Where-Object { $_.Name -like "*dbareports - Agent Job Server*" }
                    $agentserverjob.Start()
                    
                    Write-Output "Starting Windows Server Information job"
                    $winserverInfoJob = $sourceserver.JobServer.Jobs | Where-Object { $_.Name -like "*dbareports - Windows Server Information*" }
                    $winserverInfoJob.Start()
                    
                    Write-Output "Starting SQL Server Information job"
                    $sqlserverinfojob = $sourceserver.JobServer.Jobs | Where-Object { $_.Name -like "*dbareports - SQL Server Information*" }
                    $sqlserverinfojob.Start()
                    
                    Write-Output "Done!"
                }
                catch
                {
                    Write-Output "Well that didn't go as planned. Please ensure that SQL Server Agent is running on $sqlserver"
                    Write-Exception $_
                }
            }
        }
        catch
        {
            Write-Output "The Agent Job on $sqlserver cannot contact all servers in the InventoryList. Check job history for details."
            Write-Exception $_
        }
    }
    
    END
    {
        $sourceserver.ConnectionContext.Disconnect()
        
    }
}