Operating based if statement in an action script plus a bonus question

I am having a bit of an issue where I have a python script for a work project that I am creating inside of a bigfix action script which works fine but I need the script to run on Windows or Linux devices. I went ahead and tried to throw in an if linux run this else if windows line but BigFix is coming back with a failure. I ran it for all computers so the relevance wouldn’t be in the way as a way to debug. The script before I tried to separate out linux and windows works as I have run it previously and it ran without issue.

I am sure I am missing something obvious but I tried using syntax like you’d see in the relevance like this followed by the script:

if {(exists true whose (if true then (exists (operating system) whose (it as string as lowercase contains “linux” as lowercase)) else false)))}

Then the windows piece would be

else if {{(exists true whose (if true then (exists (operating system) whose (it as string as lowercase contains “Win” as lowercase)) else false)))}}

Then I end the entire thing with an endif line.

I also had a secondary question about how bigfix looks at folders.

In linux the folders are separated by foreslashes so /var/lib/mysql as an example. Windows on the other hand uses backslashes so C:\var\lib\mysql. I have a folder named beanstore I need to verify exists on every system from the relevance. Will I need to look for both /beanstore or C:\beanstore to cover both windows and linux systems?

I ses a couple of things to note…
The structure in ActionScript does not have a space in ‘elseif’. Your ‘elseif’ clause seems to double-up on the curly brackets, which should be single-brackets.

The basic structures are

if {relevance condition}
Some Actionscript
elseif {relevance condition}
Other Actionscript
else
Other Actionscript
endif

The ‘elseif’ and ‘else’ are optional, but ‘endif’ is required.

As for the folder checks, yes you’ll have to look for each. You could wrap that in an if/else clause, or you can rely on plurals. The simplest check might be exists folders ("/beans";"c:\beans")

For an example of several if/elseif/else/endif statements, and building different scripts per OS, the Log4j scan task at this link may be helpful

Thank you Jason, ill peruse over your notes and see if that doesn’t get me over the hump. I really appreciate your assistance and quick response.

One more question actually. @JasonWalker in my relevance part of the security of my action script is to verify the SHA1 values of particular files that exist out on the linux and windows devices but im struggling with coming up with the basic syntax for that relevance.

Can I call out the operating system again in the relevance to make rules between each version? Heres what I have so far

if (operating system as lowercase contains “Linux”) and (sha1 of file “/beanstore-client/dg/util/Monitoring_Tool/mariadb-java-client-1.7.3.jar” != “aaaa”) then false else true

This comes back as not relevant but it is a linux till and it is relevant if I remove the operating system piece so clearly im missing something

Since you are checking for the sha1 of a file, if the file doesn’t exist that would trigger a relevance error and evaluate as ‘not relevant’.

With a series of OS checks like this, the general form is ‘if linux then (relevance check) else true’

You also have to watch that you’re comparing ‘operating system as lowercase’ to the mixed-case ‘Linux’, so you’d want to lowercase both of those.

Try

if (operating system as lowercase contains "linux") then not exists (files "/beanstore-client/dg/util/Monitoring_Tool/mariadb-java-client-1.7.3.jar") whose (sha1 of it = "aaaa") else true

This clause will return ‘true’ if the system is Linux, and the file is missing or has the wrong sha1; it will also return True for Windows systems, so the next relevance clause should check for the Windows OS with a different filepath and different sha1.

(and, there should probably be a clause somewhere to limit to just the OS’s you’re checking - like

operating system as lowercase contains "linux" or operating system as lowercase starts with "win"

Otherwise, a Mac or AIX or whatever could trigger a false-true relevance.

edit: fixed a ‘not’

1 Like

For whatever reason this as relevance always fails but everything else discussed in regard to relevance setup worked appropriately.

The other issue im having is the if statement to split up the python script between linux and windows within the action script. From what I have read on other threads it must contain an if, then and else statement to be valid correct? Would the elseif being used to separate the two count as the required else or do I need an else in the initial statement? The only statement ive found that goes through and completes I just grabbed from a different thread and I am going to assume that it reads as false because it completes but the script doesn’t produce results despite saying it has completed. Here is that example:

if {exists true whose(if true then ((operating system) as lowercase contains “linux” as lowercase) else false)}

I was thinking maybe it needs to be something along the lines of if operating system as lowercase contains linux is true then continue else false but I am unclear syntactically how to put that together.

I think the ‘exists true whose()’ is being used to avoid an error and may not actually give the right result.
I can check tomorrow, but my first inclination is we may need to force operating system into a string first, ie ‘operating system as string as lowercase’

I’d appreciate the assistance tomorrow. I tried

if {true then ((operating system) as string as lowercase contains “linux” as lowercase) else false)}

