Monday, June 8, 2015

Video surveillance - Hikvision IP cameras with Xeoma NVR software solution

I recently switched from analogue cameras and dedicated DVR to IP cameras in order to consolidate my infrastructure.
I acquired 2 different Hikvision full-HD (3MP) IP cameras which appear to be a good quality/cost compromise.
These cameras are :
for internal use : DS-2CD2432F-I(W)
for external use : DS-2CD2332-I

These IP cameras come with internal software but I wanted to manage them centrally.
I had a look at different NVR software solutions.
- Hikvision offers a free but limited software (iVMS-4200 PCNVR) (Windows).
- ISpyConnect (Windows)
- ZoneMinder (Linux)
- Xeoma (Windows, Linux, MacOS, Android)

I wished to run it on Linux preferably to lower the resource requirements.

  • Hikvision solution runs well with good video quality but has no remote access for mobile devices, and event/trigger/action is pretty limited.

  • ISpyconnect seemed to work initially but has some smearing effects very often. It also requires to use a cloud account to remotely access your own NVR.

  • ZoneMinder is free and runs on Linux which are good points and offers mobile device oriented web portal. It has many many settings but interface is basic.
Main drawback here again is the smearing effect which is blocking for this purpose.

    •  First excellent point, the video quality is as good as on the proprietary Hikvision software

    • Then it runs on multiple OS
    •  It is composed of a server and a client, and you can then run the server only on a light headless linux machine (or a VM) and operate it from your Windows laptop for instance
    • The interface is clean, intuitive and event/trigger/action are graphically managed by chaining module boxes

    • You can as well use external service like clickatell to send text messages on alerts.

    •  I found that it lacks some monitoring app for IOS and Windows Phone, but you can create a custom view web server using the web server module and access it from your phone's browser or any device, so it's not blocking.
    • Basic network layout
 Definitely this piece of software makes it easy to manage your camera and if you have Hikvision IP cameras, Xeoma is the only one that displays/records correctly the streams (in addtion to Hikvision own software of course).

Tuesday, May 3, 2011

TAPI Calling from Outlook and Lync 2010 issues

After installing Lync 2010 the TAPI calling feature in Outlook 2010 no longer was working. It seems that Outlook uses Lync as it’s default “Call Contact” method.

To change this you need to override this setting in the registry with the following key (you can paste this to a “.reg” file and double click it to add it to the registry):

[HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Office\Outlook\Call Integration]

Monday, April 4, 2011

Enable hidden features in Zune

When I switched the Windows Live account I was using in Zune from a US registered account to a German registered account I wondered where all the features like podcast browsing and SmartDJ disappeared to.

For some reason Microsoft thinks that if you are in Germany you might not understand how these things work if there are not in the German language ;).

To turn these features on you have to add a registry key “FeaturesOverride” in HKCU\Software\Microsoft\Zune\ and add the DWORD values as in the graphic below:


Open up Zune and the features should be there :D

Blob Cache for SharePoint 2010

On a SharePoint Web Front End you can turn on the BLOB cache which allows the webserver to cache certain file types on the front end without having to go back to the SQL server.

The setting for doing this is in the web.config file of the web application. For example to activate it on the cp Portal I used the following configuration:

<BlobCache location="C:\BlobCache\14" path="\.(gif|jpg|jpeg|jpe|jfif|bmp|dib|tif|tiff|ico|png|wdp|hdp|css|js|asf|avi|flv|m4v|mov|mp3|mp4|mpeg|mpg|rm|rmvb|wma|wmv)$" maxSize="10" enabled="true" />


The line was already in the web.config file but I had to change enabled to “true” and also create the folder c:\BlobCache

The users also have to be changed a la:

Monday, March 14, 2011

Issues with Delta CRL Publishing to IIS

I have an Enterprise CA that publishes its CRL to an IIS (7.5) website. The CA adds a plus (+) character to the file name for the Delta CRL.

In order for IIS to show this plus sign properly you need to allow double escaping. You can do this with powershell:

