Windows 2012 R2 Windows Backup – Hyper-V .Vhdx restore manually and run it on another machine

Recently I have upgraded my home server to Windows 2012 R2 which runs Hyper-V, after converting all my old Windows 2008 images from .VHD to .VHDX then I tried the Windows Server Backup. It is actually pretty good since it uses volume shadow copy and there is no downtime on all the VMs. The question is, can I restore the Windows Backup files manually? Let me put it to the test and restore the image and run it on my Windows 8 desktop.

Setup:

  • Hyper-V: Windows Server 2012 R2
  • VM image: Windows 7 (called “Atlas”)
  • Desktop: Windows 8 (for testing to see if I can mount it and run the image on desktop)
  1. Windows Server backup created a GUID .vhdx on my Qnap NAS called “16ceb1f0-6d10-4843-a45a-96b7594aacb2.vhdx” (64 GB). If you try to mount this .vhdx directly to Hyper-V, it will fail and it will not boot.
  2. I copied that GUID .vhdx file to my Windows 8 desktop, but when I clicked on it or tried to mount it like an ISO file, it gave me an error message
  3. Go to Disk Management, assign Drive “E”
  4. Look for the image on Drive E and found the real image “Atlas.vhdx”
  5. Created a new VM on Windows 8 desktop and mount the .vhdx file on Drive E
  6. Bingo, VM started successfully
Posted in Network/Hardware | Tagged , , , | Leave a comment

Simple Mistake – Dynamically load images into multiple HTML Canvas

I haven’t written Javascript for a while as I have been focusing on the backend stuff in the past years. This is supposed to be a very simple task but took me some time to figure out. Indeed, coming from a strongly typed language like Java and C#. The Javascript .onload() event syntax actually threw me off a bit. Let’s examine.

This is HTML:

1
2
3
<canvas id="ImageCanvas0" />
<canvas id="ImageCanvas1" />
<canvas id="ImageCanvas2" />

This is Javascript:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
 
$(document).ready(function () {
    renderImage();
});
 
function renderImage() {
    for (var i = 0; i < 3; i++) {
 
        var canvas = $('#ImageCanvas' + (i));
        var context = canvas[0].getContext('2d');
 
        var imageObj = new Image();
 
        imageObj.onload = function () {
            context.drawImage(imageObj, 0, 0);
        };
         imageObj.src = "/ImageRepository/?id=" + i;
    }
}

By reading the Javascript above, there seems nothing is wrong. Indeed the script was working partially without error, but just the result wasn’t expected. The ImageCanvas0 and ImageCanvas1 were blank but ImageCanvas2 was actually loaded properly.

Why? It’s because imageObj was treated like a global variable. Okay, let’s fix it by having 2 Arrays for Canvas and Image and then pass the ID. Simple fix, right?

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
function renderImage() {
    var CanvasContextList = new Array(3);
    var ImageList = new Array(3);
 
    for (var i = 0; i < 3; i++) {
 
        var canvas = $('#ImageCanvas' + (i));
        var context = canvas[0].getContext('2d');
        CanvasContextList[i] = context;
 
        ImageList[i] = new Image();
        ImageList[i].onload = function () {
            CanvasContextList[i].drawImage(ImageList[i], 0, 0);    // Problem: undefined in Array[3]
        };
 
         ImageList[i].src = "/ImageRepository/?id=" + i;
    }
}

Not really, Javascript is throwing undefined error. Looking at the debugger and traced the variable, interestingly when the FIRST onload happened, the variable “i” was actually having the value “3″. Of course, it is undefined.

Onload is multi-threaded and it is triggered by .src. When the function (event) is executed, it looks for the variable “i” which was last used by the for-loop having the value “3″.

Now, this is the final solution and it worked.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
function renderImage() {
    var CanvasContextList = new Array(3);
    var ImageList = new Array(3);
 
    for (var i = 0; i < 3; i++) {
 
        var canvas = $('#ImageCanvas' + (i));
        var context = canvas[0].getContext('2d');
        CanvasContextList[i] = context;
 
        ImageList[i] = new Image();
        ImageList[i].id = i;                  // Assigning an ID to Image object
        ImageList[i].onload = function () {
            CanvasContextList[this.id].drawImage(ImageList[this.id], 0, 0);   // ID is used
        };
 
        ImageList[i].src = "/ImageRepository/?id=" + i;
    }
}

Simple mistake, I guess I have to write more Javascript. Hope this helps other people.

Posted in Development - Javascript | Tagged , , | Leave a comment

Lorex LNR200 series – How to get snapshot still image for your web site and custom C# streaming video from NVR?

I have been using Geovision card and analog cameras for home security for 10 years and it is time to upgrade to HD. I have been using Lorex analog cameras for many years because of its quality therefore I decided to buy Lorex LNR280 with 8 IP cameras (LNB2153 + LNB2152). I am amazed by the PoE + HD 1080p although 2 cameras were not working properly (night vision couldn’t see anything despite the infrared LEDs were working) and I had to replace them via RMA. Customer service was not too bad.

Lorex is a very smart company, not only it uses Costco as sales channel, they indeed not to spend money on R&D for these IP cams and NVR. They just “white-label” a company called HikVision‘s products and of course firmware was developed in mainland China. If you view the HTML code on NVR, you can find simplified Chinese. LOL.

Lorex Viewing – Admin web site + Mobile App Security Concerns

First of all, Lorex admin web site is using ActiveX control. If you are using Proxy (at work), the video streaming will not work. On the mobile side, the HDNet app. is great but it requires you to open multiple ports 8000 + 1025 publicly on the router and most importantly, data is not encrypted.

My solution to get around it is to use SSH + Putty (On Windows Desktop) and SSH + ConnectBot (On Android), none of those ports have to be opened. Well, this is a separated topic for advanced users.

Analysis of NVR and video streaming using RTSP

If you look at the configuration and documentation of Lorex, there are information about 3 ports: 80, 8000 and 1025. Port 80 is the administration web site, 8000 is remote data admin port, 1025 is RTSP video streaming (H264).

I am interested in RTSP. Looking at the black box, I need to find the URL. Fiddler guided me to a javascript called /doc/script/preview.js and I could find out the RTSP URL from the code. (see photo). Then I used VLC Media Player (it’s open source free to download) I could actually stream the video on VLC player! Bingo!

Lorex_LNR200_LNR280_0001

Lorex_LNR200_LNR280_0002

Assuming your LAN is on 192.xx.xx.xx and NVR is on your LAN:

rtsp://user:pass@192.xx.xx.xx:1025/PSIA/streaming/channels/101 (cam#1)
rtsp://user:pass@192.xx.xx.xx:1025/PSIA/streaming/channels/201 (cam#2)
rtsp://user:pass@192.xx.xx.xx:1025/PSIA/streaming/channels/301 (cam#3)
….

Proof of Concept: on using C# and .NET for streaming

Download:

1. vlc-2.1.3-win32.exe (Install it)
2. VideoLan DotNet for WinForm, WPF, SL5

I am using Visual Studo 2013 for the proof of concept. Follow the documentation to initialize the VLC context in your Program.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
        static void Main()
        {
            Application.EnableVisualStyles();
            Application.SetCompatibleTextRenderingDefault(false);
 
            //Set libvlc.dll and libvlccore.dll directory path
            VlcContext.LibVlcDllsPath = CommonStrings.LIBVLC_DLLS_PATH_DEFAULT_VALUE_AMD64;
            //Set the vlc plugins directory path
            VlcContext.LibVlcPluginsPath = CommonStrings.PLUGINS_PATH_DEFAULT_VALUE_AMD64;
 
            //Set the startup options
            VlcContext.StartupOptions.IgnoreConfig = true;
            VlcContext.StartupOptions.LogOptions.LogInFile = true;
            VlcContext.StartupOptions.LogOptions.ShowLoggerConsole = true;
            VlcContext.StartupOptions.LogOptions.Verbosity = VlcLogVerbosities.Debug;
 
            //Initialize the VlcContext
            VlcContext.Initialize();
 
            Application.Run(new Form1());
 
            //Close the VlcContext
            VlcContext.CloseAll();
 
        }

