Jump to content

yet Another Microsoft Update Download


Camarade_Tux

Recommended Posts

Hi,

During the last holidays I wrote a program that would parse the now famous mssecure.xml file in order to retrieve updates automatically.

The result is a 130-lines ocaml code which atm relies on an external wget (will be fixed once I get the ocaml terminology for networks):

exception Xml_not_found_by_name_in_xml_list
exception Missing_mssecure_cab
exception Bad_number_of_characters_read_from_mssecure_cab
exception Error_during_expansion_of_mssecure_cab of int
exception Xml_not_found_by_attrib_name_and_value_in_xml_list of string * string

let lang_code=ref ""
let lang_string=ref ""
let product=ref ""
let service_pack=ref ""
let product_id=ref ""
let product_family_id=ref ""
let service_pack_level=ref 0
let service_pack_id=ref ""
let dest_dir=ref "Windows XP Professional SP2 English"
let number_of_updates=ref 0

let rec find_xml_by_name_in_xml_list name=function
|xml::q->if (name=Xml.tag xml) then xml
else find_xml_by_name_in_xml_list name q
|[]->Printf.printf "%s" name; raise Xml_not_found_by_name_in_xml_list

let rec find_xml_by_attrib_name_and_value_in_xml_list attrib_name attrib_value=function
|xml::q->if try attrib_value=Xml.attrib xml attrib_name with _->false then xml
else find_xml_by_attrib_name_and_value_in_xml_list attrib_name attrib_value q
|[]->raise (Xml_not_found_by_attrib_name_and_value_in_xml_list (attrib_name,attrib_value))

let set_lang ()=
Printf.printf "language ?\n";
lang_string:=read_line ();
lang_code:=match !lang_string with
|"English"->"1033"
|"French"->"1036"
|"German"->"1031"
|"Japanese"->"1041"
|_->read_line ()

let set_product ()=
Printf.printf "product ?\n";
product:=read_line ()

let set_service_pack ()=
Printf.printf "service pack level ?\n";
service_pack_level:=int_of_string (read_line ())

let set_destdir ()=
dest_dir:=!product^" "^"SP"^(string_of_int !service_pack_level)^" "^(!lang_string)