and that failed and I also tried without the else false and that also failed.

Maybe this type of approach might work (there are other ways too just using "name of operating system" inspection).

if {windows of operating system}
	do Windows stuff
elseif {((unix of it) and (name of it as lowercase contains "linux")) of operating system}
	do Linux stuff
endif

I think @JasonWalker hit the nail on the head as “operating system” doesn’t return a string so you need to cast it to a string or use an inspector that does return a string, such as "name".

q: operating system
A: Win10 10.0.19044.1620 (21H2)
T: 0.324 ms
I: singular operating system
1 Like

So I tried your setup I assume the “Windows Stuff” and “Linux Stuff” pieces were where my script would go. It ran and completed but it didn’t do anything. Here’s my full script any sensitive bits are in the relevance so this should be okay to show.

if {windows of operating system} do
//
//Deleting the append file
//
delete __appendfile

//
//Moving to the Monitoring_Tool table, removing any remnants of Monitor.py, json, and zip and then running the jar file
//
appendfile cd C:\beanstore-client\dg\util\Monitoring_Tool
appendfile delete Monitor.py
appendfile delete *.json
appendfile delete *.zip
appendfile java -cp .:mariadb-java-client-1.7.3.jar ProductSkuTest

//
// Python program starts after the following line
//
createfile until _EOF
#!/usr/bin/env python

##Import Statements
import glob
import csv
import re
import zipfile
import os
from datetime import date

##This is the engine that calls every function in the program
def engine():
	fileread()
	products = fileread()
	datavalidation(products)
	productfields = datavalidation(products)
	removal(products)
	csvwriting(products, productfields)
	zippy(products, productfields)

def fileread():
##Using glob glob to grab the correct json file
	name = glob.glob('s*-cr*.json')

##Reading the file into a dictionary
	for fname_in in name:
		f = open(fname_in)
		s = f.read()
	f.close()
	filedict = eval(s)

##Pulling out the list of products as that's all we want
	products = filedict["Products"]
	return products


##Products now = all of the data being read in

def datavalidation(products):
## The "Tax Codes" field is not a single value, but rather a list of dicts
## Need to consolidate it to a single value.  For now just make a string
## from the whole thing.
## Also using replaces while its a string to remove unwanted characters from the output
## Also setting up additional fields as requested by pricing team with store number and till + store number	
	with open('/beanstore-client/pos/global.properties', 'r') as f:
		count = 0
		for line in f:
			if not line.startswith("beanstore.till.tillnumber="):
				continue
			count = count + 1
			if count == 2: 
				break
			global ATILL
			ATILL = re.findall('s[0-9]+-cr[0-9]+', str(line))
			ATILL = str(ATILL)
			ATILL = ATILL.replace("']", "")
			ATILL = ATILL.replace("['", "")
			STORE = ATILL
			STORE = re.findall('([0-9]+)-', str(line))
			STORE = str(STORE)
			STORE = STORE.replace("']", "")
			STORE = STORE.replace("['", "")	
	
	for product in products:
		product["2TILL"] = ATILL
		product["1STORE"] = STORE
	try:
		product["Tax Codes"] = str(product["Tax Codes"])
		product["Tax Codes"] = product["Tax Codes"].replace("[{{", "")
		product["Tax Codes"] = product["Tax Codes"].replace("}]", "")
		product["Tax Codes"] = product["Tax Codes"].replace("'", "")	
		product["Tax Codes"] = product["Tax Codes"].replace("Tax ", "")	
		product["Tax Codes"] = product["Tax Codes"].replace("Code: ", "")
		product["Tax Codes"] = product["Tax Codes"].replace("To Date: ", "")
		product["Tax Codes"] = product["Tax Codes"].replace("Description: ", "")
		product["Tax Codes"] = product["Tax Codes"].replace("From Date: ", "")	
		product["Tax Codes"] = product["Tax Codes"].replace("for state ", "")
		product["SorN"] = product["Tax Codes"][0]
		product["StartDate"] = product["Tax Codes"][35:]
		product["ZEndDate"] = product["Tax Codes"][5:27]
	except:
		pass
