Loops in Action Script

So I’ve searched the forums and the internet a few times but it seems there is no real “looping” action that can be performed within action script.

My conundrum is this: I want to deploy one action to perform the same task against user accounts. I need to change a flag on the account but there are many different account names that need this change. Rather than submit a multitude of tasks to achieve this, I was to deploy one task that will grab all accounts that need this flag changed

My first thought was to append the list of accounts that will be affected by this change and have a separate script deploy using that list as its target. Is there anyone who thinks there is or knows of an easier way to accomplish this?

Here is what I have so far:

Collect list of users who will need to be changed

appendfile {concatenation "%0d%0a" of (names of local users whose (not (not no password required flag of it)))

Export list to temp folder

if {exists folder "C:\Temp"}
move "__appendfile" "C:\Temp\users.txt"
elseif {not exists folder "C:\Temp"}
dos md "C:\Temp"
move "__appendfile" "C:\Temp\users.txt"
endif

Remove the__appendfile and start the script

delete __appendfile
appendfile *Script to run through using generated list*

I don’t particularly care for this method but if it’s the only option I can live with it.

Could you not create a script (on the fly or deploy with the fixlet) that would take the users.txt as input and loop with in that script. The script could be powershell, bat, vbs, perl, whatever. So the loop is not in the action script, just a call to a single run of a script that loops.

Or maybe I am missing something :smile:

1 Like

Yes I stated as much. My question was is there another way? I want to know if there’s a way to fool the relevance into doing something until it can’t do it anymore through relevance while targeting what needs to be changed.

Currently there is no native support in actionscript to do this.

I think what you would like would be something like

foreach {relevance expression returning multiple values} {wait|run} <executable>

and that executable/batch etc would get values from the list run on it

Would that be the idea? Similar in a way to the bash foreach

Something like that. Or, in this case, I would need something like this:

if exists user name whose (value of flag of it != 1)
run command against user name
if statement 1 false then end 
else run statement 1

Crude statement but it would be useful in other cases as well.

I just hate patching in other scripts to get something from action script. It’s a minor annoyance really.

Or to create an array of the user names that have this flag incorrectly set and run the command through the array as many times as necessary removing remediated entries. So it would look more like this:

exists names of users whose (value of flag of it != 1)
names of users whose (value of flag of it != 1)
run command against first user name
run statement 1
if statement 1 = false then end

Why not let the ‘looping’ happen when the Task/Fixlet is deployed as an Action. Reapply when Relevant. Let the Action update the first User it finds each time it executes. The second time the Action fires on the Endpoint, it should update the second user. Repeat until the Task/Fixlet is no longer Relevant.

I can imagine cases where this could be problematic, I used to manage a few machines (usually in conference rooms) with several hundred user profiles each. We used to rebuild them each Semester, but it didn’t take long for the numbers to climb again.

1 Like

That is likely the route I will take. In that case something like this should do the trick.

appendfile {concatenation of %0a%0d of (names of users whose (user flag !=1)}
run command against {line 1 of __appendfile}
delete __appendfile

Set reapply to repeat 10 times or so to get them all

1 Like

I think you are correct on the limitations. I do this fairly regularly and I end up putting it all into one statement -

appendfile { concatenation "%0d%0a" of ("scriptname.cmd " & it) of (names of local users whose (not (no password required flag of it ))) }
2 Likes

This nifty trick just solved a problem I’ve been noodling on for quite a while. Thanks!

1 Like

Maybe a thread like this could go towards creating a loop action in ActionScript?

There are 4 main ways I know of to do looping in ActionScript. (many of these have been pointed out above)

  1. Create a Fixlet/Task that addresses a single instance, and have it reapply
  2. Use relevance to create a batch file dynamically that addresses all of the instances at once
  3. Use 2 separate actions: one to determine what needs done, and another to do it.
  4. Have the Fixlet/Task run a script written in another language that can do actual looping

There are some instances where the looping issue can be avoided entirely, which are preferred if possible. For example, if you need to change the user registry, use Local GPO instead. See this example: http://bigfix.me/fixlet/details/3741

Here is an example of #1 above. This action will resolve the issue for the currently logged in user only. If this is taken as an open action applied to all endpoints, then if a new user logs in, this should run within a few minutes of that happening, which in this case is sufficient: http://bigfix.me/fixlet/details/3933

Here is an example of #2 above. This relevance will generate the contents of a BAT file that will delete all shortcuts on the Public Desktop for adobe products that were created during the action being executed. This was created to deal with installing Adobe Creative Cloud which would create an unknown number of Desktop shortcuts which could not be deleted by non-admins: http://bigfix.me/relevance/details/2999306


Here is a very complicated example of using relevance to create a file which contains an unknown number of items. This task actually downloads all tasks within a custom site, then it creates an XML representation of tasks which uninstall all MSI products found on the client that are not already existing within the custom site to prevent duplication. These tasks are then created using the REST API. This uses a secure parameter to send console credentials to the endpoint which is used to interact with the REST API. This is really an example of using relevance to generate a plural list of items to operate on, then using relevance to add to it in a very specific way. See the example here: http://bigfix.me/fixlet/details/3876

This is the idea in a simplified form:

("start: " & it & " :end") of ("abc";"def";"qwerty")

Which is actually more like this:

("start: " & it & " :end") of (it as string as trimmed string) of values "DisplayName" of keys whose(value "UninstallString" of it as string as lowercase contains "msiexec") of keys "HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall" of (x64 registries;x32 registries)
1 Like