Thursday, 5 July 2012

How to deploy Adobe CS6 Master Collection

This is actually surprisingly easy to do. I mean I have come from deploying CS4 to CS6 and I skipped all the editions between so I don't know if it got better at any point between these two but it is certainly better for CS6. Adobe is now offering the CS6 for digital download as well as the physical copies which are received. In the download section you will also have access to this awesome little app called "Application Manager Enterprise" :)

first thing to do is install the Application Manager Enterprise through the Adobe Licensing Website linky: and of course you will need to have a valid adobe CS license to do

A new version of AAMEE is now available and can be downloaded directly without logging in now 
from there blog here and a directly link to download AAMEE is here . That blog also contains doco with a lot of in-depth deployment tips if you want to have a look.

Install AME and then you will get this awesome shortcut in your start menu under adobe, yes i know it doesn't make a desktop shortcut unless they have updated it since I installed it :p

gee... i think we might select the "Create Install Package" :P
Obviously we can also create update packages and also alter existing package settings

Also pretty self explanatory, put the paths and package name you would like for the Adobe install

You can enter the serial number, or continue to build the package without a SN and have to enter it later
 now I feel silly because this really is so easy, select what you do or do not want to install and click next :p
This is where you get to select some options about the install like removing the EULA prompt and ect
The "Ignore conflicts and continue with installation" is especially handy if your computers already have the adobe reader installed when you want to install the CS6 pack. This will actually force the installer to simply upgrade the adobe reader to what ever it requires to run the rest of the pack contrary to simply ignoring the conflicts, it fixes them :)

This i am particularly impressed with. It will roll any updates that are avalaibel for CS6 install you install pack meaning its still only a single install to deploy.

Pretty nifty i reakon
Select the build button once you have selected the updates to roll in to the install.
The pack that is building, can take a while and seems to be hard drive and ram intensive, not so CPU intensive.
 its finished building. yep that's right that's all you need to do to build the CS pack.
Honestly it actually feels like it should be harder.
now you can browse to where so selected the installer to save to which in my case was
There will then be a folder name of the what you called the installer ie D:\AdobeCS6FullInstall\AdobeCS6FullInstall1\
and within this there will be two folders and a file. The folder you want is the "Build" folder which will contain all of the setup files including the MSI file. The "Exceptions" folder contains a whole bundle of dependency installs which may be required by the installer.

Now that you have the MSI you can choose your favorite deployment system and off you go!
use the command
msiexec /i "AdobeCS6.msi" /qb         substitute what ever your msi is named into the command
to install the software silently onto the computer.

all up that's about it, the package with everything in it is roughly 6.5 to 7 gig so it is a large package to deploy probably not suitable for  wireless based deployment.

Monday, 7 May 2012

How to redirect a specific browser in IIS7

Web services is one of those funny things that once it is setup, you really can simply leave it running for eternity and it will just keep on working, besides the regular vulnerability patch, but that will almost never require you to change the config. Even if you do need to add some form of webpage to IIS(Internet Information Services) it is very easy to configure and gone are the days of fiddling for endless hours to make something, which should be so easy, actually work properly.

Having said all this, I found that trying to redirect specific browsers to specific pages to be a some what painful experience when it came to IIS7. It wasnt a "hard" process, but the syntax for it can be some what .... Annoying.

It all started because we have users occasionally ring us up claiming they cannot install printers. We have now been, for a number of years, using the Microsoft IPP webpage solution to allow our users to install printers which works very well but here is the kicker. It only works properly in internet explorer. I don't care what anyone says or what the technet says. It simply works perfectly in IE, nothing else.
So how do I go about trying to force my users who have already been told 1000 times they need to use IE and even with a note at the top of the webpage still ring up asking why it wont work... We force a page up telling them to open Internet Explorer of course :) and thus the saga begins

To get started make sure you have at lease IIS7(no this will NOT work on IIS6, upgrade you slacko) and install the URL Rewriter module from Microsoft.

When you open your IIS Manager you will now get a pretty URL Rewriter icon, yay!!