# This could be overkill, but not going to assume that all items have
# the same fields.  So I look at all of them to make sure I have the complete
# list of all fields from all items.
# If you are for sure they all have the same columns, then you could just
# look at the first one to get the field names.
	productfields = set()
	for product in products:
		productfields.update(product.keys())


# only problem with a set is that the order of items in a set is not defined
# or guaranteed to be consistent.  To have some consistency in the order of
# fields, I am putting them in a list and sorting them.
# I am also removing the fields we don't want to display at this time in the results output
	productfields.remove('Tax Codes') 
	productfields.remove('Description') 
	productfields.remove('Status')
	productfields = list(productfields)
	productfields.sort()
	return productfields

def csvwriting(products, productfields):
# Setting up the csv file name setup
	today = date.today()
	time = today.strftime("_%m%d%y")
	today = str(today)
	finals = 'ngpos_' + ATILL + '_extract' + time
	finalfile = "%s.csv" % finals

# write out the csv but not including headers
	with open(finalfile , 'w') as f:
		mywriter = csv.DictWriter(f, productfields, extrasaction='ignore')
		for product in products:
			mywriter.writerow(product)
	return finals, finalfile

def zippy(products, productfields):
## Creating the zipfile, calling the returned finals, finalfile values from the csvwriting function
	zf = zipfile.ZipFile(csvwriting(products, productfields) [0]+".zip",'w', compression=zipfile.ZIP_DEFLATED)
	zf.write(csvwriting(products, productfields) [1])
	zf.close()

## This removes the csv file so we are only left with the deflated zip file
	os.remove(csvwriting(products, productfields) [1])

def removal(products):
	#Removing products that aren't needed at this time for our monitoring purposes
	for product in products:
		try: 
			del product["Tax Codes"]
			del product["Description"]
			del product["Status"]
		except:
			pass
engine()
_EOF
//Python program ends before the previous line

//Create a file with the Python program on the local filesystem
//
copy __createfile C:\beanstore-client\dg\util\Monitoring_Tool\Monitor.py

//Shell to Action Script Conversion Utility
delete __appendfile

appendfile cd C:\beanstore-client\dg\util\Monitoring_Tool
appendfile wait Monitor.py
appendfile delete Monitor.py
appendfile delete items.txt
appendfile delete *.json

delete __appendfile

elseif {((unix of it) and (name of it as lowercase contains “linux”)) of operating system} do
//
//Deleting the append file
//
delete __appendfile

//
//Moving to the Monitoring_Tool table, removing any remnants of Monitor.py, json, and zip and then running the jar file
//
appendfile #!/bin/sh
appendfile cd /beanstore-client/dg/util/Monitoring_Tool
appendfile rm Monitor.py
appendfile rm *.json
appendfile rm *.zip
appendfile java -cp .:mariadb-java-client-1.7.3.jar ProductSkuTest


//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

//
// Python program starts after the following line
//
createfile until _EOF
#!/usr/bin/env python

##Import Statements
import glob
import csv
import re
import zipfile
import os
from datetime import date

##This is the engine that calls every function in the program
def engine():
	fileread()
	products = fileread()
	datavalidation(products)
	productfields = datavalidation(products)
	removal(products)
	csvwriting(products, productfields)
	zippy(products, productfields)

def fileread():
##Using glob glob to grab the correct json file
	name = glob.glob('s*-cr*.json')

##Reading the file into a dictionary
	for fname_in in name:
		f = open(fname_in)
		s = f.read()
	f.close()
	filedict = eval(s)

