{"id":4601,"date":"2009-01-16T03:52:13","date_gmt":"2009-01-16T03:52:13","guid":{"rendered":"https:\/\/blogs.msdn.microsoft.com\/powershell\/2009\/01\/16\/how-to-make-your-own-module-repository\/"},"modified":"2019-02-18T13:12:52","modified_gmt":"2019-02-18T20:12:52","slug":"how-to-make-your-own-module-repository","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/powershell\/how-to-make-your-own-module-repository\/","title":{"rendered":"How To Make Your Own Module Repository"},"content":{"rendered":"<p>Andy Schneider (from <a href=\"http:\/\/get-powershell.com\/\">Get-PowerShell.com<\/a>) recently asked me how he could make sure that everyone at <a href=\"http:\/\/www.avanade.com\/\">Avanade<\/a> could get a consistent set of modules.&nbsp; I run into a somewhat similar problem here at Microsoft, where I want to take scripts I&#8217;ve built to work with internal applications and make them easy for people to use, even if they&#8217;re not already using PowerShell.&nbsp; I don&#8217;t want the scripts to be broadly available (after all, what is someone outside of Microsoft going to do with a script that works with Product Studio?) but I want the scripts (and PowerShell) to be installed or updated with a single click.<\/p>\n<p>Doing this is actually really easy.&nbsp; All I need is a windows file share. In that file share, I&#8217;ll put this little batch file (InstallModule.cmd) and I&#8217;ll make two subfolders, x86 (where I&#8217;ll put the x86 CTP3 msi) and amd64 (where I&#8217;ll put the amd64 CTP msi).&nbsp; Writing a .CMD file on the PowerShell Team Blog makes me want to take a shower, but its a necessary evil in this case.<\/p>\n<p>Here&#8217;s InstallModule.cmd:<\/p>\n<blockquote>\n<pre>if exist %windir%\\system32\\WindowsPowerShell\\v1.0\\powershell.exe goto :AlreadyInstalled\n\\\\MyServer\\MyShare\\%processor_architecture%\\PowerShell_Setup.msi\n:AlreadyInstalled\necho %~dp0\nxcopy \"%~dp0\\%1\" \"%userprofile%\\Documents\\WindowsPowerShell\\Modules\\%1\" \/y \/s \/i \/d<\/pre>\n<\/blockquote>\n<pre><\/pre>\n<p>Excuse my while I take a shower&#8230;&nbsp; Still there?&nbsp; I feel better now.&nbsp; I feel fairly dirty for posting this .CMD script on a PowerShell blog, but after about 5 minutes in the fetal position I think I feel comfortable enough to explain it.<\/p>\n<p>The first line goes to the Windows Directory (%windir%) and checks for powershell.exe.&nbsp; If it&#8217;s there, it goes to the label :AlreadyInstalled, thus skipping the install.&nbsp; If it&#8217;s not there, then it goes to the directory with the appropriate .MSI and installs PowerShell.&nbsp;&nbsp; echo %~dp0 will output the location that the .CMD file InstallModule.cmd is in.&nbsp; It&#8217;s an artifact of when I wrote it, and a sanity check for the next person running the script.&nbsp; The final line uses some batch voodoo and the xcopy command to install the module.&nbsp; %~dp0\\%1 translates to the subdirectory of the directory InstallModule.cmd is in + the first argument, so if I say \\\\MyServer\\MyShare\\InstallModule FooBar, It will copy from \\\\MyServer\\MyShare\\FooBar. The destination is a little clearer: it&#8217;s %userprofile% (in my case C:\\Users\\JamesBru) + \\Documents\\WindowsPowerShell\\Modules\\<em>ModuleName<\/em>.&nbsp; The first flag (\/y) prevents you from seeing prompts.&nbsp; The second flag (\/s) copies subdirectories.&nbsp; The third flag (\/i) indicates that the destination is a directory.&nbsp; The final flag (\/d) indicates that I should only copy files <em>newer <\/em>than ones already in the directory, if the directory already existed. This means I can update the modules simply by putting newer files on my share and re-running InstallModule.cmd on it.&nbsp; XCopy is useful, but I need another shower.<\/p>\n<p>Still there? Good.<\/p>\n<p>Now you can simply create a lot of folders beneath \\\\MyServer\\MyShare that contain modules.&nbsp; It doesn&#8217;t matter to this script if the modules were compiled or scripts.&nbsp; If you want to make it easier to install a single module, you can put in a small file, like InstallMyModule.cmd.&nbsp; InstallMyModule.cmd is always very simple.&nbsp; It&#8217;s just: \\\\myServer\\MyShare\\InstallModule.cmd MyModule.&nbsp; Since each module is being installed to the users&#8217; directory, you don&#8217;t even need to bother to run InstallMyModule.cmd elevated.<\/p>\n<p>My sincere apologies for blogging command scripts on the PowerShell team blog, but this useful tidbit of knowledge allows you to set up as many small module repositories as you&#8217;ll ever need and makes it easier for everyday users to start using PowerShell.<\/p>\n<p>Hope this Helps,<\/p>\n<p>James Brundage [MSFT]<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Andy Schneider (from Get-PowerShell.com) recently asked me how he could make sure that everyone at Avanade could get a consistent set of modules.&nbsp; I run into a somewhat similar problem here at Microsoft, where I want to take scripts I&#8217;ve built to work with internal applications and make them easy for people to use, even [&hellip;]<\/p>\n","protected":false},"author":600,"featured_media":13641,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[1],"tags":[137,217],"class_list":["post-4601","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-powershell","tag-ctp3","tag-modules"],"acf":[],"blog_post_summary":"<p>Andy Schneider (from Get-PowerShell.com) recently asked me how he could make sure that everyone at Avanade could get a consistent set of modules.&nbsp; I run into a somewhat similar problem here at Microsoft, where I want to take scripts I&#8217;ve built to work with internal applications and make them easy for people to use, even [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/4601","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/users\/600"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/comments?post=4601"}],"version-history":[{"count":0,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/posts\/4601\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media\/13641"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/media?parent=4601"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/categories?post=4601"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/powershell\/wp-json\/wp\/v2\/tags?post=4601"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}