Open the URL Rewriter and select "Add Rules" in the top right corner.

Select Black Rule and press OK

Match URL
Name: IE Allow
Using: Wildcards
Pattern: *
This means anything that hits this webserver will have this rule apply since the pattern we are searching for is * and wildcards apply, it applies to everything :)

Select Add
Condition Input: {HTTP_USER_AGENT}
Pattern: *MSIE*
It will search the User Agent to see if it contains MSIE in it, since basically no third party browser ever wants to claim to be IE this works pretty well.

Action Type: Redirect
Redirect URL:
This will redirect the webpage if the conditions are true, ie that Internet Explorer is used which will contain the MSIE in the User Agent. Google is just a place holder, you can forward it to what ever url you want, such as a page telling them to use firefox or chrome instead of IE :)

This rule will now redirect IE to a different URL but all the other browsers will simply pass through to the webpage since the rule does not apply to them. Since the most common theme is to actually block IE, rather than force it as I have done.(I hope your happy, you know who I am talking to person that complained about the doco I originally typed!) Obviously with this you can basically get any combo of browser to connect or not connect to your website all you will need to do is change the User Agent strings it is searching for. A massive list of User Strings for basically any browser can be found here so now you can make weird and wonderful rules to your hearts content!

Here is a list of website that helped me along the way in getting this working
There are all posts/blogs that helped me understand the formatting, I actually did it through the XML, then worked out you can do it through the UI easily as well.
The Microsoft doco on using URL Rewriter. its actually pretty good and easy to read

Tuesday, 3 April 2012

Tick box HTA in a SCCM Task Sequence?

I really like SCCM, System Center Configuration Manager. I think its pretty awesome and I mean we are still only using the 2007 version since, well we are still following the golden rule of waiting for SP1 to come out and/or for Windows 8 to force us to SCCM 2012 but I guess we will cross that bridge when we come to it.

The SCCM with all its goodness, can be a pain in the ass. It is incredibly flexible with the use of Task Sequences for deploying an OS and I believe that we have taken this to the most extreme point possible with SCCM. We are imaging our machines with only 2 task sequences for every model of computer in the school but why do we have two? because of one being x32 bit and one being x64. That's the only difference between the two since they both require enough differences that it was just easier to make two task sequences. Not to mention that our x64 Task Sequence is already massive and loads a little slow in the console :).
Anyway onto the actual subject at hand which is that we had a problem during development that we wanted to select custom software options for the task sequence to install but we did not have a static information source that could be gained from the local computer to perform this. ie we want some computers of the same model to have the Adobe CS4 software installed, but not all, and more over we did not want to have a separate task sequence for every possible combination of custom software to be installed. We then thought about moving on to using a custom screen after the task sequence had started that would allow us to select what software we wanted installed. Sounds simple enough until you actually try to do this since SCCM has now native support for this what so ever which I find amazing that a system so flexible can sometimes be so limiting....
So in our great search of the mighty google I stumbled across this post which kinda got me started on the whole saga

There are some other people that have also done a "similar" thing since we have now implemented(thanks a lot everyone! if you had done this a year earlier it would have made my job a lot easier!)
So off I went and implemented the above post with one exception, that there was no good way to get rid of the Task sequence progress window, or was there?

So lets get started
You will need the following to get this all up and going
-We will need to download the Windows AIK(Automated Installation Kit) from here
and install it onto the computer.

First we need to add HTA support to the WinPE which is not natively in the WinPE which MDT installs

Now since someone else has done all the hard work for me I will just link to there instructions :P

Once you have added the HTA support to the WinPE we can now add the scripts and package.
The scripts I have been using are from a collection of sources but the main ideas came from here and here so credit where its due for these two websites :)
The VBS Script I use is as follows
' Hides current Progress UI to bring the HTA to the front
Set ProgressUI = CreateObject("Microsoft.SMS.TsProgressUI")
' Create a WshShell object
set sh = CreateObject("Wscript.Shell")
' Call the Run method, and pass your command to it (eg. "mshta.exe MyHTA.hta").
' The last parameter ensures that the VBscript does not proceed / terminate until the mshta process is closed.
call sh.Run("select.hta", 1, True)
 My script name is "select.vbs" when I have used it and the HTA page script is as follows

