Create a script based monitor for the existence of a file, with recovery to copy file


 

This is going to be an example of making a two state monitor to check for the existence of a file on an agent managed server.

If the file does not exist, we can run a recovery to copy the file there from a network location.

 

The context of this example is for a scenario, where we expect the OOMADS.MSI file (Active Directory Helper Objects) to be placed in a specific directoy on the agent:   C:\Program Files\Microsoft Monitoring Agent\Agent\HelperObjects

However, if the agent is manually installed, we do not copy this file, it is copied only if the agent is pushed from the SCOM console.  This might leave several active directory domain controllers without these necessary scripting objects deployed.  Marnix wrote about this here:  http://thoughtsonopsmgr.blogspot.com/2010/10/eventid-10-active-directory-helper.html

The AD management pack will automatically deploy this MSI if and when it is needed, but the MP expects the OOMADS.MSI to be in that specific directly above.  Hence, this example.  Smile

We will start with a simple monitor example, which will use the Microsoft.Windows.TimedScript.TwoStateMonitorType.  This monitor will run a VBscript, which we adapted from Pete Zerger’s script at http://www.systemcentercentral.com/opsmgr-creating-a-monitor-to-determine-if-a-file-exists-sample-script-and-tutorial/

Here is my customized version of Pete’s script:

'========================================================================== ' ' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2009 ' ' NAME: DoesFileExist ' ' AUTHOR: Pete Zerger, MVP (Cloud and Datacenter Admin) ' DATE : 3/12/2012 ' ' COMMENT: Verifies a target file (including path) exists. ' Intended for use with OpsMgr two state script monitor. ' '========================================================================== OPTION EXPLICIT Call Main Sub Main() 'Declare Variables 'File-related variables Dim fso, folder, file, FilePath 'OpsMgr related variables Dim oArgs, oAPI, oBag Set oArgs = Wscript.Arguments ' Retrieve parameters folder = CStr(oArgs.Item(0)) file = CStr(oArgs.Item(1)) FilePath = folder & "\" & file WScript.Echo folder WScript.echo file WScript.Echo FilePath ' Instantiate File System Object Set fso = CreateObject("Scripting.FileSystemObject") ' Instantiate MOM API Set oAPI = CreateObject("MOM.ScriptAPI") Set oBag = oAPI.CreatePropertyBag() ' Verify the path to the file exists xists If (fso.FolderExists(folder)) Then 'Folder exists, submit property bag and continue Call oBag.AddValue("FolderExists","Yes") WScript.Echo "Folder exists" Else 'Folder does not exist, submit property bag and exit Call oBag.AddValue("FolderExists","No") Call oBag.AddValue("FileExists","No") WScript.Echo "Folder doesn't exist" oAPI.AddItem(oBag) Call oAPI.ReturnItems Exit Sub End If ' Verify the file exists If (fso.FileExists(FilePath)) Then 'File exists, submit property bag and exit Call oBag.AddValue("FileExists","Yes") oAPI.AddItem(oBag) Call oAPI.ReturnItems Else 'File does not exist, submit property bag and exit Call oBag.AddValue("FileExists","No") WScript.Echo "File doesn't exist" oAPI.AddItem(oBag) Call oAPI.ReturnItems Exit Sub End If End Sub

I will pass two parameters to this script – the directory and the filename I am looking for.  This is a very reuseable monitor for other purposes:

image

 

I will create an expression for unhealthy, stating that if either the folder or file is missing, this is bad:

image

And expression for healthy requires BOTH to exist:

image

That part is quite simple – and will generate an alert with context:

image

Next, I will add a recovery task.  This recovery will do two things.  FIRST, it will include a condition detection, to ensure that for all the “unhealthy” monitors, we will only attempt a recovery action IF the required folder is present, just the file is missing.  Then, it will call another VBscript which will copy the file locally for us.

The condition detection is a simple expression:

image

I could not find any good examples on the web for how to pass a property from a monitor, to a condition detection in a Recovery.  There are lots of examples of passing the monitor property directly to a recovery script as a parameter, but none for a system.expression filter in a condition detection.  The hardest part of this was figuring out the syntax for comparing the output of the variable property from the monitor: 

StateChange/DataItem/Context/DataItem/Property[@Name='FolderExists']

Here is my recovery script… which is VERY basic:

Dim oAPI, fso Set oAPI = CreateObject("MOM.ScriptAPI") Call oAPI.LogScriptEvent("CopyFile.vbs",6002,0,"Starting copyfile script") set fso=CreateObject("Scripting.FileSystemObject") fso.CopyFile "\\scom01\AgentStuff\amd64\oomads.msi", "C:\Program Files\Microsoft Monitoring Agent\Agent\HelperObjects\" WScript.Quit

Now that we have that, putting it all together in a management pack is quite simple.

Here is the entire XML….