##Pulling out the list of products as that's all we want
	products = filedict["Products"]
	return products


##Products now = all of the data being read in

def datavalidation(products):
## The "Tax Codes" field is not a single value, but rather a list of dicts
## Need to consolidate it to a single value.  For now just make a string
## from the whole thing.
## Also using replaces while its a string to remove unwanted characters from the output
## Also setting up additional fields as requested by pricing team with store number and till + store number	
	with open('/beanstore-client/pos/global.properties', 'r') as f:
		count = 0
		for line in f:
			if not line.startswith("beanstore.till.tillnumber="):
				continue
			count = count + 1
			if count == 2: 
				break
			global ATILL
			ATILL = re.findall('s[0-9]+-cr[0-9]+', str(line))
			ATILL = str(ATILL)
			ATILL = ATILL.replace("']", "")
			ATILL = ATILL.replace("['", "")
			STORE = ATILL
			STORE = re.findall('([0-9]+)-', str(line))
			STORE = str(STORE)
			STORE = STORE.replace("']", "")
			STORE = STORE.replace("['", "")	
	
	for product in products:
		product["2TILL"] = ATILL
		product["1STORE"] = STORE
	try:
		product["Tax Codes"] = str(product["Tax Codes"])
		product["Tax Codes"] = product["Tax Codes"].replace("[{{", "")
		product["Tax Codes"] = product["Tax Codes"].replace("}]", "")
		product["Tax Codes"] = product["Tax Codes"].replace("'", "")	
		product["Tax Codes"] = product["Tax Codes"].replace("Tax ", "")	
		product["Tax Codes"] = product["Tax Codes"].replace("Code: ", "")
		product["Tax Codes"] = product["Tax Codes"].replace("To Date: ", "")
		product["Tax Codes"] = product["Tax Codes"].replace("Description: ", "")
		product["Tax Codes"] = product["Tax Codes"].replace("From Date: ", "")	
		product["Tax Codes"] = product["Tax Codes"].replace("for state ", "")
		product["SorN"] = product["Tax Codes"][0]
		product["StartDate"] = product["Tax Codes"][35:]
		product["ZEndDate"] = product["Tax Codes"][5:27]
	except:
		pass
# This could be overkill, but not going to assume that all items have
# the same fields.  So I look at all of them to make sure I have the complete
# list of all fields from all items.
# If you are for sure they all have the same columns, then you could just
# look at the first one to get the field names.
	productfields = set()
	for product in products:
		productfields.update(product.keys())


# only problem with a set is that the order of items in a set is not defined
# or guaranteed to be consistent.  To have some consistency in the order of
# fields, I am putting them in a list and sorting them.
# I am also removing the fields we don't want to display at this time in the results output
	productfields.remove('Tax Codes') 
	productfields.remove('Description') 
	productfields.remove('Status')
	productfields = list(productfields)
	productfields.sort()
	return productfields

def csvwriting(products, productfields):
# Setting up the csv file name setup
	today = date.today()
	time = today.strftime("_%m%d%y")
	today = str(today)
	finals = 'ngpos_' + ATILL + '_extract' + time
	finalfile = "%s.csv" % finals

# write out the csv but not including headers
	with open(finalfile , 'w') as f:
		mywriter = csv.DictWriter(f, productfields, extrasaction='ignore')
		for product in products:
			mywriter.writerow(product)
	return finals, finalfile

def zippy(products, productfields):
## Creating the zipfile, calling the returned finals, finalfile values from the csvwriting function
	zf = zipfile.ZipFile(csvwriting(products, productfields) [0]+".zip",'w', compression=zipfile.ZIP_DEFLATED)
	zf.write(csvwriting(products, productfields) [1])
	zf.close()

## This removes the csv file so we are only left with the deflated zip file
	os.remove(csvwriting(products, productfields) [1])

def removal(products):
	#Removing products that aren't needed at this time for our monitoring purposes
	for product in products:
		try: 
			del product["Tax Codes"]
			del product["Description"]
			del product["Status"]
		except:
			pass
engine()
_EOF
//Python program ends before the previous line

