//---------------------------------------------------------------------
// Project: BuildsHistory
// Version: 1.0
// FileId: f:\Delme\CleanBCD\BuildsHistory
// When: 29 May 2015, Friday, 07:14, Windows build 10125
// Who: Oleg Kulikov,
sysprg@live.ru //---------------------------------------------------------------------
// What for: just for fun: this code is Stand-alone and thus use
// it's own class to work with Registry.
//---------------------------------------------------------------------
//
// Set of the project independent methods used by the project code
//
String.prototype.strip = function()
{
return this.replace( /^(\s*)/, "" ).replace( /(\s*)$/, "" );
}
if ( typeof( repeat ) == "undefined" )
{
String.prototype.repeat = function( n )
{
var tmp = "";
for ( var i = 0; i < n; i++ ) tmp += this;
return tmp;
}
}
String.prototype.left = function( n, char )
{
if ( typeof( char ) == "undefined" ) char = " ";
if ( this.length >= n ) return this.substr( 0, n );
return this + char.repeat( n - this.length );
}
String.prototype.right = function( n, char )
{
if ( typeof( char ) == "undefined" ) char = " ";
if ( this.length > n ) return this.substr( this.length - n );
return char.repeat( n - this.length ) + this;
}
Date.prototype.DateToYYYYMMDD = function()
{
var YYYY = this.getFullYear();
var MM = ( this.getMonth() + 1 ).toString().right( 2, "0" );
var DD = this.getDate().toString().right( 2, "0" );
var hh = ( this.getHours() + 1 ).toString().right( 2, "0" );
var mm = ( this.getMinutes() + 1 ).toString().right( 2, "0" );
var ss = ( this.getSeconds() + 1 ).toString().right( 2, "0" );
return YYYY + "." + MM + "." + DD + " " +
hh + ":" + mm + ":" + ss;
}
//
// end-of-methods Set
//
//
// Start of the project code. Small class myStdReg() follows
//
//---------------------------------------------------------------
// Old-style objectes creation function. Contains some methods
// used to enumerate and read data from the Windows Registry.
// All the methods used in this class are derived from the
// correspondent methods of WMI-class root\default\StdRegProv
//---------------------------------------------------------------
function myStdReg()
{
function StdRegFailed( method, objInParam, objOutParam )
{
var prefix = null;
var valuename = null;
var msg = "";
var GetMethod = ( method.indexOf( "Get" ) > - 1 );
if ( GetMethod )
{
if ( method.indexOf( "StringValue" ) > - 1 ) prefix = "s";
else prefix = "u";
valuename = objInParam.sValueName;
if ( typeof( valuename ) == "undefined" )
{
msg = "*** INTERNAL ERROR: Property sValuName" +
" is not set in input parameters for the method " + method;
WScript.Echo( msg );
WScript.Quit();
}
}
var root = objInParam.hDefKey;
var regPath = objInParam.sSubKeyName;
var msg = "StdRegProv method " + method +
" ReturnValue = " + objOutParam.ReturnValue +
" for the path " + regPath;
if ( GetMethod )
{
var value = objOutParam[ prefix + "Value" ];
msg += ", value name = " + valuename +
" IS_NULL = " + ( value == null );
}
WScript.Echo( msg );
WScript.Quit();
}
var HKCR = 0x80000000;// HKEY_CLASSES_ROOT
var HKCU = 0x80000001;// HKEY_CURRENT_USER
var HKLM = 0x80000002;// HKEY_LOCAL_MACHINE
var HKU = 0x80000003;// HKEY_USERS
var HKCC = 0x80000005;// HKEY_CURRENT_CONFIG
var objLocator = new ActiveXObject( "WbemScripting.SWbemLocator" );
var objService = objLocator.ConnectServer( ".", "root\\default" );
var objReg = objService.Get( "StdRegProv" );
var objMethod = null;
var objInParam = null;
var objOutParam = null;
var res = null;
var root = HKLM;
this.RegReadStringValue = function ( root, regPath, valueName )
{
var res = null, rc;
objMethod = objReg.Methods_.Item( "GetStringValue" );
objInParam = objMethod.InParameters.SpawnInstance_();
objInParam.hDefKey = root;
objInParam.sSubKeyName = regPath;
objInParam.sValueName = valueName;
var res = null;
objOutParam = objReg.ExecMethod_( objMethod.name, objInParam );
if( objOutParam.ReturnValue == 0 && objOutParam.sValue != null )
{
res = objOutParam.sValue;
}
else// ( method, objInParam, objOutParam )
{
rc = StdRegFailed( "GetStringValue", objInParam, objOutParam );
}
return res;
}// End-of-RegReadStringValue
this.RegReadMultiStringValue = function( root, regPath, valueName )
{
var res = null;
objMethod = objReg.Methods_.Item( "GetMultiStringValue" );
objInParam = objMethod.InParameters.SpawnInstance_();
objInParam.hDefKey = root;
objInParam.sSubKeyName = regPath;
objInParam.sValueName = valueName;
objOutParam = objReg.ExecMethod_( objMethod.name, objInParam );
if ( objOutParam.ReturnValue == 0 && objOutParam.sValue != null )
{
res = objOutParam.sValue.toArray().join( "," );
}
else
{
rc = StdRegFailed( "RegReadMultiStringValue", objInParam, objOutParam );
}
return res;
}// End-of-RegReadMultiStringValue
this.RegReadDWORDValue = function ( root, regPath, valueName )
{
var res = null;
objMethod = objReg.Methods_.Item( "GetDWORDValue" );
objInParam = objMethod.InParameters.SpawnInstance_();
objInParam.hDefKey = root;
objInParam.sSubKeyName = regPath;
objInParam.sValueName = valueName;
objOutParam = objReg.ExecMethod_( objMethod.name, objInParam );
if( objOutParam.ReturnValue == 0 && objOutParam.uValue != null )
{
res = objOutParam.uValue;
}
else
{
rc = StdRegFailed( "RegReadDWORDValue", objInParam, objOutParam );
}
return res;
}// End-of-RegReadDWORDValue
this.RegEnumSubKeys = function( root, strRegPath )
{
var res = null;
objMethod = objReg.Methods_.Item( "EnumKey" );
objInParam = objMethod.InParameters.SpawnInstance_();
objInParam.hDefKey = root;
objInParam.sSubKeyName = strRegPath;
objOutParam = objReg.ExecMethod_( objMethod.name, objInParam );
if ( objOutParam.ReturnValue == 0 )
{
res = objOutParam.sNames == null ? null : objOutParam.sNames.toArray();
}
else
{
rc = StdRegFailed( "RegEnumSubKeys", objInParam, objOutParam );
}
return res;
}// End-of-this.RegEnumSubKeys
//
// this method converts registry REG_DWORD date to
// standard JS Date object and returns it.
//
this.RegDateToDate = function( regDate )
{
var jsDate = new Date( 1000 * regDate );
return jsDate;
}
}
//
// End-of-myStdReg()-Class-code
//
//
// Function counts duration of Windows installation
// on base of two Date objects. Is called from
// main object presentation function Show for
// each Build object collected.
//
function CountDuration( WhenFinished, WhenStarted )
{
var Seconds = ( WhenFinished.getTime() / 1000 ).toFixed() -
( WhenStarted.getTime() / 1000 ).toFixed();
var Minutes = ( Seconds / 60 ).toFixed();
if ( Minutes < 60 )
{
return Minutes.toString() + " minutes";
}
var Hours = ( Minutes / 60 ).toFixed();
Minutes = Minutes % 60;
return Hours.toString() + " hours " + Minutes.toString() + " minutes";
}
//
// Objectes collection presentation function.
// Is called from the project test code only.
// Presents detailed information about each of
// the Build objects. The only one presentaion
// function which shows Installation duration.
// Example output for one of the objects is
// given below.
//
/*
-----------------------------------------------------------------------------------------
Windows 10 Pro Technical Preview 10049 was installed at Tue Mar 31 15:25:14 UTC+0300 2015
Updated by 10061 at Thu Apr 23 01:55:16 UTC+0300 2015
Setup media ID 10049.0.amd64fre.fbl_impressive.150325-1700
Installation continued 48 minutes
-----------------------------------------------------------------------------------------
*/
function Show( arr )
{
var bObj, msg = "\n", duration;
var maxL = "Windows 10 Pro Technical Preview".length;
for ( var i = 0; i < arr.length; i++ )
{
bObj = arr[ i ];
msg += bObj.ProductName + " " + bObj.BuildNumber +
" was installed at " + bObj.Install.toString() + "\n";
if( bObj.IsNext )
{
msg += "Updated by " + arr[ i + 1 ].BuildNumber.right( 5 ) +
" at " + ( arr[ i ].Uninstalled ).toString() + "\n";
}
msg += "Setup media ID " + bObj.BuildLabEx + "\n";
if ( bObj.IsNext && i < arr.length - 1 )
{
duration = CountDuration( arr[ i + 1 ].Install, bObj.Uninstalled );
msg += "Installation continued " + duration + "\n";
}
msg += "\n";
}
WScript.Echo( msg );
return false;
}
//
// Objectes collection presentation function.
// Is called from the project test code only.
// Presents each object in one line. Example
// output is given below.
//
/*
--------------------------------------------------------------------------------
2015.03.24 22:10:19 - 2015.03.31 15:45:14 Windows 8.1 Pro 9600
2015.03.31 16:26:15 - 2015.04.23 02:56:17 Windows 10 Pro Technical Preview 10049
2015.04.23 03:44:13 - 2015.04.29 06:36:13 Windows 10 Pro Technical Preview 10061
2015.04.29 07:25:43 - 2015.05.21 11:32:07 Windows 10 Pro Insider Preview 10074
2015.05.21 14:21:40 - 2015.05.28 21:13:37 Windows 10 Pro Insider Preview 10122
2015.05.28 22:04:16 - 2015.05.30 19:11:22 Windows 10 Pro Insider Preview 10125
2015.05.30 20:16:43 - Windows 10 Pro Insider Preview 10130
--------------------------------------------------------------------------------
*/
function BriefShow( arr )
{
var bObj, msg = "";
var maxL = "Windows 10 Pro Technical Preview".length;
var timestampL = "2015.05.28 21:13:37".length;
WScript.Echo( "\n" );
for ( var i = 0; i < arr.length; i++ )
{
bObj = arr[ i ];
msg += bObj.ShortInstall + " - ";
msg += ( bObj.IsNext ? bObj.ShortUninstalled :
" ".left( timestampL ) ) + " ";
msg += bObj.ProductName.left( maxL ) + " ";
msg += bObj.BuildNumber.right( 5 ) + "\n";
}
WScript.Echo( msg + "\n" );
return false;
}
//
// Objectes collection presentation function.
// Debug-time presentation. Each property of
// each of the objects is printed in one line.
// Example output for one of the objects is
// given below.
//
/*
------------------------------------------------------------
Uninstalled Thu Apr 23 01:55:16 UTC+0300 2015
PreviousBuild 9600
BuildLabEx 10049.0.amd64fre.fbl_impressive.150325-1700
BuildNumber 10049
Install Tue Mar 31 15:25:14 UTC+0300 2015
ProductName Windows 10 Pro Technical Preview
ShortInstall 2015.03.31 16:26:15
ShortUninstalled 2015.04.23 02:56:17
IsNext true
-------------------------------------------------------------
*/
function DebugShow( arr )
{
var bObj, msg = "\n";
var maxPL = "ShortUninstalled".length;
for ( var i = 0; i < arr.length; i++ )
{
bObj = arr[ i ];
for ( var p in bObj )
{
msg += p.left( maxPL ) + " " + bObj[ p ] + "\n";
}
msg += "-------------------\n";
}
WScript.Echo( msg );
WScript.Echo( "--------All done-------" )
return false;
}
function SetShortDates( bObj, ind )
{
if ( typeof( bObj.Install ) == "object" )
{
//bObj.ShortInstall = DateToYYYYMMDD( bObj.Install );
bObj.ShortInstall = bObj.Install.DateToYYYYMMDD();
}
else bObj.ShortInstall = " ";
if ( typeof( bObj.Uninstalled ) == "object" )
{
bObj.ShortUninstalled = bObj.Uninstalled.DateToYYYYMMDD();
}
else bObj.ShortUninstalled = " ";
return bObj;
}
//
// Input:
// regObj - myStdReg class object created by the caller
// path - Registry path which contains necessary values
// bObj - Build object created by the caller
// Function gets necessary data from the Registry using
// methods of the class myStdReg and set bObj properties.
// Updated bObj is returned to the caller.
// Function is called some times from the main function
// BuildsHistory() and returns updated object.
//
function SetBuildObjectProperties( regObj, path, bObj, pbObj )
{
var HKLM = 0x80000002;// HKEY_LOCAL_MACHINE
var res, sDate;
bObj.PreviousBuild = " "; // on a case that unknown
if ( typeof( pbObj ) != "undefined" )
{
bObj.PreviousBuild = pbObj.BuildNumber;
}
res = regObj.RegReadStringValue( HKLM, path, "BuildLabEx" );
bObj.BuildLabEx = res;
bObj.BuildNumber = res.split( "." )[ 0 ];
res = regObj.RegReadDWORDValue( HKLM, path, "InstallDate" );
bObj.Install = regObj.RegDateToDate( res ); // save Date object
bObj.ProductName = regObj.RegReadStringValue( HKLM, path, "ProductName" );
return bObj;
}
/*
-------------------------------------------------------------------------------------
Main project function: is called by the project test code to create Builds objects
array.
-------------------------------------------------------------------------------------
This function will create an object for each of the Builds detected in the Registry.
Objects will be sorted by the build numbers. Each object has some primary properties
and some secondary. Primary properties are those which values were set on base of the
data read from the Registry. Secondary propierties are those which were derived from
the primary properties.
There are only 4 primary properties:
ProductName - Windows product name
Install - product installation date
Uninstalled - date of the product update to the next build
BuildLabEx - Setup media identification
BuildNumber - is derived from BuildLabEx
PreviousBuild - is derived from BuildLabEx
ShortInstall - YYYYMMDD presentaion of Install date
ShortUninstalled - YYYYMMDD presentaion of Install date
IsNext - true if Build objec is not last in chainn
and false for the current product.
-------------------------------------------------------------------------------------
*/
function BuildsHistory()
{
var myRegObj = new myStdReg();// create service object to work with Registry
var HKLM = 0x80000002;// HKEY_LOCAL_MACHINE
var bObj = {}, pbObj = {}, currObj = {}, prevObj = {}, builds = [], rc, res;
//
// Step 1, we will set some of the current Build object properties. Besides we will
// set some properties of the previous build object.
// HKLM\SYSTEM\Setup, value with the name CloneTag contains date of uninstallation
// of the previous build and build number of the previous build. Though it seems
// that time stamp of the previous build uninstallation is also timestamp for the
// current build installation, we will use another source to get precise value
// of this date together with some more properties of the current build object.
//
var regPath1 = "SYSTEM\\Setup";
var regPath2 = "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion";
res = myRegObj.RegReadStringValue( HKLM, regPath1, "UninstallSourceVersion" );
pbObj.BuildNumber = res;
res = myRegObj.RegReadMultiStringValue( HKLM, regPath1, "CloneTag" );
res = new Date( res );
pbObj.Uninstalled = res;
bObj = SetBuildObjectProperties( myRegObj, regPath2, bObj, pbObj );
prevObj = pbObj; //
currObj = bObj; // do not place current into array: it should be the last one
//
// Step 2, we will enumerate all builds present in HKLM\SYSTEM\Setup.
// They are pesented by subkeys with a names like
// "Source OS (Updated on 3/31/2015 14:44:13)". Thus we will enumerate
// subkeys of HKLM\SYSTEM\Setup, then filer those subkeys which
// corresponds to the builds and create objects for them.
//
var key = regPath1, path, p, needKey = "Source OS (Updated on ";
var needKeyL = needKey.length, tmp1, tmp2, rc;
res = myRegObj.RegEnumSubKeys( HKLM, regPath1 );
for ( var i = 0; i < res.length; i++ ) // In this loop we filter out
{ // unnecessary subkeys.
p = res[ i ].indexOf( needKey ); // Try to detect if we need subkey
if ( p > - 1 ) // Yes, subkey presents Build and
{ // we will create Build object
bObj = new Object; // and set object properties
pbObj = builds[ builds.length - 1 ]; // get previous Build object
p += needKeyL;
// get date field from subkey and save it in tmp1
tmp1 = res[ i ].substr( p, res[ i ].indexOf( ")", p ) - 1 );
tmp1 = tmp1.substr( 0, tmp1.length - 1 ).strip();
bObj.Uninstalled = new Date( tmp1 );
path = key + "\\" + res[ i ]; // prepare path for reading values
bObj = SetBuildObjectProperties( myRegObj, path, bObj, pbObj );
builds[ builds.length ] = bObj;
}
}
// add Build object correspondent to
builds[ builds.length ] = currObj; // the current Windows build as a last
// object in the chain.
for ( var i = 0; i < builds.length; i++ ) // In this loop we set secondary
{ // properties other then BuildNumber
builds[ i ] = SetShortDates( builds[ i ], i );
builds[ i ].PreviousBuild = ( i ) ? builds[ i - 1 ].BuildNumber : " ";
builds[ i ].IsNext = ( i < ( builds.length - 1 ) );
}
// all Builds presentaion objects were
return builds; // created. Return to the caller an array
} // of the objects created.
//--------------------------- Project test code -----------------------
var rc;
var arr = BuildsHistory(); // create an array of Builds objects
rc = BriefShow( arr ); // get brief presentation
rc = Show( arr ); // get detailed presentation
rc = DebugShow( arr ); // get debug, full presentation
WScript.Quit();
//--End-of-File-BuildsHistory------------------------------------------