let localized_mssecure_cab_location=function
|"1033"->"http://go.microsoft.com/fwlink/?LinkId=18922"
|"1036"->"http://go.microsoft.com/fwlink/?LinkId=18122"
|"1031"->"http://go.microsoft.com/fwlink/?LinkId=18121"
|"1041"->"http://go.microsoft.com/fwlink/?LinkId=18120"
|_->assert false
(* [url="http://go.microsoft.com/fwlink/?LinkID=74689"]http://go.microsoft.com/fwlink/?LinkID=74689[/url] *)

let rec update_concerns_product=function
|xml::q->(("AffectedProduct"=(Xml.tag xml)) && (!product_id=Xml.attrib xml "ProductID") && (!service_pack_id<>"") && (int_of_string !service_pack_id = int_of_string (Xml.attrib (List.hd (Xml.children xml)) "ServicePackID"))) || (update_concerns_product q) (* est-ce qu'il n'y aura toujours qu'un seul "AffectedServicePack" ? *)
|[]->false

let rec list_updates_for_product_out_of_bulletin=function
|xml::q->if ((update_concerns_product (Xml.children xml)) && ("0"=Xml.attrib xml "SBID")) then (Xml.attrib xml "PatchLocationID")::(list_updates_for_product_out_of_bulletin q) else list_updates_for_product_out_of_bulletin q
|[]->[]

let rec list_updates=function
|xml::q->let patches_list=try Xml.children (find_xml_by_name_in_xml_list "Patches" (Xml.children xml)) with _->[] in
let updates=list_updates_for_product_out_of_bulletin patches_list in
if updates!=[] then updates@(list_updates q) else list_updates q
|[]->[]

let rec list_locations updates locations=
match updates,locations with
|[],_
|_,[]->[]
|(update::update_queue),(xml::xml_queue)->begin match compare update (Xml.attrib xml "LocationID") with
|0->((Xml.attrib xml "Path")^"\n")::(list_locations update_queue xml_queue)
|_->list_locations (update::update_queue) xml_queue
end

let rec run_wget_for_each_element_of_the_list n=function
|t::q->let _=Printf.printf "downloading update %d of %d\n" n !number_of_updates in
let _=flush stdout in
let _=Unix.system ("..\\wget.exe -N -nv \""^t^"\"") in
let _=print_endline "" in
run_wget_for_each_element_of_the_list (n+1) q
|[]->Printf.printf "All %d updates successfully downloaded in %s.\n" (n-1) !dest_dir

let solve_escaped_quote in_channel=
let mssecure_xml_length=in_channel_length in_channel in
let s=String.create mssecure_xml_length in
let _=try really_input in_channel s 0 mssecure_xml_length with End_of_file -> raise Bad_number_of_characters_read_from_mssecure_cab in
let i=ref 0 in
let _=while (try s.[!i]<>'3' || s.[!i+1]<>'2' || s.[!i+2]<>'\\' || s.[!i+3]<>'\"' with _->false) do
incr i;
done in
let _=if !i<(mssecure_xml_length-2)
then (s.[!i+2] <- '\"'; s.[!i+3]<-' ')
else Printf.printf "Seems MS has fixed the \\\" problem in mssecure.xml\n"
in s
;;

set_lang (); set_product (); set_service_pack (); set_destdir (); print_endline "";;

let _=print_endline "\nDownloading the localized mssecure cab-file." in
let _=Unix.system (".\\wget.exe -N -nv \""^(localized_mssecure_cab_location !lang_code)^"\"") in
let _=if (Sys.file_exists ("MSSecure_"^(!lang_code)^".cab")) then
let expand_exit_code=Sys.command ("expand MSSecure_"^(!lang_code)^".cab mssecure.xml") in
if expand_exit_code<>0 then raise (Error_during_expansion_of_mssecure_cab expand_exit_code)
else ()
else raise Missing_mssecure_cab
in let xml_parsed=Xml.parse_string (solve_escaped_quote (open_in_bin "mssecure.xml")) in
let this_product_xml=
find_xml_by_attrib_name_and_value_in_xml_list "Name" !product (Xml.children (find_xml_by_name_in_xml_list "Products" (Xml.children xml_parsed))) in
let _=product_id:=
Xml.attrib this_product_xml "ProductID" in
let _=product_family_id:=
Xml.attrib (List.hd (Xml.children (find_xml_by_name_in_xml_list "ProductFamilies" (Xml.children this_product_xml)))) "ProductFamilyID" in
let _=service_pack_id:=
Xml.attrib (List.nth (Xml.children (find_xml_by_name_in_xml_list "AvailableSPs" (Xml.children this_product_xml))) (!service_pack_level-1)) "ServicePackID" in
let bulletins=find_xml_by_name_in_xml_list "Bulletins" (Xml.children xml_parsed) in
let updates=list_updates (Xml.children bulletins) in
let locations=Xml.children (find_xml_by_name_in_xml_list "Locations" (Xml.children xml_parsed)) in
let _=if not (Sys.file_exists !dest_dir) then Unix.mkdir !dest_dir 0o777 else () in
let _=Unix.chdir !dest_dir in
let urls=list_locations updates locations in
let _=number_of_updates:=List.length urls in
let _=Printf.printf "%d updates and %d URLs collected, beginning download :\n" (List.length updates) !number_of_updates in
let _=run_wget_for_each_element_of_the_list 1 urls in
let _=print_endline "All done. The program will now exit." in
read_line ()
;;

(all rights for this source code belong to me, will give a nicer license later on)

Just compile it with "ocamlopt.opt -o upddl.exe unix.cmxa xml-light.cmxa main.ml".

What ? You don't have an ocaml compiler on your computer ! :blink:

OK, you can have binaries too : http://tools.yaxm.org/upddl.7z :P

Just expand and double-click the upddl.exe file but read the instructions and details that follow. ;)

It should work for any product, service pack and language (Japanese is problematic in fact) described in mssecure.xml a.

I get 64 critical updates and HFNetChk returns only this :

	* WINDOWS XP SP2

Patch NOT Installed MS06-014 911562
File C:\Programs\Fichiers communs\system\msadc\msadco.dll has a file
version [2.81.1117.0] that is less than what is expected
[2.81.1124.0].



* INTERNET EXPLORER 6 SP2

Information
There are no entries for Internet Explorer 6 SP2 in the XML file.

The use is a bit strict at the moment : it needs a precise string and is case-sensitive.

- You have four choices for language : French, German, Japanese, English.

- For the product, you have much more choices as this program is not limited to windows, here is the part relevant to hfslip (don't forget, precise names, unlocalized and case-sensitive, I'll make it nicer next week) :

upddl_supported.png

- And for the service pack level, 0, 1, 2 and so on.

For XP SP2 french, I type:

French<return>

Windows XP Professional<return>

2<return>

edit:

Internet Explorer are in another place and can be downloaded with "Internet Explorer 5.5", "Internet Explorer 6", "Internet Explorer 6.0 for Windows Server 2003" as product.

Same goes for MSXML, Outlook Express, WMP (which won't appear in hfnetchk's log as it has been removed by nlite).

But of course there's a problem.

Microsoft just discontinued mssecure.xml files. They are still availables but not updated anymore (probably the reason why I lack some recent updates).

There's a new format but there's no information available about it : http://support.microsoft.com/kb/927745

Basically what is available is "the v2 format is compatible with the v1 [which is not mssecure.xml], refer to information about v1" but there's no way to find information about v1 as everything links to v2...

So I can't have recent hotfixes.

I think I understood the spec but it uses UIDs instead of names (as Microsoft Windows XP) for which I don't have a list. If anyone has a list of UIDs for microsoft products, please share it. Thanks. :)

Have fun. :beer:

Edited by Camarade_Tux
Link to comment
Share on other sites


try ct offline update

Heise is a german publisher and ct a german computer newspaper.

This is the version 4 of offline-updates.

offline-updates is a collection of scripts, some are compiled auto-it-scripts. Source is provided.

It is also based on wget

Edit: new version (4.1) fixed some errors and now supports more languages

Edited by murvun
Link to comment
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now
  • Recently Browsing   0 members

    • No registered users viewing this page.
×
×
  • Create New...