What is the best way to run dashboard scripts in parallel?

Product: PowerShell Universal
Version: 2.7

On my dashboard script I have a foreach loop that executes a series of queries to return data for each server and it stores it in an array of hashtables, which is ultimately what I use to populate my UDTable. What is the proper way of executing this foreach loop in parallel in regards to Powershell Universal?

Hey, Take a look at the docs here:

If you utilize scripts in PSU, you can have them run on triggers such as ‘dashboard start’ or cron/scheduled expressions like every hour etc.
You can then call the data/output directly from those scripts in your dashboards.
PSU will handle parallel jobs for you this way - you can chance concurrency in the admin menu.

I guess the issue with this is that I would need to get the timing right between the two. Let’s say I have a dashboard that refreshes every 60 seconds and 5 SQL scripts that need to run and return data, but those SQL scripts take 50 seconds (10 seconds each). I need my dashboard table to refresh every 60 seconds and contain the data from all 5 SQL runs.

Not sure I follow, There’s lots of ways to tackle what I think you’re trying to achieve though.
Lookup the docs for pre-loaders on your tables, also look up skeletons, finally lookup the Sync-UDElement command which would effectively allow you to push an update to the table as soon as the data is refreshed, rather than the other way around.

But if the scripts are running in parallel, it would only take 10 seconds to pull the data not 50.
if you want to update your tables every 10 seconds, you could just sync them from the script getting the data.

Also take a look at the $cache variable scope in the docs too, that might be useful to you if you’re not already using it and dont want to use the direct job output in your tables

If I have a dashboard with a table setup to automatically refresh every 60 seconds does it only re-query the data when a user has the webpage open and also does it execute 1 query per page that is open? It is my understanding that Powershell Universal runs the refresh interval even when the page is not open and also it only runs 1x regardless of how many users have the dashboard open… is this correct?

I am aware of sync-udelement, but what would I wrap that in so that it runs autonomously on a schedule? Would I just wrap it in a New-UDElement with a refresh interval set?

New-UDElement -Tag 'div' -Endpoint {
Get-Date
} -AutoRefresh -RefreshInterval 1

If I do decide to use Scripts, can I trigger a dashboard refresh after the script is complete or does my dashboard need to constantly poll the Script to look for new data to refresh with?

Edit: One last thing that is sort of unrelated, but will effect how I architect my dashboards… Is there a way to “pause” the refresh with a button so that if I am looking at my dashboard I can temporarily prevent it from refreshing on my screen? I haven’t been able to find any functionality that would allow me to do this within the docs or forums.

The page code that the user visits is executed when they hit the page. Therefore, if you have an auto refresh every 60 seconds, its happening for that user in their session.
If you have 10 users, its running the page code 10x, and you’ll have the refresh happening individually for each user. Now if you’re running your script to pull that data for the table in the same page, that were duplication of effort comes in.
Sometimes it’s feasible to do it this way, lets say you pull from a very quick SQL table, and you’re only accessing a small dataset and not many users, shouldnt be an issue as it’s quick and wont hang anything.
But if you for example have an API you want to pull data from, a large data set, and alot of users.
It’s going to take time, and people will notice loading times for pages and components as the data is gathered.

Personally the way I’d approach this is by adding a script in the automation part of PSU to gather the data required for your table.
This is outside the dashboard page code and thus can be configured on a schedule - e.g dashboard start, or at a regular time interval.
It will only run when it is scheduled, so not multiple times depending on visiting users.

In your page code, you can use the commands to get PSU job and it’s data into a variable.
Wrap the whole table in a dynamic element.
You can remove the autorefresh you have, and just put a sync-udelement inside your scheduled script, at the end, that way it will update the table when it completes, you can use a -broadcast flag so that any one browsing the page with that element on it will have it updated.

