Sunday 12 February 2012

Forcing Gadgets on a Desktop? COMPUTER SAYS NO!

We recently decided to implement a new software solution for printing called PaperCut to try and decrease the amount of paper wasted through out the school. Although PaperCut does do account balances, crediting and print job releases, we where wanting it more for the monitoring of print jobs and to display a users environmental impact of there printing. This will mean lower maintenance for the IT Department for the new system as we will not be having to credit users as they begin to run low and the ethos of printing will be changed to the users considering the environmental impact of there printing rather than our department being seen as "The Big Bad Wolf".

This is working well, but to display the individual user impact could be done a few different ways:
- Client run on login
- Local web gadget on sharepoint portal
- Win 7 Gadget on the desktop

The local sharepoint portal display will be very easy to implement once a gadget has been made to interpret a JSON stream which the Paper Cut server makes available and has the added bonus of showing the total impact throughout the entire schools printing.
This works well but we also discussed and decided that we wanted something more confronting than a web gadget in the portal to show an immediate consequence to there printing so it was decided to force a Win 7 Gadget onto the desktop of the computers.
I had thought this would have actually been a simple task with the flexibility that has been added to Win 7 with group policies I had assumed this had extend to gadgets also but as I quickly found out, this isn't so.

Pushing a gadget out was not a problem, simply building an MSI using wItem Installer to install a gadget folder that comes with PaperCut to C:\Program Files\Windows Sidebar\Gadgets and viola you can now open and add the Gadget using the right-click menu on the desktop!
To easy, except if you want the gadget to be automagically forced onto the desktop and not allow it to be closed :S That is where fun part came in!

We eventually settled on the fact that you cannot prevent the users from closing the Gadget since we also still wanted to allow users to install and use there own gadgets, as well as still displaying our PaperCut Gadget so we moved on the idea that if it is closed can we make it re-appear?
We ended up writing a small script which checks the gadget ini file and adjusts the file to re-add PaperCut if it has been closed.

The How:
The Gadgets on a Users desktop are Profile dependent and can be found under
C:\Users\%username%\AppData\Local\Microsoft\Windows Sidebar\Settings.ini
The Settings.ini file will change dynamically based off what gadgets are currently being displayed on the desktop.
Below is a blank Settings.ini file
[Root]
SettingsVersion="00.00.00.02"
ShowGalleryPrivacyStatementOnceComplete="true"


[Hashes]
 C:\Program Files\Windows Sidebar\Gadgets\PCEnvironmentalImpact.gadget="%7B5E373E6F-DE7E-76D7-A10B-DA294544DC6B%7D"

Once a Gadget has been added to the desktop Settings.ini file changes to


[Root]
SettingsVersion="00.00.00.02"
ShowGalleryPrivacyStatementOnceComplete="true"
Section0="1"

[Hashes]
C:\Program Files\Windows Sidebar\Gadgets\PCEnvironmentalImpact.gadget="%7B5E373E6F-DE7E-76D7-A10B-DA294544DC6B%7D"

[Section 1]
PrivateSetting_GadgetName="C:%5CProgram%20Files%5CWindows%20Sidebar%5CGadgets%5CPCEnvironmentalImpact.gadget"
server.hostName="SERVER"
server.port="9191"
PrivateSetting_GadgetDropLocationX="1520"
PrivateSetting_GadgetDropLocationY="0"
PrivateSetting_GadgetSize="small"


We can see it has added a Root setting Section0="1" which indicates which order the gadget is in with the Section0= .If there is a second gadget this would be Section1= . The "1" indicates [Section 1] of the ini file to tell the gadget where it should pull its settings and location from. The [Hashes] info will now stick in the ini file statically after the gadget was installed using the MSI and will not need to be altered to force the gadget to display on the desktop.

Since we now have all the information that needs to be in the Settings.ini file to display our gadget on the desktop we can now write a script to re-apply these settings if this gadget is ever closed. We have made the script run during login since this software only works while there notebooks are onsite but it could theoretically be made to run on a timed basis to permanently place the gadget on the desktop, even when they are logging in locally.

[Rant]Now before we get started on the scripting lets get one thing straight,
I AM NOT A PROGRAMMER!!  
Yes there will be a better way of doing it, could I make it work? no so if you can make it work feel free to make a post and I will change the script :) [/Rant]

The script has been written in Powershell then used PS2EXE to convert the script into an exe so we can run it through our login script. Even with the wrapper the EXE file is only 32k and runs very quickly.
# file path to the ini file
$fileName = "C:\Users\"+$env:username+"\AppData\Local\Microsoft\Windows Sidebar\Settings.ini"
# folder path to the ini file, the file is locked while in use so Test-Path generates an error thus we use Folder Path to check for Win 7
$filePath = "C:\Users\"+$env:username+"\AppData\Local\Microsoft\Windows Sidebar"
#a variable to loop to check for the section value
$replaceNo = 0
#check if the process need resarting
$ProcessRestart = 0

function PaperCutFun {

#filepath check to make sure this computer can run gadgets
if(Test-Path $filePath){
    #Checking to see if the settings are already in the ini
    if (!(Get-Content $fileName | Select-String "Section0=`"50`"" -quiet)){
        #killing the sidebar.exe if it is running to edit the Settings.ini file
        if ((Get-Process sidebar -ea 0)) {
            Stop-Process -Force -processname sidebar
            #sleeping the kill to give sidebar time to close
            sleep -Seconds 5
        }
        #Searching the Settings.ini file to see if the gadget has been re-opened in a different order, thus causing a duplicate gadget
        if (Get-Content $fileName | Select-String "Section0=" -quiet)  {
            do{
                (Get-Content $fileName) |
                Foreach-Object {$_ -replace ("Section0=`""+$replaceNo+"`""), "Section0=`"50`""} |
                Set-Content $fileName
                $replaceNo++
            }
            while($replaceNo -le 100)
        }
        #if it hasnt been re-opened, add it back in
        else {
            (Get-Content $fileName) |
            Foreach-Object {$_ -replace "\[Root\]", "[Root]
Section0=`"50`""} |
            Set-Content $fileName
        }
        $ProcessRestart++
    }
   
    #Checking to see if the settings are already in the ini
    if (!(Get-Content $fileName | Select-String "Section 50" -quiet))  {
        #killing the sidebar process to edit the ini
        if ((Get-Process sidebar -ea 0)) {
            Stop-Process -Force -processname sidebar
        }
        #adding the Section settings to the ini
        Add-Content $fileName ("
[Section 50]
PrivateSetting_GadgetName=`"C:%5CProgram%20Files%5CWindows%20Sidebar%5CGadgets%5CPCEnvironmentalImpact.gadget`"
server.hostName=`"STUDENTFILE`"
server.port=`"9191`"")
    $ProcessRestart++
    }
    #Start the sidebar again if it has had to be killed to edit the ini file
    if ($ProcessRestart -ge 1){
        #checking to make sure it really is closed before we restart it.
        if ((Get-Process sidebar -ea 0)) {
        Stop-Process -Force -processname sidebar
        }
        #start sidebar
        Start-Process "C:\Program Files\Windows Sidebar\sidebar.exe"
    }
}
}

PaperCutFun


Download
PaperCutDemo.ps1

Add a prompt to start the script, we still use vbs as out login script

' Launch PaperCut Gadget Check
Set WshShell = WScript.CreateObject("WScript.Shell")
WshShell.Run "\\domain\NETLOGON\papercut.exe", 0


And viola!, even if the gadget is closed, it will now get dumped back onto the desktop.

2 comments: