Wednesday, February 8, 2012

Using System Center Orchestrator 2012 to monitor folders

One big drawback with the existing "Monitor Folder" activity in System Center Orchestrator 2012 RC is that it will only trigger on files dropped while your runbook is actually running. That means that if you temporarily stop your runbook to do an adjustment, all files that some other system drops in your folder while doing this will be ignored when you start your runbook again.

It's pretty easy to avoid this by instead scheduling a powershell script that returns all files in your folder.
Here's a simple example:

Start by adding a Monitor Date/Time activity and set an appropriate polling interval. I'll set mine to 1 minute.


Next add a "Run .Net Script" activity and link that to the monitor acitivity. Select PowerShell as language and paste this into the script window (modify it to your own lab folder). The *copy* file mask is by the way a handy tip when developing these kind of workflows. Using this you will be able to keep a file in your dev directory and just copy-paste it in the same directory to kick your workflow.

$FileName = (Get-ChildItem c:\temp\lab\*copy*.xml) | Select-Object FullName
$Count=@(Get-ChildItem c:\temp\lab\*copy*.xml).Count

The $Count parameter will be used to decide whether or not to continue and the $FileName parameter will be used to perform some kind of operations on that file.



Now set the data that will be published:


Now you're all set to continue building your runbook. In my example i will just copy the file to another location. On the link set the following condition




Now add the copy file activity. 

As you may note I do a little magic on the FileName parameter…Here’s a better view on that




This is what my runbook looks like. I also log when no files are found in this example (set NumberOfFiles equals 0 on the link if you want to do that as well)


11 comments:

  1. Nice workaround, I was having this same problem. I can't copy/paste this line and can't get it to work, and can't figure out what it's suppose to be doing:

    [field(field({FileName from "Run .Net Script"},'=',2),'}',1)]

    ReplyDelete
  2. Hi there

    The reason for doing this is that, at least for me, looking at the resulting filename parameter string from the Run .Net Script activity is something like "@{FullName=\\myserver\dropzone\incomingfiles\testfilecopy.xml}".

    I then need to extract just the filepath by
    1. split on '=' and take second part. Leaving us with "\\myserver\dropzone\incomingfiles\testfilecopy.xml}" - note that we still have an ending '}'
    2. split on '}' and take the first part. Leaving us with "\\myserver\dropzone\incomingfiles\testfilecopy.xml"

    And you cant copy paste the {FileName from "Run .Net Script"}. Right click and choose Subscribe - Published data and choose the FileName parameter from Run.Net Script.

    Hope this helps!

    //Joakim

    ReplyDelete
  3. Hi,

    Great workaround, thanks for that. I'm using Scorch 2012 SP1, and am planning on using this workaround for a runbook. Just one question, is there some way to get the monitor date/time activity to stop once the .NET script has run and found a file? I basically want the runbook to keep checking for a file, but once the file is found, it should stop checking until the runbook is restarted manually.

    Thanks

    ReplyDelete
  4. Hi Kunal!

    sorry for a very late reply. I havn't tried it myself but I found this....

    http://jmattivi.blogspot.se/2012/06/stopping-canceling-runbook-job-w.html

    ReplyDelete
  5. Maybe a bit late reply to this article as well but I see a problem when you only have 1 file in the directory. If there is only one file then you cannot use the '.count' method since it's not an array. Therefore you will receive a null value instead of 0 so the link afterwards will not work. I suppose you can work-around it by using a "ForEach" in the script to count the files or changing the link to also allow a null value to pass on.

    ReplyDelete
    Replies
    1. Forgot to mention: 'count' does work when you use PowerShell 3.0 but at the moment the version of Powershell used by Orchestrator is still 2 afaik.

      Delete
    2. Hi

      Thats strange. I tried it and it works for me with both powershell 2 and 3

      Delete
    3. That is pretty weird indeed... This is a little piece of code I just ran on the two machines with different versions of PS

      Machine A:
      PS C:\> $a = get-childItem "C:\temp\OneFileFolder"
      PS C:\> write-output "I am Version: $($host.version.major)"
      I am Version: 3
      PS C:\> If(!$($a.count)) { "I have no value"} else {"My value is $($a.count)"}
      My value is 1

      Machine B:
      PS C:\> $a = get-childItem "C:\temp\OneFileFolder"
      PS C:\>
      PS C:\> write-output "I am Version: $($host.version.major)"
      I am Version: 2
      PS C:\> If(!$($a.count)) { "I have no value"} else {"My value is $($a.count)"}
      I have no value


      Another Powershell mystery I guess :) ...






      Delete
    4. Not sure if you saw this...

      Aaah, now I see. You have to add the @ like I've done, otherwise it will fail. So....

      @(Get-ChildItem c:\temp\lab\*copy*.xml).Count - works
      (Get-ChildItem c:\temp\lab\*copy*.xml).Count - returns nothing

      Delete
  6. Aaah, now I see. You have to add the @ like I've done, otherwise it will fail. So....

    @(Get-ChildItem c:\temp\lab\*copy*.xml).Count - works
    (Get-ChildItem c:\temp\lab\*copy*.xml).Count - returns nothing

    ReplyDelete
    Replies
    1. Ahah great ... a small change that makes a big difference. Thanks for your time.

      Delete