Community forum

Please note that VisualCron support is not actively monitoring this community forum. Please use our contact page for contacting the VisualCron support directly.


Pedro Silva
2016-05-19T13:24:57Z
Greetings,

I am trying to automate the deployment of our software and was trying to use Powershell to run a script post my deployment to point a group of existing Jobs to the folder of the new version of the software. Basically, when I open VisualCron I have something like this:

- Group : CUSTOMER on SERVER (2 items)
1) JOB1
2) JOB2

If I double click the Job, then the Task list, there's only one task which is to execute an executable file. This file is located usually in a folder with this structure:

C:\Program Files (x86)\COMPANY\CUSTOMER\VERSION1.0\EXECUTABLE.exe

Everytime I do a new deployment of our software, I will have it deployed to a different folder, like this:

C:\Program Files (x86)\COMPANY\CUSTOMER\VERSION1.1\EXECUTABLE.exe

What I was trying to do via Powershell was to connect to the VisualCron Server and find the relevant jobs, and then set their Execute.CmdLine property to the new folder. I checked the documentation of the API and managed to get this script together, for testing purposes, which I am running through Powershell ISE:

function Get-VCAPIPath
{
$programFilesPath = if (${Env:PROCESSOR_ARCHITECTURE} -eq 'x86') { ${Env:ProgramFiles} } else { ${Env:ProgramFiles(x86)} }
Join-Path $programFilesPath VisualCron\VisualCronAPI.dll
}

