Three years ago, my employers left the Kaseya remote management system behind and migrated to ConnectWise Automate (formerly known as LabTech before the CW juggernaut bought it up, along with a variety of other acquisitions). While there are large benefits to being on this new system, such as not having been part of a gigantic supply-chain malware attack, we do miss a few things from the Kaseya system. Kaseya’s agent status indicators were far superior to Automate’s indicators, its agent software installed and updated far more reliably than Automate’s does, the agent software could be removed via the remote management system, and Kaseya featured a built-in staging share function.

We used the heck out of that share system, mostly for patches but also for other kinds of software deployment. We’ve just kind of gone without that functionality in the years since, but every so often we lament the loss and wonder if there’s a solution.

So this month I’ve started building one. In the stupendously unlikely event that another Automate admin is looking to do something like this, here are the building blocks I’ve put together.

  • I added a few Extra Data Fields set aside for this, a few under Locations (not under Clients, since one Client may have different physical sites that are denoted by Locations) and the rest under Computers.
    • In Locations I added a checkbox for “is there a staging share present,” which allows me to just ignore the entire system in my scripts at Locations that don’t have a staging share. At those sites the installer script defaults to doing it “the old way,” directly downloading installers on each machine.
    • Also in Locations I enter the UNC path for the share. I’m putting it here so other machines in the same Location can pull this EDF via the %locationid% as part of the script building.
    • The third EDF under Locations is one for the host server’s agent ID. Not the name, but the ID. Why? Because part of the script logic will involve switching to the server hosting the share and then back to the computer we’re installing software onto, and that entire @computerid@ trick relies on the numeric indicator rather than the name.
    • Under Computers we need a way to tell which server’s the one with the share, and what the local path for that share is. (Note that you still need to actually create the directory & share it out.) So there are two EDFs to cover that.
  • I have three “function” scripts, two related to regular maintenance and one that’s called by the “installer” script(s). Each one has a sanity check in case someone tries to run it manually or there’s a problem with the various EDFs.
    • Text File Seeding – If the file is not already present, write a text file (I’m using ‘zPlaceholder.txt’) into the local path to the staging share. The text file contents basically boil down to, “Don’t delete this, it’s here for a reason, ask [our company name] if you’re curious.”
    • Clean Up Old Files – We don’t want stuff just filling up our share directory forever, so I have a PowerShell command deleting anything older than 30 days, and this script is automatically scheduled on anything that has the “I’m a staging share host” EDF set. (Groups, Searches, and Scripts. That combination is what makes Automate shine.) The last line of this script calls the text file seeding script because after 30 days it would otherwise disappear.
    • Download Installer – This is called by the various deployment scripts. It relies on variables for the source website and the filename to acquire. (In my specific script this results in a File Download URL step where the URL is @SourceSite@/@SourceFile@ and the local save is to @StagingLocalPath@\@SourceFile@.)
  • Then there’s the actual install script which will be cloned off for each piece of software we want to deploy using this system. It has a lot of moving parts, so here goes…
    • Start with an IF check to make sure the staging share is present in this Location. The Else block can just be an old-fashioned “download installer & run it” with no extra logic at all.
    • Set a stack of variables… Source Site, Source File (separated so the executable filename can be used in a script step separately from the rest of the download URL), Install Target (which should be set to %computerid% so the script will later know which agent ID is “this computer” when it comes time to run the install after copying from the share), and grab the Staging Host (another agent ID, this time for the staging share’s server) and Staging Source (the UNC path of the share).
    • Do a ‘dir’ of the UNC path looking for the installer filename (already, keeping it separated is coming in handy). If it’s present, go to a block where you do the install. If it’s not present, go to a block that calls the Download Installer script described above, and after that script executes the next step should be to copy the installer locally and do the install. There’s a tricky part to this! You need to change @computerid@ from that of the computer you’re trying to install software on to that of the server with the share, call the Download Installer script, then change @computerid@ back to the original ID so the software doesn’t try to install onto your server. (I don’t know why Automate doesn’t have a “run this script on THAT machine” function. Seriously, this would make my life orders of magnitude easier.) This is where the Install Target and Staging Host variables come in.
    • You might want to include some logic where a result other than “I found the file on the UNC path” or “I got a File Not Found” leads to some kind of notification to you or another admin to the effect of “something unexpected happened, here’s everything I know about what was going on at the time” and then bail on the script so nothing awkward happens.
    • Note that we also need handling for the strong possibility that we’re running this on a laptop that isn’t in the office today so it’ll never be able to see the UNC path, which fails back to just downloading the installer directly. How you detect this accurately is up to you.
    • After the installation, whichever way that happens, stick a Resend Software step in there so the Automate agent info display shows that the install finished (hopefully) successfully.

And that’s it! Simple as pie! Easy as cake!

Duplicating your first successful version of the script and modifying it for whatever new software product you want to deploy should be a breeze, provided you left notes in the script saying “Change these next two variables, TOUCH NOTHING ELSE” or something along those lines.

Now, for some hypothetical questions from a hypothetical reader:

Q: Why not just use Ninite (or other similar turnkey system)?

A: Not everything’s in Ninite (or other similar turnkey system). Sometimes you need a very specific line-of-business application. Sometimes it’s a backup product agent installer. A Ninite-type solution is great, in fact we use that for the products it’s good at! But it doesn’t solve all problems.

Q: Why not use the Automate server’s L: drive file deployment feature?

A: Two main reasons. One, you can’t assign an Automate server file source (aka, “stuff in the Transfer directory”) to a variable, which makes the script-to-script handoff a non-starter. Two, for cases where a lot of machines are trying to grab a file from the Automate server at once, it can render your Automate server a bit… unusable while the bandwidth and I/O are being overtaxed.

Q: What if, as is common, there is no direct download for the installer you want?

A: Get yourself an S3 bucket with a public-read-only path or a VPS webserver or something. You’re a clever managed services admin, I’m sure you can come up with something.

At any rate, I hope someone comes along and finds this rambling pile of text useful in their endeavors some day. Let me know, won’t you please?