Here's something simple that might do it:
1) Put this in a file named something like usercount.php (or whatever you want) and put it in includes/cron.
PHP Code:
<?php
// ######################## SET PHP ENVIRONMENT ###########################
error_reporting(E_ALL & ~E_NOTICE);
if (!is_object($vbulletin->db))
{
exit;
}
// SQL for creating table, do once before starting task (add your table prefix to the table name
//CREATE TABLE usercounts (
//time INT UNSIGNED NOT NULL DEFAULT '0',
//users SMALLINT UNSIGNED NOT NULL DEFAULT '0',
//guests SMALLINT UNSIGNED NOT NULL DEFAULT '0')
$datecut = TIMENOW - $vbulletin->options['cookietimeout'];
$guests = $vbulletin->db->query_first("
SELECT COUNT(*) AS guests
FROM " . TABLE_PREFIX . "session
WHERE lastactivity > $datecut AND userid = 0
");
$users = $vbulletin->db->query_first("
SELECT COUNT(DISTINCT userid) AS users
FROM " . TABLE_PREFIX . "session
WHERE lastactivity > $datecut AND userid != 0
");
$vbulletin->db->query_write(
"UPDATE " . TABLE_PREFIX . "usercounts
VALUES(" . TIMENOW . ", $users[users], $guests[guests])
");
log_cron_action('', $nextitem, 1);
?>
2) Create a table in your database called usercounts (with your table prefix in front of it if you have one). I put the SQL for creating the table in a comment in the code above.
3) Add a scheduled task using ./includes/cron/usercount.php as the file name. My guess is that it won't make any sense to run the task at a shorter interval than your session timeout is set to.
A couple other things - scheduled tasks don't run if no one visits your board, so during times of no users (if you have any) you won't have counts. Also, if your board is very busy I think there's a chance that the task will occasionally run twice. But since the records have a timestamp, you should be able to deal with either of those things when analyzing your data.
I tested this a little, but not that much so you'll probably want to test it some before counting on it to work right.