Then, simply add the 3 DLLS to your project reference and also add the Vlc.DotNet.Forms.dll to your Toolbox (for the form designer). After dragging the control to your Form, a vlcControl1 instance should be created. After that, add 3 buttons. Edit your Form.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
 
        public Form1()
        {
            InitializeComponent();
        }
 
        private void button1_Click(object sender, EventArgs e)
        {
            string path = "rtsp://username:password@192.168.xxx.xxx:1025/PSIA/streaming/channels/701";
 
            LocationMedia media = new LocationMedia(path);
 
            vlcControl1.Media = media;
            vlcControl1.Play();
 
        }
 
        private void button2_Click(object sender, EventArgs e)
        {
            vlcControl1.Stop();
        }
 
        private void button3_Click(object sender, EventArgs e)
        {
            string outputFile = "C:\\capture.jpg";
            vlcControl1.TakeSnapshot(outputFile, 1920, 1080);
        }

Although there are some errors on the command prompt logs, but the video was actually streaming properly. Even screen capture was working as you can see from the photos. The JPG captured is in HD 1920 x 1080.

Lorex_LNR200_LNR280_0003

Lorex_LNR200_LNR280_0004

Playback on certain time (Recorded video)

This example is to play back on Cam#1, from 2014-05-27 0:0:0 to 2014-05-28 23:59:59

rtsp://username:password@192.168.xxx.xxx:1025/PSIA/streaming/tracks/101?starttime=20140527T000000Z&endtime=20140528T235959Z (cam#1)

This is working perfectly on VLC player.

Getting single still image from Lorex LNR200 (LNR280)

Finally getting still image is something I need to do for my custom home automation and mobile app., just like my previous Geovision Hack. If you are business owner, you can use this to post the live images on your web site. Getting the image is extremely simple

http://192.168.xxx.xxx/PSIA/Streaming/channels/101/picture (cam#1)
http://192.168.xxx.xxx/PSIA/Streaming/channels/201/picture (cam#2)
http://192.168.xxx.xxx/PSIA/Streaming/channels/301/picture (cam#3)
…..

There are 2 streams for each channel, for cam#1: Main-Stream 101 (1920×1080) and Sub-Stream 102 (704×576). However, I am keep getting 704 x 576 as resolution (wide screen with blank top/bottom) which is not ideal, I am not sure if it is a bug or not.

According to the HikVision documention, this should work:

  • /Streaming/channels/101/picture?videoResolutionWidth=1920&videoResolutionHeight=1080
    (Empty respond in ResponseStatus XML)
  • /Streaming/channels/101/picture?snapShotImageType=JPEG
    (Invalid Operation in ResponseStatus XML)

But obviously they are not working on Lorex.

Anyways, 704×576 is kind of acceptable and it uses Basic Authentication, so you can embed your username/password in the URL and get the picture on your browser for testing:

http://username:password@192.168.xxx.xxx/PSIA/Streaming/channels/101/picture

To publish it on your site, this is a simple proof of concept (not using PHP this time), I am using traditional ASP.NET and MVC. For Web Form, this is your Image.aspx.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
 
    protected void Page_Load(object sender, EventArgs e)
    {
        Response.Clear();
        Response.ContentType = "image/jpeg";
 
        Uri uri = new Uri("http://192.168.xxx.xxx/PSIA/Streaming/channels/701/picture");  // cam#7
        HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
 
        webRequest.Credentials = new NetworkCredential("username", "password");  // authenication
 
        HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
        StreamReader reader = new StreamReader(webResponse.GetResponseStream());
 
        var bytes = default(byte[]);
        using (var memstream = new MemoryStream())
        {
            reader.BaseStream.CopyTo(memstream);
            bytes = memstream.ToArray();
        }
 
        Response.BinaryWrite(bytes);         
    }

This is your Defualt.aspx or Index.html:

1
2
3
 
<h3>This is your web page, demo image from Lorex LNR280</h3>
<img src="./Image.aspx" style="width:350px; height:300px" />

As for ASP.NET MVC, Create a ImageController.cs:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
 
 public class ImageController : Controller
    {
        //
        // GET: /Image/
        public ActionResult Index()
        {
            Response.Clear();
            Response.ContentType = "image/jpeg";
 
            Uri uri = new Uri("http://192.168.xxx.xxx/PSIA/Streaming/channels/701/picture");  // cam#7
            HttpWebRequest webRequest = (HttpWebRequest)WebRequest.Create(uri);
 
            webRequest.Credentials = new NetworkCredential("username", "password");  // authenication
 
            HttpWebResponse webResponse = (HttpWebResponse)webRequest.GetResponse();
            StreamReader reader = new StreamReader(webResponse.GetResponseStream());
 
            var bytes = default(byte[]);
            using (var memstream = new MemoryStream())
            {
                reader.BaseStream.CopyTo(memstream);
                bytes = memstream.ToArray();
            }
 
            Response.BinaryWrite(bytes);     
 
            return View();
        }
	}

This is your Razor Home page Index.cshtml:

1
2
3
4
5
6
@{
    ViewBag.Title = "Home Page";
}
 
<h3>This is your web page, demo image from Lorex LNR280</h3>
<img src="/Image/Index" style="width:350px; height:300px" />