Set-WebConfiguration -Filter system.webServer/security/requestFiltering -PSPath ‘IIS:\sites\My Web Site’ -Value @{allowDoubleEscaping=$true}

You may need to import the IIS module first with:

Import-Module Webadministration

Friday, February 25, 2011

Batch edit shortcut targets with a VB Script

On some file servers, users create multiple shotcuts pointing to different locations on the same server.
When migrating data from this server to another, these shorcuts are deprecated, so you need to update them and you can have thousands...
Here is a VB script that let you batch edit these shortcuts so that you can keep all of them updated.

Dim objFSO

Const srcServer = "\\formerServer\"
Const dstServer = "\\newServer\"

args = WScript.Arguments.Count

If args < 1 then
WScript.Echo "usage: cscript replaceLinkTarget.vbs [folder]"
End If

Set objFSO = CreateObject("Scripting.FileSystemObject")

Call FindEditShortcut(WScript.Arguments.Item(0))

Sub FindEditShortcut(currentDrive)
Dim objFile
Dim objFolder

For Each objFolder In objFSO.GetFolder(currentDrive).SubFolders
For Each objFile In objFolder.Files
'Check extension
If LCase(objFSO.GetExtensionName(objFile)) = "lnk" Then
Set objShell = CreateObject("WScript.Shell")
Set shortcut = objShell.CreateShortcut(objFile.path)
target = LCase(shortcut.TargetPath)

If (InStr(target, srcServer) > 0) Then
target = replace(target,srcServer,dstServer)
Wscript.Echo "New target : " & target
shortcut.TargetPath = target
End If
End If

Call FindEditShortcut(objFolder)
End Sub

Wednesday, January 19, 2011

Browse a Windows Server 2008 through an alias with explorer

When migrating a server to a new one, you may want to create an alias with the old server name to the new one.
DNS will resolve it, but browsing through explorer will fail.
In order to solve this, start RegEdit and deploy :
Then create a new DWORD value called : DisableStrictNameChecking and set it to 1.
Restart your server.

Thursday, January 13, 2011

Add language pack even if the feature is missing / unavailable in Windows 7 (or Vista)

On computers purchased from manufacturers like Dell, HP..., a Windows 7 OEM version is installed.
In these OEM versions, contrary to Microsoft contracted versions, the button to add a language pack from a MUI is unavailable (Control Panel / Region and Language / Keyboards and Languages).

If you bought your system abroad or Windows doesn't match the user's language, you can still do it successfully on Windows 7 and Vista with this little utility : Vistalizator

Monday, November 15, 2010

Password change reminder script for all AD

If you have remote users in your domain, they are not notified by the DC when their password is about to expire, because they open their windows session before the VPN client can connect to the DC.

Here is a script that you can run daily on your DC to send an email to users from an OU, everyday for some days before it expires.
So they know they have to change it before it really expires.

Option Explicit

' Per environment constants - you should change these

Const SMTP_SERVER = "emailserv.mydomain.intra"               ' your mail server

Const STRFROM = "dcserv@mydomain.intra"               ' your DC

Const DAYS_FOR_EMAIL = 14                          'Send notification when pwd will expire in this number of days

Const GROUPDN = "CN=USERS_OU,OU=Groups,OU=Domain Users,DC=mydomain,DC=intra"     ' Recurse this user OU

Const LOGFILE = "C:\Scripts\PasswordExpiration\passwordexpiration.log"     ' Log file path

' System Constants - do not change

Const ONE_HUNDRED_NANOSECOND = .000000100 ' .000000100 is equal to 10^-7

Const SECONDS_IN_DAY = 86400



' Change to "True" for extensive debugging output

Const bDebug = False

Dim numDays, iResult

Dim strDomain

Dim objGroup, objMember, member

Dim objFSO, objFile, strOutput

Set objFSO = CreateObject("Scripting.FileSystemObject")

If objFSO.FileExists(LOGFILE) = True Then


End If

Set objFile = objFSO.OpenTextFile(LOGFILE, 8, True)

