Hi,

The following Lua script can detect if a drive is unmounted or disappears from a Windows machine. 

The first test after KNM is started, it enumerate all drives on the machine and have that as a baseline to compare every subsequent test with. There is a option to ignore removable drives such as external SATA drives and USB sticks. There is also an exclusion field to exclude a fixed disk name.

The script uses WMI to perform the test, the monitored machine must accept incoming WMI requests.

You can reset this baseline by entering "reset" (without the quotes) into the exclude drive field, let it test once. Remember to enter the orginal value of the exclude field and resave the monitor afterwards.

To use the script, copy it as a text file with the .lua extension to the \script directory and create a Lua script monitor.

-- This function is called when enumerating a field
function OnEnumerate(sFieldToEnum)
	-- The variable returned must be called "Config".
	Enum = LuaScriptEnumResult() 
	if sFieldToEnum == "Ignore removables" then
		Enum:Add("Yes")
		Enum:Add("No")
	end
	return Enum
end
-- This function is called to retrieve a script configuration
function OnConfigure()
	-- The variable returned must be called "Config".
	Config = LuaScriptConfigurator() 
	-- Author.
	Config:SetAuthor("Kaseya International Limited")
	-- Description.
	Config:SetDescription("Verifies that all drives that are mounted the first test, continues to be mounted. Option for ignoring removable drives and specifc drive letters included.")
	-- Minimum build version needed, set to zero for if no specific build version is required.
	Config:SetMinBuildVersion(2000)
	-- Script version (major/minor)
	Config:SetScriptVersion(1,0)
	-- A parameter configuration, add them in the order the script is extracting them.
	Config:AddArgument("Exclude drive","Drive to exlude from check, separate drive names with space", LuaScriptConfigurator.CHECK_NOTHING)
	-- A parameter configuration, add them in the order the script is extracting them.
	Config:AddArgument("Ignore removables","Ignore removable drives ?",LuaScriptConfigurator.CHECK_NOT_EMPTY + LuaScriptConfigurator.ENUM_AVAIL)
	-- Set the entry point, this is the function called to start execution of script
	Config:SetEntryPoint("main")
	-- Done with configuration, return the object
	return Config
end
function GetStoredData(sKey)
 	
	Storage = TLuaStorage()
	sName = GetObjectAddress()..sKey
	-- Create a new storage item if needed
    	if(Storage:CreateItem(sName,sKey)==false) then
        	StorageItem = Storage:FindItem(sName,sKey)
        	if(StorageItem.m_pData ~= nil) then
            	return StorageItem.m_pData
        	end
    	else
        	-- No item found, this is the first test since creation of monitor or restart of KNM
        	return ""
    	end
	return ""
end
-- Updates stored data
function UpdateStoredData(sKey,sTemp)
      
	Storage = TLuaStorage()
	sName = GetObjectAddress()..sKey
	Storage:UpdateItem(sName,sKey,sTemp)
end
function MakeTokenTable(_s)
	
	sep = ' ';
	fields = {}
	if string.find(_s,sep) == nil then
		fields[_s] = true;
		return fields;
	end
	
	string.gsub(_s,"([^"..sep.."]*)"..sep, function(c) fieldsCoffee = true end)
	return fields;
end
function FindToken(tTable,sToFind)
	for k,v in pairs(tTable) do
		if k == sToFind then
			return true
		end
	end
	return false
end
-- This is the entry point
function main()
	sExcludeList = GetArgument(0)
	sIgnoreRemovableDrives = GetArgument(1)
	-- Check if user specified account to use
	sUser = GetAccountUser();
	sPass = GetAccountPassword();
	-- Check if we should ignore removable drives
	bIgnoreRemovableDrives = false;
	if sIgnoreRemovableDrives == "Yes" then
		bIgnoreRemovableDrives = true;
	end
	
	skey = "_drivechecker"
	-- Nifty function to reset the entry
	if sExcludeList == "reset" then
		UpdateStoredData(skey,"")
		SetExitStatus("Monitor reset, set the orginal exclude list",true)	
		return
	end
	bRet = false;
	Query = TLuaWMIQuery(); 
	if sUser == "" then
		bRet = Query:Execute("select Deviceid,DriveType from win32_logicaldisk"); 
	else
		bRet = Query:Execute("select Deviceid,DriveType from win32_logicaldisk",sUser,sPass); 	
	end
	if bRet == false then
		SetExitStatus("Test failed, "..Query:GetErrorDescription(),false)
		return
	end
	sDriveString = ""
	sOldDriveString = GetStoredData(skey)
	tExcludeTable = MakeTokenTable(sExcludeList)
	bFirst = false
	if sDriveString == "" then
		bFirst = true
	end
	sErrorString = ""
	sOKString = "Test ok, "
	while (Query:NextInstance()) do
		sDriveType,sDeviceID = "";
		bOk,sDeviceID = Query:GetProperty("Deviceid",sDeviceID);
		bOk,sDriveType= Query:GetProperty("DriveType",sDriveType);
		bIgnore = false
		if bIgnoreRemovableDrives == true and sDriveType == 2 then
			bIgnore = true
		end
		if bIgnore == false then
			sDriveString = sDriveString..sDeviceID.." ";	
		end
	end
	if sOldDriveString == "" then
		UpdateStoredData(skey,sDriveString)
		SetExitStatus("First test ok",true);
		return;
	end
	-- Compare two drive strings
	tDriveTable = MakeTokenTable(sDriveString)
--	print("Old drives:" .. sOldDriveString);
	tOldDriveTable = MakeTokenTable(sOldDriveString)
	for k,v in pairs(tOldDriveTable) do
		-- If entry is in 
		if FindToken(tExcludeTable,k) == false then
			-- not excluded, check we still got it
			if FindToken(tDriveTable,k) == false then
				sErrorString = sErrorString .. "Drive "..k.." not present\n"
			else
				sOKString = sOKString .."Drive "..k.." present\n"
			end
		end
	end
	if sErrorString == "" then
		SetExitStatus(sOKString,true)
	else
		SetExitStatus(sErrorString,false)		
	end
end



[edited by: RA at 7:23 AM (GMT -8) on 1-11-2012] More fixing