A version that gets an Array with each SO represented only once.

// determine duplicated smart objects;
// 2024, use it at your own risk;
if (app.documents.length > 0) {
var theThings = collectSmartObjectsWithIDs();
alert (theThings.length+" smart objects:\n"+theThings.join("\n"));
};
////////////////////////////////////
////// collect smart objects, probably based on code by paul, mike or x //////
function collectSmartObjectsWithIDs () {
// get number of layers;
var ref = new ActionReference();
ref.putEnumerated( charIDToTypeID("Dcmn"), charIDToTypeID("Ordn"), charIDToTypeID("Trgt") );
var applicationDesc = executeActionGet(ref);
var theNumber = applicationDesc.getInteger(stringIDToTypeID("numberOfLayers"));
// process the layers;
var theLayers = new Array;
for (var m = 0; m <= theNumber; m++) {
try {
var ref = new ActionReference();
ref.putIndex( charIDToTypeID( "Lyr " ), m);
var layerDesc = executeActionGet(ref);
var layerSet = typeIDToStringID(layerDesc.getEnumerationValue(stringIDToTypeID("layerSection")));
var isBackground = layerDesc.getBoolean(stringIDToTypeID("background"));
// if not layer group collect values;
if (layerSet != "layerSectionEnd" && layerSet != "layerSectionStart" && isBackground != true) {
var theName = layerDesc.getString(stringIDToTypeID('name'));
var theID = layerDesc.getInteger(stringIDToTypeID('layerID'));
if(layerDesc.hasKey(stringIDToTypeID('smartObject'))) {
var soDesc = layerDesc.getObjectValue(stringIDToTypeID('smartObject'));
var soDescMore = layerDesc.getObjectValue(stringIDToTypeID('smartObjectMore'));
var theFileRef = soDesc.getString(stringIDToTypeID('fileReference'));
var theDocID = soDesc.getString(stringIDToTypeID('documentID'));
var soID = soDescMore.getString(stringIDToTypeID('ID'));
var theCheck = false;
for (var x = 0; x < theLayers.length; x++) {
if (theLayers[x][2] == soID) {theCheck = true}
};
if (theCheck == false) {theLayers.push([theName, theID, soID, theFileRef, theDocID])}
}
}
}
catch (e) {};
};
return theLayers
};