{"id":52563,"date":"2009-09-01T03:01:00","date_gmt":"2009-09-01T03:01:00","guid":{"rendered":"https:\/\/blogs.technet.microsoft.com\/heyscriptingguy\/2009\/09\/01\/hey-scripting-guy-can-i-open-a-file-dialog-box-with-windows-powershell\/"},"modified":"2009-09-01T03:01:00","modified_gmt":"2009-09-01T03:01:00","slug":"hey-scripting-guy-can-i-open-a-file-dialog-box-with-windows-powershell","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/scripting\/hey-scripting-guy-can-i-open-a-file-dialog-box-with-windows-powershell\/","title":{"rendered":"Hey, Scripting Guy! Can I Open a File Dialog Box with Windows PowerShell?"},"content":{"rendered":"<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\"><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Question\" border=\"0\" alt=\"Hey, Scripting Guy! Question\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/q-for-powertip.jpg\" width=\"34\" height=\"34\"><\/p>\n<p class=\"MsoNormal\">Hey, Scripting Guy! I am a faithful reader of the Hey, Scripting Guy! articles and have been a Dr. Scripto fan for years. I love your new TechNet Script Center Gallery too by the way. It is much easier to use and to locate scripts than what you had before. I had no idea you had so many scripts up there. WOW! Anyway, I have this script that I have used for a while that I got off the old Script Repository that creates a <a href=\"http:\/\/bit.ly\/18Mj7p\"><font face=\"Segoe\">common dialog box to open a file explorer<\/font><\/a> window.<span>&nbsp;<\/span>The problem is the script does not work on Windows Vista, and I have also tried it on Windows 7 and it does not work there either. Is there any easy way to open a file dialog box so that I can use a file picker to select a file path instead of having to type in a long file name and location?<\/p>\n<\/p>\n<p class=\"MsoNormal\">&#8212; PG<\/p>\n<p class=\"MsoNormal\">\n<p><span><img decoding=\"async\" class=\"nearGraphic\" title=\"Hey, Scripting Guy! Answer\" border=\"0\" alt=\"Hey, Scripting Guy! Answer\" align=\"left\" src=\"https:\/\/devblogs.microsoft.com\/wp-content\/uploads\/sites\/29\/2019\/02\/a-for-powertip.jpg\" width=\"34\" height=\"34\"><\/span><\/p>\n<\/p>\n<p class=\"MsoNormal\">Hello PG, Microsoft Scripting Guy Ed Wilson here. Ah, the old <b>UserAccounts.CommonDialog<\/b> problem. There was an article posted way back in January 2005 called, <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2005\/01\/28\/how-can-i-show-users-a-dialog-box-for-selecting-files.aspx\"><font face=\"Segoe\">How Can I Show Users a Dialog Box for Selecting Files?<\/font><\/a> Along with the script you found on the Script Repository, that is about it for documentation. As far as I can recall, I never saw any documentation about the <b>UserAccounts.CommonDialog<\/b> object on MSDN, so it was an undocumented object. (I actually had another question a while back that I answered during <a href=\"http:\/\/blogs.technet.com\/heyscriptingguy\/archive\/2009\/05\/15\/quick-hits-friday-the-scripting-guys-respond-to-a-bunch-of-questions-05-15-09.aspx\"><font face=\"Segoe\">Quick-Hits Friday<\/font><\/a>.) Using undocumented objects is always an iffy proposition at best, but it is also fun<span>&mdash;<\/span>until your scripts start to break. The <b>UserAccounts.CommonDialog<\/b> object was removed from Windows Vista because of security concerns. <\/p>\n<p class=\"MsoNormal\">You can accomplish the same thing, in a very similar manner as a matter of fact, by using Windows PowerShell. I have taken the liberty of writing a pretty cool function that is called <b>Get-FileName<\/b> that you will be able to use to accomplish your file-picking needs. The good thing is that the <b>Get-FileName<\/b> function uses a standard .NET Framework class that is documented on MSDN, so it will be easy for you to add additional capabilities to the function if you desire to do so. I have placed the function in a script that I call Get-FileNameFunction.ps1, so you will be able to easily play around with the function, get familiar with it, and do some exploration with it. After you get it tuned the way you like it, you may want to consider placing it in a function library or even putting it in your Windows PowerShell profile. The complete Get-FileNameFunction.ps1 script is seen here. <\/p>\n<p class=\"CodeBlockScreenedHead\"><strong>Get-FileNameFunction.ps1<\/p>\n<p><\/strong><\/p>\n<p class=\"CodeBlockScreened\"><span><font><font face=\"Lucida Sans Typewriter\">Function Get-FileName($initialDirectory)<br>{<span>&nbsp;&nbsp; <\/span><br><span>&nbsp;<\/span>[System.Reflection.Assembly]::LoadWithPartialName(&#8220;System.windows.forms&#8221;) |<br><span>&nbsp;<\/span>Out-Null<\/p>\n<p><span>&nbsp;<\/span>$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog<br><span>&nbsp;<\/span>$OpenFileDialog.initialDirectory = $initialDirectory<br><span>&nbsp;<\/span>$OpenFileDialog.filter = &#8220;All files (*.*)| *.*&#8221;<br><span>&nbsp;<\/span>$OpenFileDialog.ShowDialog() | Out-Null<br><span>&nbsp;<\/span>$OpenFileDialog.filename<br>} #end function Get-FileName<\/p>\n<p># *** Entry Point to Script ***<\/p>\n<p>Get-FileName -initialDirectory &#8220;c:fso&#8221;<\/p>\n<p><\/font><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The <b>Get-FileName<\/b> function begins by using the <b>Function<\/b> keyword to define the function, followed by the function name, and then the <b>input<\/b> parameter. The function name uses the two part Verb-Noun naming standard that is important for Windows PowerShell 2.0. The <b>input<\/b> parameter is defined inside the parentheses by the variable <b>$initialDirectory<\/b>. This variable will have a scope inside the <b>Get-FileName<\/b> function. The function then opens with a script block, which is delimited by a pair of curly brackets. The opening curly bracket immediately follows the function declaration. The function declaration, input variable, and opening curly bracket are seen here. <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Function Get-FileName($initialDirectory)<br>{<span>&nbsp;&nbsp; <\/span><\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Next we will need to load the .NET Framework assembly that contains the ability to create Windows forms. To do this in Windows PowerShell 1.0, you must use the <b>LoadWithPartialName<\/b> static method from the <b>System.Reflection.Assembly<\/b> .NET Framework class. <\/p>\n<p class=\"Readeraidonly\"><span>(Actually there <i>is<\/i> another method to load the assembly, but it is worse than this one, and I will not go over it right now. To be fully transparent, the <b>LoadWithPartialName<\/b> static method is deprecated. However, it has been deprecated for several versions of the .NET Framework, and has not been made obsolete yet, I suspect partially because the other method is so much worse. ) <\/p>\n<p><\/span><\/p>\n<p class=\"MsoNormal\">The <b>LoadWithPartialName<\/b> static method takes the name of the assembly that contains the .NET Framework classes you want to use. This is important because you will not always know the name of the assembly, unless you look it up on MSDN. Today we will be using the <b>System.Windows.Forms.OpenFileDialog<\/b> .NET Framework class. When we look at the <a href=\"http:\/\/bit.ly\/SNEH9\"><font face=\"Segoe\">class reference information on MSDN<\/font><\/a> at the top of the class page, it tells you the namespace and the assembly. In this example, the <b>OpenFileDialog<\/b> class resides in the <b>System.Windows.Forms<\/b> namespace. The assembly is also named <b>System.Windows.Forms<\/b>. (Sometimes, the assembly name and the namespace name are different. These are occasions when you must get familiar with the MSDN documentation.) This is seen here:<\/p>\n<p class=\"Fig-Graphic\"><span><img decoding=\"async\" title=\"Image of the OpenFileDialog Class\" alt=\"Image of the OpenFileDialog Class\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/september\/hey0901\/hsg-09-01-09-01.jpg\" width=\"600\" height=\"429\"><a href=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/september\/hey0901\/hsg-09-01-09-01.jpg\"><font face=\"Segoe\"><\/font><\/a><\/span><\/p>\n<p class=\"Fig-Graphic\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"MsoNormal\">Because I always refer to .NET Framework classes by their full name, I always know the namespace. This is because the <b>System.Windows.Forms.OpenFileDialog<\/b> class resides in the <b>System.Windows.Forms<\/b> namespace. Only the last part of the name is the actual class name. The first portion (<b>System.Windows.Forms<\/b>) points to the namespace in which the class resides. Knowing about the .NET Framework class namespaces is a great way to find other classes that are related to a common topic. Because this week we are looking at creating Windows PowerShell scripts that use graphical components, it makes sense to open MSDN and peruse the <b>System.Windows.Forms<\/b> .NET Framework namespace. This is kind of like going to the library, finding a single book on a topic such as <a href=\"http:\/\/blogs.msdn.com\/microsoft_press\/archive\/2009\/07\/06\/ed-wilson-lessons-from-glenn-miller.aspx\"><font face=\"Segoe\">big band music<\/font><\/a> in the United States, going to the open stacks, and looking around in that general area for other books about big band music. It is a great way to find interesting books, and by extraction, the technique is a great way to find interesting .NET Framework classes. <\/p>\n<p class=\"MsoNormal\">When you call the <b>LoadWithPartialName<\/b> static method, it provides feedback when the assembly is loaded. If the assembly is not loaded, because it is not found or it is spelled incorrectly, no error is generated. Because of this, you will want to insure that the code is working properly. I like to test this inside a Windows PowerShell console. This is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">PS C:&gt; [System.Reflection.Assembly]::LoadWithPartialName(&#8220;System.windows.forms&#8221;<br>)<\/p>\n<p>GAC<span>&nbsp;&nbsp;&nbsp; <\/span>Version<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>Location<br>&#8212;<span>&nbsp;&nbsp;&nbsp; <\/span>&#8212;&#8212;-<span>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <\/span>&#8212;&#8212;&#8211;<br>True<span>&nbsp;&nbsp; <\/span>v2.0.50727<span>&nbsp;&nbsp;&nbsp;&nbsp; <\/span>C:WINDOWSassemblyGAC_MSILSystem.Windows.Forms2.0&#8230;.<\/p>\n<p><br>PS C:&gt;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Once I know it is working properly, I pipe the returned information to the <b>Out-Null<\/b> cmdlet to remove the distracting feedback mechanism. This is seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>[System.Reflection.Assembly]::LoadWithPartialName(&#8220;System.windows.forms&#8221;) |<br><span>&nbsp;<\/span>Out-Null<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">It is time to create an instance of the <b>System.Windows.Forms.OpenFileDialog<\/b> .NET Framework class. To do this you will want to use the <b>New-Object<\/b> cmdlet and give it the full name of the .NET Framework class you are working with. Store the resulting instance of an <b>OpenFileDialog<\/b> class in a variable named <b>$OpenFileDialog<\/b>. This is seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$OpenFileDialog = New-Object System.Windows.Forms.OpenFileDialog<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">After you have an instance of the <b>OpenFileDialog<\/b> class, you can assign values for a couple of properties. The <b>initialDirectory<\/b> property is used to control where the file dialog box will open. This is something that is best left up to the script to decide, so I decided to use a variable here (the same one that is passed to the function) to control the initial location. A cool thing to do is to store the location in the registry and to read the value from the registry each time the function is called. In this way, the file dialog box will always return to the last used location. The <a href=\"http:\/\/msdn.microsoft.com\/en-us\/library\/system.windows.forms.filedialog.filter.aspx\"><font face=\"Segoe\">Filter property<\/font><\/a> is used to configure which files are displayed in the dialog box. The filter string contains a description of the filter, followed by the vertical bar (|), and the filter pattern. You are allowed to have multiple filters as long as you separate each filter by a semicolon. The filter pattern I have defined is a simple one that shows all files. This is seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$OpenFileDialog.initialDirectory = $initialDirectory<br><span>&nbsp;<\/span>$OpenFileDialog.filter = &#8220;All files (*.*)| *.*&#8221;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">To show the dialog box, you call the <b>ShowDialog<\/b> method. Because the method will return status information to the Windows PowerShell console, I pipe the return to the <b>Out-Null<\/b> cmdlet as seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$OpenFileDialog.ShowDialog() | Out-Null<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">Windows PowerShell functions always return a value. There is little need to use the <b>Return<\/b> statement to return the value. When the <b>filename<\/b> property is neither captured in a variable nor written out, it will be returned to the calling code. This makes it easy to use the returned <b>filename<\/b> that was selected in the dialog box for other purposes. After we have returned the file name and closed the curly brackets, the function is complete. When closing curly brackets to close out a function, I consider it to be a best practice to always include an ending comment character that states the curly bracket is ending the function and the name of the function. This practice makes your code much easier to read. This is seen here: <\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\"><span>&nbsp;<\/span>$OpenFileDialog.filename<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">\n<p>&nbsp;<\/p>\n<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">} #end function Get-FileName<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">The entry point to the script is simple; I pass a path to the <b>initialDirectory<\/b> parameter when I call the <b>Get-FileName<\/b> function. This is seen here:<\/p>\n<p class=\"CodeBlock\"><span><font face=\"Lucida Sans Typewriter\">Get-FileName -initialDirectory &#8220;c:fso&#8221;<\/p>\n<p><\/font><\/span><\/p>\n<p class=\"MsoNormal\">When the script runs, the <strong>Open<\/strong> dialog box that is seen here appears:<\/p>\n<p class=\"Fig-Graphic\"><span><img decoding=\"async\" title=\"Image of the Open file dialog box\" alt=\"Image of the Open file dialog box\" src=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/september\/hey0901\/hsg-09-01-09-02.jpg\" width=\"563\" height=\"412\"><a href=\"http:\/\/img.microsoft.com\/library\/media\/1033\/technet\/images\/scriptcenter\/qanda\/hsg\/2009\/september\/hey0902\/hsg-09-01-09-02.jpg\"><font face=\"Segoe\"><\/font><\/a><\/span><\/p>\n<p class=\"MsoNormal\">&nbsp;<\/p>\n<p class=\"MsoNormal\">PG, thank you for your kind words, and thank you for asking us to look at <strong>Open<\/strong> file dialog boxes. Join us tomorrow as graphical Windows PowerShell week continues. If you want to know what we will be looking at tomorrow, follow us on <a href=\"http:\/\/www.twitter.com\/scriptingguys\/\"><font face=\"Segoe\">Twitter<\/font><\/a> or <a href=\"http:\/\/www.facebook.com\/group.php?gid=5901799452&amp;ref=ts\">Facebook<\/a>. If you have any questions, send e-mail to <a href=\"http:\/\/blogs.technet.commailto:scripter@microsoft.com\"><font face=\"Segoe\">scripter@microsoft.com<\/font><\/a> or post it on the <a href=\"http:\/\/social.technet.microsoft.com\/Forums\/en\/ITCG\/threads\/\">Official Scripting Guys Forum<\/a>. See you tomorrow. Until then, take care and happy scripting.&nbsp;<br><\/p>\n<p>&nbsp;<\/p>\n<\/p>\n<p><b><span>Ed Wilson and Craig Liebendorfer, Scripting Guys<\/p>\n<p><\/span><\/b><\/p>\n<p>&nbsp;<\/p>\n","protected":false},"excerpt":{"rendered":"<p>&nbsp; Hey, Scripting Guy! I am a faithful reader of the Hey, Scripting Guy! articles and have been a Dr. Scripto fan for years. I love your new TechNet Script Center Gallery too by the way. It is much easier to use and to locate scripts than what you had before. I had no idea [&hellip;]<\/p>\n","protected":false},"author":595,"featured_media":87096,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[71,3,4,45],"class_list":["post-52563","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scripting","tag-graphical","tag-scripting-guy","tag-scripting-techniques","tag-windows-powershell"],"acf":[],"blog_post_summary":"<p>&nbsp; Hey, Scripting Guy! I am a faithful reader of the Hey, Scripting Guy! articles and have been a Dr. Scripto fan for years. I love your new TechNet Script Center Gallery too by the way. It is much easier to use and to locate scripts than what you had before. I had no idea [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/52563","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\/595"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/comments?post=52563"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/posts\/52563\/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=52563"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/categories?post=52563"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/scripting\/wp-json\/wp\/v2\/tags?post=52563"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}