Friday, January 15, 2016

SCOM Migration

Hello everyone! 

We are currently in the process of migrating our all of the servers from one domain to our 'main' domain and as part of this project we are migrating the servers from their current SCOM environment to ours. This is normally very simple to be done through the SCOM Management Console; however, I have found that about 25% of the servers that I have been migrating are failing either during the uninstall, or the installation of the new client. 

The failures are due to a number of things, because of permission issues, or ports not being opened, or just because the server doesn't feel like cooperating. Either way in order to make my work easier I created two functions to remotely install and uninstall the agent using Invoke-command and msiexec.exe and would like to share this scripts. 

<#
       .SYNOPSIS
              Install SCOM Agent in a remote computer using MSIExec

       .DESCRIPTION
              This function will Install the SCOM Agent on a remote computer using msiexec.exe. The function will require that you provide the name of the computer, and if different to modify the path where the SCOM Agent folder is located.

       .PARAMETER  computerName
              The computer where you wish to uninstall the SCOM Agent from.

       .PARAMETER  agentPath
              The script will use the MOMAgent.msi to install the SCOM Agent, therefor we'll need to copy the file over to the server.
              This is currently done by copying the folder where the file is located. The folder will be copied to the C drive under the folder
              name SCOMAgent and will clean it up after the installation is completed.

              You can hard code this parameter so that it will always use a default location under the 'Begin' section.

       .EXAMPLE
              PS C:\> Install-SCOMAgentMsiExec -ComputerName SERVERNAME

       .EXAMPLE
              PS C:\> Install-SCOMAgentMsiExec -ComputerName SERVERNAME -agentPath C:\agentPath\Folder
                     * Note: This is the folder where it is located, not the msi file itself.

       .INPUTS
              System.String, [System.String]

       .OUTPUTS
              System.String
