{"id":8691,"date":"2012-07-17T00:01:00","date_gmt":"2012-07-17T00:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2012\/07\/17\/use-powershell-to-monitor-for-the-creation-of-new-files\/"},"modified":"2012-07-17T00:01:00","modified_gmt":"2012-07-17T00:01:00","slug":"use-powershell-to-monitor-for-the-creation-of-new-files","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/use-powershell-to-monitor-for-the-creation-of-new-files\/","title":{"rendered":"Use PowerShell to Monitor for the Creation of New Files"},"content":{"rendered":"<p><b>Summary<\/b>: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to monitor for the creation of new files.<\/p>\n<p>Microsoft Scripting Guy, Ed Wilson, is here. Yesterday&rsquo;s email from KS about his problems with files that contain leading spaces in them got me thinking. Although running a script on demand to find and rename files in a folder might work, it would be better to use an event to monitor the folder for newly created files. Then if the files match the naming pattern discovered yesterday, rename them by using the procedure from the script I posted yesterday in <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2012\/07\/16\/use-powershell-to-detect-and-fix-files-with-leading-spaces.aspx\" target=\"_blank\">Use PowerShell to Detect and Fix Files with Leading Spaces<\/a>.<\/p>\n<p style=\"padding-left: 30px\"><b>Note<\/b>&nbsp;&nbsp;&nbsp;For more information about WMI event driven scripts, see <a href=\"http:\/\/www.aka.ms\/insideWMIevents\" target=\"_blank\">An Insider&rsquo;s Guide to Using WMI Events and PowerShell<\/a>.<\/p>\n<p>Today I am going to develop a WMI event query to detect newly created files in a particular folder. Then I will use this WQL event query tomorrow to create a permanent WMI event consumer. In fact, whenever I am creating a permanent WMI event consumer, I always test it out as a temporary event consumer first. Creating a temporary event consumer with Windows PowerShell&nbsp;2.0 is really easy, so it only makes sense to take this first step.<\/p>\n<h2>Creating a WMI WQL event query<\/h2>\n<p>The hardest part of creating a WMI WQL event query is, well&hellip;just about everything. This stuff does not make much sense. Luckily, if you have WQL event query from VBScript or some other language, it is not too difficult to migrate the query to Windows PowerShell.<\/p>\n<p>When you start trying to do this, however, you run into weird quoting rules that only make a confusing situation more confusing. Luckily, Windows PowerShell can bring some sanity to this part of the process. The secret is to use a here-string. Here-strings are really finicky (they make <a href=\"http:\/\/en.wikipedia.org\/wiki\/Morris_the_Cat\" target=\"_blank\">Morris the Cat<\/a> seem like an omnivore). The basic syntax is to use a variable to hold the resulting here-string. The here-string begins with an ampersand and an opening quotation mark: <b>@&#8221;<\/b>. Everything inside the here-string is interpreted literally so you do not need to worry with escaping special characters or quotation marks or any of that stuff. The here-string closes with a closing quotation mark ampersand: <b>&#8220;@<\/b>.<\/p>\n<p>There are two rules that you must follow:<\/p>\n<ol>\n<li>Immediately after the opening tag <strong>@&#8221;<\/strong>, hit ENTER. Do not press the spacebar and then ENTER; you need the return right after the <b>@&#8221;<\/b>.<\/li>\n<li>The closing tag (<b>&#8220;@<\/b>) must be in position 1 of its own line. You cannot place it at the end of your last line of text, nor can you indent to make things &ldquo;line up.&rdquo; It must be in the first position of its own line.<\/li>\n<\/ol>\n<p>I referred to an old Hey Scripting Guy! Blog, <a href=\"http:\/\/blogs.technet.com\/b\/heyscriptingguy\/archive\/2004\/10\/11\/how-can-i-automatically-run-a-script-any-time-a-file-is-added-to-a-folder.aspx\" target=\"_blank\">How Can I Automatically Run a Script Any Time a File is Added to a Folder<\/a>, which was written nearly eight years ago in VBScript. Guess what? The query was just the thing I needed to refresh my memory for creating my new query. Here is the VBScript query from that blog.<\/p>\n<p style=\"padding-left: 30px\">(&#8220;SELECT * FROM __InstanceCreationEvent WITHIN 10 WHERE &#8221; _<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp; &#8220;Targetinstance ISA &#8216;CIM_DirectoryContainsFile&#8217; and &#8221; _<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp; &#8220;TargetInstance.GroupComponent= &#8221; _<\/p>\n<p style=\"padding-left: 30px\">&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; &amp; &#8220;&#8216;Win32_Directory.Name=&#8221;&#8221;c:\\\\\\\\scripts&#8221;&#8221;&#8216;&#8221;)<\/p>\n<p>You can see where the use of a here-string vastly simplifies things by allowing me to forget about line continuation and having to escape quotation marks and other things. But also you can see how having a nice reference query, even from an eight-year old VBScript script, is also beneficial.<\/p>\n<p style=\"padding-left: 30px\"><b>Note<\/b>&nbsp;&nbsp;&nbsp;This is ONE of the major reasons I insisted on migrating all of the old Hey Scripting Guy! Blogs to the new Hey, Scripting Guy! Blog format four years ago when I became the Scripting Guy. I knew that a lot of that old code was easily adaptable to Windows PowerShell and would be useful for years to come. &nbsp;<\/p>\n<p>The WQL query itself is not too horribly bad. It begins by selecting everything from the <b>__InstanceCreationEvent<\/b> WMI class. This class is a generic event class, and it will monitor for new instances of &ldquo;stuff.&rdquo; It can be anything from a new entry in an event log to a new file. The problem with monitoring for a newly created file is that a file must reside somewhere&mdash;for example, inside a directory. To find a file in a directory by using WMI means that we need to use an association WMI class.<\/p>\n<p>The <b>Cim_DirectoryContainsFile<\/b> WMI class associates files and directories. When working with association classes, there is always a property that relates one to the other. Here we are looking for the <b>GroupComponent <\/b>portion of the association. <b>GroupComponent <\/b>is an instance of the <b>Win32_Directory<\/b> WMI class. Because we are interested in a particular directory, we need to use the <b>Key<\/b> property for <b>GroupComponent<\/b>. Here, the key is the name of the folder. The name of the folder uses POSIX notation; therefore, it requires \\\\\\\\ (four back slashes). The query is shown here.<\/p>\n<p style=\"padding-left: 30px\">$query = @&#8221;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Select * from __InstanceCreationEvent within 10<\/p>\n<p style=\"padding-left: 30px\">&nbsp;where targetInstance isa &#8216;Cim_DirectoryContainsFile&#8217;<\/p>\n<p style=\"padding-left: 30px\">&nbsp;and targetInstance.GroupComponent = &#8216;Win32_Directory.Name=&#8221;c:\\\\\\\\test&#8221;&#8216;<\/p>\n<p style=\"padding-left: 30px\">&#8220;@<\/p>\n<h2>Register the WMI event<\/h2>\n<p>Now I need register the WMI event. In Windows PowerShell&nbsp;2.0 and Windows PowerShell&nbsp;3.0, this is really easy. I use the <b>Register-WmiEvent<\/b> cmdlet and specify the WQL query. I also need to create a value for the <b>SourceIdentifier<\/b><i> <\/i>property so I can monitor the job. Here, I register the WMI event by using the query contained in the <b>$query<\/b> variable, and I specify a <b>SourceIdentifier<\/b><i> <\/i>of <b>MonitorFiles<\/b>.<\/p>\n<p style=\"padding-left: 30px\">Register-WmiEvent -Query $query -SourceIdentifier &#8220;MonitorFiles&#8221;<\/p>\n<p>Upon registering the event, I can do any number of things. The easiest thing to do is to wait for the event to occur. The <b>Wait-Event<\/b> cmdlet will wait for the event that is identified by the <b>SourceIdentifier<\/b><i> <\/i>to trigger. After it does, I store the generated event in the <b>$fileEvent<\/b> variable as shown here.<\/p>\n<p style=\"padding-left: 30px\">$fileEvent = Wait-Event -SourceIdentifier &#8220;MonitorFiles&#8221;<\/p>\n<p>Once again, I could do anything I want to do upon notification that an event triggers. Here, I simply display the complete path to the newly created file. I will use this information tomorrow in my follow-up to today&rsquo;s blog. Notice that the <b>$fileEvent<\/b> variable contains a rich object. You might want to play around with <b>Get-Member<\/b> to explore this object.<\/p>\n<p style=\"padding-left: 30px\">$fileEvent.SourceEventArgs.NewEvent.TargetInstance.PartComponent<\/p>\n<p>When the script runs, it waits for an event to trigger. This behavior is shown in the image that follows.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6102.HSG-7-17-12-01.png\"><img decoding=\"async\" title=\"Image of command output\" alt=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6102.HSG-7-17-12-01.png\" \/><\/a><\/p>\n<p>When I create a file in the c:\\test folder, within 10 seconds the temporary event consumer detects the presence of the newly created file, and <b>Wait-Event<\/b> returns the event to the <b>$fileEvent<\/b> variable. The script then displays the path to the newly created file. The image that follows illustrates the Windows PowerShell ISE following the generation of the new event.<\/p>\n<p><a href=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6746.HSG-7-17-12-02.png\"><img decoding=\"async\" title=\"Image of command output\" alt=\"Image of command output\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/6746.HSG-7-17-12-02.png\" \/><\/a><\/p>\n<h2>Clean up after creating a temporary event subscriber<\/h2>\n<p>If you attempt to run the script a second time, you will more than likely receive errors. The error is because the event <b>SourceIdentifier<\/b><i> <\/i>&ldquo;MonitorFiles&rdquo; already exists. The way to correct this is to unregister the event. You can do this by name, by specifying the <b>SourceIdentifier<\/b><i> <\/i>property of the <b>Unregister-Event<\/b> cmdlet. But the easier way to do this is to use the <b>Get-EventSubscriber<\/b> cmdlet, and pipe the event subscriber to the <b>Unregister-Event<\/b> cmdlet as shown here.<\/p>\n<p style=\"padding-left: 30px\">Get-EventSubscriber | Unregister-Event<\/p>\n<p>The unpredictable results portion of the scenario is that one WMI event already exists&mdash;the one that generated during testing. It is certainly possible to work with multiple events, but it is also easier to just clean up. The easiest way to do this is to find all of the WMI events by using the <b>Get-Event<\/b> cmdlet, and then pipe all the found WMI events to the <b>Remove-Event<\/b> cmdlet. This command is shown here.<\/p>\n<p style=\"padding-left: 30px\">Get-Event | Remove-Event<\/p>\n<p>If you are writing a temporary WMI event consumer script, it makes sense to place the two previous commands into a function called something like <b>Remove-WMIEventAndSubscriber<\/b>. Such a function is shown here.<\/p>\n<p style=\"padding-left: 30px\">Function Remove-WMIEventAndSubscriber<\/p>\n<p style=\"padding-left: 30px\">{<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Get-EventSubscriber | Unregister-Event<\/p>\n<p style=\"padding-left: 30px\">&nbsp;Get-Event | Remove-Event<\/p>\n<p style=\"padding-left: 30px\">} #end function Remove-WmiEventAndSubscriber<\/p>\n<p>A function such as <b>Remove-WMIEventAndSubscriber<\/b> makes testing your script inside the Windows PowerShell ISE much easier, and it saves a lot of typing because you reset the environment each time you decide to run an additional test.<\/p>\n<p>The complete <a href=\"http:\/\/gallery.technet.microsoft.com\/scriptcenter\/Temporarily-monitor-a-0180f189\">TemporaryWMIEventToMonitorFolderForNewFiles.ps1 script<\/a> is uploaded to the Scripting Guys Script Repository. You can download the entire script from there.<\/p>\n<p>That is all there is to using a temporary WMI event to monitor a folder for the creation of a new file. Join me tomorrow for more Windows PowerShell cool stuff.<\/p>\n<p>I invite you to follow me on <a href=\"http:\/\/bit.ly\/scriptingguystwitter\" target=\"_blank\">Twitter<\/a> and <a href=\"http:\/\/bit.ly\/scriptingguysfacebook\" target=\"_blank\">Facebook<\/a>. If you have any questions, send email to me at <a href=\"mailto:scripter@microsoft.com\" target=\"_blank\">scripter@microsoft.com<\/a>, or post your questions on the <a href=\"http:\/\/bit.ly\/scriptingforum\" target=\"_blank\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, peace.<\/p>\n<p><b>Ed Wilson, Microsoft Scripting Guy<\/b>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to monitor for the creation of new files. Microsoft Scripting Guy, Ed Wilson, is here. Yesterday&rsquo;s email from KS about his problems with files that contain leading spaces in them got me thinking. Although running a script on demand to find and rename [&hellip;]<\/p>\n","protected":false},"author":596,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[42,3,45,6],"class_list":["post-8691","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-events-and-monitoring","tag-scripting-guy","tag-windows-powershell","tag-wmi"],"acf":[],"blog_post_summary":"<p>Summary: Microsoft Scripting Guy, Ed Wilson, shows how to use Windows PowerShell to monitor for the creation of new files. Microsoft Scripting Guy, Ed Wilson, is here. Yesterday&rsquo;s email from KS about his problems with files that contain leading spaces in them got me thinking. Although running a script on demand to find and rename [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/8691","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/users\/596"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=8691"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/8691\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media\/87096"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/media?parent=8691"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=8691"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=8691"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}