You know how it is – you’re doing something on a server and just now putty.exe or some other small executable would come in handy. Unfortunately, it’s not there, and maybe the server you’re on does not have internet access, either. Every administrator has been in this situation before, and you know what’s next. Search for the tool on another machine, maybe download it first from the internet, then copy it to the server’s c:\temp etc.
I’ve run into this situation once too often and decided to do something about it. While I was at it, I also decided to have a look at BGInfo and make sure all my servers were always up to date with the newest version of BGInfo. The solution uses Group Policy Preferences to create a c:\tools folder on all machines in my environment and copies some binaries into it. Additionally on servers, a c:\tools\bginfo folder is created, also complete with binaries and configuration files. Last but not least I use Group Policy Preferences to create a scheduled task on servers that is triggered at logon and calls BGInfo.
First you need a central repository for the files that are going to be copied to your c:\tools folder. Since at the moment I’m only copying a small number of files I’ve decided to use the good old NETLOGON share, in other words the folder where the NT4 logon script used to reside. This has the added benefit of automatic replication of my “global tools”. Small companies might want to go for this, too, especially if they only have one or a limited number of physical locations. I would not recommend using this approach if you have a large number of sites, since replication can take quite some time and depending on the number of changes to the global tools you could end up with network performance issues.
So first I created the “tools” folder in my NETLOGON share, for which you need Administrator rights. I also created the “BGInfo” subfolder and copied the appropriate binaries and other files to the two folders:
The next step is configuring the Group Policy. Since I want the “c:\tools” folder to be created on all machines in my network (clients and servers) and the “c:\tools\BGInfo” should only be created on server operating systems I used a Group Policy at the top (domain) level. And since I don’t like to change the Default Domain Policy too much I created a “Global Tools and Settings” policy at the same location.
After creating and linking the Group Policy, open it and navigate to Computer Configuration > Preferences > Windows Settings > Folders. Here we’ll create two policies to automatically create the “c:\tools” folder on all computers and the “c:\tools\BGInfo” folder only if it’s a server operating system.
The first one is straightforward:
After that, create the second item:
We’re not quite done yet; navigate to the “Common” tab. There, select “Item-level targeting” and click on the “Targeting…” button and create this:
As you can see, this policy will target all editions, releases and roles of any Windows Server 2003, 2008 or 2008 R2 system. Make sure to switch the operator to “OR” from its default “AND” by selecting the “Item Options” dropdown for the second and third entry. When finished, close this and the previous dialog box with “OK”.
Finally, make sure you got the order right. The “c:\tools” folder needs to be created before its subfolder, so the final setup should be like this:
After having created the folders the files need to be copied. You could do this in the computer configuration part of the Group Policy (Computer Configuration > Preferences > Windows Settings > Files) or like in my setup in the user configuration part: User Configuration > Preferences > Windows Settings > Files. The reason I do this in the user part is because I also copy a PowerShell profile where I have to target the user’s profile path (%userprofile%\Documents…). I’m a big believer in keeping my policies relatively simple and doing similar stuff all in one place.
The two policy items needed to do the copy are quite similar to the items we created before. First the one that will apply to all machines:
No additional settings are needed for this one. Also this will ONLY copy the files that are in the directory specified as “Source file(s)”. It will NOT copy any subfolders and their files, which in this case is actually what we want.
The second item again uses item level targeting to make sure only servers get the BGInfo binaries and config files:
And finally we need to create the BGInfo scheduled tasks. Yes that’s right, plural – the Scheduled Tasks engine changed in Windows Server 2008, therefore you can create scheduled task items that will run on Windows 2000/2003 or items that will target Windows Server 2008 and later.
Navigate to User Configuration > Preferences > Control Panel Settings > Scheduled Tasks. The first step is identical for both items we’re going to create:
Fill in the information on the first page, including the targeted operating system:
Next, change to the “Triggers” tab and click “New…”. Select to begin the task “At log on” and leave the rest of the settings at their default values:
Switch to the “Actions” tab and create a new action:
Skip the “Conditions” and “Settings” tabs and use the “Common” tab to enable item level targeting:
Since on the first page we defined that the task would apply to Windows 2000/2003/XP operating systems all that is needed here is the restriction to only apply to any edition of Windows Server 2003 (and 2000 should you still have some really old stuff hanging around).
After this you can create the second scheduled task that will target Windows Server 2008 and later. The configuration looks the same with the exception of the first and last pages:
As an additional bonus here’s what my BGInfo looks like.
Configuration in BGInfo:
The “<IPv6>” and “<Uptime>” values are gathered using two VBScript files which are also located in the “c:\tools\BGInfo” folder:
On Error Resume Next strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set arrIP = objWMIService.ExecQuery _ ("SELECT IPAddress FROM Win32_NetworkAdapterConfiguration where IPEnabled = TRUE") 'IPv6 = "" For Each oIP in arrIP IPs = oIP.IPAddress For Each strIP in IPs If Instr(strIP,":") Then IPv6 = IPv6 & strIP & vbCrLf 'IPv6 = IPv6 & vbTab & strIP & vbCrLf End If Next Next 'WSCript.echo does not work from BGInfo - have to use echo instead: Echo IPv4 & vbCrLf & IPv6
On Error Resume Next strComputer = "." Set objWMIService = GetObject("winmgmts:\\" & strComputer & "\root\cimv2") Set colOperatingSystems = objWMIService.ExecQuery _ ("Select * From Win32_PerfFormattedData_PerfOS_System") For Each objOS in colOperatingSystems intSystemUptime = objOS.SystemUpTime Next ' Calculate Days: save total seconds intSecsTotal = intSystemUpTime ' Divide total seconds by daily seconds and truncate decimal portion intDays = Fix( intSecsTotal / 86400 ) ' Isolate remaining [hourminutesecond] total seconds = total seconds - ( days * 86400 seconds ) intSecsRemaining = ( intSecsTotal - ( intDays * 86400 )) ' Calculate Hours: save total remaining seconds intSecsTotal = intSecsRemaining ' Divide total seconds by hourly seconds and truncate decimal portion intHours = Fix( intSecsTotal / 3600 ) ' Isolate remaining [minutesecond] total seconds = total [hourminutesecond] seconds - ( hours * 3600 seconds ) intSecsRemaining = ( intSecsTotal - ( intHours * 3600 )) ' Calculate Minutes and Seconds: save total remaining seconds intSecsTotal = intSecsRemaining ' Divide total seconds by minute seconds and truncate decimal portion intMinutes = Fix( intSecsTotal / 60 ) ' Isolate remaining total seconds = Total [minuteandsecond] seconds - (minutes * 60 seconds) intSeconds = ( intSecsTotal - ( intMinutes * 60 )) 'WSCript.echo does not work from BGInfo - have to use echo instead: Echo intDays & " days, " & intHours & " hours, " & intMinutes & " minutes and " & intSeconds & " seconds" 'WScript.Echo intDays & " days " & intHours & " hours " & intMinutes & " minutes " & intSeconds & " seconds"
One last point – theoretically the first policy items to create the folder shouldn’t be necessary, since the “copy file” operations should create any folders that do not yet exist at the destination. I’ve had mixed success with this and decided to make sure the folders really exist before trying to copy any files. It’s been a while since I’ve set this up, so it’s possible that this now works 100% of the time. And if Microsoft ever changes the copy file behavior to include subfolders you’ll need to adjust the folder structure of your global repository accordingly or you’ll end up with the “BGInfo” subfolder on all clients, too.