//Create a file with the Python program on the local filesystem
//
copy __createfile /beanstore-client/dg/util/Monitoring_Tool/Monitor.py

//Shell to Action Script Conversion Utility
delete __appendfile

appendfile cd /beanstore-client/dg/util/Monitoring_Tool
appendfile chmod +x Monitor.py
appendfile ./Monitor.py
appendfile rm Monitor.py
appendfile rm items.txt
appendfile rm *.json

//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

delete __appendfile

endif

So using the below if/elseif I can get it to run as completed with a fixcode of 0 but it’s not running the python query. It’s deleting items.txt and the json file so I know it’s doing something but it’s just skipping past the script for some reason. Any ideas?

if {windows of operating system}
elseif {(name of (operating system) as string as lowercase contains “linux”)}

Maybe you misinterpreted the example. Replace the “Do Windows stuff” with your ActionScript. “do” isn’t an ActionScript command so it may be failing in that, eg

if {windows of operating system}
	wait "cmd.exe /c myscript.cmd"
elseif {((unix of it) and (name of it as lowercase contains "linux")) of operating system}
	wait /bin/sh /path/myscript.sh
endif

Probably doesn’t do what you want.

It is correct to delete __appendfile before you start to write to it, but having added the content you require, you need to do something with it before deleting it again

…brief post because I am using a phone…

For the bonus question, you can again inspect the OS to dynamically select the correct path/syntax for the folder to check, eg

Q: exists folders ((if (windows of it) then ("C:\beanstore") else ("/beanstore")) of (operating system))
A: True
T: 0.239 ms
I: singular boolean

So I removed the appendfile delete and this is what I have on the linux side of things but the problem is that it’s deleting the scripts but not running the Monitor.py program that or it’s never running the jar file.

So this is at the beginning before the python script where it should be deleting the append file then using the appendfile to set everything up and run the jar file which may be the culprit of my issues if it doesn’t run the jar:

//
//Deleting the append file
//
delete __appendfile

//
//Moving to the Monitoring_Tool table, removing any remnants of Monitor.py, json, and zip and then running the jar file
//
appendfile #!/bin/sh
appendfile cd /beanstore-client/dg/util/Monitoring_Tool
appendfile rm Monitor.py
appendfile rm *.json
appendfile rm *.zip
appendfile java -cp .:mariadb-java-client-1.7.3.jar ProductSkuTest


//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

So this is the end where it should run the monitor script and delete the files we don’t need any longer on the file system:

//Create a file with the Python program on the local filesystem
//
copy __createfile /beanstore-client/dg/util/Monitoring_Tool/Monitor.py

//Shell to Action Script Conversion Utility

appendfile cd /beanstore-client/dg/util/Monitoring_Tool
appendfile chmod +x Monitor.py
appendfile ./Monitor.py
appendfile rm Monitor.py
appendfile rm items.txt
appendfile rm *.json

//modify appendfile to allow execution
wait /bin/sh -c "chmod 555 {(client folder of current site as string) & "/__appendfile"}"

//execute shell script as written
wait "{(client folder of current site as string) & "/__appendfile"}"

Does the OS know how to run “__appendfile”? What happens if you copy __appendfile to an actual shell file and run it via /bin/sh?

Isn’t that what this line is already doing?

//modify appendfile to allow execution
wait /bin/sh -c “chmod 555 {(client folder of current site as string) & “/__appendfile”}”

My Linux knowledge is limited. 555 makes the file executable but does it know what to execute it with or with what shell? Maybe a more explicit approach is to copy the file as an .sh then execute it with /bin/sh or /bin/bash, eg wait /bin/sh -c "{(pathname of client folder of current site) & "/myscript.sh"}

You should also check the client logs to see if any errors were recorded when the actionscript ran. Debugging Windows OS much easier as you can test it all in the FixlerDebugger.

I don’t have access to the FixletDebugger at least when ive run through tutorials of using it I don’t have the icon to get to it.

Its available as a standalone download for Windows - https://developer.bigfix.com/tools/fixlet_debugger.html. The “icon” would only exist on a system that has either the main Bigfix application or the admin console.

1 Like