RES One Automation PowerShell Module

Note: This blogpost is also posted on my personal blog.

resam-posh

When you’re a system administrator and a PowerShell enthousiast a single solution to a problem can result in something big and elaborate. A while ago I was implementing a MDT environment for a customer. I wanted to fill the MDT database with all existing client computers. For that I needed all the clients names and their MAC addresses. Client names weren’t the issue but MAC addresses were a little bit more challenging. I decided to turn to RES One Automation (RES AM) for help. I knew RES AM has the ability to identify agents by their MAC address so it has to store all agent MAC addresses in the datastore. After figuring out how to pry this information from the database I started to wonder what else I could find in there. This resulted in a complete PowerShell module (my first!) for RES One Automation! 

Of course I googled around first to check if anyone else had created a RES One Automation module and I came across a great post by LucD. He had created the module using RES AM’s WebAPI. The module works great but the information returned by the API is minimal. So I dedicated my spare time to writing some helper functions to connect to the database, run SQL queries on the appropriate tables and translate the SQL output to a custom object. With these helper functions I was able to create all the commands necessary to access important information from the database.

One of the challenges I came across is that some of the information in the RES AM datastore is stored in byte arrays. Fortunately they can be easily converted to a string. It turns out the string was actually in xml format, so that had to be processed as well. Because it take a little longer to process that information I gave the commands a switch parameter named Full. When omitted only the basic information is processed.

For scheduling jobs I still had to utilize the WebAPI. I adapted the function from LucD’s API module for usage with my other commands. The New-RESAMJob command automatically prompts for missing required RES AM parameter values, so you won’t accidentally schedule a job with empty values.

Requirements

The module has the following requirements:

Info only:

  • RES AM database should be a SQL database.
  • User account with at least Read privileges on the database.

Remove agent from database:

  • RES AM database should be a SQL database.
  • User account with Write privileges on the database.