#>
function Install-SCOMAgentMsiExec
{
       [CmdletBinding()]
       param (
              [Parameter(Position = 0, Mandatory = $true)]
              [System.String]$computerName,
              [Parameter(Position = 0, Mandatory = $false)]
              [System.String]$agentPath
       )
       begin
       {
              if ($agentPath.Length -eq 0 -or $agentPath -eq $null)
              {
                     $msiPath = # Default path here
              }
             
              $serverAgentPath = "\\$($computerName)\c$\SCOMAgent"
       } # endbegin
       process
       {
              if (-not (Test-Connection -ComputerName $computerName -Count 1 -Quiet)) # Testing if Computer is online.
              {
                     Write-Error -Message "$computerName cannot be pinged." -Category ResourceUnavailable -ErrorAction Stop
              }
              else
              {
                     Write-Verbose -Message "$computerName is accepting pings."
              } # endelse

              if (-not(Get-Service HealthService -ComputerName $computerName -ErrorAction SilentlyContinue)) # Ensure that the HealthService doesn't exists.
              {
                     # Install the Agent if the service is not found.
                     Write-Verbose -Message "The HealthService service is not installed. Installing."
                    
                     if (-not (Test-Path -Path $msiPath)) # Test to ensure the Agent Path exists.
                     {
                           Write-Error -Message "Unable to find the location $msiPath." -Category ObjectNotFound -ErrorAction Stop
                     } # endif
                    
                     try
                     {
                           if (Test-Path -Path $serverAgentPath) # Test if the destination folder exists.
                           {
                                  Write-Verbose -Message "The destination folder already exists. Ensure no files are missing."
                                  # If the Path exists, we'll compare the files to not have to re-write data.
                                  $sourceFiles = Get-ChildItem $msiPath
                                  $destinationFiles = Get-ChildItem $serverAgentPath
                                 
                                  if (-not (Compare-Object -ReferenceObject $sourceFiles -DifferenceObject $destinationFiles)) # Test if the folders are the same, and not missing files.
                                  {
                                         # If the folders do not match delete the current folder.
                                         Write-Verbose -Message "The folders do not match completely."
                                         Remove-Item $serverAgentPath -Recurse
                                         # Copy the correct Agent data into the local folder.
                                         Write-Verbose "Copying files from $msiPath to $serverAgentPath"
                                         Copy-Item $msiPath -Destination $serverAgentPath -Recurse -Force
                                  } # endif
                                  else
                                  {
                                         Write-Verbose -Message "The folders are identical. Proceeding."
                                  } # endelese
                           }
                           else
                           {
                                  # If the folder doesn't exist copy the Agent data into the local drive.
                                  Write-Verbose "Copying files from $msiPath to $serverAgentPath"
                                  Copy-Item $msiPath -Destination $serverAgentPath -Recurse -Force
                           }
                     } # endtry
                     catch
                     {
                           Write-Error -Message $Error[0].Exception -ErrorAction Stop
                     } # endcatch
                    
                     Write-Verbose -Message "Uninstalling the SCOM Agent."
                     Invoke-Command -ComputerName $computerName -ScriptBlock {
                           Start-Process "C:\Windows\System32\msiexec.exe" -ArgumentList "/i C:\SCOMAgent\MOMAgent.msi /qn USE_SETTINGS_FROM_AD=0 USE_MANUALLY_SPECIFIED_SETTINGS=1 MANAGEMENT_GROUP=[GROUPNAME] MANAGEMENT_SERVER_DNS=[SERVERNAME] SECURE_PORT=[PORT] AcceptEndUserLicenseAgreement=1" -Wait
                     }
                    
                     # We look in the computers eventlog to find the MsiExec log for the installation in the last 5 minutes.
                     Write-Verbose -Message "Confirming that the installation has been a success."
                     $eventLog = Get-EventLog -ComputerName $computerName -LogName Application -InstanceId 11707 -Newest 1 -Message "Product: Microsoft Monitoring Agent -- Installation operation completed successfully." -After $((Get-Date).AddMinutes(-5))
                    
                     if ($eventLog -ne $null) # Check if the EventLog was found.
                     {
                           Write-Verbose -Message "The HealthService service has been installed."
                     } # endif
                     else
                     {
                           Write-Error -Message "The installation failed." -Category NotInstalled -ErrorAction Stop
                     } # endcatch
              } # endif
              else
              {
                     Write-Error -Message "The HealthService is already installed." -Category InvalidOperation -RecommendedAction "Uninstall the agent before proceeding." -ErrorAction Stop
              } # endelse
       } # endprocess
       end
       {
              Write-Verbose -Message "Removing the Agent folder."
              Remove-Item $serverAgentPath -Recurse
       } # endEnd
} # endfunction



<#
       .SYNOPSIS
              Uninstall SCOM Agent in a remote computer using MSIExec

       .DESCRIPTION
              This function will Uninstall the SCOM Agent on a remote computer using msiexec.exe. The function will require that you provide the
              name of the computer, and if different to modify the path where the SCOM Agent folder is located.

       .PARAMETER  computerName
              The computer where you wish to uninstall the SCOM Agent from.

       .PARAMETER  agentPath
              The script will use the MOMAgent.msi to uninstall the SCOM Agent, therefor we'll need to copy the file over to the server.
              This is currently done by copying the folder where the file is located. The folder will be copied to the C drive under the folder
              name SCOMAgent and will clean it up after the uninstallation is completed.

              You can hard code this parameter so that it will always use a default location under the 'Begin' section.

       .EXAMPLE
              PS C:\> Uninstall-SCOMAGentMsiExec -ComputerName SERVERNAME

       .EXAMPLE
              PS C:\> Uninstall-SCOMAGentMsiExec -ComputerName SERVERNAME -agentPath C:\agentPath\Folder
                     * Note: This is the folder where it is located, not the msi file itself.

       .INPUTS
              System.String, [System.String]

       .OUTPUTS
              System.String