In one of the photos in this article, Fiddler complained about a HTTP protocol error!! What? In order to bypass that, add the following to the web.config (applies to both Web Form and MVC:

1
2
3
4
5
  <system.net>
    <settings>
      <httpWebRequest useUnsafeHeaderParsing="true" />
    </settings>
  </system.net>

Lorex_LNR200_LNR280_0005

Lorex_LNR200_LNR280_0006

Other discoveries + Full Hikvision API

The architecture of Lorex/Hikvision NVR is using simple REST web services, it uses HTTP GET/POST/PUT/DELETE to do all operation in plain XML. Nothing fancy, no encryption, no serialization (since it is not object-oriented). All the logic are handled on client side by javascript and Jquery. I used Fiddler and Firebug to do the reverse engineering, there are some URLs that you can use it as API:

/PSIA/Custom/SelfExt/ContentMgmt/DynVideo/inputs/channels
/PSIA/Custom/SelfExt/ContentMgmt/DynVideo/inputs/channels/status
/PSIA/Custom/SelfExt/OSD/channels/1/capabilities (cam#1)
/PSIA/Custom/SelfExt/OSD/channels/1 (cam#1)
/PSIA/Custom/SelfExt/ContentMgmt/DynVideo/inputs/channels/1 (cam#1)
/PSIA/System/deviceInfo (cam#1)
/PSIA/Custom/SelfExt/UPnP/ports/status (cam#1)
/PSIA/Custom/SelfExt/ContentMgmt/DynStreaming/channels
/PSIA/ContentMgmt/search/
/PSIA/Streaming/channels/101/capabilities (cam#1)
……
……

HikVision is different from Lorex, either firmware version or maybe Lorex has disabled some features on the NVR. Reference:

You will be amazed by the API available to the advanced users. However, many of them don’t work on Lorex NVR. But maybe it will work on the camera directly, not sure.

If you have a POE switch or use an power adapter, you can use your laptop directly connect to the admin port (8000) of the individual camera at 172.168.1.xxx (note: you need to switch your NIC from 192. to 172.) instead of connecting to the NVR. You can download a Hikvision iVMS-4200 PCNVR v1.02.00.03 (Windows) to change advance settings on the camera. I haven’t tried that, not sure if it will work or not.

Lorex vs HikVision

Take a look at the FAQ and Driver/SDK web pages of both HikVision and Lorex, compare them by yourself. Hikvision makes Lorex look like shit for advanced users. Hikvision wins hands down!! But if you are non-technical users, Lorex is pretty good. If I knew HikVision earlier, I wouldn’t be that stupid to go with Lorex.

Have fun with your Lorex 200 series. This article is based on my Lorex LNR280 firmware V2.2.3 build 130412.

Posted in Development - .NET, Network/Hardware | Tagged , , , , , , , , , , | Leave a comment

Bypassing annoying password policy at work which does not allow you to use the same Windows password again

Windows password expire policy at work is extremely annoying, many companies force you to change the password every few months. Honestly speaking, I am so sick of it.

What is the Problem?

Most companies have set the Enforce password history value in AD, however according to MSDN article “Enforcing Strong Password Usage Throughout Your Organization”, the maximum value for Enforce password history is 24 times. In other words, you can restore to your original password at 25th time. However, this only works if your network administrator does not set the “Minimum Password Age”.

The solution is extremely simple. If your original password is “p@ssw0rd1″, it will be changed to “p@ssw0rd10″, “p@ssw0rd11″, “p@ssw0rd12″,…. “p@ssw0rd124″ and at 25th time, your password will be changed back to the original one “p@ssw0rd1″. But this process is so tedious and repetitive, it’s not fun to do this manually.

There are 2 automated solutions and I have tested them at work and both are proved to work perfectly.

 

Solution 1 – Using C# and .NET Windows Form

The following source code and .EXE can be downloaded:

To use it, you need to first find out the Active Directory host name/IP address. Credit goes to Stackoverflow.com article. Here is summary of how to find it:

1
2
3
4
5
6
7
8
C:\> nslookup 
> set types=all
> _ldap._tcp.<<your.AD.domain>>
_ldap._tcp.<<your.AD.domain>>  SRV service location:
      priority       = 0
      weight         = 100
      port           = 389
      svr hostname   = <<ldap.hostname>>.<<your.AD.domain>>

Here is the C# source code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
 
// PasswordChanger - Bypassing corporate annoying password policy that does not allow you to use the same password
 
// Description: The flaw in Microsoft AD is that "Enforce password history" value is 0 to 24 
//               Idea is to change the password for 24 times (e.g. password01 + password02 + ..) 
//               And on 25th time, it changes it back to your original password
 
//Tested on: Windows 7 Enterprise 64-bit
 
//Written and Copyrighted by: Mythos and Rini
//Created on: 2014-03-21
 
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.DirectoryServices;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;
 
namespace PasswordChanger
{
 
    public partial class Form1 : Form
    {
        private enum ResetType { resetToOld, resetToNew }
 
        private string _username;
        private string _password;
        private string _activeDirectoryHost;
        private int _repeat;
        private string _newPassword;
        private DirectoryEntry _directoryEntry;
        private ResetType _resetType;
 
        public Form1()
        {
            InitializeComponent();
 
            ResetTypeComboBox.SelectedIndex = 0;
 
        }
 
        /// <summary>
        /// Button click
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void StartButton_Click(object sender, EventArgs e)
        {
            try
            {
                // Get values from UI (No validation)
                _username = UserNameTextBox.Text;
                _password = PasswordTextBox.Text;
                _activeDirectoryHost = ActiveDirectoryTextBox.Text;
                _repeat = Convert.ToInt32(RepeatTextBox.Text);
                _newPassword = NewPasswordTextBox.Text;
                _resetType = (ResetTypeComboBox.SelectedIndex == 0) ? ResetType.resetToOld : ResetType.resetToNew;
 
                string oldPass = _password;
                string newPass = null;
 
                _directoryEntry = new DirectoryEntry(@"WinNT://" + _activeDirectoryHost + "/" + _username + ",User");
 
                // Change password loop
                for (int i = 1; i <= _repeat; i++)
                {
                    newPass = _password + Convert.ToString(i);
 
                    if (ChangePassword(oldPass, newPass))
                        WriteLog("Successful: changed to = " + newPass);
 
                    oldPass = newPass;
 
                }
 
                // Last one based on reset type
                if (_resetType == ResetType.resetToOld)
                {
                    if (ChangePassword(oldPass, _password))
                        WriteLog("Successful: set to old password = " + _password);
                }
                else if (_resetType == ResetType.resetToNew)
                {
                    if (ChangePassword(oldPass, _newPassword))
                        WriteLog("Successful: set to new password = " + _newPassword);
                }
 
            }
            catch (Exception ex)
            {
                WriteLog("Error: " + ex.ToString());
            }
 
        } // method
 
        /// <summary>
        /// Change Password
        /// </summary>
        /// <param name="oldPass"></param>
        /// <param name="newPass"></param>
        private bool ChangePassword(string oldPass, string newPass)
        {
            bool isSuccessful = false;
 
            try
            {
                _directoryEntry.Invoke("ChangePassword", oldPass, newPass);
                isSuccessful = true;
            }
 
            catch (System.Reflection.TargetInvocationException e)
            {
                WriteLog("Error: password change failed, old password = " + oldPass);
 
                Exception innerEx = e.InnerException;
                WriteLog("Exception: " + innerEx.Message);
                isSuccessful = false;
            }
 
            return isSuccessful;
        }
 
        /// <summary>
        /// Write Log
        /// </summary>
        /// <param name="text"></param>
        private void WriteLog(string text)
        {
            LogTextBox.AppendText(text + "\r\n");
        }
 
        /// <summary>
        /// Dropdown change
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void ResetTypeComboBox_SelectedIndexChanged(object sender, EventArgs e)
        {
            NewPasswordTextBox.Enabled = (ResetTypeComboBox.SelectedIndex == 1) ? true : false;
        }
 
    } // class
} // ns

Solution 2 – AutoIt

If you have read the article of mine How to reset “Away (x minutes)” in Microsoft Lync? Lock/Unlock workstation automatically (Securely Slacking), you may want to try to play with this solution. It is purely for prove of concept, just to show that it is “doable” using AutoIt. It requires VNC, Virtual PC/Vmware and it’s too complicated for general users.

The advantage is that you don’t need to find out the Host name/IP address of the Active Directory server.

The following .au3 source code downloaded:

  • Source Code – PasswordChanger.au3 (6 KB – Requires AutoIt 3.3.8.1 + TightVNC 2.6.4 + Vmware/Vpc ) To download, RIGHT-CLICK > Save Target/Link As
 
; Bypassing corporate annoying password policy that does not allow you to use the same password
;
; Description: The flaw in Microsoft AD is that "Enforce password history" value is 0 to 24 
;              Idea is to change the password for 24 times (e.g. password01 + password02 + ..) 
;              And on 25th time, it changes it back to your original password
;
 
; Pre-req: VNC - Setup can be found in this article - YOU MUST GET THIS WORKING FIRST
;          "How to reset “Away (x minutes)” in Microsoft Lync? Lock/Unlock workstation automatically (Securely Slacking)"
;          http://www.mythos-rini.com/blog/archives/7593
 
; Required:
; AutoIt Version: 3.3.8.1
; tightvnc-2.6.4-setup-64bit.msi  (64 bit) or tightvnc-2.6.4-setup-32bit.msi  (32 bit)
 
; Tested on: Windows 7 Enterprise 64-bit
;
; Written and Copyrighted by: Mythos and Rini
; Created on: 2014-03-31
 
; Reference: 
; Jason More - Unlock the computer using VNC
; ref: http://www.autoitscript.com/forum/topic/71333-solution-to-computer-locked-screen-ctrl-alt-del-scripting/
 
; Note that TightVNC upgraded,  vncviewer.exe has been changed to tvnviewer.exe
;           and "Standard VNC Authentication" has been changed to "Vnc Authentication" (case sensitive)
 
#include <Array.au3>
 
; This script requires full Administrative rights
#requireadmin
 
; The configuration based on Tight VNC 2.6.4  32-bit installation
Dim $vncPath = "C:\Program Files\TightVNC"
Dim $vncViewerExe = "C:\Program Files\TightVNC\tvnviewer.exe"
Dim $vncNewConnectionWindowName = "New TightVNC Connection"
Dim $vncAuthWindowName = "Vnc Authentication"
 
; Change the VNC host/port accordingly
 
Dim $vncServerHostPort = "172.11.22.33:40"
Dim $vncPassword = "f@@kwork"
 
; Windows password (do not need username)
Dim $windowsPassword = "p@ssw0rd1"
Dim $oldPassword = $windowsPassword;
Dim $newPassword = ""
 
; AD Maximum value is 24
Dim $maxPasswordHistory = 24
Dim $i = 0
 
; Delay for 5 seconds for you to Minimize the Virtual PC  
sleep(5000);    
 
	  ; Slowing down the key presses helps with the connection
	  opt("SendKeyDelay",10)
 
	  ; This should point to your tight vnc installation
	  run($vncViewerExe,$vncPath)
 
	  ; Wait for the new connection windows to come up
	  winwait($vncNewConnectionWindowName)
	  controlsend($vncNewConnectionWindowName ,"","Edit1", $vncServerHostPort)
	  controlclick($vncNewConnectionWindowName ,"","Button4")
 
	  ; Wait for the authenication window and send password
	  winwait($vncAuthWindowName)
	  controlsend($vncAuthWindowName,"","Edit2", $vncPassword)
	  controlclick($vncAuthWindowName,"","Button1")
 
	  ; Sleep for 2 seconds
	  sleep(2000)
 
      ; Use AutoIt WindowsInfo or Microsoft Spy++ to get the class name
	  $VncClassName="[CLASS:TvnWindowClass]"
 
		; Get all the active/minimized VNC windows
		$winList = WinList($VncClassName)
 
		For $a = 0 to $winList[0][0]
 
		   ; Activate Communicator window if there is any
		   If WinActivate($winList[$a][0]) Then
 
			  ; Get title of VNC
			  $title = WinGetTitle($winList[$a][0], "")	  
 
			   ; Loop 
			    While $i < ($maxPasswordHistory + 1)
 
			 ; Debug
			 ; MsgBox(0, "Title", $title)
 
			  ; Clear any keys pressed or input waiting box
			  controlsend($title,"","TvnWindowClass1","{ESC}")
			  sleep (1000);
 
			  ; Click the button "Ctrl-Alt-Del" on the TightVNC toolbar
			  controlclick($title,"","ToolbarWindow321","left",1,170,13)			  
 
              ; In some Windows evironments if you have if you are on Active Directory domain
			  ; "Lock this computer"
			  ; "Switch User"  
			  ; "Log Off"
			  ; "Change Password"
			  ; "Start Task Manager"
 
              ; Send key down and go to "Change Password" option
              sleep (2000);
			  controlsend($title,"","TvnWindowClass1","{DOWN}");
			  controlsend($title,"","TvnWindowClass1","{DOWN}");
			  controlsend($title,"","TvnWindowClass1","{DOWN}");   
			  controlsend($title,"","TvnWindowClass1","{ENTER}");
 
			  sleep(4000);
 
			  ; Enter Original password
			  controlsend($title,"","TvnWindowClass1", $oldPassword);
			  controlsend($title,"","TvnWindowClass1","{TAB}");
			  sleep(4000);
 
			  ; Add the count at the end
			  $newPassword = $oldPassword & $i
 
			  ; On the last one, change it back to the original password
			  If ($i = $maxPasswordHistory) Then
                 $newPassword = $windowsPassword;
			  EndIf
 
			  ; Enter new password
			  controlsend($title,"","TvnWindowClass1",$newPassword);
			  controlsend($title,"","TvnWindowClass1","{TAB}");
			  sleep(4000);
 
              ; Enter new password again
			  controlsend($title,"","TvnWindowClass1",$newPassword);
			  controlsend($title,"","TvnWindowClass1","{TAB}");
 
			  sleep(4000);
			  controlsend($title,"","TvnWindowClass1","{ENTER}");
 
			  ; Wait for it to connect to AD (has to wait becuase of possible network delay)
			  ; Send Space and go back to desktop
			  sleep(10000);		 
			  controlsend($title,"","TvnWindowClass1","{SPACE}");
 
              ; Set the oldPassword for next round loop
			  $oldPassword = $newPassword;
 
			  MsgBox(0, "Last Password Changed", $newPassword)
 
				  $i = $i + 1
 
			   sleep(2000)
 
			WEnd
 
		   ENdIf
 
		Next
 
; Close the VNC viewer
WinClose($title)
Posted in Network/Hardware | Tagged , , , , | Leave a comment

DIY Fix – DSC Alarm GSM Unit GS-3070 Mod: Relocation for stronger signal + Battery upgrade

We hired a professional alarm company which has been in business for 30 years to install the DSC hard wired alarm system with GSM monitoring. The team of 4 people did the whole house with pretty high quality, except I had problem with the GSM unit.  On the day of the installation, the guy put both central unit + GSM module in the basement as usual but later I found out that the GSM signal was too weak (red light – no signal) and called him to come and fix it.

Signal too week – How professional solved the problem?

Before the guy came to fix the  issue, I did the research on the alarm forum. The proper way to fix GS3060/GS3070 signal issue is to buy a DSC ANT-50 (50″) Antenna Extension Kits. However,  at around $200 U.S. for such stupid antenna which you cannot easily find it on eBay/Amazon (since DSC wants to protect the installers business, you have to go through the authorized dealers). So,  I phoned the alarm guy and asked about that,  he asked me to save the money because it was not needed.

Okay, so no need eh?  Next day, he came and I wondered how he solved the issue. He moved the GSM unit to the garage!!!! What???? I told him to read the manual, it said clearly that Operating Temperature is 0c to 49c (32F to 120F). We are in Canada, outside temperature can go as low as -20c in winter, garage goes below freezing point.  The guy told me to trust him because he has been in business for 30 years.

I guess he wanted me to pay for another one when it is broken. Also, the dust and dirt in garage is not ideal for this little puppy because I do a lot of crazy shit in garage in summer.  To me, it is a security concern if burglar breaks into the garage as point of entry.

 

DIY Fix – Relocation to secret place and Battery Upgrade

So, I relocated the GSM unit out of garage and put it in a secret place, one of the best location is to put it behind the drywall between the wood studs, install a surface mounted access door for future maintenance, then cover it with an extremely heavy mirror or painting. This is what I meant by heavy mirror – Mirror Mirror project.

There are many secret locations, use your creativity. The idea is to delay as much as possible from burglar cutting your GSM communication or interfere with a GSM jammer after the alarm goes off.

Since I was relocating the unit,  I decided to do another mod.  During the snow storm in December 2013, our power was out for 16 hours. The factory battery of the GSM unit (GS3070) couldn’t last for 1 hour (main unit stayed online for 16 hours surprisingly). Further reading the manual, the unit was shipped with a crappy battery at 1.2Ah and the recommended one is 7Ah. But large battery would not fit in the factory metal box!!?? What? DSC is so screwed up. So, here is the DIY fix:

  • Metal case $20 CAD at Sayal Electronics and Hobbies store
  • 12V 8Ah Battery $30 CAD at Sayal Electronics and Hobbies store
  • Phillips  24 awg  4 Conductor 100 ft. phone cable ($5 CAD – at Sayal)
  • Plastic ring prevent sharp metal from cutting the wire (short circuit)
  • Wire protection for cars, technical name is called “Split Poly Loom” to prevent sharp metal from cutting the wire (short circuit)
  • Drilled several holes for ventilation on the metal box – because Lead-acid battery generates hydrogen. It can cause explosion if not vented.

Now, as you can see. After the battery fully charged, it has 2 Green LED signals. Everything is fixed.  For serious security, forget about alarm and get a German Shepherd.

Posted in Home Improvement | Tagged , , , , , , , , , , | Leave a comment

Home Depot Installation Service Fail – Garage Door opener fell after 1 week!

Deb and I bought the Chamberlain HD620EVC from Home Depot and because of the tight timeline we had, we decided to get the professional to install it. It was a huge mistake to let Home Depot Installation Service do the job. Looked what happened after less than 1 week!!!! Luckily no one was injured or we would have contacted the lawyer and sued them. The time I spent on fixing it could have been used on the installation ourselves.

WayneDalton_HD_Installation_Failed_00003

Can you believe this is called professional installation from Home Depot Installation Service? Okay, let’s examine the problems.

At least 10 mistakes the installer had made

First of all, I am just another DIY guy but with many years of Home improvement Projects experience, I feel I have enough qualification to point out what went wrong with such a simple installation and I will show you my DIY fix.

Installation Quality: (see photos for details)

  • Angle iron bent by using too much force on screw/bolt from impact wrench
  • Installer did not even know how to screw/bolt properly in a straight line, leaving the bolt rested with 30 degree angle on the iron
  • Angle iron was not level with the drywall tape line! Installer did not know use tape to measure, probably eyeballing.
  • Opener buttons were not even level and they were not lined up

Lack of Common Sense and Customer Care: (see photos for details)

  • Buttons mounted top of another – How can you tell which one controls LEFT/RIGHT door? Common sense on usability! Possible reason: Drywall Anchors were provided by Chamberlain package but installer did not use any. Why? Because there was wood stud vertically, taking short cut to finish the job faster instead of focusing on customer care.

Lack of Structural knowledge: (see photos for details)

  • Using only a small piece 2×4 with 4 screws to support the track, that’s the first reason why the whole thing fell
  • Wood was not pre-drilled and screws were placed too close to the edge, causing the wood to split. That’s the second reason for the track to go down
  • Wayne Dalton garage door has the warning label in RED color not to install on that thin metal plate. No common sense or knowledge on structure/support.
  • On one of the metal brackets, they have given you 4 holes for a reason. But 2 bolts were missing.
  • With such high ceiling, whenever the garage door opener was engaged, the whole unit was wobbling so much. Additional support was missing from the whole structure.

Quote from the warning label “Do not attach trolley type operator to this stile. Its only purpose is to meet ULC ORD-C263.7. Attach trolley type operator to top of section using Wayne-Dalton operator bracket. Part No. 324864″.

The solution and DIY Fix

Obviously the installer was not in Garage Door installation business, probably Home Depot just hired some handyman off the street. As I said, I am not a professional either but with some common sense and help of Google, I have fixed all of the issues in the proper way. What a waste of time. See the photos in details (with description).

Home Depot – Full Refund (satisfaction guaranteed) but they didn’t communicate

We told Home Depot about the incident at Customer Service and they were glad that there was no person being injured or damaged to the cars, otherwise we would have contacted the lawyer and sued both the installer and Home Depot. Well, they gave us full refund on the installation – that’s good part about the satisfaction guaranteed. We told them we would fixed this ourselves and asking them not to send anyone attempt to fix it.

Next day, guess what happened? The same installation guy showed up and apologized for the incident, his boss told him to come to fix it. Of course, I politely sent him away. Obviously, Home Depot management had some internal communication issues – we have told them repeatedly (several associates at Customer Service desk) not to send anyone. Sigh.

Mike Holmes standard

The installation guy was actually a very nice person with good personality but I am sorry just being nice doesn’t cut it, my standard is based on Mike Holmes.

Side Note: Chamberlain HD620EVC – same problem with Nest/Honeywell

On the side note of Chamberlain, it’s a very good product. The “Timer-To-Close” feature is the best, it is a must have. Strongly recommended. However, the SmartPhone Control has huge privacy and security concern, the problem is that it doesn’t let you communicate with your unit via WiFi without Internet. It forces you to go through the cloud, the problem is exactly like Honeywell/Nest Smart Thermostat. The unit does not have a local web server, MyQ internet gateway sends data to the server every 10-20 seconds. Therefore, if hackers break into their cloud database, they can sell the data to the local burglars. They will know exactly your daily routine (what time you usually leave the house and what time you come back). For people with high security and privacy concern, do not use.

Posted in Home Improvement | Tagged , , , , , , | Leave a comment

Amazon EC2 – Your company blocks RDP Port 3389

Amazon EC2 is a wonderful cloud service, you have probably signed up one for various reasons. One of the reasons to use that is to prevent your company’s I.T. or management from spying on your daily web surfing activities. However, many companies block RDP port 3389 and you cannot connect to your virtual machine.

Assuming you have signed up Amazon EC2 and running Windows instance successfully.

 

  • Download SPI Port Forwarder (free, Google it)
  • No need to install, Just put it C:\Program Files (x86)\PortForward\PortForward.exe
  • Add a firewall rule on Amazon console to allow port 80
  • Add a local Windows Firewall rule to your VM instance
  • Launch PortForward.exe (Run as “Administrator” *** VERY IMPORTANT ***)
  • Set up the port mapper to map port 80 to 3389
  • RDP client needs to configure to use port 80 instead of 3389

Done! Now, you can connect to your EC2 VM via port 80!

Posted in Network/Hardware | Tagged , , , | Leave a comment

DIY Backsplash Project – Glass subway tile + Under cabinet lights + Pacific Rangehood SC8830 installation

This DIY project took 2 months for me to complete (one person, mostly worked on weekends and limited statutory holidays). During this renovation period, Deb and I could not even cook and ate out every single night. Finally, this is done and the result looks stunning! Just in time to hand the kitchen back to Deb on Valentine’s Day.

The following is the summary of tasks. For technical details I have added the short description to each photo. Enjoy!

  • Removing existing tiles and drywall
  • Electrical work for under cabinet lights
  • Vapour barrier and insulation
  • Cut and installing new drywall
  • Drywall mudding + sanding + Primer
  • Tile installation (Cutting tiles + Thinset)
  • Tile Grouting
  • Rangehood installation

Why DIY instead of hiring professional?

A lot of friends asked us why DIY instead of hiring professional? Simple, next time if you go to Starbucks, Home depot/Lowes kitchen department, IKEA show room, restaurants or any place that has backsplash (look for glass tiles), pay attention to the vertical and horizontal grout lines and ask yourself if they are perfectly level. Even those so-called Pros who do backsplash for a living (some even has a dedicated channel on YouTube) suck so badly. Go to YouTube, search for “glass tile installation” and pause some of those videos and look carefully on the grout lines, you will see what I mean.  It’s not about the cost, it’s about seeking for perfection.

Additional DIY Tips:

I am not a professional, but I believe anyone should be able to get the same high quality result if you have common sense.  Every project I did in the past (check out my Home Improvement section), I did extensive research before starting a project.  Here are some tips for DIY-ers,  also these are some important points to consider if you are to hire a contractor to do the job. Hope this helps.

  • Removing tiles vs Replacing drywall: You don’t have to replace drywall like mine, you can pry the old tiles instead. But I wanted a perfectly smooth surface, and I had to run the wires behind the walls for under cabinet lights, that’s why I decided to replace the drywall.
  • Thinset: It is extremely messy because of the sand, it takes time to mix and clean up. But thinset is recommended for glass tile over pre-mixed glue (mastic). Google this topic for details.  If you are not using glass tile, avoid thinset and use mastic glue if possible to save time, because they are pre-mixed.
  • Glass tile: Glass is extremely sharp, I cut myself several times. I recommend you cut the tiles in the garage, not inside the house. Any small piece of glass can scratch your existing floor.
  • Vertical and Horizontal lines: The most annoying part is how to align and level the tiles perfectly, there are many potential problems. Firstly, the tiles have defects, not all tiles are having the exact same size, believe it or not!!! It happened to ours because it’s Made in China.  Secondly, the  cutting of the tile is not perfect. By drawing the guidelines, it helps you to correct mistake before it’s too late.
  • Back butter or not? If you read this topic on the tiles forum, the answer is about 50/50. Half of the people say you don’t need to do it (some of those with 30-40 years trade experience really against it, saying it’s not necessary and waste of time). The other half say you do need to ensure close to 100% coverage. For me, I am scientific based – simply do an experiment with one back butter and one without, after they both dried completely and pry them out, tell me which one do you think has stronger bond – you decide it for yourself.
  • Caulking vs Grout: There are tons of discussion on the forums on “change of plane” (edges/corners) to use caulking vs grout. I prefer to use caulking because it can hide imperfection or slight misalignment. Also, grout will crack on these particular areas. Use masking tape to make the perfect caulk lines, see photos for details.
  • Sitting tiles on counter top vs leaving a gap: It is a MUST to leave a single grout line space at the bottom and that joint should be finished with caulk, not grout. The reason is that counter top will have slight movement, especially for glass tile, they will crack. Thinset/glue is the one holding the tiles structurally on the wall, not the counter top non the grout.
  • Pacific Rangehood SC8830 review - Made in Taiwan Rangehood with 1000 CFM (7″ duct) is really powerful. Honestly speaking, I don’t really freaking care about “True Steam” or “False Steam”.  But what bugged me was that,  they came with drywall screws instead of wood screws (see photos, it didn’t match the manual). What is the problem? Firstly, drywall screws are having very low shear strength and they break into pieces easily. Secondly, it’s countersunk – how does it fit with the washers!!  Now, I am not sure if I have faith in this Pacific product, seriously.
  • Rangehood 1-person installation: The Pacific rangehood is very heavy, I could only lift it up in the air for less than 10 seconds. The trick is to put the screws half way into the wood, then slide the Rangehood in place, let it temporary hang the Rangehood there. Unscrew each screw one-by-one and add the washer to secure them. With the tight space, flexible shaft bit extension is your friend.

Materials and Total cost:

We bought the glass tile, thinset and grout from TileMaster in Aurora. The Rangehood was from First Markham Place and LED lights were from Lowes. Everything else was from Home Depot. For tiles/thinset/grout were around $900 CAD, Rangehood was around $800 CAD and LED lights was around $300 CAD. Total cost for the whole project we spent was around $2000 CAD. Since it is DIY, labour is zero.

  • Glass tile bellavita (Quality is okay, 10% defect. Made in China crap)
  • Kiesel ServoStar 3000 Flex thinset (Made in Germany – high quality thinset)
  • Kiesel Servoperl grout (Made in Germany – warning: working time is very short)
  • Pacific Range Hood SC-8830 – (Made in Taiwan, 1000 CFM, 7″ duct but comes with drywall screws with countersunk instead of flat wood screws!? WTF!)
  • Utilitech Plug-In Cabinet LED Light Bar Kit (Lowes Canada item# 366089 + 366083)

Conclusion and Verdict

  • Overall Difficulty: 3/5
  • Most Challenge: Tiles/grout lines are perfectly level vertically and horizontally
  • Most Annoying: The dust generated by tile demolition and working with messy thinset
  • Time Taken:  2 months – I have a full time job (one person, only work on weekends and limited statutory holidays)
Posted in Home Improvement | Tagged , , , , , | Leave a comment

How to reset “Away (x minutes)” in Microsoft Lync? Lock/Unlock workstation automatically (Securely Slacking)

If you have read my article 4 years ago Making yourself always “Available” + Auto Reply on Microsoft Office Communicator, Outlook Web App and Live Meeting (pretend to be working hard when working from home), you will definitely love this one.

Lync_001_LyncAwayScreen

Problem: In the office, I want to step out for 2.5 hours but I don’t want other people to know. At the same time, I want to lock my workstation for security reason (important requirement). With Microsoft Lync being the primary communicating tool in our office, the annoying feature “Away (x minutes/hours)” really bugs me when the workstation is locked. The “Always available” I posted 4 years ago didn’t really solve this particular problem, since I am physically in the office instead of working from home, so I began to research other options.

Solution: There are many solutions I found on Internet,  including Registry change like HKCU\SOFTWARE\Microsoft\Communicator\AwayThreshold;  but none of them worked well, especially after you lock your machine.   Until I read Jason More : Unlock the computer using VNC,  this started to give me an idea on writing this AutoIt script, so I have to give credit to Jason More.

The basic idea is to unlock your workstation every X minutes and then re-lock it again, so that it makes Lync reset the Away counter to zero. For example, your coworkers will only see you away for 25 minutes maximum on Lync even you have been gone for hours.  This solution is more advance and requires you to have basic knowledge of networking, VNC, AutoIt and VPC.

Here is what you need:

  • Virtual PC, VMware with Win 7 or Windows XP Mode
  • AutoIt Version: Tested on 3.3.8.1 and 3.3.10.0
  • tightvnc-2.6.4-setup-32bit.msi  : 32-bit (do not use any other version)
  • tightvnc-2.6.4-setup-64bit.msi  : 64-bit (do not use any other version)

VM Option (A) – Windows 7 with Windows XP Mode (Free from Microsoft)

- Download and Install “WindowsXPMode_en-us.exe” (Google it)
- Download and Install “Windows6.1-KB958559-x64-RefreshPkg.msu”
- user: XPMUser, pass: password

VM Option (B) – Laptop is Windows 7 or 8 – Use VMplayer to run Windows 7

- Download and Install “VMware-player-6.0.1-1379776″  (or other version)
- Install Windows 7 (You need a valid license key or get a pirate one from BitTorrent)

VMware with Windows 7 is strongly recommended,  because there are something odd in Windows XP Mode, the keyboard/mouse is acting weird sometimes after connected to VNC.  Therefore, Windows XP Mode isn’t 100% work all the time. However, VMware is way more solid and I have been using it for 1 year with no issues at all.

Background

According to the forum and Jason’s idea, we should don’t need another virtual machine since we can enable loop back on VNC. However, it didn’t work for me. So I went with virtual machine option.

Note: In order to run the script smoothly, you should download the EXACT version of the TightVNC matching what I have. If you are running older version of TightVNC the filename may vary (vncviewer.exe vs tvnviewer.exe), also the title is different (“Standard VNC Authentication” vs “Vnc Authentication”). The script is hard coded to look for these values and it will not work if you use different version.  This can save you time from debugging the AutoIt script.

This has been tested on 64-bit workstation:

  • Host: Windows 7 Enterprise 64-bit (Dell laptop)
  • VM:  Windows XP Mode and VMware running Windows 7 Ultimate SP1
  • Lync 2010 Version 4.0.7557.4356 and 4.0.7577.4409

Installation and Configuration Steps

On your workstation:

  • Install Virtual Machine (VPC, VM or Windows XP Mode) software
  • VM Option (A) Windows XP Mode: If you are using Windows XP Mode,  on virtual network properly, do not use NAT. Connect the virtual NIC as direct connection (either LAN or wireless will work). Then make sure the VM can communicate with your workstation by using ping or file sharing, vice versa
  • VM Option (B)  VMWare:  If you are using VMware which is way smarter, you can use NAT (by default), it is even smart enough to connect to both your LAN and WiFi of your workstation
  • Install the Tight VNC SERVER and configure it with a password, in my example  I am using p@ssw0rd
  • For security, I changed the VNC default listening port 5800/5900 to 5840/5940
  • Check your workstation ip address, ipconfig and write it down. If you have both LAN and Wireless make sure you get the one that binds to the VM

On your virtual machine:

  • Install AutoIt software
  • Install TightVNC CLIENT
  • Download the LyncResetAwayStatus.au3 script (see link below) and copy to the VM
  • Open the .au3 file in AutoIt editor and check the $vncPath and $vncViewerExe are valid
  • Change the $vncServerHostPort to the IP address of your workstation. In my example, I have 172.11.22.33:40  (note: I have changed the default port t0 40, which is a short form for 5840/5940)
  • Change the $vncPassword   – VNC password
  • Change the $windowsPassword – your windows password that normally you log on to your workstation. In my example, I am using “f00kwork” as the windows password

Download: LyncResetAwayStatus.au3 (Right-click, Save Target As)

Source Code: (The script is totally free to use/distribute as long as you keep the copyright line)

; Auto Login to computer to get around "Away XXX minutes" in Microsoft Lync
;
; Usage: Pretend to be at desk preventing to show maximum XXX away time
;        You can have 2 hours lunch but people always see you are away for maximum 20 minutes
 
; Required:
; (1) AutoIt Version: 3.3.8.1+
; (2) TightVNC - install both on client and server depends on your OS 32/64bit (you need to update the path if 32bit is used)
;     tightvnc-2.6.4-setup-64bit.msi  (64 bit)
;     tightvnc-2.6.4-setup-32bit.msi  (32 bit)
;     *** TightVNC you are using must match the SAME VERSION specified here, because different version
;         may have different windows name and coordinate. Google .msi file and download the exact one. ***
 
; Tested on: Windows 7 Enterprise 64-bit
;            Lync 2010  Version 4.0.7557.4356 and Version 4.0.7577.4409
;            AutoIt 3.3.8.1 and 3.3.10.0
;
 
; Written and Copyrighted by: Mythos and Rini
; Created on: 2013-03-08
; Update:  2013-04-29 (Adding sleep to multiple places otherwise it does not always work)
 
; Jason More
; Unlock the computer using VNC
; ref: http://www.autoitscript.com/forum/topic/71333-solution-to-computer-locked-screen-ctrl-alt-del-scripting/
 
; Note that TightVNC upgraded,  vncviewer.exe has been changed to tvnviewer.exe
;           and "Standard VNC Authentication" has been changed to "Vnc Authentication" (case sensitive)
 
#include 
 
; This script requires full Administrative rights
#requireadmin
 
; The configuration based on Tight VNC 2.6.4  32-bit installation
Dim $vncPath = "C:\Program Files\TightVNC"
Dim $vncViewerExe = "C:\Program Files\TightVNC\tvnviewer.exe"
Dim $vncNewConnectionWindowName = "New TightVNC Connection"
Dim $vncAuthWindowName = "Vnc Authentication"
 
; Change the VNC host/port accordingly
 
Dim $vncServerHostPort = "172.11.22.33:40"
Dim $vncPassword = "f@@kwork"
 
; Windows password (do not need username)
Dim $windowsPassword = "p@ssw0rd"
 
; 60000 = 60 sec = 1 min.  sleep(60000 * 25) = 25 min
; This unlock the computer every 25 mins (it shows maximum 25 min on Lync)
; Dim $delay = 60000 * 25
 
Dim $delay = 60000 * 25
Dim $repeat = 5
Dim $i = 0
 
; Loop forever until being stopped manually
While $i &lt; $repeat
 
	  ; Script Start
 
	  sleep($delay)
 
	  ; Slowing down the key presses helps with the connection
	  opt("SendKeyDelay",10)
 
	  ; This should point to your tight vnc installation
	  run($vncViewerExe,$vncPath)
 
	  ; Wait for the new connection windows to come up
	  winwait($vncNewConnectionWindowName)
	  controlsend($vncNewConnectionWindowName ,"","Edit1", $vncServerHostPort)
	  controlclick($vncNewConnectionWindowName ,"","Button4")
 
	  ; Wait for the authenication window and send password
	  winwait($vncAuthWindowName)
	  controlsend($vncAuthWindowName,"","Edit2", $vncPassword)
	  controlclick($vncAuthWindowName,"","Button1")
 
	  ; Sleep for 2 seconds
	  sleep(2000)
 
      ; Use AutoIt WindowsInfo or Microsoft Spy++ to get the class name
	  $VncClassName="[CLASS:TvnWindowClass]"
 
		; Get all the active/minimized VNC windows
		$winList = WinList($VncClassName)
 
		For $a = 0 to $winList[0][0]
 
		   ; Activate Communicator window if there is any
		   If WinActivate($winList[$a][0]) Then
 
			  ; Get title of VNC
			  $title = WinGetTitle($winList[$a][0], "")
 
			 ; Debug
			 ; MsgBox(0, "Title", $title)
 
			  ; Clear any keys pressed or input waiting box
			  controlsend($title,"","TvnWindowClass1","{ESC}")
			  sleep (8000)
 
			  ; Click the button "Ctrl-Alt-Del" on the TightVNC toolbar
			  controlclick($title,"","ToolbarWindow321","left",1,170,13)
 
			  ; CTRL-ALT-DEL does not guarentee to work, for reference only. It is commented out
			  ;sleep(1000)
			  ;controlsend($title,"","TvnWindowClass1","{LCTRL down}{ALT down}{DEL down}")
			  ;sleep(1000)
			  ;controlsend($title,"","TvnWindowClass1","{LCTRL up}{ALT up}{DEL up}")
 
                          ; Logon to Windows using the password 
			  sleep (8000)
			  controlsend($title,"","TvnWindowClass1", $windowsPassword)
			  sleep (8000)
			  controlsend($title,"","TvnWindowClass1", "{ENTER}")
 
 
                          ; Move mouse with random coordinates (if doesn't do this, it will still be away)
                          $x=Random(0,800)
                          $y=Random(0,600)
                          MouseMove($x, $y, 50)
                          sleep (8000)
 
			  ; Re-lock the screen by vnc toolbar
			  sleep (8000)
			  controlclick($title,"","ToolbarWindow321","left",1,170,13)
 
			  sleep (8000)
			  controlsend($title,"","TvnWindowClass1","{ENTER}")
 
			  ; CTRL-ALT-DEL does not guarentee to work, for reference only. It is commented out
			  ; Re-lock the screen by using CTRL-ALT-DEL
			  ;sleep(1000)
			  ;controlsend($title,"","TvnWindowClass1","{LCTRL down}{ALT down}{DEL down}")
			  ;sleep(1000)
			  ;controlsend($title,"","TvnWindowClass1","{LCTRL up}{ALT up}{DEL up}")
			  ;sleep(1000)
			  ;controlsend($title,"","TvnWindowClass1","{ENTER}")
 
			  ; Close the VNC viewer
			  sleep(8000)
			  WinClose($title)
		   ENdIf
 
		Next
 
		$i = $i + 1
 WEnd

Before running the script, test it manually using the VNC client from the VM, see if you are able to connect to the VNC server. If it works, then run the AutoIt script.

Configurations

  • $repeatDelay = 60000 * 25 (Your coworker/boss will see you being away for 25 minutes max.)
  • $repeat = 5 (Repeat this 5 times, this can buy you 2.5 hours to step away from the office)

Steps to execute this successfully

  1. Because of DHCP, your workstation IP can change every day. Update the IP address in AutoIt script on the VM, use the VNC client to test it
  2. On the VM, Run the .au3 script
  3. On your workstation, minimize the VM window to your taskbar to prevent infinite windows popping
  4. Lock your workstation
  5. Power off your monitor (if you are using workstation) and Close the lid about 70% (if you are using laptop – don’t close it complete or your laptop will go to sleep. Of course, you can change your power settings on the lid behavior.

Make sure you do the last 3 steps, otherwise people working around will see your mouse moves as well as someone typing on your computer. They will freak out and/or ruin your step away from the office plan. Enjoy and keep slacking!!!

Event Log

Check the event log on your workstation to make sure everything is working, in the last 2 screenshots, I have successfully audited the 2 events:

- 2013-1-13 1:52:16 PM (UnLocked) Event 4801
- 2013-1-13 1:52:32 PM (Locked) Event 4800

 

Related Useful Files for AutoIt

(1)  Always On Mouse Only (Updated): The article I wrote 4 years ago came with this “Always On Mouse Only” script but I found that the mouse movement was to big, so this is an updated version. It moved by 1 tiny pixel. Enjoy!

Download: AlwaysOnMouseOnlySmallMove.au3 (Right-click, Save Target As)

(2) Lock workstation after certain time: Combine with “Always On Mouse script” running on your workstation, you can actually leave the office (take the subway and gone home) to pretend someone is in the office somewhere and it will lock the workstation after 3 hours. I used this script during holiday season.  Well, you can use “shutdown /t” to log off or shutdown actually, but this script just try to demonstrate how to just “lock” instead.

Download: LockWorkstationAfterCertainTime.au3 (Right-click, Save Target As)

Posted in Network/Hardware | Tagged , , , | Leave a comment

C#/SQL Singleton: The connection was not closed. The connection’s current state is open or state is connecting

We had a multiple-million dollar project written by a 3rd party consulting company, one of the SOAP WCF web services has been failing occasionally  (this is the hint).  Looking at the log of a black box, I saw the error:  “The connection was not closed. The connection’s current state is open (or connecting)”. Interesting thing is that, it only happened when 2 transactions were extremely close to each other (milliseconds apart).

2014/01/11 11:02:33.130 [ID:111] Opening DB, previous state: Closed
2014/01/11 11:02:33.145 [ID:123] Opening DB, previous state: Connecting.
2014/01/11 11:02:33.149 [ID:123] The connection was not closed. The connection’s current state is connecting.

Result:  ID:111  successfully wrote the record to database, but ID:123 never made it.  In some other cases, the error was “The connection was not closed. The connection’s current state is open.”

Before looking into the code,  I wrote a simple asynchronous WCF client tool (Using windows form with BackgroundWorker to generate concurrent threads) to simulate the multi-threaded high volume environment.  When I used the tool to hit the WCF service with > 50 threads.  Bingo!!  I was able to reproduce the error.

After some analysis,  here is the snippet. Let’s look at the problematic code:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Data;
using System.Data.SqlClient;
using System.Diagnostics;
 
public class Database
{
    private SqlConnection sqlConnection;
    private static Database _instance;
 
    // Bad Singleton - do not use!!!
    public static Database DBInstance()
    {
        if (_instance == null)
            _instance = new Database();
 
        return _instance;
    }
 
    // Constructor
    private Database()
    {
        sqlConnection = new SqlConnection(ConfigurationManager.ConnectionStrings["DB_ConnectionString"].ConnectionString);
    }
 
    // Create Record in DB
    public void CreateRecord()
    {
        try
        {
            sqlConnection.Open();
            SqlCommand sqlCommand = new SqlCommand();
            sqlCommand.CommandText = @"INSERT INTO table (ProductName, Description) VALUES('test', 'test')";
            sqlCommand.Connection = sqlConnection;
            sqlCommand.ExecuteNonQuery();
        }
        catch (Exception ex)
        {
            Debug.WriteLine(ex.ToString());
        }
        finally
        {
            sqlConnection.Close();
        }
 
    }
}

On the other side of a consumer class, we had the following 2 lines. One took a database instance and created a record in the table, the other one wrote some info to audit log (no need to show details implementation).

1
2
Database.DBInstance().CreateRecord();
Logger.WriteAuditLog(Database.DBInstance(), "audit info");

Quiz: As a developer, do you see any problem?

At this point, do you see any problems? If you don’t, obviously you are one of those developers who started to write code without going through formal Software Engineering study. This is a very simple race condition problem. The code will run perfectly fine on your local machine passing all Unit Testing cases, and even running fine on QA/UAT/PRD until high traffic hits. Okay, what is the problem then?

First of all,  the original developer was trying to do lazy initialization using Singleton-like code without implementing DCL (Double Check Locking), i.e. the “Database” instance is not thread-safe.  I am not going to discuss Singleton and DCL since there are tons of articles out there.  In my opinion, Singleton with SqlConnection is really stupid because you don’t take the advantage of Connection Pool implemented by Microsoft.

By implementing DCL, the code should look like this. Now this guarantees there is only 1 instance of “Database” object at all times.  “Database” instance is now thread-safe.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
........
........
public class Database
{
    private SqlConnection sqlConnection;
 
    // Singleton with padlock for DCL
    private volatile static Database _instance;
    private static readonly object _padLock = new Object();
 
    public static Database DBInstance()
    {
        // Singleton with Double Check Locking
        if (_instance == null)
        {
            lock (_padLock)
            {
                if (_instance == null)
                    _instance = new Database();
            }
        }
        return _instance;
    }
 
    .....
    ..... 
    .....
}

Does DCL alone solves the problem?

No,  still got the previous connection connecting/open error.  The problem is CreateRecord(),  having Singleton doesn’t mean the methods within the same class is using the same thread.

Solution #1: Synchronization and Double Check Locking 

To solve the problem,  we can put the synchronization logic on method level:

1
2
3
4
5
6
7
8
    .....
    using System.Runtime.CompilerServices;
    .....
 
    [MethodImpl(MethodImplOptions.Synchronized)]
    public void CreateRecord()
    {
    .....

This solved the CreateRecord() issue. But remember, there is another line WriteAuditLog that passes the Database instance to the Logger class. This is really bad. By commenting out the 2nd line for testing,  all records have written to the database successfully.

1
2
Database.DBInstance().CreateRecord();   // pass
Logger.WriteAuditLog(Database.DBInstance(), "audit info"); // fail

 Passed:  I threw > 1000 records using concurrent threads via WCF calls (comment out 2nd line Logger for temporary test)

Now, what is the problem with 2nd line WriteAuditLog? Same issue, the WriteAuditLog is not thread-safe! So you need to ensure all methods are synchronized. Well, fixing methods is fine, but how can you prevent developers in the future passing Database.DBInstance() to some new class they are creating? This can get out of control.

Solution #2: Quickest way to fix the problem with ThreadStatic

See how complicated it can get above? Let’s forget about Singleton and use [ThreadStatic] attribute.  One line of code fixes everything – this can ensure each Database instance runs on its own thread. Note, this is not real singleton anymore. It’s your choice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
.....
.....
 
public class Database
{
    private SqlConnection sqlConnection;
 
   [ThreadStatic]
    private static Database _instance;
 
    public static Database DBInstance()
    {
        if (_instance == null)
            _instance = new Database();
 
        return _instance;
    }
 
.....
.....

 Passed:  I threw > 1000 records using concurrent threads via WCF calls

Solution #3:  Simply creating a new instance of object like Factory method

Again, forget about Singleton and return a new object by calling Database() constructor. Note, this is not real singleton anymore, it’s just like a generic factory method.  It’s your choice.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
......
......
 
public class Database
{
    private SqlConnection sqlConnection;
 
    public static Database DBInstance()
    {
        // Calling Constructor to create new instance of SqlConnection
        return new Database();   
    }
    ......
    ......
}

Passed:  I threw > 1000 records using concurrent threads via WCF calls


Why Singleton and/or Static? 

There is nothing wrong with Singleton and/or Static, they will work perfectly if they are implemented properly. But in real life you are dealing with inexperience developers, people may not even have experience in Threading. Many people just think these design patterns are cool and try to use them in the project, especially after going for training or reading the famous book design pattern GOF. Sigh…. This is a lesson learned when it comes to outsourcing.

Most of the web/SOA/WCF applications in business world, creating objects vs static vs singleton don’t make a huge difference in terms of memory and performance. The time you spend to troubleshoot, the data you lose and complains from clients may not worth it. I believe these problems are totally avoidable – just create the damn objects always!  One less to worry about.  Why not spend time on optimizing your LINQ and SQL instead? There are so many potential performance issues in Microsoft applications –  why not try to throw 500K records of data to see if your LINQ perform as fast?  Then, try to delete all 500K records from application and see how long it takes?  If you are talking about pure memory/performance, why not forget about C#/java and go with C++/assembly?

Evil Plan

Bad people write viruses to infect other people machine, but you can intentionally implant these bugs in your company’s applications where you hate the most. Software bugs kill people is not new, Google Toyota’s Prius case.  The coolest thing is that, it is legal to have bugs in software,  there is nothing the law can do to you since they cannot prove you do it intentionally or you get benefits from it.  Also, if you ask an inexperience developer,  they will probably blame on the network and hardware since these only happens occasionally.   Probably for some, they will never able to figure it out.

Remember, Guns can be used to protect people and at the same time it can be used to kill. Can you blame the inventor of guns?  How to use your knowledge is your choice.

 

Posted in Development - .NET | Tagged , , , , , , , , , , | Leave a comment