Hi Everyone,
I have often run into a situation where I have been asked to collect some data or perform a small task on a Windows Server.
I don't really like having to install the CAPA Agent on the server just to perform small tasks, as where I work that involves a big pile of paperwork, change controls, and then the future responsibility for maintaining the agent!
Once of the ways I have found to avoid having to install agents, is to use PowerShell Remoting to run the action(s) that I am looking for on the remote server.
As there are already lots of articles out there in Google-Land about configuring and setting up PowerShell Remoting, I won't be covering that aspect of the process.
Once you know a remote server can be accessed, on the CAPA side, executing a PowerShell Remoting session is really pretty easy.
(I generally develop my PowerShell code locally on my PC, and then add it to the code in CAPA once I know it works (mostly) the way I want it to)
While there are several ways to invoke a remote PowerShell session, in this example I will be using the Invoke-Command
With Invoke-Command you can either pass a block of script, or a local (to the agent, not the remote host) file name:
-ScriptBlock { **PowerShell Commands Go Here ** }
-FilePath **Path to a local file that contains the PowerShell code**
The process is basically two steps:
- Create temporary local file(s) on an Agent
- Using the Run Script operator to have PowerShell invoke the remote session.
I have also built in some basic checks like getting the real server host name (as the Invoke-Command will usually fail when using a DNS alias), and validating the server is responding.
Step 1: Create the remote (on the agent) files, for the purposes of this example, I have included two simple PowerShell scripts you can use to see if the remoting works.
This one I called "TEST_Working.ps1"
# ** START **
Param(
[string]$Environmemt
)
$X = "SUCCESS - " + $Environmemt
$X
# ** END **
And this one I called: "TEST_Failed.ps1"
# ** START **
Param(
[string]$Environmemt
)
$x = 5 / 0
$X = "SUCCESS - " + $Environmemt
# ** END **
Step 2: Insert a Run Script operator
- Change: Script extension to .ps1
- Assign the following parameters to the script (and don't forget to create/set them in the process).
[0] Process.AD_Username The AD Username that has access to the remote server
[1] Process.AD_Password The AD Password for the username
[2] Process.DestinationServerName The FQDN of the server (can be an Alias if you use the GetHostByName func)
[3] Process.PowerShellFileName The full path & filename to the PS1 file on my Agent/Orchestrator
[4] Process.Remote_Environment This is just an example variable that I will be passing to the remote script, so it can pass it back in the output.
- Post output to dataset variable - Checked (since you want to know what is going on)
- I always also set the Target, under the Execution Settings, to make sure that the Run Script operator will run on the same Agent/Orchestrator Node that I created the file on (when I do it dynamically in-process).
Inline Script Code:
# ** Start of Inline Script for Run Script Operator**
Param(
[string]$Remote_Username,
[string]$Remote_Password,
[string]$RemoteComputer,
[string]$LocalTmpPowerShellScriptFile,
[string]$Environment
)
$SECURE_Password = convertto-securestring $Remote_Password -asplaintext -force
$Remote_Credentials = new-object -typename System.Management.Automation.PSCredential -argumentlist $Remote_Username, $SECURE_Password
try
{
$ServerName = ([System.Net.Dns]::GetHostByName($RemoteComputer)).HostName
}
catch
{
write-host "Exception: "$_.Exception.Message
Throw $_.Exception
}
If (Test-Connection -ComputerName $ServerName -Quiet)
{
try
{
Invoke-Command -Credential $Remote_Credentials -ComputerName $ServerName -ErrorAction Stop -FilePath $LocalTmpPowerShellScriptFile -ArgumentList $Environment
}
catch
{
write-host "Exception: "$_.Exception.Message
Throw $_.Exception
}
}
else
{
Throw "Failed to connect"
}
# ** End of Inline Script **
Step 3: Set your variables, and run the process!
Don't forget, the PowerShellFileName should be the full path to the file on the Agent!
If you run TEST_Working.ps1, passing the environment variable of "Production" you should see the following:
If you run TEST_Failed.ps1, passing the environment variable of "Production" you should see the following:
If you run either of them, and it fails with one of the following messages, it means the AD_Username/AD_Password are incorrect, or the AD account does not have access to the remote server.
- Exception: Connecting to remote server (servername) failed with the following error message : Access is denied. For more information, see the about_Remote_Troubleshooting Help topic. Connecting to remote server (servername) failed with the following error message : Access is denied. For more information, see the about_Remote_Troubleshooting Help topic.
- Exception: Connecting to remote server (servername) failed with the following error message : Logon failure: unknown user name or bad password. For more information, see the about_Remote_Troubleshooting Help topic. Connecting to remote server (servername) failed with the following error message : Logon failure: unknown user name or bad password. For more information, see the about_Remote_Troubleshooting Help topic.
I hope you guys find this little trick will come in handy as much as I do!
Ian Rich
Sr. Automation Analyst, IT Operations Management
CN Rail