WORKLET :: Evaluate and install multiple apps using one worklet

as i am learning this platform, i have a few items in my environment to fix. today, i wanna knock out getting CylancePROTECT installed globally and rollout CylanceOPTICS.

i have looked at the required app policy (in fact, i am using this to push a few other apps). i think this would work for most required apps. three small items prove challenging for me:

  1. i would like to install multiple apps under one policy (prolly just over complicating things??). this would be a nifty concept for PC Imaging or Day 1 Patching kinda workflows.
  2. i am not sure i understand how to best leverage the version field.

in my small mind, if i insert a version number in the required app versioning field, the policy would run if the version number of the installed app is lower than the defined version number - OR if the application is not installed, at all.

what if i i want to install an app ONLY if it is not present, could i set this value to 0.001? would the value of 0.001 fundamentally function as an “is not installed” trigger? idk. i will dig into this soon…

  1. where does Automox place the installation file on the destination machine if you upload an installer into a worklet? or, maybe Automox has a online repository kinda feature? something where tenant can upload content that could be used across all worklets? a secure, online library of installers that could be called by a Invoke-WebRequest (omg!?..think about that session request url that had to be built to pull down the 1909 .iso)?

Anyway…focus.

Evaluation code (disclaimer: the evaluation completed here isn’t perfect. i have yet to comprehend/determine if the evaluation code block can pass variables to the remediation code block. if it can, game on!?):

$Software_Target1 = "Cylance PROTECT"
$Software_Target2 = "Cylance OPTICS"	
# $Software_Target... = "wanna evaluate something else?"

if (!((gp HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -Contains $Software_Target1)){
		Exit 1
	}elseif (!((gp HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -Contains $Software_Target2)){
		Exit 1
	<# rinse and repeat until all apps can be evaluated... #>	
	# } elseif (!((gp HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -Contains $Software_Target3)){
		# Exit 1
	} else { Exit 0 }

Remediation code:

Function InstallMultipleApplications {
<# define your software list #>
$Software_Target1 = "Cylance PROTECT"
$Software_Target2 = "Cylance OPTICS"	
# $Software_Target... = "wanna install something else?"	

<# for a .msi file :: build installer #>
if (!((gp HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -Contains $Software_Target1)){
		<# stash installer online (if you are cheap like me, use github!?) #>
		powershell -command "Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/.../CylanceProtect_x64.msi' -OutFile c:\temp\CylancePROTECT_x64.msi"
		$Installed_Target1 = ((Start-Process "msiexec.exe" -ArgumentList "/i c:\temp\cylanceprotect_x64.msi PIDKEY=<APP KEY HERE> LAUNCHAPP=1 REGWSC=1 REBOOT=ReallySuppress /l*v C:\Windows\Temp\CylancePROTECT_Install.log" /qn -NoNewWindow -Wait -PassThru).ExitCode)
		<# if you wanna test this in a lab/sans email notifications, uncomment the next few Write-Host lines  #>
		# Write-Host "'$Software_Target1' attempted to install :: (CODE: $Installed_Target1)"
	} else {
		$Installed_Target1 = 2
		# Write-Host "'$Software_Target1' was already installed :: (CODE: $Installed_Target1)"
	}

<# for a .exe file :: build installer #>
if (!((gp HKLM:\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\*).DisplayName -Contains $Software_Target2)){
		<# stash installer online #>
		powershell -command "Invoke-WebRequest -Uri 'https://raw.githubusercontent.com/.../CylanceOPTICSSetup.exe' -OutFile C:\temp\CylanceOPTICSSetup.exe"
		$Installed_Target2 = ((Start-Process -FilePath "C:\temp\CylanceOPTICSSetup.exe" -ArgumentList ('/q', '/i', '/n', '/l*v C:\Temp\CylanceOPTICS_Install.log') -Wait -Passthru).ExitCode)
		# Write-Host "'$Software_Target2' attempted to install :: (CODE: $Installed_Target2)"
	} else {
		$Installed_Target2 = 2
		# Write-Host "'$Software_Target2' was already installed :: (CODE: $Installed_Target2)"
	}

    <#rinse and repeat until you have all your app installers built... #>

    <# wanna email notification this worklet's activity? #>
    if (($Installed_Target1 -ne 2) -and ($Installed_Target2 -ne 2)){
	    <# plugin email notification code block here (see below "email notification code block" link)... #>
    }
}

<# ask politely and i bet PowerShell will run this function for you??? :) #>
InstallMultipleApplications

Example email notification generated by remediation actions (Happy learned how to putt. Uh-oh!?):

image
Email notification code block:

Please test any gold nugget you find using your mad google-fu skills BEFORE you fling it at your production systems. :crazy_face::mask::skull_and_crossbones:

Thanks for sharing this! Unfortunately you can’t pass variables between the evaluation code and the remediation code, unless you were to write something to a file and then pull it in later. Both code blocks run at different times. The evaluation code runs when the device is scanned (that schedule is set on the group the device belongs to). The remediation code runs when the policy is run, which has its own separate schedule.

For #1 - that’s a common request and we’re looking into that as a possible future feature

For #2 - When the required software policy runs, it will accept the version you put in the policy, or anything newer, as considering the policy compliant. It won’t try to reinstall if there’s a higher version on there.

For #3 - The installation file goes in C:/ProgramData/amagent/


and you can reference it in a Worklet just by referring to the file name without any path needed. It will assume the current directory.

1 Like

awesome-sauce!! :star_struck: :money_mouth_face: :star_struck:

Bookmarked - This is a super cool concept. Can’t wait to see where it goes

1 Like