Returns Google Sheet cells from a named range
I didn't run unit tests for this on different search inputs, but it should give an idea of how you can bundle index information into the results for consumption with array class methods. Because you are working in a fairly robust environment (Google Sheets), you can be confident that the search array you are working with has a guaranteed nesting level (which limits a lot of possible issues).

The general idea is to replace the raw value with an annotated object, after which you can remove the row &amp; column structure and work only with the value. (It's possible you could just use the reduce | forEach and push Array methods to go from the values array to the flattened array of annotated values.)

function annotateAndCase_(input2DArr, lower) {
  // Map the 0-base row and column indices onto the value.
  return input2DArr.map(function (row, rowIndex) {
    return row.map(function (val, colIndex) {
      var v = (lower &amp;&amp; typeof val.toLowerCase === 'function') ? val.toLowerCase() : val;
      return {r: rowIndex, c: colIndex, v: v};
    });
  });
}

function getCellsWithValueInRange(SearchRange, search_string, case_sensitive) {
  // Pass exactly `false` to disable case sensitivity. Other falsy (0, "", null, undefined) -&gt; `true`
  case_sensitive = case_sensitive !== false;
  if (case_sensitive) {
    search_string = search_string.toLowerCase();
  }
  const startRow = SearchRange.getRow(),
        startCol = SearchRange.getColumn();

  const indexedValues = annotateAndCase_(SearchRange.getValues(), !case_sensitive);

  // 2D array with max nesting level = 1 -&gt; https://stackoverflow.com/a/10865042
  const flattened = Array.prototype.concat.apply([], indexedValues);

  const results = flattened.filter(function (cell) {
    return cell.v === search_string;
  }).map(function (match) {
    // Return a string R1C1 notation of each matched value.
    return ["R", match.r + startRow, "C", match.c + startCol].join("");
  });

  // Use a RangeList to optimize obtaining a large number of possibly-disjoint ranges.
  return results.length ? SearchRange.getSheet().getRangeList(results).getRanges() : [];
}


As mentioned in comments by @Dimu, you should reconsider why you need the individual cell references (perhaps just the collection as a RangeList is sufficient, e.g. for treating them in the same manner).

It's a similarly good idea to separate the functionality of annotating from this specific function that searches for values, since that allows reusing code, e.g. annotated a range object, use various filter predicates, various transformative maps, various final consumers, and so on. Probably you should further separate the casing from the annotation step - only certain filter predicates for the annotated array would care.