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. I run into a somewhat similar problem here at Microsoft, where I want to take scripts I’ve built to work with internal applications and make them easy for people to use, even if they’re not already using PowerShell. I don’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.
Doing this is actually really easy. All I need is a windows file share. In that file share, I’ll put this little batch file (InstallModule.cmd) and I’ll make two subfolders, x86 (where I’ll put the x86 CTP3 msi) and amd64 (where I’ll put the amd64 CTP msi). Writing a .CMD file on the PowerShell Team Blog makes me want to take a shower, but its a necessary evil in this case.
if exist %windir%\system32\WindowsPowerShell\v1.0\powershell.exe goto :AlreadyInstalled \\MyServer\MyShare\%processor_architecture%\PowerShell_Setup.msi :AlreadyInstalled echo %~dp0 xcopy "%~dp0\%1" "%userprofile%\Documents\WindowsPowerShell\Modules\%1" /y /s /i /d
Excuse my while I take a shower… Still there? I feel better now. 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.
The first line goes to the Windows Directory (%windir%) and checks for powershell.exe. If it’s there, it goes to the label :AlreadyInstalled, thus skipping the install. If it’s not there, then it goes to the directory with the appropriate .MSI and installs PowerShell. echo %~dp0 will output the location that the .CMD file InstallModule.cmd is in. It’s an artifact of when I wrote it, and a sanity check for the next person running the script. The final line uses some batch voodoo and the xcopy command to install the module. %~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’s %userprofile% (in my case C:\Users\JamesBru) + \Documents\WindowsPowerShell\Modules\ModuleName. The first flag (/y) prevents you from seeing prompts. The second flag (/s) copies subdirectories. The third flag (/i) indicates that the destination is a directory. The final flag (/d) indicates that I should only copy files newer 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. XCopy is useful, but I need another shower.
Still there? Good.
Now you can simply create a lot of folders beneath \\MyServer\MyShare that contain modules. It doesn’t matter to this script if the modules were compiled or scripts. If you want to make it easier to install a single module, you can put in a small file, like InstallMyModule.cmd. InstallMyModule.cmd is always very simple. It’s just: \\myServer\MyShare\InstallModule.cmd MyModule. Since each module is being installed to the users’ directory, you don’t even need to bother to run InstallMyModule.cmd elevated.
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’ll ever need and makes it easier for everyday users to start using PowerShell.
Hope this Helps,
James Brundage [MSFT]