<title>OSD Front End Script</title>

<script language="vbscript" type="text/vbscript">

' Set objects and declare global variables
Set env = CreateObject("Microsoft.SMS.TSEnvironment")
Set objWMIService = GetObject("winmgmts:{impersonationLevel=impersonate}!\\.\root\cimv2")
Sub Window_onLoad
    window.resizeTo 400,550 ' Resize the HTA window on first load
    window.moveTo 100, 10 ' Move the window to the center
End Sub

Sub ButtonFinishClick
    ' ButtonFinishClick is executed by the "Finish" button.
    ' Set value of variable to true/false based on whether the checkbox is selected or not
    If FullImage.Checked Then
        strFullImage = "true"
        else strFullImage = "false"
    End If
    If Office2010.Checked Then
        strOffice2010 = "true"
        else strOffice2010 = "false"
    End If
    If Office2007.Checked Then
        strOffice2007 = "true"
        else strOffice2007 = "false"
    End If
    If AdobeCS4.Checked Then
        strAdobeCS4 = "true"
        else strAdobeCS4 = "false"
    End If
    ' Set value of variables that will be used by the task sequence, then close the window and allow the task sequence to continue.
    env("OSDFullImage") = strFullImage

    env("OSDOffice2010") = strOffice2010
    env("OSDOffice2007") = strOffice2007

    env("OSDAdobeCS4") = strAdobeCS4
End Sub


<body STYLE="font:14 pt arial; color:white; background-color: #000000">
<span id = "List"></span>
<p>Disk Partition<br>
<input type="checkbox" name="FullImage"> Full Image - C: 100GB<br>
<input type="checkbox" name="Office2010"> Office 2010<br>
<input type="checkbox" name="Office2007"> Office 2007<br>
<input type="checkbox" name="AdobeCS4"> Adobe CS4<br>
<button accesskey=N type=submit id=buttonFinish onclick=ButtonFinishClick >Install</button>
 The HTA Script is called "select.hta". I know I am so creative with my naming!!

As you can see in the script above I have environmental variables being set with the tick boxes which you can customize to your own including adding/removing some of the tick boxes to add more or less options.
piccy of HTA page

Once the enviromental variables are set, they are then accessible by the SCCM Task Sequencer which allows us to make variable dependent Software installs which I will go through how to add a bit later.
both scripts can be downloaded from here

Once you have both the scripts you can dump them into a package to be added to the Task Sequence. As a side note for some reason I have to add Read Access for Guests to my package for it to run correctly but I have not seen anyone else having to do this and this is the only package I have had to do it for. To add a guests access to the package right click on the Access Accounts and Select Generic Access Account.

Click Set, select Guests and OK. Make sure that the Permissions is set to "Read" then select OK

 All this means is the Distribution Point(DP) share can be accessed by anyone, not that there is anything particularly interesting to look at in the scripts but it is something to be aware of because if you have anything with sensitive data that you where planning to include in this bundle, you may want to make another one that doesn't have Guests Access :) I suspect that the problem "may" have to do with the way a VBS script tries to open the HTA page which doesn't really make sense but the important thing is that this fixes it!

The package name I have used is SCCM UI(yeh i know another creative name:P) and now 
Its time to add the Package to the Task Sequence
Add a "Run Command Line" step to the TS and enter the "cscript select.vbs" or what ever your vbs script is called and select the Package that currently contains the scripts


I have had a couple of people have problems with the Task Sequence not continuing when you click finish because the TS is not correctly detecting that the VBS has actually finished and closed. I didn't get this problem, but I have seen it with other software installs. If this happens to you change the following under "Option", "Success codes:"

And Viola! next time you start the TS you will be prompted on which Tick Boxes you would like!

but how do we make the Software installs variable dependent? Its actually surprisingly easy
Select a package or Group you would like the variable dependence to be on and select Options, Add Condition then Task Sequence Variable


Type the name of the Variable, set the Condition to equals and the Value as True

