A customer asked me to assist with implementing a “Message of the Day” (MOTD) banner into their logon scripts. I had written one years ago that was part of a kix32 script, but found that it no longer worked with the wkix32 script processor. I guess that I could have debugged it and fixed it up, but it was old and tired, and needed a face lift. I was always keen to write one using a HTA (HTML Application), so took this opportunity to do so. In my opinion a HTML Application provides a far more professional look for the users.
When I sat down and designed the application I wanted to implement the following features:
- Separate the MOTD text into a text file, motd.txt, so that no one was actually modifying the HTA itself. This is also how my old kixtart one worked.
- Have it look for the motd.txt file in the same location as the HTA itself.
- Provide the ability to supply a command line argument to look for the motd.txt file on a common file share, such as the “netlogon” share on Domain Controllers, which would be “%LogonServer%\netlogon”.
- If the motd.txt file is missing, close the application. This is important, as it allows you to leave the HTA in place with the existence of the text file determining whether or not it runs.
- It was also important that the text from the motd.txt file is read in as it is typed. ie. No need to consider formatting, etc. To address this, my script simply appends a <BR> html tag to the end of each line. The <BR> tag provides a carriage return and line feed.
- I didn’t want multiple instances to run in the same user session at the same time. This can easily be controlled by using singleInstance property of the HTA Application.
- I didn’t want users being able to simply close or minimise the application. This can easily be controlled by using sysMenu property of the HTA Application. In fact, the only way for them to close the application is for them to accept that they have read and understood it. Unfortunately, if they have permission to do so, they can end the mshta.exe task from Task Manager. This may well be the case for some Desktop/Notebook fleets, but not on locked down Citrix/Terminal Servers.
It took me a while to get my head around the VBScript code for a few of the features I wanted to implement, as a HTML Application only supports pure VBScript and not the added commands I am used to using with the WScript/CScript Windows scripting host.
If you open a HTA using IE, you will get a security prompt. So to open the HTA silently without the IE security prompt you have two options:
- Associate .hta extensions with mshta.exe (Microsoft HTML Application host), the script host for a HTA, which is found in the %SystemRoot%\System32 folder. Then just double click or open the HTA itself.
- Simply launch it from the command line using mshta.exe in the syntax.
i.e. mshta.exe motd.hta
Passing command line parameters/arguments was a challenge until I came across a great Microsoft article by the “Scripting Guy” called How Can I Pass Command-Line Variables to an HTA When It Starts?. It provided me with the exact code required.
So if using command line parameters, you need to use quotes around them. For example:
mshta.exe motd.hta “netlogon”
If you read the Scripting Guy’s article, you will understand that the first argument is array member 3, second is 5, etc. But we are only concerned here with array member 3.
Now I have the mechanism to launch the HTA via the two methods I was looking for in my design.
- mshta.exe motd.hta - This will look for the motd.txt file in the same location as the motd.hta.
- mshta.exe motd.hta “netlogon”- This will look for the motd.txt file in the %LogonServer%\netlogon share.
Update from 27th March 2012
I received a lot of feedback to suggest that the HTA flashes on the screen and closes. This is due to the parameters not being passed correctly, and therefore the HTA is closing because it cannot find a valid motd.txt file. So I updated the Window-Onload subroutine as per the following:
Sub Window_Onload Dim strMOTDFile, arrCommands, strFullName, arrFullName, strScriptFileName, strLogonServer Dim strCommonPath, strPath, strcurrentPath, strLine, strContents, i, WshShell, oFSO, objFile Set WshShell = CreateObject("WScript.Shell") strMOTDFile = "motd.txt" arrCommands = Split(objHTAInfo.commandLine, chr(34)) strFullName = replace(objHTAInfo.commandLine,chr(34),"") arrFullName = split(strFullName,"\") strScriptFileName = arrFullName(ubound(arrFullName)) ' Uncomment the next three lines for testing only. ' For i = 3 to (Ubound(arrCommands) - 1) Step 2 ' Msgbox arrCommands(i) ' Next If Ubound(arrCommands) < 2 Then If instr(1,arrCommands(0),"Netlogon",1) = 0 Then strcurrentPath = replace(strFullName,strScriptFileName,"") strPath = strcurrentPath Else strLogonServer = WshShell.ExpandEnvironmentStrings("%LogonServer%") strPath = strLogonServer & "\Netlogon\" End If ElseIf Ubound(arrCommands) = 2 Then If (arrCommands(2) = "" OR arrCommands(2) = " ") AND instr(1,arrCommands(1),"Netlogon",1) = 0 AND instr(1,arrCommands(2),"Netlogon",1) = 0 Then strcurrentPath = replace(strFullName,strScriptFileName,"") strPath = strcurrentPath ElseIf instr(1,arrCommands(1),"Netlogon",1) > 0 OR instr(1,arrCommands(2),"Netlogon",1) > 0 Then strLogonServer = WshShell.ExpandEnvironmentStrings("%LogonServer%") strPath = strLogonServer & "\Netlogon\" Else ' Note that there are two different ways for presenting the path ' strcurrentPath = Left(document.location.pathname,InStrRev(document.location.pathname,"\")) strcurrentPath = Replace(Left(document.location.pathname,InStrRev(document.location.pathname,"\")),"%20"," ") strPath = strcurrentPath End If ElseIf Ubound(arrCommands) = 3 Then strLogonServer = WshShell.ExpandEnvironmentStrings("%LogonServer%") strPath = strLogonServer & "\Netlogon\" Else If instr(1,arrCommands(0),"Netlogon",1) > 0 OR instr(1,arrCommands(3),"Netlogon",1) > 0 Then strLogonServer = WshShell.ExpandEnvironmentStrings("%LogonServer%") strPath = strLogonServer & "\Netlogon\" Else strcurrentPath = replace(strFullName,strScriptFileName,"") strPath = strcurrentPath End If End If ' Uncomment the next line for testing only. ' Msgbox "Path to " & strMOTDFile & " is:" & strPath Set oFSO = CreateObject("Scripting.Filesystemobject") If oFSO.fileexists(strPath & strMOTDFile) Then Set objFile = oFSO.OpenTextFile(strPath & strMOTDFile, ForReading) Do Until objFile.AtEndOfStream strLine = objFile.ReadLine strContents = strContents & strLine & "<BR>" Loop objFile.Close document.getelementbyid("textarea").innerHTML = strContents End If Set WshShell = Nothing Set oFSO = Nothing Set objFile = Nothing End Sub
Update from 20th August 2013
I received feedback that the HTA was not working correctly with IE9 and IE10. I found that the code needed to be enhanced in two places:
1. Set the <!DOCTYPE> declaration for HTML 4 at the very top of the script as per the code below:
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
2. Set the http-equiv attribute to be compatible with IE8 within the <head> entry as per the code below:
<head> <meta http-equiv="X-UA-Compatible" content="IE=8"/> <title>Message of the Day</title>
The following screenshot is an example of what the MOTD HTA looks like when running.
There are four ways that you can implement this:
- Chain or call it from an existing logon script.
- Add it as a Logon Script in a Group Policy Object.
- Add it to the HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Run key on all computers.
- Add a shortcut to the “%ALLUSERSPROFILE%\Start Menu\Programs\Startup” folder on all computers.
Download the code: motd.zip
- Log the acceptance to a file or registry before closing the application. This can provide some legal and compliance tracking if needed.
- Add the customers logo into the application. This is simple to do, but I need to consider where on the banner to locate the logo, and how I can construct some code that manages different size logos.
- Implement different messages based on Group Membership. Could be of value to different organisations. You can actually do this already using multiple Group Policy Objects. However, my idea was to implement this by using different group membership tags within the one motd.txt file that would expose different lines and paragraphs to users depending on their group membership. Probably more complex than it needs to be, but would make a nice feature.
Please feel free to use as you wish and provide any useful feedback you feel may be of benefit to others.