'API Export Agent Restriction Status: %REM This agent will output information about all the agents in all databases on a given server (as specified by the serverName variable in the Initialize section). Obviously, no information will be available for any databases that you don't have access to. In this version of the agent, we're looking specifically for the value of the $Restricted field of the agents. This is because in ND6, that field determines what the runtime security level of the agent is (the property is actually set in the Security tab of the Agent Properties dialog). If an agent has a runtime security level of "1" (the default setting), if won't be able to run "restricted" operations, which can cause your agent to fail with errors like: Error 201: Operation is disallowed in this session This agent outputs information to a comma-delimited text file, which can easily be opened up and manipulated in your favorite spreadsheet program. You should make special note of scheduled agents with a runtime security level of "1", because those are the ones that are most likely to fail rather silently on the server. This will probably be your biggest issue when you upgrade to ND6. For reference, see "Setting up agent security using the Security tab" http://www-12.lotus.com/ldd/doc/domino_notes/6.5/help65_designer.nsf/0/ec288ebfaf54fd7b85256d9b0042f05b?OpenDocument and "Restricted LotusScript and Java agent operations" http://www-12.lotus.com/ldd/doc/domino_notes/6.5/help65_designer.nsf/0/ee10397697892fa285256d9b0042f1a0?OpenDocument version 1.0 January 18, 2004 Julian Robichaux -- http://www.nsftools.com %END REM Option Public Option Explicit '** we're using a global list to store agent NoteIDs, which is safer than '** passing a list around as a parameter in some versions of Notes Dim agentList List As String '** Notes API functions we'll be using Declare Function OSPathNetConstruct Lib "nnotes.dll" (Byval portName As Integer, _ Byval serverName As String, Byval fileName As String, Byval pathName As String) As Integer Declare Function NSFDbOpen Lib "nnotes.dll" (Byval dbName As String, rethDb As Long) As Integer Declare Function NSFDbClose Lib "nnotes.dll" (Byval hDb As Long) As Integer Declare Function NSFDbGetModifiedNoteTable Lib "nnotes" ( Byval hDB As Long, Byval noteClassMask As Integer, _ Byval startDate As Double, retEndDate As Double, rethTable As Long ) As Integer Declare Function IDEntries Lib "nnotes" ( Byval hTable As Long ) As Long Declare Function IDScan Lib "nnotes" ( Byval hTable As Long, Byval tFirstBool As Integer, retID As Long) As Integer Declare Function OSMemFree Lib "nnotes" (Byval handle As Long) As Integer Const TIMEDATE_MINIMUM = 0 Const TIMEDATE_MAXIMUM = 1 Const TIMEDATE_WILDCARD = 2 Declare Sub TimeConstant Lib "nnotes" ( Byval timeConstantType As Long, retDateTime As Double) '** Error code masks Const ERR_MASK = &H3fff Const PKG_MASK = &H3f00 Const ERRNUM_MASK = &H00ff Declare Function OSLoadString Lib "nnotes.dll" (Byval hModule As Long, Byval stringCode As Integer, _ Byval retBuffer As String, Byval bufferLength As Integer) As Integer '** flag constants taken from Damien Katz's API library, because I was too lazy to import '** them myself from the C API header files Const NOTE_CLASS_DOCUMENT = &H0001 ' document note Const NOTE_CLASS_DATA = NOTE_CLASS_DOCUMENT ' old name for document note Const NOTE_CLASS_INFO = &H0002 ' notefile info (help-about) note Const NOTE_CLASS_FORM = &H0004 ' form note Const NOTE_CLASS_VIEW = &H0008 ' view note Const NOTE_CLASS_ICON = &H0010 ' icon note Const NOTE_CLASS_DESIGN = &H0020 ' design note collection Const NOTE_CLASS_ACL = &H0040 ' acl note Const NOTE_CLASS_HELP_INDEX = &H0080 ' Notes product help index note Const NOTE_CLASS_HELP = &H0100 ' designer's help note Const NOTE_CLASS_FILTER = &H0200 ' filter note Const NOTE_CLASS_FIELD = &H0400 ' field note Const NOTE_CLASS_REPLFORMULA = &H0800 ' replication formula Const NOTE_CLASS_PRIVATE = &H1000 Const NOTE_CLASS_ALLNONDATA = &H7FFE Const DESIGN_FLAG_ADD = "A" Const DESIGN_FLAG_ANTIFOLDER = "a" ' VIEW: Indicates that a view is an antifolder view Const DESIGN_FLAG_BACKGROUND_FILTER = "B" ' FILTER: Indicates FILTER_TYPE_BACKGROUND is asserted Const DESIGN_FLAG_INITBYDESIGNONLY="b" ' VIEW: Indicates view can be initially built only by designer and above Const DESIGN_FLAG_NO_COMPOSE = "C" ' FORM: Indicates a form that is used only for ' query by form (not on compose menu). Const DESIGN_FLAG_CALENDAR_VIEW = "c" ' VIEW: Indicates a form is a calendar style view. Const DESIGN_FLAG_NO_QUERY = "D" ' FORM: Indicates a form that should not be used in query by form Const DESIGN_FLAG_DEFAULT_DESIGN = "d" ' ALL: Indicates the default design note for it"s class (used for VIEW) Const DESIGN_FLAG_MAIL_FILTER = "E" ' FILTER: Indicates FILTER_TYPE_MAIL is asserted Const DESIGN_FLAG_PUBLICANTIFOLDER = "e" ' VIEW: Indicates that a view is a public antifolder view Const DESIGN_FLAG_FOLDER_VIEW = "F" ' VIEW: This is a V4 folder view. Const DESIGN_FLAG_V4AGENT = "f" ' FILTER: This is a V4 agent Const DESIGN_FLAG_VIEWMAP = "G" ' VIEW: This is ViewMap/GraphicView/Navigator Const DESIGN_FLAG_OTHER_DLG = "H" ' ALL: Indicates a form that is placed in Other... dialog Const DESIGN_FLAG_V4PASTE_AGENT = "I" ' FILTER: This is a V4 paste agent Const DESIGN_FLAG_IMAGE_RESOURCE = "i" ' FORM: Note is a shared image resource Const DESIGN_FLAG_JAVA_AGENT = "J" ' FILTER: If its Java Const DESIGN_FLAG_JAVA_AGENT_WITH_SOURCE = "j" ' FILTER: If it is a java agent with java source code. Const DESIGN_FLAG_LOTUSSCRIPT_AGENT = "L" ' FILTER: If its LOTUSSCRIPT Const DESIGN_FLAG_DELETED_DOCS = "l" ' VIEW: Indicates that a view is a deleted documents view Const DESIGN_FLAG_QUERY_MACRO_FILTER = "M" ' FILTER: Stored FT query AND macro Const DESIGN_FLAG_SITEMAP = "m" ' FILTER: This is a site(m)ap. Const DESIGN_FLAG_NEW = "N" ' FORM: Indicates that a subform is listed when making a new form. Const DESIGN_FLAG_HIDE_FROM_NOTES = "n" ' ALL: notes stamped with this flag 'will be hidden from Notes clients 'We need a separate value here 'because it Is possible To be 'hidden from V4 AND to be hidden 'from Notes, and clearing one 'should not clear the other Const DESIGN_FLAG_QUERY_V4_OBJECT = "O" ' FILTER: Indicates V4 search bar query object - used in addition to "Q" Const DESIGN_FLAG_PRIVATE_STOREDESK = "o" ' VIEW: If Private_1stUse, store the private view in desktop Const DESIGN_FLAG_PRESERVE = "P" ' ALL: related to data dictionary Const DESIGN_FLAG_PRIVATE_1STUSE = "p" ' VIEW: This is a private copy of a private on first use view. Const DESIGN_FLAG_QUERY_FILTER = "Q" ' FILTER: Indicates full text query ONLY, no filter macro Const DESIGN_FLAG_AGENT_SHOWINSEARCH = "q" ' FILTER: Search part of this agent should be shown in search bar Const DESIGN_FLAG_REPLACE_SPECIAL = "R" ' SPECIAL: this flag is the opposite of DESIGN_FLAG_PRESERVE, used 'only for the "About" and "Using" notes + the icon bitmap in the icon note Const DESIGN_FLAG_PROPAGATE_NOCHANGE = "r" ' DESIGN: this flag is used to propagate the prohibition of design change Const DESIGN_FLAG_V4BACKGROUND_MACRO = "S" ' FILTER: This is a V4 background agent Const DESIGN_FLAG_SCRIPTLIB = "s" ' FILTER: A database global script library note Const DESIGN_FLAG_VIEW_CATEGORIZED = "T" ' VIEW: Indicates a view that is categorized on the categories field Const DESIGN_FLAG_DATABASESCRIPT = "t" ' FILTER: A database script note Const DESIGN_FLAG_SUBFORM = "U" ' FORM: Indicates that a form is a subform. Const DESIGN_FLAG_AGENT_RUNASWEBUSER = "u" ' FILTER: Indicates agent should run as effective user on web Const DESIGN_FLAG_PRIVATE_IN_DB = "V" ' ALL: This is a private element stored in the database Const DESIGN_FLAG_WEBPAGE = "W" ' FORM: Note is a WEBPAGE Const DESIGN_FLAG_HIDE_FROM_WEB = "w" ' ALL: notes stamped with this flag 'will be hidden from WEB clients ' WARNING: A formula that build Design Collecion relies on the fact that Agent Data"s '$Flags is the only Desing Collection element whose $Flags="X" Const DESIGN_FLAG_V4AGENT_DATA = "X" ' FILTER: This is a V4 agent data note Const DESIGN_FLAG_SUBFORM_NORENDER = "x" ' SUBFORM: indicates whether 'we should render a subform in 'the parent form Const DESIGN_FLAG_NO_MENU = "Y" ' ALL: Indicates that folder/view/etc. should be hidden from menu. Const DESIGN_FLAG_SACTIONS = "y" ' Shared actions note Const DESIGN_FLAG_MULTILINGUAL_PRESERVE_HIDDEN = "Z" ' ALL: Used to indicate design element was hidden ' before the "Notes Global Designer" modified it. ' (used with the "!" flag) Const DESIGN_FLAG_FRAMESET = "#" ' FORM: Indicates that this is a frameset note Const DESIGN_FLAG_MULTILINGUAL_ELEMENT = "!"' ALL: Indicates this design element supports the ' "Notes Global Designer" multilingual addin Const DESIGN_FLAG_JAVA_RESOURCE = "@" ' FORM: Note is a shared Java resource Const DESIGN_FLAG_HIDE_FROM_V3 = "3" ' ALL: notes stamped with this flag ' will be hidden from V3 client Const DESIGN_FLAG_HIDE_FROM_V4 = "4" ' ALL: notes stamped with this flag ' will be hidden from V4 client Const DESIGN_FLAG_HIDE_FROM_V5 = "5" ' FILTER: "Q5"= hide from V4.5 search list ' ALL OTHER: notes stamped with this flag ' will be hidden from V5 client Const DESIGN_FLAG_HIDE_FROM_V6 = "6" ' ALL: notes stamped with this flag 'will be hidden from V6 client Const DESIGN_FLAG_HIDE_FROM_V7 = "7" ' ALL: notes stamped with this flag 'will be hidden from V7 client Const DESIGN_FLAG_HIDE_FROM_V8 = "8" ' ALL: notes stamped with this flag 'will be hidden from V8 client Const DESIGN_FLAG_HIDE_FROM_V9 = "9" ' ALL: notes stamped with this flag 'will be hidden from V9 client Const DESIGN_FLAG_MUTILINGUAL_HIDE = "0" ' ALL: notes stamped with this flag 'will be hidden from the client 'usage is for different language 'versions of the design list to be 'hidden completely Sub Initialize '** loop through all the databases and output information about the agents On Error Goto processError '** specify which server to run this against (use "" for the local machine). Dim serverName As String serverName = "" '** grab the database directory for that server, and dim a few related variables Dim dbdir As New NotesDbDirectory(serverName) Dim db As NotesDatabase Dim doc As NotesDocument Dim retString As String Dim restrictLevel List As String Dim isScheduled As String restrictLevel("1") = "1. Do not allow restricted operations" restrictLevel("0") = "2. Allow restricted operations" restrictLevel("2") = "3. Allow restricted operations with full administration rights" restrictLevel("") = "1. Do not allow restricted operations" '** open a text file for output Dim fileName As String Dim fileNum As Integer fileNum = Freefile() fileName = "C:\AgentRestriction.csv" Open fileName For Output As fileNum Print #fileNum, "Database Name, NoteID, Agent Name, $Flags, Scheduled?, $Restricted, Restriction Level" Print #fileNum, "" '** and step through the databases Set db = dbdir.GetFirstDatabase(DATABASE) While Not (db Is Nothing) Print "Processing " & db.FileName Print #fileNum, db.FilePath '** open the database and grab the NoteIDs of all the agents '** using the GetScriptElementList function Call db.Open("", "") retString = GetScriptElementList(db) '** if we were able to open the database and we got the list of '** agent notes, output information about the agents to the file If (retString = "") And (db.IsOpen) Then Forall noteid In agentList '** try to open each agent as a regular NotesDocument, '** so we can read the fields Set doc = db.GetDocumentByID(noteid) If Not (doc Is Nothing) Then '** if this is a valid agent note, output information about it If (Len(doc.~$Title(0)) > 0) And (Instr(1, doc.~$Flags(0), "f", 0) > 0) Then If (doc.~$AssistTrigger(0) = "1") Then isScheduled = "Yes" Else isScheduled = "" End If Print #fileNum, db.FileName & "," & noteid & "," & doc.~$Title(0) & "," & _ doc.~$Flags(0) & "," & isScheduled & "," & doc.~$Restricted(0) & "," & _ restrictLevel(doc.~$Restricted(0)) End If End If End Forall Else Print #fileNum, "Could not get agent list for " & db.FileName Print #fileNum, retString End If '** use a separator so we can easily see where one database ends and '** another begins in the output file Print #fileNum, "==================================================================" Set db = dbdir.GetNextDatabase Wend Close fileNum Print "All Done!" Exit Sub processError: Dim errMsg As String errMsg = "Error " & Err & ": " & Error$ If (fileNum > 0) Then Print #fileNum, errMsg Resume Next Else Print errMsg Messagebox errMsg Exit Sub End If End Sub Function GetScriptElementList (db As NotesDatabase) As String '** Get all the agents and script libraries in this database, and store '** their NoteIDs in a global list called agentList (so we can step '** through the list later and look at the documents). I used a global '** list because sometimes lists would get corrupted if you passed '** them as parameters in older versions of Notes (the problem was '** fixed in 5.08 or something), and a list was a lot easier to manage '** in this case than an array. '** '** Sorry about all the goto statements -- it was just easier to write it '** that way than to either create a lot of If-Then nestings, or duplicate '** a lot of the code that releases handles and frees memory. '** '** version 1.0 '** Julian Robichaux -- http://www.nsftools.com Dim hDb As Long Dim hIDTable As Long Dim pathName As String*256 Dim startDate As Double, endDate As Double Dim noteID As Long Dim firstFlag As Integer Dim result As Integer '** clear the global list of agents and script libraries Erase agentList '** create a proper network path name with OSPathNetConstruct Call OSPathNetConstruct(0, db.Server, db.FilePath, pathName) '** open the database and get a handle with NSFDbOpen result = NSFDbOpen(pathName, hDb) If result <> 0 Then GetScriptElementList = "Cannot open database " & db.FilePath & " on server " & db.Server & _ ". Error was " & Cstr(result) & ": " & GetAPIError( result ) Goto endOfFunction End If '** get the ID table of the database, with all of the design elements that are either agents '** or script libraries (use TIMEDATE_MINIMUM to get all but the deleted items) Call TimeConstant(TIMEDATE_MINIMUM, startDate) result = NSFDbGetModifiedNoteTable(hDb, NOTE_CLASS_FILTER Or NOTE_CLASS_PRIVATE, _ startDate, endDate, hIDTable) If result <> 0 Then GetScriptElementList = "Cannot open ID Table on " & db.FilePath & " on server " & db.Server & _ ". Error was " & Cstr(result) & ": " & GetAPIError( result ) Goto closeDb End If '** make sure we got some IDs returned to us (if not, just exit) If (IDEntries(hIDTable) = 0) Then Goto freeIDTable End If '** get the IDs in the table firstFlag = True Do While IDScan(hIDTable, firstFlag, noteID) > 0 agentList(noteID) = ConvertNoteID(noteID) firstFlag = False Loop freeIDTable: '** free the memory used when we grabbed the ID table Call OsMemFree(hIDTable) ' should possibly use IDDestroyTable instead? closeDb: '** close the database with NSFDbClose Call NSFDbClose(hDb) endOfFunction: Exit Function End Function Function GetAPIError (errorCode As Integer) As String '** this function translates Notes API error codes into their '** corresponding error strings Dim errorString As String*256 Dim returnErrorString As String Dim resultStringLength As Long Dim errorCodeTranslated As Integer '** mask off the top 2 bits of the errorCode that was returned; this is '** what the ERR macro in the API does errorCodeTranslated = (errorCode And ERR_MASK) '** get the error code translation using the OSLoadString API function resultStringLength = OSLoadString(0, errorCodeTranslated, errorString, Len(errorString) - 1) '** strip off the null-termination on the string before you return it If (Instr(errorString, Chr(0)) > 0) Then returnErrorString = Left$(errorString, Instr(errorString, Chr(0)) - 1) Else returnErrorString = errorString End If GetAPIError = returnErrorString End Function Function ConvertNoteID (noteID As Long) As String '** convert the noteID to a Hex value, and left-pad it with zeros Dim noteIDString As String noteIDString = Hex$(noteID) noteIDString = String(8 - Len(noteIDString), "0") & noteIDString ConvertNoteID = noteIDString End Function