Scheduling:

  • A dispatcher with the Web API enabled (The Dispatcher WebAPI is disabled by default. You can enable it by enabling the global setting WebAPI state (at Infrastructure > Datastore > Settings > Global Settings > Dispatcher WebAPI settings section).
  • RES AM credentials with at least rights to schedule jobs.

The module has been tested and works with RES AM 2012 and up.

Use cases

So what are the use cases for this module? I’ve been using it for a while now and found it very helpful for the following scenario’s:

  • Get a list of agents that haven’t been used for a certain period of time and export the results to a csv file.
  • Find duplicate agent objects in your environment (agents with the same name) and remove the .
  • Search RES AM objects for references to a deprecated server or share. You can search the contents of scripts in every module.
  • Create reports of job results. Find out which agents weren’t started when using WakeOnLan, which agents had failed tasks and which agents were processed without errors.
  • Start RES AM jobs during an MDT deployment and display the progress in the Task sequence progress bar (Seriously cool, I’ll write a seperate post on how to accomplish this in the near future).

Examples

Here are some examples on how to use the module:

-------------------------- Connect to database --------------------------
 
 C:\PS> $Cred = Get-Credential
 C:\PS> Connect-RESAMDatabase -DataSource SRV-SQL-01\RES -DatabaseName RES-AM -Credential $Cred
 
 Sets up a connection to database 'RES-AM' on the 'RES' Instance on SQL server 'SRV-SQL-01'.
 -------------------------- Full agent information --------------------------
 
 C:\PS> Get-RESAMAgent -Name PC1234 -Full
 
 Displays full information on RES Automation Manager agent PC1234.

 Output:
  
 Name          : PC1234
 Status        : Online
 OSName        : Microsoft Windows 10 Enterprise
 OSServicePack : 
 FreeSpace(GB) : 29,42
 MACAddress    : 90:1B:0E:28:95:68
 IPAddress     : 192.168.10.213
 PrimaryTeam   : Team1
 Teams         : {Team1, Team2}
 -------------------------- Get online team agents --------------------------
 
 C:\PS> Get-RESAMTeam -Name Team1 | Get-RESAMAgent -Status Online
 
 Displays default information on online agents that are a member of team 'Team1'.
-------------------------- Remove old duplicate agents --------------------------
 
 C:\PS> Get-RESAMAgent -HasDuplicates | Remove-RESAMAgent -DuplicatesPreference KeepLatest -IncludeJobHistory
 
 Removes all duplicate agents and their job history from the database except for the ones that were deployed the latest.
 -------------------------- List duplicate agents --------------------------
 
 C:\PS> Get-RESAMAgent -HasDuplicates
 
 Lists all duplicate agents. Can be piped back to Get-RESAMAgent to get the agent objects.
 
 Output:
 
 Name #Duplicates
 ---- -----------
 PC1234 2 
 PC2345 4 
 NB5432 6 
 NB4321 3
 -------------------------- Get members of a team --------------------------
 
 C:\PS> Get-RESAMTeam -Name Team1 | Get-RESAMAgents
 
 Get RES Automation Manager team 'Team1' and display it's team members (agents)
 -------------------------- Get module by name using a wildcard --------------------------
 
 C:\PS> Get-RESAMModule -Name '*WSUS*'
 
 Displays default information on RES Automation Manager Modules that have 'WSUS' in the name.
 -------------------------- Get full project information --------------------------
 
 C:\PS> Get-RESAMProject -Name 'Install WSUS patches' -Full
 
 Displays full information on RES Automation Manager Project 'Install WSUS patches'.
 -------------------------- Get query results by masterjob --------------------------
 
 C:\PS> Get-RESAMMasterJob -Description 'Query Services' | Get-RESAMQueryResult
 
 Displays the result of the MasterJobs whose description is 'Query Services'.
 -------------------------- Schedule project in one hour using parameters --------------------------
 
 C:\PS> Get-RESAMAgent | New-RESAMJob -Dispatcher SRV-DISP-001 -Credential $Cred -Description 'New Test Job' -Project 'Test Project' -Start (Get-Date).AddHours(1) 
 -Parameters @{Param1='TEST'}
 
 Schedules the project 'Test Project' to run in an hour on all agents using dispatcher 'SRV-DISP-001' with a credential object saved in a variable. Required parame
 ter 'Param1' is set with value 'TEST'.

Script example

Here is an example of a script that uses this module:

<# This section will show how to use the RESAM module in a script. First the module is imported, then the credentials are created and a connection to the database is set up. #>

Import-Module RESAM
# Create SQL user credential object
$username = "RES-AM"
$password = "R@Mpw1!" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $password

Connect-RESAMDatabase -DataSource dba-ram-01 -DatabaseName res-am -Credential $cred

#region Agents and Teams

#Get agents from team 'Team1'
$TeamAgents = Get-RESAMTeam -Name Team1 | Get-RESAMAgent -Full

#endregion Agents

#region modules

#Get module 'Module X'
$ModuleX = Get-RESAMModule -Name "Module X" -Full

#Display required parameters for scheduling
$ModuleX.RequiredParameters

<# Output: Name : ModX-Param2 Description : Required parameter for Module X Hint : Please provide the necessary input Type : Text Default : This is the default value for this required module parameter ListItems : {} #>

#endregion modules

#region Projects

#Get the project by name
$ProjectX = Get-RESAMProject -Name 'Project X' -Full

#Get all modules in this project
$ProjectModules = $ProjectX.Modules | Get-RESAMModule

#endregion Projects

#region Scheduling a job

# Create WebApi credential object
$username = "RESAM-API"
$password = "R@MAp1!" | ConvertTo-SecureString -AsPlainText -Force
$cred = New-Object -typename System.Management.Automation.PSCredential -argumentlist $username, $password

$Parameters = @{
'ModX-Param2' = 'Not a default value'
'ModX-NonRequired' = 'Something'
}
$Job = $TeamAgents | New-RESAMJob -Dispatcher RAM-DISP-001 -Credential $cred `
-Description 'Project X' -Module $ModuleX -Start 11:00AM -UseWOL -Parameters $Parameters

#endregion Scheduling a job

#region Job Results

<# This Section shows how to get some job result information. #>

# First get the masterjobs. The masterjob is the one that's directly visible in the console
$MasterJobs = Get-RESAMMasterJob -Description "Project X*" -Last 5
# Get the job status per agent.
$AgentJobs = $MasterJobs | Get-RESAMJob
#Get result from module that was invoked by a runbook
$Job = Get-RESAMMasterJob -Description "Project X*" -InvokedByRunbook | Get-RESAMJob

<# Get Name and MAC address for clients that have status 'Cancelled'. This status represents only agents where the masterjob was aborted before it started on those agents. This can be used to detect agents that where offline during Job Activity. If WOL was used this would indicate that WOL failed for these agents. #>
$WOLFailure = $AgentJobs | ?{$_.status -eq 'Cancelled'} | Get-RESAMAgent $_.Agent -Full | select Name,MACAddress

#Get statistics of all agent jobs
$TotalResults = [pscustomobject]@{
'Agents Total' = ($AgentJobs | select agent -Unique).count
'Completed' = ($AgentJobs | ?{$_.status -eq 'Completed'}).Count
'Completed with Errors' = ($AgentJobs | ?{$_.status -eq 'Completed with Errors'}).Count
'Cancelled' = ($AgentJobs | ?{$_.status -eq 'Cancelled'}).Count
'Aborted' = ($AgentJobs | ?{$_.status -eq 'Aborted'}).Count
'Failed' = ($AgentJobs | ?{$_.status -eq 'Failed'}).Count
}

#Get results per MasterJob
$Results = foreach ($MasterJob in $MasterJobs)
{
$ChildJobs = $AgentJobs | ?{$_.MasterJobGUID -eq $MasterJob.MasterJobGUID}
$Success = $ChildJobs | ?{$_.status -eq 'Completed'}
$WithError = $ChildJobs | ?{$_.status -eq 'Completed with Errors'}
$TaskFreeze = $ChildJobs | ?{$_.status -eq 'Aborted'}
$Failed = $ChildJobs | ?{$_.status -eq 'Failed'}

If ($MasterJob.WOL)
{
$wolFAILED = $ChildJobs | ?{$_.status -eq 'Cancelled'} | %{Get-RESAMAgent $_.Agent -Full}
}
else
{
$wolFAILED = ''
}
$Object = [pscustomobject]@{
'MasterJob' = $MasterJob
'#Agents' = $ChildJobs.count
'#Success' = $Success.count
'#WOLFailed' = If ($wolFAILED){$wolFAILED.Count};
'WOLFailed' = If ($wolFAILED){$wolFAILED | select Name,LastContact,Status};
'TaskFreeze' = $TaskFreeze.Agent
'Failed' = $Failed.Agent
'WithError' = $WithError
}
#Output
@{$MasterJob.Description = $Object}
}

# Display results in console
Write-host "Total Job Statistics:`n===============`n"
$TotalResults

#

#endregion Job Results

Wishlist

Here’s what I want to add to the module in the future (if I can figure out how to do it):

  • Display grabbed log files.
  • Download resources.
  • Remove library items (Modules, Projects, etc.)

Give it

I’m hosting the module on my GitHub. Please download it, give it a whirl and let me know what you think.

Michaja van der Zouwen

Comments are closed.