<?xml version="1.0" encoding="utf-8"?><ManagementPack ContentReadable="true" SchemaVersion="2.0" OriginalSchemaVersion="1.0" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> <Manifest> <Identity> <ID>Demo.FileExists.Monitor</ID> <Version>1.0.0.3</Version> </Identity> <Name>Demo.FileExists.Monitor</Name> <References> <Reference Alias="Windows"> <ID>Microsoft.Windows.Library</ID> <Version>7.5.8501.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="System"> <ID>System.Library</ID> <Version>7.5.8501.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="SC"> <ID>Microsoft.SystemCenter.Library</ID> <Version>7.0.8433.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> <Reference Alias="Health"> <ID>System.Health.Library</ID> <Version>7.0.8433.0</Version> <PublicKeyToken>31bf3856ad364e35</PublicKeyToken> </Reference> </References> </Manifest> <Monitoring> <Monitors> <UnitMonitor ID="Demo.FileExists.Monitor.FileExists" Accessibility="Internal" Enabled="true" Target="Windows!Microsoft.Windows.Server.OperatingSystem" ParentMonitorID="Health!System.Health.ConfigurationState" Remotable="true" Priority="Normal" TypeID="Windows!Microsoft.Windows.TimedScript.TwoStateMonitorType" ConfirmDelivery="false"> <Category>AvailabilityHealth</Category> <AlertSettings AlertMessage="Demo.FileExists.Monitor.FileExists_AlertMessageResourceID"> <AlertOnState>Warning</AlertOnState> <AutoResolve>true</AutoResolve> <AlertPriority>Normal</AlertPriority> <AlertSeverity>Information</AlertSeverity> <AlertParameters> <AlertParameter1>$Data/Context/Property[@Name='FolderExists']$</AlertParameter1> <AlertParameter2>$Data/Context/Property[@Name='FileExists']$</AlertParameter2> </AlertParameters> </AlertSettings> <OperationalStates> <OperationalState ID="Success" MonitorTypeStateID="Success" HealthState="Success" /> <OperationalState ID="Error" MonitorTypeStateID="Error" HealthState="Warning" /> </OperationalStates> <Configuration> <IntervalSeconds>60</IntervalSeconds> <SyncTime /> <ScriptName>fileexists.vbs</ScriptName> <Arguments>"C:\Program Files\Microsoft Monitoring Agent\Agent\HelperObjects" "OomADs.msi"</Arguments> <ScriptBody>'========================================================================== ' ' VBScript Source File -- Created with SAPIEN Technologies PrimalScript 2009 ' ' NAME: DoesFileExist ' ' AUTHOR: Pete Zerger, MVP (Cloud and Datacenter Admin) ' DATE : 3/12/2012 ' ' COMMENT: Verifies a target file (including path) exists. ' Intended for use with OpsMgr two state script monitor. ' '========================================================================== OPTION EXPLICIT Call Main Sub Main() 'Declare Variables 'File-related variables Dim fso, folder, file, FilePath 'OpsMgr related variables Dim oArgs, oAPI, oBag Set oArgs = Wscript.Arguments ' Retrieve parameters folder = CStr(oArgs.Item(0)) file = CStr(oArgs.Item(1)) FilePath = folder &amp; "\" &amp; file WScript.Echo folder WScript.echo file WScript.Echo FilePath ' Instantiate File System Object Set fso = CreateObject("Scripting.FileSystemObject") ' Instantiate MOM API Set oAPI = CreateObject("MOM.ScriptAPI") Set oBag = oAPI.CreatePropertyBag() ' Verify the path to the file exists xists If (fso.FolderExists(folder)) Then 'Folder exists, submit property bag and continue Call oBag.AddValue("FolderExists","Yes") WScript.Echo "Folder exists" Else 'Folder does not exist, submit property bag and exit Call oBag.AddValue("FolderExists","No") Call oBag.AddValue("FileExists","No") WScript.Echo "Folder doesn't exist" oAPI.AddItem(oBag) Call oAPI.ReturnItems Exit Sub End If ' Verify the file exists If (fso.FileExists(FilePath)) Then 'File exists, submit property bag and exit Call oBag.AddValue("FileExists","Yes") oAPI.AddItem(oBag) Call oAPI.ReturnItems Else 'File does not exist, submit property bag and exit Call oBag.AddValue("FileExists","No") WScript.Echo "File doesn't exist" oAPI.AddItem(oBag) Call oAPI.ReturnItems Exit Sub End If End Sub</ScriptBody> <TimeoutSeconds>30</TimeoutSeconds> <ErrorExpression> <Or> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">Property[@Name='FolderExists']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">No</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">Property[@Name='FileExists']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">No</Value> </ValueExpression> </SimpleExpression> </Expression> </Or> </ErrorExpression> <SuccessExpression> <And> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">Property[@Name='FolderExists']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">Yes</Value> </ValueExpression> </SimpleExpression> </Expression> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">Property[@Name='FileExists']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">Yes</Value> </ValueExpression> </SimpleExpression> </Expression> </And> </SuccessExpression> </Configuration> </UnitMonitor> </Monitors> <Recoveries> <Recovery ID="Demo.FileExists.Monitor.CopyFile" Accessibility="Internal" Enabled="true" Target="Windows!Microsoft.Windows.Server.OperatingSystem" Monitor="Demo.FileExists.Monitor.FileExists" ResetMonitor="false" ExecuteOnState="Warning" Remotable="true" Timeout="300"> <Category>Custom</Category> <ConditionDetection ID="CD" TypeID="System!System.ExpressionFilter"> <Expression> <SimpleExpression> <ValueExpression> <XPathQuery Type="String">StateChange/DataItem/Context/DataItem/Property[@Name='FolderExists']</XPathQuery> </ValueExpression> <Operator>Equal</Operator> <ValueExpression> <Value Type="String">Yes</Value> </ValueExpression> </SimpleExpression> </Expression> </ConditionDetection> <WriteAction ID="SWA" TypeID="Windows!Microsoft.Windows.ScriptWriteAction"> <ScriptName>CopyFile.vbs</ScriptName> <Arguments /> <ScriptBody>Dim oAPI, fso Set oAPI = CreateObject("MOM.ScriptAPI") Call oAPI.LogScriptEvent("CopyFile.vbs",6002,0,"Starting copyfile script") set fso=CreateObject("Scripting.FileSystemObject") fso.CopyFile "\\scom01\AgentStuff\amd64\oomads.msi", "C:\Program Files\Microsoft Monitoring Agent\Agent\HelperObjects\" WScript.Quit </ScriptBody> <TimeoutSeconds>60</TimeoutSeconds> </WriteAction> </Recovery> </Recoveries> </Monitoring> <Presentation> <StringResources> <StringResource ID="Demo.FileExists.Monitor.FileExists_AlertMessageResourceID" /> </StringResources> </Presentation> <LanguagePacks> <LanguagePack ID="ENU" IsDefault="true"> <DisplayStrings> <DisplayString ElementID="Demo.FileExists.Monitor"> <Name>Demo File Exists Monitor MP</Name> </DisplayString> <DisplayString ElementID="Demo.FileExists.Monitor.CopyFile"> <Name>Copy File</Name> </DisplayString> <DisplayString ElementID="Demo.FileExists.Monitor.FileExists"> <Name>Demo File Exists Monitor</Name> <Description /> </DisplayString> <DisplayString ElementID="Demo.FileExists.Monitor.FileExists" SubElementID="Error"> <Name>Error</Name> </DisplayString> <DisplayString ElementID="Demo.FileExists.Monitor.FileExists" SubElementID="Success"> <Name>Success</Name> </DisplayString> <DisplayString ElementID="Demo.FileExists.Monitor.FileExists_AlertMessageResourceID"> <Name>Demo File Exists Monitor</Name> <Description>The expected file or folder is missing. FolderExists: {0} FileExists: {1}</Description> </DisplayString> </DisplayStrings> </LanguagePack> </LanguagePacks> </ManagementPack>

