UPDATE: I am now maintaining this script over on my Warcraft Wiki site on pbwiki. Please go there for documentation and the most recent updates.
I couldn’t resist. Sometimes I don’t even know why I do these things. Last night I decided to start playing with System.Net.WebClient from Windows PowerShell and four hours later I had something close. A few more hours today and now I have a PowerShell script that:
- Updates Subversion working copies (can be disabled w/ a switch)
- Can be configured to check for updates from wowinterface.com using a simple data file in your addons folder called addons.ps1 (see the comment header below for a sample of this file) and a nice XML endpoint provided by the guys at wowi (thanks Dolby!)
- Will check to see if an addon is one of the WowAce family of addons and will try to update it from their using their RSS feed for information.
I know I can add more addon sites to this later, but now that Auctioneer is up on wowi (ID: 4812) I don’t know if I have any addons that I use that can’t be updated by this script. Perhaps one or two, but that isn’t bad given that I have 169 addons in my Addons directory.
This script has a few dependencies for extracting ZIP and RAR files. You will need to get unzip.exe from Info-ZIP and UnRar.exe from RARLabs _place_holder;and put them both on your path. Both are free.
Anyway, here is the script. There is a download at the bottom of this post for those of you who just want to have it.
DISCLAIMER: This script is supplied without warranty or support. If you play WoW and don’t know anything about PowerShell, this might be a bit much for you. Take a look at WowAceUpdater or WUU instead.
1 #########################################################################
2 # Name: update-addons.ps1
3 # Version: 1.0
4 # Author: Peter Provost <peter@provost.org>
5 #
6 # Usage: update-addons [-skipSvn]
7 #
8 # Remarks: This is a simple powershell script for updating your
9 # World of Warcraft addons. It will autodetect SVN working copies
10 # and update them. It will look for a file called addons.ps1
11 # in your Addons folder to define special locations for downloading
12 # addons (see below for a sample addons.ps1). After that it will test
13 # if the addon can be updated from [http://files.wowace.com](http://files.wowace.com). Any addon
14 # still unmatched will be skipped.
15 #
16 # This sample addons.ps1 hows how to configure updates from
17 # wowinterface.com:
18 #
19 # $wowiAddons = @{
20 # 'FlightMap' = 3897;
21 # 'Clique' = 5108;
22 # };
23 #
24 # At this point only wowinterface.com is supported in this data file
25 # but more may be added later.
26 #
27 #########################################################################
28
29 **param** (
30 **[switch]** $skipSvn
31 );
32
33 # Configuration - change these as needed
34 $wowAddonDir = "C:\World of Warcraft\Interface\Addons";
35 $stateFile = "PSUpdateAddons.state";
36
37 **function** update-addon($addonSource, $downloadUrl, $remoteVersion, $fileName)
38 {
39 **if** ( $remoteVersion -**ne** $localVer) {
40 **write-host** "$_ : ($addonSource) Update required: Current ver=$localVer, Remote ver=$remoteVersion";
41
42 $tempFilePath = **join-path** $tempDir $fileName;
43 **downloadextract-addon** $downloadUrl $tempFilePath;
44
45 **write-host** "`tUpdating state file..." -noNewLine;
46 $remoteVersion > $stateFilePath;
47 "done." | **write-host**;
48 } **else** {
49 **write-host** "$_ : ($addonSource) Addon up-to-date. Skipping.";
50 }
51 }
52
53 # Helper function for updating a single addon]
54 **function** downloadextract-addon (**[string]** $uri, **[string]** $tempFile)
55 {
56 **write-host** "`tDownloading $uri to $($tempFile)..." -noNewLine;
57 $wc.DownloadFile( $uri, $tempFile );
58 **write-host** "done.";
59
60 $ext = **[System.IO.Path]**::GetExtension($tempFile);
61 **switch** ($ext) {
62 ".rar" {
63 **write-host** "`tExtracting RAR Archive..." -noNewLine;
64 & unrar x -o+ $tempFile $wowAddonDir;
65 }
66 ".zip" {
67 **write-host** "`tExtracting ZIP Archive..." -noNewLine;
68 & unzip -o $tempFile -d $wowAddonDir;
69 }
70 **default** { **write-host** "UNKNOWN EXTENSION TYPE!" }
71 }
72 **write-host** "done.";
73
74 **write-host** "`tDeleting zip file..." -noNewLine;
75 **remove-item** $tempFile;
76 **write-host** "done.";
77 }
78
79 **function** test-wowaceaddon( **[string]** $addonName )
80 {
81 **return** ((**get-wowaceaddon** $addonName)-**ne** $null)
82 }
83
84 **function** get-wowaceaddon( **[string]** $addonName )
85 {
86 $xpath = ("//item[title='ADDON']" -**replace** 'ADDON', $_.Name);
87 **return** $indexXmlDoc.SelectSingleNode($xpath);
88 }
89
90 # Setup a few things before we get started
91 $wc = **new-object** System.Net.WebClient;
92 $tempDir = **join-path** (**get-content** env:\temp) "PsWowUpdater";
93 **if** (-**not** (**test-path** $tempDir)) { **new-item** -type directory -path $tempDir; }
94
95 # Load in the WowAce Index file
96 **write-host** "Downloading latest.xml from [http://files.wowace.com](http://files.wowace.com)";
97 $uri = "[http://files.wowace.com/latest.xml](http://files.wowace.com/latest.xml)";
98 $rssData = $wc.DownloadString($uri);
99 $indexXmlDoc = **[xml]** $rssData;
100
101 # Load in the WOWI config database
102 . (**join-path** $wowAddonDir "addons.ps1")
103
104 (**get-childitem** $wowAddonDir | ? { $_.PSIsContainer }) | % {
105 ## SVN UPDATE
106 **if** (**join-path** $_.Fullname ".svn" | **test-path** ) {
107 **if** ($skipSvn.isPresent) {
108 **write-host** "$_ : Skipping SVN working copy";
109 } **else** {
110 **write-host** "$_ : Updating SVN working copy";
111 svn up -q $_.Fullname;
112 }
113 }
114
115 ## WOWINTERFACE.COM
116 **elseif** ($wowiAddons.Contains($_.Name)) {
117 $stateFilePath = **join-path** $_.Fullname "PSUpdateAddons.state";
118 $localVer = "";
119 **if** (**test-path** $stateFilePath) { $localVer = (**get-content** $stateFilePath); }
120
121 $uri = ("[http://www.wowinterface.com/patcherXXXX.xml](http://www.wowinterface.com/patcherXXXX.xml)" -**replace** "XXXX", $wowiAddons[$_.Name]);
122 $wowiXml = **[xml]** $wc.DownloadString($uri);
123
124 $downloadUrl = $wowiXml.UpdateUI.Current.UIFileURL;
125 $remoteVersion = $wowiXml.UpdateUI.Current.UIVersion;
126 $fileName = $wowiXml.UpdateUI.Current.UIFile;
127 $addonSource = "WowInterface.com";
128
129 **update-addon** $addonSource $downloadUrl $remoteVersion $fileName
130 }
131
132 ## WOWACE FILES
133 **elseif** (**test-wowaceaddon** $_.Name) {
134 $stateFilePath = **join-path** $_.Fullname "PSUpdateAddons.state";
135 $localVer = "";
136 **if** (**test-path** $stateFilePath) { $localVer = (**get-content** $stateFilePath); }
137
138 $elt = **get-wowaceaddon** $_.Name;
139
140 $downloadUrl = $elt.enclosure.url;
141 $remoteVersion = $elt.version;
142 $fileName = $downloadUrl.Substring($downloadUrl.LastIndexOf("/")+1);
143 $addonSource = "WowAce.com";
144
145 **update-addon** $addonSource $downloadUrl $remoteVersion $fileName
146 }
147
148 ## Unknown addon source
149 **else** {
150 **write-host** "$_ : Can't figure this one out. Skipping.";
151 }
152 }
Download update-addons.zip (2KB). And here is my addons.ps1 data file to update my wowi addons. Create a file like that in your Addons folder and the script will find it.