Morpheus Windows Agent - Useful Powershell Functions

Morpheus Windows Agent Configuration

Powershell Functions for managing the Morpheus Agent config files

In this post want to share some Powershell functions that can be used in Morpheus Tasks to obtain information about the Morpheus Windows Agent and allow tasks to view and make updates to the Windows Agent config file.

Powershell Functions

Function Get-MorpheusAgentConfig {
    <#
    .SYNOPSIS
        Returns the current contents of the Morpheus Windows Agent config file

    .OUTPUTS
        if successful the contents of the MorpheusAgent.exe.config file are returned

    #>     
    if (IsElevated) {
        $Agent = Get-CIMInstance -Class win32_Service -Filter "Name like 'Morpheus Windows Agent'"
        if ($Agent) {
            $AgentFolder = Split-Path -Path ($Agent.PathName -replace '"','') -Parent
            $ConfigFile = Join-Path -Path $AgentFolder -ChildPath "MorpheusAgent.exe.config"
            if (Test-Path -Path $ConfigFile) {
                # Config file exists
                $CF = Get-Content -Path $ConfigFile -Raw
                return $CF
            }
            else {
                Write-Warning "Agent Config file $($ConfigFile) Not Found"
            }
        }
        else {
            Write-Warning "Morpheus Windows Agent Not Found"
        }
    }
    else {
        Write-Warning "This function must have Administrator privilege"
    }
}

Function Set-MorpheusAgentConfig {
    <#
    .SYNOPSIS
        Optionally Sets the values of LogLevel, Host and ApiKey in the Morpheus Windows Agent config file

    .PARAMETER LogLevel
        Sets the LogLevel 0 = debug; 1 = info; 2 = warn; 3 = error; 4 = off
        Default value is 1

    .PARAMETER ApplianceUrl
        Optionally sets the appliance Host. There is no Default value.
        Only specify if you need to change the Host name

        Format is "https://ApplianceNameOrIp/"

    .PARAMETER ApiKey
        Optionally sets the Instance ApiKey. There is no Default value.
        Only specify if you need to change the ApiKey

        The ApiKey MUST match exactly the ApiKey on the Compute Server details page

    .PARAMETER RestartAgent
        Specify this parameter to schedule a delayed restart (60 seconds) of the Morpheus Windows Agent Service

    .OUTPUTS
        if successful the updated contents of the MorpheusAgent.exe.config file are returned

    #> 
    [CmdletBinding()]
    param (
        [ValidateRange(0,4)]
        [Int32]$LogLevel=1,
        [String]$ApplianceUrl=$null,
        [String]$ApiKey=$null,
        [Switch]$RestartAgent
    )
    
    if (IsElevated) {
        $Agent = Get-CIMInstance -Class win32_Service -Filter "Name like 'Morpheus Windows Agent'"
        if ($Agent) {
            $AgentFolder = Split-Path -Path ($Agent.PathName -replace '"','') -Parent
            $ConfigFile = Join-Path -Path $AgentFolder -ChildPath "MorpheusAgent.exe.config"
            if (Test-Path -Path $ConfigFile) {
                # Config file exists - load the file as XML - Fail and exit if not valid
                try {
                    [Xml]$Config = Get-Content -Path $ConfigFile -Raw
                }
                Catch {
                    Write-Warning "Failed to Parse XML Agent Config file"
                    $Config = $null
                }
                if ($Config) {
                    #Navigate the XML - run through the app settings modifying the attributes as required
                    foreach ($node in $Config.SelectNodes("/configuration/appSettings/add")) {
                        if (($LogLevel -ge 0 -AND $LogLevel -lt 5) -AND $node.GetAttribute("key") -eq "LogLevel") {$node.SetAttribute("value",$LogLevel.toString())}
                        if ($ApplianceUrl -AND $node.GetAttribute("key") -eq "Host") {$node.SetAttribute("value",$ApplianceUrl)}
                        if ($ApiKey -AND $node.GetAttribute("key") -eq "ApiKey") {$node.SetAttribute("value",$ApiKey)}
                    }
                    $Config.Save($ConfigFile)
                    # Restart Service - use Delay-AgentRestart to detach a process to do the restart otherwise it kills this job
                    if ($RestartAgent) {
                        $RestartPid = Delay-AgentRestart -Delay 60
                        Write-Host "Delaying Agent Service Restart - detaching process $($RestartPid)"
                    }
                    else {
                        Write-Warning "Agent Service must be restarted to use new configuration"
                    }
                    Write-Host "Returning Updated Agent Config ..."
                    # Return the updated Config File (as a String)
                    return (Get-MorpheusAgentConfig)
                }
            }
            elget-se {
                Write-Warning "Agent Config file $($ConfigFile) Not Found"
            }
        }
        else {
            Write-Warning "Morpheus Windows Agent Not Found"
        }
    }
    else {
        Write-Warning "This function must have Administrator privilege"
    }
}  
  