We will detect all the agents that are missing this file:

image

Give context:

image

Run a recovery:

image

And finally, redetect that the file exists, set the monitor to healthy, and close any associated alerts:

image

 

This is a VERY simple example… and this specific example should be modified as it will copy the AMD64 version of OOMADS.MSI to all agents missing it, even if they are 32bit.  If you wanted to actually use this, I’d recommend changing the target to your domain controller class, and this assumes all your DC’s are 64bit (they sure should be!)

Regardless, this should be a fairly useful example for monitoring for the existence of a file, and how to pass a property to a condition detection in a recovery.

I will attach the demo MP below.

Demo.FileExists.Monitor.xml.zip


Comments (6)

  1. Kevin Holman says:

    David’s example is a good one – however that was exactly my point – he is passing the output of the monitor state as a parameter to the script. There are actually a lot of examples on the web about how to do this. My blog post was how to take an output from the monitor, and use it in a condition detection of a recovery, which is unique, and the syntax changes.

  2. Anonymous says:

    SCOM has many different ways to monitor for a file size. Here are some simple examples using script and

  3. Sunil_03 says:

    Hi Kevin thanks for the post,
    Can we modify the script for two parameters.

    File age should ne less than 10 minutes than only alert should come and auto resolve after 30 minutes.
    file name contains the date also in the name , is it possible to include wildcard option in the file name here as the file gets created whenever any job fails.
    so we have multiple files with the common name with date mentioned

    For eg hs_data_1103,hs_data_1203.

    Thanks
    Sunil

  4. Hi Kevin,

    I have a script which test the share availability.

    I am trying to create a script based monitor, when the share doesn’t exit I want a alerts. The script looks good however in the monitor I am bit confused what Expressions I have to use for Health and Unhealthy. Below is the script.

    =====================================================
    Dim objFSO, strRevBackupServerPath, strNetworkPathFolder

    strRevBackupServerPath="\inb-om2012R2labTest"

    Set objFSO = CreateObject("Scripting.FileSystemObject")

    If objFSO.FolderExists(strRevBackupServerPath & strNetworkPathFolder) Then
    Wscript.Echo "Share Exists"

    Else
    WScript.Echo "Share Does Not Exist"

    End If
    ========================================================

    Any assistance in this is Highly appreciated.

    Regards,
    Satish Phatge.

  5. Andre says:

    Good Day Kevin,

    Fantastic post, very informative, however: how does the VBScript Execute? For instance, if you have a gateway server where the server is contactable through that gateway, will the VBScript run on the Gateway where the server is managed? regards

Skip to main content