Cycles image sequence node offset and the object info random
here is a quick and dirty script, its really inefficient though, creates a distinct material for each cube. I Suggest maybe investigating the animation nodes plugin? you can do fancier programming logic with that.

import bpy
import random
import glob

scene = bpy.context.scene


image_names = glob.glob("/Users/myuser/Blender/images/*")

for name in image_names:
    bpy.ops.image.open(filepath=name)

cube_count = 1000

for c in range(cube_count):
    bpy.ops.mesh.primitive_cube_add(view_align=False,
     enter_editmode=False,
      location=(3*random.random(), 3*random.random(), 3*random.random()))




for ind,ob in enumerate(scene.objects):
    if ob.type == 'MESH' and ob.name.startswith("Cube"):
        ob.select = True


        #make a new material
        rand = "--"+ str(random.randint(0,100))
        mat = bpy.data.materials.new(name="Mat"+str(ind)) #set new material to variable
        #add the material to the object
        ob.data.materials.append(mat) 
        ob.active_material_index = len(ob.material_slots) - 1

        #make a new node texture node
        mat.use_nodes = True
        node_tree = mat.node_tree
        node = node_tree.nodes.new("ShaderNodeTexImage")
        tex_coord_node = node_tree.nodes.new("ShaderNodeTexCoord")
        mapping_node = node_tree.nodes.new("ShaderNodeMapping")
        diff_node = node_tree.nodes['Diffuse BSDF']

        node_tree.links.new(tex_coord_node.outputs['Generated'],       mapping_node.inputs['Vector'])
        node_tree.links.new(mapping_node.outputs['Vector'], node.inputs['Vector'])
        node_tree.links.new(node.outputs['Color'], diff_node.inputs['Color'])

        node.projection = 'BOX'
        node.select = True
        node_tree.nodes.active = node


        rand_image_index = random.randint(0, len(bpy.data.images))
        node.image = bpy.data.images[rand_image_index]

    else: 
        ob.select = False
`