This will cause the group/software to only run if that task sequence "condition" is met, which is this case is that OSDOffice2010 is set to true and since all Env variables will return a null or false value unless otherwise set the Variable will only be set during the HTA page.

Since we have our package to download locally from the DP I have then run into the problem of the package generating an error when it tries to run sometimes. This turned out to be that if the Hard Drive did not have a usable NTFS partition, the software would not be able to download and then be run locally. To fix this problem a format and partition setup step must be added before the HTA page that runs to check for a partition and if it does not exist, to create one on the drive.

To do this add a "Format and Partitions Disk" prior to the HTA Page running
Create the partitions that are used in a clean disk scenario since this will only run if it is a clean disk.
and don't forget to select the "Quick format" tick box under the properties of the partition created

  After that this is where we add the condition to only run if there is not an existing partition.
Go to options add add the "If" Statement specifying if "None" of the conditions are true. This will cause the Partitioning to run if the following query returns a false value which would mean that the partition infact does not exist.
Select the If statement then add a Query WMI with the following statement 
SELECT * FROM Win32_DiskPartition WHERE Caption LIKE "%Disk #0, Partition #0%"
this will run a WMI Query which will check to see if a partition on Disk 0, and if it does it will cause the Query to return a True value which will then cause the disk partitioning to not run. Simple enough :)

Please note because you are playing with disk partitions, you could potentially wipe disks if you make a mistake so please PLEASE test these before going into production


I have also been made aware of yet another way of doing the same thing I have done(great, more work wasted, but I will stick with what I have :P). Feel free to have a look

Wednesday, 29 February 2012

Installing Windows 8 Consumer Preview on Acer Iconia W500... and its still better than when it had Windows 7

So our department a while ago was asked about getting some iPads..DUN! DUN! DAHHH
yep its all fun and games till we asked for an actual real word use for them that a laptop couldn't do. I don't have problem with the iPad as a device per-say but don't really see very many valid business uses for them ontop of the fact that they are a down right pain in the ass to manage both Policy wise and User wise. Yeh don't try and pretend like its easy.... its still easier to manage full fledged computers so don't even bother arguing fanbois.

Anyway off topic a little, we ended up buying a whole raft of different computers to let them choose from, including the Acer Iconia Tab W501, which was running Windows 7. Honestly? it was horrible. The touch was horrbile, it was unbelievably slow and just a pain to use so when the Windows 8 Dev Preview we jumped on board and installed it on the Iconia straight away.


It was pretty funny the fact that a Dev Preview ie pre-beta Windows 8 OS was nicer on the touch interface than the Windows 7 machine, but who are we to argue. The other big plus was the much faster boot times. Windows 7 took roughly 5 minutes to boot on the Iconia, including logins. The Win 8 Preview took under a minute from startup to login. All in all we where very impressed.
The Consumer Preview has now come out for Windows 8 now and is even nicer to use on the Icionia than the Dev Preview. Its clear that Microsoft has put alot of work into startup times and the touch interface is really very nice.

It was no mean feat to install the Windows 8 on the Iconia either. What would seem like a simple task was actually a bit of a pain in the umm hmm finger?

So we start with downloading.

If you already have the Dev Preview installed you can go here and download the Windows 8 Consumer Executable file which you simply run on the Dev Preview and Viola! you have now upgraded to the Consumer Edition of Windows 8. Ignore everything below this :P

A Clean install is a little more fun. First you want to download the Windows 8 Consumer ISO file here and extract the iso into a folder once it has finished downloading. If you are doing this for the Acer Iconia, x64 runs well on it.

The Serial Key you will need for the install is DNJXJ-7XBW8-2378T-X22TX-BKG7J