Set objGroup = GetObject("LDAP://" & GROUPDN)

objFile.WriteLine "Executed at " & Now() & vbCRLF

objFile.WriteLine "Enumerating members of " & objGroup.distinguishedName & ":" & vbCRLF

Call GetSubMembers(objGroup)

objFile.WriteLine "Done. Finished at " & Now() & "."



Function GetSubMembers (GroupObject)

Dim TmpMember

numDays = 0

If (TypeName(GroupObject.Member) = "Empty") Then

Exit Function

End If

If (TypeName(GroupObject.Member) = "String") Then

     TmpMember = GroupObject.Member

     Set objMember = GetObject("LDAP://" & GroupObject.Member)

     If (LCase(objMember.Class) = "user") then

      Wscript.Echo objMember.sAMAccountName

strDomain = Mid(objMember.distinguishedname, InStr(objMember.distinguishedname, "DC="))

      numdays = GetMaximumPasswordAge (strDomain)

objFile.WriteLine objMember.sAMAccountName & " " & TmpMember & " " & numdays & " " & objMember.Mail

Call ProcessUser (numDays)


      Wscript.Echo "Group : " & objMember.CN

objFile.WriteLine "Group 1: " & objMember.CN

      Call GetSubMembers(objMember)

     End If


For Each TmpMember In GroupObject.Member

      Set objMember = GetObject("LDAP://" & TmpMember)

If (LCase(objMember.Class) = "group") Then

      Wscript.Echo "Group : " & objMember.CN

objFile.WriteLine "Group 2: " & objMember.CN

Call GetSubMembers(objMember)


      Wscript.Echo objMember.sAMAccountName

strDomain = Mid(objMember.distinguishedname, InStr(objMember.distinguishedname, "DC="))

      numdays = GetMaximumPasswordAge (strDomain)

objFile.WriteLine objMember.sAMAccountName & " " & TmpMember & " " & numdays & " " & objMember.Mail

Call ProcessUser (numDays)

End If


End If

End Function

Function GetMaximumPasswordAge (ByVal strDomainDN)

     Dim objDomain, objMaxPwdAge

     Dim dblMaxPwdNano, dblMaxPwdSecs, dblMaxPwdDays

     Set objDomain = GetObject("LDAP://" & strDomainDN)

     Set objMaxPWdAge = objDomain.maxPwdAge

     If objMaxPwdAge.LowPart = 0 And objMaxPwdAge.Highpart = 0 Then

          ' Maximum password age is set to 0 in the domain

          ' Therefore, passwords do not expire

          GetMaximumPasswordAge = 0


          dblMaxPwdNano = Abs (objMaxPwdAge.HighPart * 2^32 + objMaxPwdAge.LowPart)

          dblMaxPwdSecs = dblMaxPwdNano * ONE_HUNDRED_NANOSECOND

          dblMaxPwdDays = Int (dblMaxPwdSecs / SECONDS_IN_DAY)

          GetMaximumPasswordAge = dblMaxPwdDays

     End If

End Function

Function UserIsExpired (objMember, iMaxAge, iDaysForEmail, iRes)

     Dim intUserAccountControl, dtmValue, intTimeInterval

     Dim strName

     On Error Resume Next


     strName = Mid (objMember.Name, 4)

     intUserAccountControl = objMember.Get ("userAccountControl")

     If intUserAccountControl And ADS_UF_DONT_EXPIRE_PASSWD Then

          dp "The password for " & strName & " does not expire."

          UserIsExpired = False


          iRes = 0

          dtmValue = objMember.PasswordLastChanged

          If Err.Number = E_ADS_PROPERTY_NOT_FOUND Then

               UserIsExpired = True

               dp "The password for " & strName & " has never been set."


               intTimeInterval = Int (Now - dtmValue)

               dp "The password for " & strName & " was last set on " & _

               DateValue(dtmValue) & " at " & TimeValue(dtmValue) & _

               " (" & intTimeInterval & " days ago)"

               If intTimeInterval >= iMaxAge Then

                    dp "The password for " & strName & " has expired."

                    UserIsExpired = True


                    iRes = Int ((dtmValue + iMaxAge) - Now)

                    dp "The password for " & strName & " will expire on " & _

                    DateValue(dtmValue + iMaxAge) & " (" & _

                    iRes & " days from today)."

                    If iRes <= iDaysForEmail Then

                         dp strName & " needs an email for password change"

                         UserIsExpired = True


                         dp strName & " does not need an email for password change"

                         'Swap commented variable below to force email to be sent (for testing).

                         UserIsExpired = False

                    End If

               End If

          End If

     End If

