Delivering Version Controlled Tools With PowerShell
The most popular PowerShell user interface IDE is Sapien’s PowerShell Studio which allows for an easy way to create WinForms applications. When packaging PowerShell code into an .exe file you can specify the version number, increasing it with each new release. If you create PowerShell based executable files with this method, the question arises as to how you should deliver the tools. The following solution works for this scenario or any situation to deliver files based on version or even a folder of files.
When delivering tools, you will want to ensure the latest version is being used and may also require the tool to be launched from the desktop to avoid file locks or slow WAN links. This problem arose for me when I was having users run my tools from a file share. The file would often be locked and I would be unable to update it, and the speed of the network to our remote locations caused a long delay in launching the file. I was able to tackle both issues with the following solution.
Step #1: The first thing we need to do is setup some variables. This isn’t required but is much easier to apply across multiple tools. What we are setting here is the source location of the tool and where it will be installed/copied to. In this case we are saving the tool in C:\Users\YourUserName\AppData\Roaming\YourToolName. AppData is a good location as it can be written to without being an administrator of the workstation.
$appfolderpath = $env:appdata.ToString() + "\YourToolName" $app = $appfolderpath + "\YourToolExecutable.exe"
Step #2: We will now expand our variables to include the current application version and the file path.
$appfolderpath = $env:appdata.ToString() + "\YourToolName" $app = $appfolderpath + "\YourToolExecutable.exe" $currentversion = "1.0.1" $sourceapppath = "\\Server\Share\YourApplication\" + $currentversion + "\YourToolExecutable.exe"
Step #3: Since I prefer to leave my PowerShell script static, I use the following method of retrieving the current version from a text file called currentversion.txt located in the source application path. The contents of the text file will simply be the version number which is 1.0.1 in this case.
$appfolderpath = $env:appdata.ToString() + "\YourToolName" $app = $appfolderpath + "\YourToolExecutable.exe" $currentversion = Get-Content "\\Server\Share\YourApplication\currentversion.txt" $sourceapppath = "\\Server\Share\YourApplication\" + $currentversion + "\YourToolExecutable.exe"
Step #4: At this point we need to add the logic that will create the local folder and copy the tool if it doesn’t exist.
$appfolderpath = $env:appdata.ToString() + "\YourToolName" $app = $appfolderpath + "\YourToolExecutable.exe" $currentversion = Get-Content "\\Server\Share\YourApplication\currentversion.txt" $sourceapppath = "\\Server\Share\YourApplication\" + $currentversion + "\YourToolExecutable.exe" if ((Test-Path -Path $appfolderpath) -eq $false) { New-Item -path $env:appdata.ToString() -Name "YourToolName" -Type directory } if ((Test-Path -Path $app) -eq $false) { Copy-Item $sourceapppath -Destination $appfolderpath }
Step #5: If the tool already exists locally, we need to check the version of the file to see if it needs to be updated.
$appfolderpath = $env:appdata.ToString() + "\YourToolName" $app = $appfolderpath + "\YourToolExecutable.exe" $currentversion = Get-Content "\\Server\Share\YourApplication\currentversion.txt" $sourceapppath = "\\Server\Share\YourApplication\" + $currentversion + "\YourToolExecutable.exe" if ((Test-Path -Path $appfolderpath) -eq $false) { New-Item -path $env:appdata.ToString() -Name "YourToolName" -Type directory } if ((Test-Path -Path $app) -eq $false) { Copy-Item $sourceapppath -Destination $appfolderpath } else { if ([System.Diagnostics.FileVersionInfo]::GetVersionInfo($app).FileVersion -ne $currentversion) { Copy-Item $sourceapppath -Destination $appfolderpath } }
Step #6: The last part of the PowerShell is to execute the application with Invoke-Item.
$appfolderpath = $env:appdata.ToString() + "\YourToolName" $app = $appfolderpath + "\YourToolExecutable.exe" $currentversion = Get-Content "\\Server\Share\YourApplication\currentversion.txt" $sourceapppath = "\\Server\Share\YourApplication\" + $currentversion + "\YourToolExecutable.exe" if ((Test-Path -Path $appfolderpath) -eq $false) { New-Item -path $env:appdata.ToString() -Name "YourToolName" -Type directory } if ((Test-Path -Path $app) -eq $false) { Copy-Item $sourceapppath -Destination $appfolderpath } else { if ([System.Diagnostics.FileVersionInfo]::GetVersionInfo($app).FileVersion -ne $currentversion) { Copy-Item $sourceapppath -Destination $appfolderpath } } Invoke-Item $app
Step #7: Now that we have created the script required in Step #6, we can save the file on our file share as \\Server\Share\YourApplication\YourTool.ps1. Let’s examine all of the files that we require to implement this solution.
1) \\Server\Share\YourApplication\YourTool.ps1 – Script from Step #6
2) \\Server\Share\YourApplication\currentversion.txt – Text file containing current version number
3) \\Server\Share\YourApplication\currentversion\YourToolExecutable.exe – Your current .exe located in a shared file share
For example, to update your tool to a new version you would simply need to update \\Server\Share\YourApplication\currentversion.txt from 1.0.1 to 1.0.2 and place your 1.0.2 version of YourToolExecutable.exe in \\Server\Share\YourApplication\1.0.2\.
Step #8: Now we simply need to implement a Shortcut on user’s workstations to launch the tool. A group policy, login script, msi package, or even PowerShell can accomplish this. The following example will create a shortcut in the user’s Start Menu that will launch the PowerShell file. The PowerShell script checks if the tool exists, copies the latest version if required, and launches it locally.
$Shell = New-Object -ComObject ("WScript.Shell") $ShortCut = $Shell.CreateShortcut($env:USERPROFILE + "\Start Menu\Programs\YourTool.lnk") $ShortCut.TargetPath="powershell.exe" $ShortCut.Arguments="-ExecutionPolicy Bypass -File \\Server\Share\YourApplication\YourTool.ps1" $ShortCut.Save()
That is everything you need, and I hope this helps others in the community that would like to improve their current environment. Creating Shortcut (.lnk) files deserves a post on its own and I will cover that in a future article.
1 Response
[…] The solution dips into all kinds of PowerShell techniques including local environment variables, getting text file contents, file version checking and even shortcut (.lnk) creation. If you are also a user of Sapien’s PowerShell Studio, then definitely give this one a read. Check out the solution over on PowerShellBlogger.com. […]