Function Get-MorpheusAgentSocketStatus {
    <#
    .SYNOPSIS
        Returns the Morpheus Windows Agent Service Status and associated TCP Socket details 

    .PARAMETER AsJson
        Specify this parameter to return output as a json string

    .OUTPUTS
        PSCustom object, or optionally json string containing the Agent and Socket status 

    #> 
    [CmdletBinding()]
    param (
        [Switch]$AsJson
    )

    $Status = [PSCustomObject]@{
        adminAccess=IsElevated;
        machineName=[Environment]::MachineName;
        agentStatus="";
        agentState=""
        agentPid=$null;
        agentSockets=$null
    }

    if (IsElevated) {
        $Agent = Get-CIMInstance -Class win32_Service -Filter "Name like 'Morpheus Windows Agent'"
        if ($Agent) {
            $Status.agentStatus = $Agent.Status
            $Status.agentState = $Agent.State
            # We have an agent - Does it have a Pid
            if ($Agent.ProcessId -Ne 0) {
                $Status.agentPid = $Agent.ProcessId
                try {
                    $Sockets = @(Get-NetTCPConnection -RemotePort 443 -OwningProcess $Agent.ProcessId)
                }
                catch {
                    $Sockets = @()
                    Write-Warning "Agent ProcessId Owns no Sockets on port 443"
                }
                $Status.agentSockets = foreach ($Socket in $Sockets) {
                    [PSCustomObject]@{
                        state = $Socket.State.ToString();
                        creationTime = $Socket.CreationTime.ToString("s");
                        localAddress = $Socket.LocalAddress;
                        localPort = $Socket.LocalPort;
                        remoteAddress = $Socket.RemoteAddress;
                        remotePort = $Socket.RemotePort
                    } 
                }
            }
            else {
                Write-Warning "Morpheus Windows Agent Installed but Not Running on  $($Status.machineName)"
                $Status.agentStatus="NotRunning"                
            }
        }
        else {
            Write-Warning "Morpheus Windows Agent Not Installed on  $($Status.machineName)"
            $Status.agentStatus="NoAgent"
        }         
    }
    else {
        Write-Warning "You need to be an Administrator to run this Function"
    }
    if ($AsJson) {
        return $Status | ConvertTo-Json -Depth 5
    }
    else {
        return $Status
    }
}

Function IsElevated {
    <#
    .SYNOPSIS
        Helper function.
        Determines if the current user has Administrator Privilege

    .OUTPUTS
        $true - Current user has Administrator role
        $false = Curent User does not have Administrator Role

    #>     
    $userIdentity =  [System.Security.Principal.WindowsIdentity]::GetCurrent()
    $userPrincipal = [System.Security.Principal.WindowsPrincipal]$userIdentity
    $adminElevated=$userPrincipal.IsInRole([Security.Principal.WindowsBuiltInRole]::Administrator)
    return $adminElevated
}


Function Delay-AgentRestart {
    <#
    .SYNOPSIS
        Helper Tool used to detach a process to delay a restart of the Morpheus Windows Agent service.
        This way you can restart the Agent from a command bus session without affecting the runnign job 

    .PARAMETER Delay
        Number of seconds to Wait before the Agent is restarted. Default is 30

    .OUTPUTS
        Returns the Process Id of the detached process responsible for restarting the Morpheus Windows Agent service.
        Returns 0 if the Detached process failed to start successfully

    #>     
    [CmdletBinding()]
    param (
        [Int32]$Delay=30
    )

        $ArgString = " -noprofile -command ""& {start-sleep -seconds $($Delay); Restart-Service 'Morpheus Windows Agent' }"" "
        $RestartProcess = Start-Process -FilePath "powershell.exe" -ArgumentList $ArgString -Verb "RunAs" -WindowStyle "Hidden" -Passthru
        if ($RestartProcess) {
            return $RestartProcess.Id
        }
        else {
            return 0
        }
} 