function Get-VCServer
{
[CmdletBinding()]
param ([string]$ComputerName,
[int]$Port,
[System.Management.Automation.PSCredential]$Credential)

$apiPath = Get-VCAPIPath
if (!(Test-Path $apiPath)) { Throw "VisualCron does not appear to be installed. API library not found at `"$apiPath`"." }
[Reflection.Assembly]::LoadFrom($apiPath) | Out-Null
$conn = New-Object VisualCronAPI.Connection
$conn.Address = if ([String]::IsNullOrEmpty($ComputerName)) { ${Env:COMPUTERNAME} } else { $ComputerName }
if (!($credential -eq $null))
{
$conn.UseADLogon = $true
$netcred = $credential.GetNetworkCredential()
$conn.UserName = $netcred.UserName
$conn.Password = $netcred.Password
}
$client = New-Object VisualCronAPI.Client
$client.Connect($conn)
}

function Get-AllVCJobs
{
[CmdletBinding()]
param ([string]$ComputerName,
[int]$Port,
[System.Management.Automation.PSCredential]$Credential,
[switch]$Active)

$ps = New-Object Collections.Hashtable($psBoundParameters)
$ps.Remove('Active') | Out-Null
$server = Get-VCServer @ps
$server.Jobs.GetAll() `
| ? { !($Active) -or $_.Stats.Active } `
| Add-Member ScriptMethod Start { $server.Jobs.Run($this, $false, $false, $false, $null) }.GetNewClosure() -PassThru
}

$jobs = Get-AllVCJobs
Foreach ($job in $jobs)
{
if ($job.Group -eq 'CUSTOMER on SERVER')
{
Write-Host $job.Id
Write-Host $job.Name
Write-Host $job.Group
$tasks = $job.Tasks
Foreach ($task in $tasks)
{
$newPath = 'C:\Program Files (x86)\COMPANY\CUSTOMER\VERSION1.1\'
$newTaskExecuteCmdLine = $newPath + 'EXECUTABLE.exe'
$task.Execute.CmdLine = $newTaskExecuteCmdLine
# I MIGHT BE MISSING SOMETHING HERE TO "SAVE" THE CHANGE?!?!
}
}
}

The above script allows me to navigate the tree, get all the relevant jobs and navigate through their tasks but it is not persisting this to the server and that's what I'm missing. I've read the API documentation and couldn't find one single example on how to persist this, plus it seems that all the samples in there are for read-only purposes.

Can you please advise?

Thanks and Regards,
Pedro Silva
Sponsor
Forum information
Support
2016-05-19T14:28:56Z
After looping through the Tasks and setting items you should call Jobs.Update to send an update to the server.
Henrik
Support
http://www.visualcron.com 
Please like  VisualCron on facebook!
Pedro Silva
2016-05-19T16:05:02Z
bbusse
2016-05-20T00:03:03Z
I know this is API related discussions. But since i'm not doing much with the API yet, I was also going to suggest something fairly easy. Use a Variable for the CurrentVersion and use that in all of your paths. Then, you stop all jobs, change that central variable, and start the jobs (start server).

It's how i'd handle it, without the API as you've done.

Nice work, btw.

Brian
Pedro Silva
2016-05-20T06:41:36Z
That's a good idea, but I want to automate it, so there is no human intervention. Hence the API.

Thanks
Pedro
Pedro Silva
2016-05-20T09:44:09Z
In the end, I managed to do it and this is the outcome Powershell script. Might be helpful for anyone else out there trying to automate their releases with Octopus Deploy and having their VisualCron Jobs automatically updated:


# Get-VCAPIPath will get the path for VisualCron API DLLs
function Get-VCAPIPath
{
    $programFilesPath = if (${Env:PROCESSOR_ARCHITECTURE} -eq 'x86') { ${Env:ProgramFiles} } else { ${Env:ProgramFiles(x86)} }
    Join-Path $programFilesPath VisualCron\VisualCronAPI.dll
}

# Get-VCServer allows you to connect to the VisualCron Server
function Get-VCServer
{
    [CmdletBinding()]
    param ([string]$ComputerName, 
           [int]$Port,
           [System.Management.Automation.PSCredential]$Credential)

    $apiPath = Get-VCAPIPath
    if (!(Test-Path $apiPath)) { Throw "VisualCron does not appear to be installed. API library not found at `"$apiPath`"." }
    [Reflection.Assembly]::LoadFrom($apiPath) | Out-Null
    $conn = New-Object VisualCronAPI.Connection
    $conn.Address = if ([String]::IsNullOrEmpty($ComputerName)) { ${Env:COMPUTERNAME} } else { $ComputerName }
    if (!($credential -eq $null)) 
    {
        $conn.UseADLogon = $true
        $netcred = $credential.GetNetworkCredential()
        $conn.UserName = $netcred.UserName
        $conn.Password = $netcred.Password
    }
    $client = New-Object VisualCronAPI.Client
    $client.Connect($conn)
}

# Get-AllVCJobs returns a list of all the jobs in VisualCron server for the current machine
function Get-AllVCJobs
{
    [CmdletBinding()]
    param ([string]$ComputerName, 
           [int]$Port,
           [System.Management.Automation.PSCredential]$Credential,
           [switch]$Active)

    $ps = New-Object Collections.Hashtable($psBoundParameters)
    $ps.Remove('Active') | Out-Null
    # Connect to the Server
    $server = Get-VCServer @ps
    # Get all the jobs
    $server.Jobs.GetAll() `
    | ? { !($Active) -or $_.Stats.Active } `
    | Add-Member ScriptMethod Start { $server.Jobs.Run($this, $false, $false, $false, $null) }.GetNewClosure() -PassThru
}

# UpdateJobs will update the Command Line for the Execute of each Job's Task 
function UpdateJobs
{
    [CmdletBinding()]
    param ([string]$ComputerName, 
           [int]$Port,
           [System.Management.Automation.PSCredential]$Credential,
           [switch]$Active)

    $ps = New-Object Collections.Hashtable($psBoundParameters)
    $ps.Remove('Active') | Out-Null
    # Connect to the VisualCron server
    $server = Get-VCServer @ps

    # Get all the jobs
    $jobs = Get-AllVCJobs
    Foreach ($job in $jobs)
    {
            $tasks = $job.Tasks # Get the Jobs' Tasks
            Foreach ($task in $tasks)
            {
                # Implement logic to populate the Command Line
            }
            # Save the job
            $server.Jobs.Update($job)
    }
}

UpdateJobs


Thanks for the help.
Regards,
Pedro Silva
Scroll to Top