Next we need to make a bootable thumbdrive since out Iconia doesn't have DVD-ROM. The Thumb drive needs to be a minimum of 4GB.
We will need to download the Windows AIK(Automated Installation Kit) from here
and install it onto the computer.
Use the following commands to format a USB and make it bootable to install Windows 8 from.
All commands are without quotes
- Plug the thumb drive in. Make sure there is nothing on it you want to keep because we are going to need to format it.
- Start the Deployment Tools Command Prompt which is installed with the AIK
- "diskpart"
- "list disk"
This will display a list of disks which are currently connected to your computer, including your thumb drive. Look at the sizes listed to determine which of the drive numbers is the thumb drive
In this list we can see that the thumb drive I am using is a 16GB(listed as 14GB) Disk number 2

In the following examples I will be using "Disk 2". you will need to substitute the relevant disk number in-place of Disk 2

- "sel disk 2"
This will format and delete all the contents on the thumbdrive, there is no turning back if you have anything on it you want to keep after this command
- "clean"

- "create part primary"
- "format fs=ntfs quick label=BOOT"
- "active"
After this a new Thumb Drive should popup on the computer, in my case drive letter "L:"

In the following examples I will be using Drive Letter "L:". You will need to substitute the relevant letter for your computer.

- "exit"

- "cd amd64" or "cd x86" based off whether you are using the x64 installer or x86 installer
- "bootsect /nt60 L:"

The thumb drive should now be bootable and ready to copy the extracted Windows files from the ISO onto the thumb drive. That's not ISO onto the thumb drive.... Extract the ISO and copy all the contents onto the thumb drive. It should look something like this once is all copied to the thumb drive.

Don't forget to remove the thumb drive safely from the computer. Since the thumb drive is now using an NTFS partition we can't have any more of that RIP THAT PUPPY OUT SHEEL BE RIGHT!! because it will break it the partition and make it unbootable.

Turn the Iconia off and if you have a Dock, take it off the dock and plug in a USB Keyboard and Thumb Drive. Funny stuff they make a dock that doesn't work properly in the BIOS :) Hold the Windows button on the Iconia and Turn it on while pressing the F2 key. If your like me you will need another person to help you with this.
Change the USB drive to be first boot, save the BIOS and reboot.
Here is a link to the Acer Iconia Tab W500 Manual if you want more detailed instructions on getting into the BIOS
*EDIT* I have also had a problem recently with booting off the thumb drive again after Win 8 was installed when I stumbled upon this post
which fixed the problem for me
I tip my hat to you
Also Drivers are now available at Acer for Win 8

You will now be able to run the Windows 8 Consumer Preview from the Thumb Drive. Happy installing!

Wednesday, 15 February 2012

You can add the logging in user as a local admin? Thats impossabarble!

The debate had gone on for a long time as to whether we should allow users to have local admin rights on there computer. Where I currently work it is a requirement to allow users to have local admin rights over there computer but then that raised the interesting question of how do you secure the network and/or devices where you do give them local admin rights?

Alot of people simply  add Domain Users to the Administrators group on the local computer to give there domain users local admin rights. This also unfortunately give the user local admin rights on every other computer in the school also so what can be done about this?

Besides the obligatory GPO settings to limit the amount of access a user has at a local admin level over another computer across the network, we also came up with the solution of only giving local admin rights to a user which has logged into a computer. ie as they login to a computer at a user level they will be granted local admin rights with a login script. I already here you thinking to yourself "but they are at a user level. They can't give themselves local admin rights!" and you are right, you cant give yourself local admin rights if you are logged in as a normal user, thus the fun-ness of this script :)

I wrote the script to check to see if it has admin rights, if it doesn't, to re-run the script under different user permissions to allow the local user to be added to the Administrators.

as always before we start :P
[Rant]Now before we get started on the scripting lets get one thing straight,

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]

 $pathTemp = "C:\Temp\Login.tmp"
$password = "lotsofnumbersandlettersinheretotisthepasswordinitsecryptedformandiwllpostthescriptandtalkaboutitlaterintheblogandyesitreallyisthislongimademine256ithinkohhandthekeyisover9000"
$key = "111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111 111"

$domain = "domain"
$strComputer = "$env:computername"

#downloaded from