Examples

Get the Morpheus Windows Agent service status and TCP Socket details

To get the current status of the Morpheus Agent Service along with the associated TCP Socket details returning the output as a json string use

$info = Get-MorpheusAgentSocketStatus -AsJson
$info
{
    "adminAccess":  true,
    "machineName":  "SP54-W-1047",
    "agentStatus":  "OK",
    "agentState":  "Running",
    "agentPid":  8104,
    "agentSockets":  {
                         "state":  "Established",
                         "creationTime":  "2023-03-10T17:39:03",
                         "localAddress":  "10.32.23.116",
                         "localPort":  51409,
                         "remoteAddress":  "10.32.23.194",
                         "remotePort":  443
                     }
}

Get the current Agent config file

To See the current Morpheus Windows Agent config file (WindowsAgent.exe.config) use the following function.

Get-MorpheusAgentConfig

<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="ServiceName" value="Morpheus Windows Agent" />
    <add key="ApiKey" value="708dbe73-9509-4858-aca5-38f1f276abdb" />
    <add key="Host" value="https://sp-morpheus.mymorpheusappliance.somewhere/" />
    <add key="VmMode" value="true" />
    <add key="LogLevel" value="0" />
    <!-- 0 = debug; 1 = info; 2 = warn; 3 = error; 4 = off;-->
    <add key="ClientSettingsProvider.ServiceUri" value="" />
  </appSettings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <system.web>
    <membership defaultProvider="ClientAuthenticationMembershipProvider">
      <providers>
        <add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
      </providers>
    </membership>
    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
      <providers>
        <add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
      </providers>
    </roleManager>
  </system.web>
</configuration>

Set the Agent Logging Level to 1 (Info) and delay a restart of the Morpheus Windows Agent service

And finally, to set the Morpheus Windows Agent Logging level to Info ($LogLevel=1) , performing a 60 second delayed restart of the Morpheus Windows Agent service use the example below.
$newConfig is the contents of the updated MorpheusAgent.exe.config.
The function has detached a process with pid 4760 which will restart the Morpheus Windows Agent service in 60 seconds.

$newConfig = Set-MorpheusAgentConfig -LogLevel 1 -RestartAgent
Delaying Agent Service Restart - detaching process 4760
Returning Updated Agent Config ...

$newConfig
<?xml version="1.0" encoding="utf-8"?>
<configuration>
  <appSettings>
    <add key="ServiceName" value="Morpheus Windows Agent" />
    <add key="ApiKey" value="708dbe73-9509-4858-aca5-38f1f276abdb" />
    <add key="Host" value="https://sp-morpheus.mymorpheusappliance.somewhere/" />
    <add key="VmMode" value="true" />
    <add key="LogLevel" value="1" />
    <!-- 0 = debug; 1 = info; 2 = warn; 3 = error; 4 = off;-->
    <add key="ClientSettingsProvider.ServiceUri" value="" />
  </appSettings>
  <startup>
    <supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.5.2" />
  </startup>
  <system.web>
    <membership defaultProvider="ClientAuthenticationMembershipProvider">
      <providers>
        <add name="ClientAuthenticationMembershipProvider" type="System.Web.ClientServices.Providers.ClientFormsAuthenticationMembershipProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" />
      </providers>
    </membership>
    <roleManager defaultProvider="ClientRoleProvider" enabled="true">
      <providers>
        <add name="ClientRoleProvider" type="System.Web.ClientServices.Providers.ClientRoleProvider, System.Web.Extensions, Version=4.0.0.0, Culture=neutral, PublicKeyToken=31bf3856ad364e35" serviceUri="" cacheTimeout="86400" />
      </providers>
    </roleManager>
  </system.web>
</configuration>

6 Likes

How to install Morpheus Windows Agent manually
??

Hi Hussain,
you need to download the agent install script and run manually on target host.
Here is a link to the docs for manually installing the agent.Morpheus Agent Install Troubleshooting — Morpheus Docs documentation
Thanks
Mousami

Thank you