End Function

Sub ProcessUser (iMaxPwdAge)

     Dim iResult, strExpire

     If Right (objMember.Name, 1) <> "$" Then

          If IsEmpty (objMember.Mail) or IsNull (objMember.Mail) Then

               dp Mid (objMember.Name, 4) & " has no mailbox"


               If UserIsExpired (objMember, iMaxPwdAge, DAYS_FOR_EMAIL, iResult) Then

                    objFile.WriteLine "Sending an email to " & objMember.givenName & " " & & _

                         " (" & objMember.Mail & "). Password expires in " & iResult & " days." & vbCRLF

                    Call SendEmail (iResult)


                    If iResult = "" Then

                         strExpire = "."


                         strExpire = " for " & iResult & " days."

                    End If

                    objFile.WriteLine "Skipping " & objMember.givenName & " " & & _

                         ". Password does not expire" & strExpire & vbCRLF

               End If

          End If

     End If

End Sub

Sub SendEmail (iResult)

     Dim objMail

     Set objMail = CreateObject ("CDO.Message")

     objMail.Configuration.Fields.Item ("") = 2

     objMail.Configuration.Fields.Item ("") = SMTP_SERVER

     objMail.Configuration.Fields.Item ("") = 25


     objMail.From = STRFROM

     objMail.To = objMember.Mail

     objMail.Subject = "[IMPORTANT] :: The Windows password of " & Mid (objMember.Name, 4) & " is going to expire"

     objMail.Textbody = "Hello, The Windows Active Directory password for user " & objMember.givenName & " " & & _

" (" & objMember.sAMAccountName & ")" & " will expire in " & iResult & " days. " & vbCRLF & vbCRLF & _

"Please change it before it expires (CTRL+ALT+DEL, then change password)." & vbCRLF & vbCRLF & _

"If you are a remote user, please connect with your VPN client and then change the password (so that DC server will be notified). The VPN peer will be automatically updated within 5 minutes." & vbCRLF & _

"You can also use Outlook Web Access with Internet Explorer (richer GUI than in Firefox) from outside to change it before it expires." & vbCRLF & vbCRLF & _

"If you have a phone with email capability, please change your password on it too." & vbCRLF & vbCRLF & _

"Thank you."


     Set objMail = Nothing

End Sub

Sub dp (str)

     If bDebug Then

          objFile.WriteLine str

     End If

End Sub

MBR / GPT partition style and Windows Server 2008 R2 system partition

GPT partition style has been introduced to expand the limitations of the MBR (2TB).

Today with disks of 2TB, you can have a raid system much larger than 2TB (eg : on a NAS, file server…)

If you wish to install a system on a 8TB partition for instance you need to create a partition on a GPT partition style of 8TB.

Windows can handle disks larger than 2TB, but not for the windows system installation…
Even Windows Server 2008R2 can only install on a MBR partition style, so up to a 2TB partition.

So you will have to split your raid into 2 and have Windows installed on the first and have data on the second.

For instance :

We have 5x 2TB HDD (initially a 8GB raid 5)

It can become :

2x 2TB HDD (raid 1) for Windows

3x 2TB HDD (raid 5) for data

So there is a lot of spare space on the first partition (system). Of course you can split into 2 partitions (system + data).

So you’d better have 2 small disks in raid 1 for the system and then have multiple large disks for data.

Be aware that NAS servers are usually sold with a bunch of large disks.