function Test-Admin {
   $currentPrincipal = New-Object Security.Principal.WindowsPrincipal( [Security.Principal.WindowsIdentity]::GetCurrent() )
   if ($currentPrincipal.IsInRole( [Security.Principal.WindowsBuiltInRole]::Administrator )) {
      return $true
   else {
      return $false
#downloaded from
function AddLocal {
    if(Test-Path $pathTemp){
       $username = Get-Content $pathTemp
    $computer = [ADSI]("WinNT://" + $strComputer + ",computer")
    $Group = $computer.psbase.children.find("administrators")
    $Group.Add("WinNT://" + $domain + "/" + $username)
    Remove-Item $pathTemp -Force
start-sleep -s 3
$Invocation=(Get-Variable MyInvocation).Value
if ($Invocation.MyCommand.Path -ne $null) {
   $arg="-file "+$Invocation.MyCommand.Path
   if (!(Test-Admin)) {
           Out-File -FilePath $pathTemp -InputObject $env:username -Force
        $passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(" "))
        $credential = New-Object system.Management.Automation.PSCredential("domain\usertorunas", $passwordSecure)
          Start-Process "$psHome\powershell.exe" -Credential $credential -ArgumentList $arg
   else {     
    if(Test-Path $pathTemp){
       $username = Get-Content $pathTemp
    #downloaded from
    $group =[ADSI]"WinNT://./Administrators"
    $members = @($group.psbase.Invoke("Members"))
    $UsersInGroup= $members | foreach {$_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)}
    foreach($DomainUsers in $UsersInGroup) {
        if ($DomainUsers -eq "Domain Users") {
            $Group.Remove("WinNT://" + $domain + "/Domain Users")
            $username = $env:username

simply add the powershell script to start and login, and viola! you will now have users granted local admin rights at login. For the astute people that noticed(so I bet no one) you will notice the script actually checks to see if there is a Domain Users group under local admin and if so removes it then adds the user and your probably thinking whats the point in that?
The one problem with this script is that if you are logging in as a user you will not have local admin rights unless you logoff the computer then back on as you have started that login session as a normal user and the effect of being in the local admin group will not be picked up until the next login. Since the majority of our school is 1 Device to 1 User we add Domain Users to the local admin group in our SOE which means the first user login will be granter admin rights on the computer without having to logoff and in again and the Domain Users group will be removed from the local admin group.

The Username and Password used to run the script at elevated privileges should be added to the local admin group of all computers and should have absolutely no network access to anything except to add the local user to the local administrator group. This means even if they get the username and password of the user, they are still limited in what they can actually do with it.

To encrypt the password for the user in the script you can use the following
 # Path to the script to be created:
$path = 'c:\temp\template.ps1'

# Create empty template script:
New-Item -ItemType File $path -Force -ErrorAction SilentlyContinue

$pwd = Read-Host 'Enter Password' -AsSecureString
$user = Read-Host 'Enter Username'
$key = 1..32 | ForEach-Object { Get-Random -Maximum 256 }
$pwdencrypted = $pwd | ConvertFrom-SecureString -Key $key
$private:ofs = ' '
('$password = "{0}"' -f $pwdencrypted) | Out-File $path
('$key = "{0}"' -f "$key") | Out-File $path -Append

'$passwordSecure = ConvertTo-SecureString -String $password -Key ([Byte[]]$key.Split(" "))' | 
Out-File $path -Append
('$cred = New-Object system.Management.Automation.PSCredential("{0}", $passwordSecure)' -f $user) |
Out-File $path -Append
'$cred' | Out-File $path -Append

ise $path


These scripts do the job fine. The debate of whether we should be giving the local admin rights to users I am sure will continue on for many years to come. I think that as the software changes and the lines between local admins and users blurs even more as it has in Windows 7, this problem will disappear.

Tuesday, 14 February 2012

JSON Why for you hurt my brain so?

You know how I said it would be easy to pull a JSON stream for our portal in my previous blog post?
here I will quote it
"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."
Yep well its not. In fact it made my brain hurt. ALLOT.

So I did get some web code working, but every time I tried putting it on our sharepoint site, it would stop working.
Here is the Code I was using
<script type="text/javascript" src=""></script>
<script type="text/javascript">
$("document").ready(function () {
    $.getJSON('http://papercut:9191/rpc/api/web/print-stats.json', function (data) {
        $.each (data.items, function (i, item) {
        $("#PaperCut").append('<div class="print-stats"><div class="TreesFormatted">' + item.TreesFormatted </div><div class="clear"></div>');

<div class="main">
<div id="PaperCut"><img src="images/ajax-loader.gif" alt="Loading..." /></div>
It worked fine on the papercut server itself. It showed the number of trees that had been cut down as a percentage, as it is in the JSON data. But would not work on the sharepoint site. I posted it on the MITIE forum and with a few replys, Kane Rogers from Bluereef (shameless plug, we don't even use bluereef so i was pretty impressed that Kane helped me as much as he did) mentioned the answer when i sent him my code.
The Same Origin Policy was the problem. I don't like it :P

So without making the job a whole lot harder I scrapped that method of getting it in sharepoint and chose the most likely dodgiest method ever. I wrote a powershell script which pulls the json data from PaperCut, formats it and dumps it into a static location on the sharepoint server as a html file. Yep that's right a local script on the server :P, I added it to Task Schedueler to run hourly and viola! a simple formatted Total Environmental Impact page in the portal.

Here is the powershell code i used
ohh and my obligatory disclaimer

[Rant]Now before we get started on the scripting lets get one thing straight,

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 json source
$source = "http://papercut:9191/rpc/api/web/print-stats.json"
# temp location to save the json file
$pathTemp = "C:\Temp\temp.json"

# location to save the html file
$pathSave = "C:\inetpub\wwwroot\PaperCut\PaperCut.html"

# webget request for the file
$wc = New-Object System.Net.WebClient
$wc.DownloadFile($source, $pathTemp)

# dumps the json file into an array spliting it via the ","
$jsonString = Get-Content $pathTemp
$jsonArray = $jsonString.split(",")

# Total Trees used
# grabs the invidual array item and splits it again using the ":"
$jsonTree = $jsonArray[2].split(":")
# Removes the " from around the value
$jsonTreeString = $jsonTree[1].Replace("`"", "")

# Total CO2 Produced
# grabs the invidual array item and splits it again using the ":"
$jsonCO = $jsonArray[3].split(":")
# Removes the " from around the value
$jsonCOString = $jsonCO[1].Replace("`"", "")

# Total No of hours a 60W lightbulb could be run
# grabs the invidual array item and splits it again using the ":"
$jsonBulb = $jsonArray[5].split(":")
# Removes the " from around the value
$jsonBulbString = $jsonBulb[1].Replace("`"", "")
# the number got split twice in the array because they used a comma ie 4,000
# which would be 4 as one array item and 000 as the second array item
# so I had to add the second half of the number
$jsonBulbString = $jsonBulbString + ($jsonArray[6].Replace("`"", ""))

# pulls all the values into a single string, including some html tags so it displays in a browser
$htmlString = "<html>" + $jsonTreeString + "<BR>" + $jsonCOString  + "<BR>" + $jsonBulbString + "</html>"

# spits out the html file, overwrites the old file if it exists
Out-File -FilePath $pathSave -InputObject $htmlString -Force
No error checking because well, does it really matter if it breaks? I guess you could put some trap exits if you felt the need.

Since its a simple HTML page, you can embedded it into sharepoint and put pretty graphics around it etc etc and your done :)

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

 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


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

[Section 1]

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,
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)  {
                (Get-Content $fileName) |
                Foreach-Object {$_ -replace ("Section0=`""+$replaceNo+"`""), "Section0=`"50`""} |
                Set-Content $fileName
            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
    #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]
    #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"



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.

Who what when what?

I work as a Network Admin quasi System Admin in a school which teachers K-12 with a notebook program. What this means is I run into weird and wonderful problems that most people in the enterprise world don't see or simply doesn't exist. I decided to make this blog to try and keep a running sheet of problems that I have either solved or simply to post small projects which I have worked on and completed. This is my first attempt at blogging so if you don't like it, feel free to abuse everyone around you and not me. :)