#>
function Uninstall-SCOMAgentMsiExec
{
       [CmdletBinding()]
       param (
              [Parameter(Position = 0, Mandatory = $true)]
              [System.String]$computerName,
              [Parameter(Position = 0, Mandatory = $false)]
              [System.String]$agentPath
       )
       begin
       {
              if ($agentPath.Length -eq 0 -or $agentPath -eq $null)
              {
                     $msiPath = # Default path here
              }
             
              $serverAgentPath = "\\$($computerName)\c$\SCOMAgent"
       } # endbegin
       process
       {
              if (-not (Test-Connection -ComputerName $computerName -Count 1 -Quiet)) # Testing if Computer is online.
              {
                     Write-Error -Message "$computerName cannot be pinged." -Category ResourceUnavailable -ErrorAction Stop
              } # endif
              else
              {
                     Write-Verbose -Message "$computerName is accepting pings."
              } # endelse

              if (Get-Service HealthService -ComputerName $computerName -ErrorAction Stop) # Check if the HealthService exists.
              {
                     Write-Verbose -Message "The HealthService service is installed. Proceeding with uninstallation."
                    
                     if (-not (Test-Path -Path $msiPath)) # Test to ensure the Agent Path exists.
                     {
                           Write-Error -Message "Unable to find the location $msiPath." -Category ObjectNotFound -ErrorAction Stop
                     } # endif
                    
                     try
                     {
                           if (Test-Path -Path $serverAgentPath) # Test if the destination folder exists.
                           {
                                  Write-Verbose -Message "The destination folder already exists. Ensure no files are missing."
                                  # If the Path exists, we'll compare the files to not have to re-write data.
                                  $sourceFiles = Get-ChildItem $msiPath
                                  $destinationFiles = Get-ChildItem $serverAgentPath
                                 
                                  if (-not (Compare-Object -ReferenceObject $sourceFiles -DifferenceObject $destinationFiles)) # Test if the folders are the same, and not missing files.
                                  {
                                         # If the folders do not match delete the current folder.
                                         Write-Verbose -Message "The folders do not match completely."
                                         Remove-Item $serverAgentPath -Recurse
                                         # Copy the correct Agent data into the local folder.
                                         Write-Verbose "Copying files from $msiPath to $serverAgentPath"
                                         Copy-Item $msiPath -Destination $serverAgentPath -Recurse -Force
                                  } # endif
                                  else
                                  {
                                         Write-Verbose -Message "The folders are identical. Proceeding."
                                  } # endelese
                           }
                           else
                           {
                                   # If the folder doesn't exist copy the Agent data into the local drive.
                                  Write-Verbose "Copying files from $msiPath to $serverAgentPath"
                                  Copy-Item $msiPath -Destination $serverAgentPath -Recurse -Force
                           }
                     } # endtry
                     catch
                     {
                           Write-Error -Message $Error[0].Exception -ErrorAction Stop
                     } # endcatch
                    
                     Write-Verbose -Message "Uninstalling the SCOM Agent."
                     Invoke-Command -ComputerName $computerName -ScriptBlock { Start-Process "C:\Windows\System32\msiexec.exe" -ArgumentList "/x C:\SCOMAgent\MOMAgent.msi /qb" -Wait }
                    
                     # We look in the computers eventlog to find the MsiExec log for the uninstallation in the last 5 minutes.
                     Write-Verbose -Message "Confirming that the uninstallation has been a success."
                     $eventLog = Get-EventLog -ComputerName $computerName -LogName Application -InstanceId 11724 -Newest 1 -Message "Product: Microsoft Monitoring Agent -- Removal completed successfully." -After $((Get-Date).AddMinutes(-5))
                    
                     if ($eventLog -ne $null) # Check if the EventLog was found.
                     {
                           Write-Verbose -Message "The HealthService service has been uninstalled."
                     } # endif
                     else
                     {
                           Write-Error -Message "The uninstallation failed." -Category NotInstalled -ErrorAction Stop
                     } # endcatch
              } # endif
              else
              {
                     Write-Error -Message "The HealthService is not installed." -Category InvalidOperation -ErrorAction Stop
              } # endelse
       } # endprocess
       end
       {
              Write-Verbose -Message "Removing the Agent folder."
              Remove-Item $serverAgentPath -Recurse
       } # endEnd
} # endfunction



The main thing to notice here is that the script will need to have access to the location where the msi SCOM Installation file is located, and local administrator rights to the server. 

The script will then copy the files to the local drive of the server and run the msi file. Once the installation runs it will check for a successful installation/uninstall eventlog and delete the data that it copied to the C drive. 

I hope that this might help someone out there, and please let me know if you have any questions, feedback or concerns. 

Kind regards,
Me.