That’s the way I would approach it, but there are other ways in which it can be achieved.
As for pausing refreshes… without playing around with it I’m not sure, but it’s possible you can have a dynamic region wrapping everything, with any auto refreshing elements inside that, have the parameters set to autorefresh based on a variable which when the user clicks a button to pause two things happen.

  1. the button updates the variable used to turn auto refresh on and off (could use splatting to make this easier and just clear the hashtable or add autorefresh / refreshinterval depending on requirements.
  2. the button refreshes the entire dynamic region, and therfore re-renders any components with your now changed splatted hashtable that tells those components if they should be auto refreshing or not.

This is such a helpful reply!!!

  1. Can you trigger other scripts within a separate script and is that a synchronous operation or an asynchronous operation? For example, let’s say script #1 runs every 10 seconds and INSERTs data into a SQL Server table for tracking. However, if a value returned is above a certain threshold, I would like to fire off a separate script to gather additional information into another details table… but I don’t want script #1 to wait on script #2 to finish as script #2 might take 3 seconds to run.

  2. “…and just put a sync-udelement inside your scheduled script” This makes sense, but is an element ID unique to all powershell universal dashboards? If I have 2 separate dashboards and each dashboard has a New-UDTable with the same ID… and in my scheduled script I run Sync-UdElement -ID myTable is that going to update both tables in both dashboards? If so, it sounds like you gotta be careful to always give your elements unique ID names even if they are in separate dashboards.

  3. This was not part of my question, but one thing I am struggling with in Powershell Universal is populating a table on a button click from a query result set. It seems that when the page loads, if the table does not have “dummy” data in it then when I go to reload it, the element technically doesn’t exist so nothing happens. I am not sure I am explaining this well, but basically I am able to fix this problem by passing in dummy data so that a “skeleton” table loads up and then I let the user hit a button if they want to query data and update the table.

  4. What you are describing regarding the “autorefresh pausing” sounds like it would only work if I was using the -autorefresh flag… based on what you said above it sounds like I want to go the route of using separate scripts that then sync independent elements on the dashboard that the user is viewing. Do you think it is still possible to design something that would allow a user to pause the updates just for their session only? Worse case scenario… could I let them pause it for everyone?

#1 - I dont see why you couldnt do this using the PSU API. Im not too familiar with it as I havent used that side of PSU much but i’m aware of the command Invoke-UAScript which also offers a -wait param if you wish for it to wait or just trigger and move on, so you have the option for either.
There’s also Get-UAJob and Wait-UAJob

#2 - I’m not 100% sure about this one, I’ll be honest I was making a few assumptions on how I used to do this back in the old version of universal dashboard (before it became PSU). I basically used to have a sync-udelement sat inside one of my API endpoints, and I’d call that (passing in an ID of the element i wanted to update). I’m assuming something similar can be done, if not directly in the PSU script, maybe via an API, but havent fully tested this in PSU.

#3 - I think I follow. If you follow the ‘simple’ example here: Table - PowerShell Universal
which takes column information from your data array automatically, and then instead just give it an empty array, you’ll notice you get a minified react error. This is due to the fact is has no information on what the column headers are supposed to be.
Instead, take a look at the table with custom columns example, in which you specify the columns as a separate parameter, now if you do the same and provide it with an empty array, it will still show the column headers but it wont have any rows.
You could have the table load on page, if you dont have data, keep it empty in this way, then when you use you button click event, you can just perform a ‘set’ on the table element to update it with the new data/get it to refresh. Hope that’s what you mean?

#4 - it doesnt nessesarily have to be the autorefresh flat, which ever way you do it, you can wrap it in a dynamic element, but depending on an if statement and the state of your button/switch, you can modify how your table, region, or whatever element you choose inside that dynamic element, functions, e.g by stopping the autorefresh. Yes you could do it on a per user basis, you’d likley have to take a copy of the data in your cache or from your script output, and store it into a $session variable, and then use that for the table display - so when the user pauses their version of the page or components, its relevant to them at the time of the pause, and it doesnt interfere with everyone else. Basically you’d be creating a cached copy of your script output for that users session. Otherwise, if you do want a pause function that effects everyone browsing, then you’d use a cache variable. Also when you use sync-udelement there’s a -broadcast param, which basically means it will update that component for everyone, otherwise you’ll just update the component for that users session only.

If you have script #1 with -wait, call script #2, and script #2 has a -wait command… and so on and so forth… will script #1 wait for that chain to complete? I am wanting my dashboard to update only once ALL scripts have actually completed their queries and I’d rather not try and “guess” when that is.

It appears Sync-UDelement is not a recognized command within the Script portion of PSU so unfortunately this will not work.