Archive for the ‘Scripting’ Category

Update to AppV launcher for Version 5

Just a quick note to say I’ve updated the AppV launcher tool to support Appv 5.



The app-V launcher tool is a self contained executable which lists your installed App-V packages and allows you to launch an executable in that virtual applications environment. This is particularly useful if you or your admins / users are not PowerShell friendly or you would prefer to not publish PowerShell scripts as programs.

You can get a copy of the latest version and/or it’s source code over here.

As an added benefit I’ve included source code for running PowerShell commands in .Net, so if you are interested in trying to do so grab the source code!

Viewing open files on a file server from powershell.

December 5, 2012 2 comments this is a situation you should all be aware of in an SBC / VDI environment, despite all warnings, you’ve redirected folders to your network drive and your file servers are screaming in agony?

Having been in this situation recently, I needed to audit and report on the types of files open on the file server, my hunch was a certain select number of users were running applications (like *gulp* lotus notes) from the network share.

Disappointed with the powershell scripts on the interwebs, I decided to write my own function to perform this task:

function get-openfiles{
    $collection = @()
foreach ($computer in $computername){
    $netfile = [ADSI]"WinNT://$computer/LanmanServer"

        $netfile.Invoke("Resources") | foreach {
                $collection += New-Object PsObject -Property @{
        		  Id = $_.GetType().InvokeMember("Name", 'GetProperty', $null, $_, $null)
        		  itemPath = $_.GetType().InvokeMember("Path", 'GetProperty', $null, $_, $null)
        		  UserName = $_.GetType().InvokeMember("User", 'GetProperty', $null, $_, $null)
        		  LockCount = $_.GetType().InvokeMember("LockCount", 'GetProperty', $null, $_, $null)
        		  Server = $computer
                if ($verbose){write-warning $error[0]}
    Return $collection

The function above (get-openfiles) has been written to accept an array of servers to the command line and it will return the following items:

  • The ID of the open file.
  • The server it’s open from.
  • The username who has the file open.
  • The amount of locks the file has.

A couple of quick examples for using this command are below:

Retrieving open files from server1:


get-openfiles -computername server1 | select server,itempath,lockcount

Retrieve a count of open files that end with the nsf file type (Lotus Notes):


(get-open files -computername server1,server2 | ? {$_.itempath -like "*.nsf*"}).count()

Retrieve a report of total open files on a number of file servers:



get-openfiles -computername server1,server2,server3,server4,server5 | group -property server


Monitoring Storage disk queue’s and IO with PowerShell

November 30, 2012 3 comments’s one that used to bother me alot. The problem usually went as follows:

“Your XenApp servers have very high disk queue’s and IO”

“What’s causing it?”


With Server 2008, the task manager’s resource monitor feature will help you find these items. But in server 2003 this was a perilous task. The specific details for disk io per process are stored in performance monitor under each specific process running. Trying to analyse each process was a massive pain, but powershell can do some very clever work to help alleviate this!

I wrote two quick functions which act similar to “top” in linux for giving an on screen view, updating at interval of what exactly is creating IO activity. These two functions are:





The code for these functions are below:

function get-iodatabytes{
    $result=(get-counter -counter "\Process(*)\IO Data Bytes/sec" -ea 0).countersamples | ? {$_.cookedvalue -gt 0} | select instancename,@{Name="SessionID";Expression={if ($_.path.contains("#")){($_.path.split("#)"))[1]}else{"0"}}},@{Name="IO Data Bytes/sec";Expression={[math]::Round($_.cookedvalue,0)}},@{Name="IO Data KBytes/sec";Expression={[math]::Round($_.cookedvalue / 1024,0)}} | sort -Descending "IO Data Bytes/sec" | ft
    $currentqueue=(((get-counter -counter "\PhysicalDisk(0 C:)\Current Disk Queue Length" -ea 0).countersamples) | select cookedvalue).cookedvalue
    write-warning "Hit [CTRL] + [C] to exit live capture"
    write-host "Current Disk queue: $currentqueue"
    return $Result

FUnction get-IODataOperations {
    $result=(get-counter -counter "\Process(*)\IO Data Operations/sec" -ea 0).countersamples | ? {$_.cookedvalue -gt 0} | select instancename,@{Name="SessionID";Expression={if ($_.path.contains("#")){($_.path.split("#)"))[1]}else{"0"}}},@{Name="IO Data Operations/sec";Expression={[math]::Round($_.cookedvalue,0)}} | sort -Descending "IO Data Operations/sec" | ft
    $currentqueue=(((get-counter -counter "\PhysicalDisk(0 C:)\Current Disk Queue Length" -ea 0).countersamples) | select cookedvalue).cookedvalue
    write-warning "Hit [CTRL] + [C] to exit live capture"
    write-host "Current Disk queue: $currentqueue"
    return $Result

if you wish to loop one of these functions, simply use the following code:

while ($true){
start-sleep 1

Silently installing the Citrix Edgesight ActiveX plugin

September 5, 2012 3 comments

Just a really quick blog post on how to silently install the reporting agent inside your environment.

Log into a server / client without the EdgeSight plugin installed, and browse to the edgesight website. Once logged in, you will receive the usual prompt to install the software:

Install the software and ensure it works, then fire up a command prompt and browse down to “c:\windows\downloaded program files”. Once in this folder, a DIR will reveal the ActiveX plugin “csmdbprov.dll”.

Now simply copy this file out to shared storage:

Once done, now its scripting time!

Below are two examples in batch (.bat , .cmd) or PowerShell (.ps1) for achieving this:

(please amend h:\csmdbprov.dll to the path you use)


copy h:\csmdbprov.dll "c:\windows\downloaded program files"
regsvr32 /s "c:\windows\downloaded program files"


if (test-path h:\csmdbprov.dll){
	copy-item H:\csmdbprov.dll 'C:\Windows\Downloaded Program Files' -Force
	start-process regsvr32 -ArgumentList "/s ""C:\Windows\Downloaded Program Files\csmdbprov.dll""" -wait

Using powershell as a replacement for the Change Logon command in Remote Desktop Services.

August 9, 2012 8 comments

Still on my PowerShell buzz for the week, this is post 2 of 3 on some Remote Desktop Services / XenApp Powershell goodness!

This is one I’ve been meaning to post for quite some time, but other things got in the way. Mainly me forgetting how to use most of the powershell native methods due to having my head stuck in .net the last few weeks… Moving on…

While trying to find a method to check the status of logon’s to a Remote Desktop server via PowerShell, I didn’t have much luck. Either people are string scraping the output of the command using select-string or going to the registry and checking the raw Value with get-itemproperty. I wasn’t happy with either approach so I dug down into WMI and found the following.

From what I’ve found, the settings for enable, disable and the two drain modes are stored under the namespace root\cimv2\terminalservices. Under the class Win32_terminalservicesetting.

There are two properties we are interested in here:

  • logons (0 = enabled, 1 = disabled*)
  • SessionBrokerDrainMode (0 = Disabled, 1 = DrainUntilRestart, 2 = Drain)

*why oh why 1 is disabled is beyond me, but I digress.

The order of priority is enabled / disabled first, before the drain options are referenced.

So what does this tell us? Well, a change logon /query is simply performing the following simple checks:

Change Logon /query

gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices" | %{
    if ($_.logons -eq 1){
    Else {
        switch ($_.sessionbrokerdrainmode)
            0 {"Enabled"}
            1 {"DrainUntilRestart"}
            2 {"Drain"}
            default {"something's not right here!"}

Ok that’s great and all, we’ve now replicated change logon /enable, but how do we set these values?

Easy! Using the native PowerShell $_.put() method, we can push values back in.

Below you will find each “Change Logon” option in server 2008 R2 and the corresponding WMI property.

Change logon /Enable

$temp = (gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices")

Change Logon /Disable

$temp = (gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices")

Change Logon /Drain

$temp = (gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices")

Change Logon /DrainUntilRestart

$temp = (gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices")

And that’s it! now if you want to wrap this up in a function be my guest, or if you would like me to do so just drop me a line.

Checking the status of Dynamic Fair Share Scheduling in Server 2008 R2

August 7, 2012 1 comment

It’s been ages since I did a good techy /Powershell blog post so here’s the first of a few “quick hit” posts I’ll be publishing in the next few days.

Dynamic Fair Share Scheduling is a fantastic feature that Microsoft included in Server 2008 R2 to reduce contention for CPU time for users. Once enabled the fare share scheduling will happily allow users to burst all CPU resources when needed, but interrupt them abruptly when another user requires resource. I’m a massive fan of this technology and even wrote a tool to provide more functionality to this technology. (ThreadLocker)

That being said, it can be quite difficult to confirm whether DFSS is working or not, and there’s even a broken Group Policy setting as documented here to make things more confusing.

If you need quick and reliable confirmation that DFSS is enabled and running, try the following powershell command which will pull the information via WMI:

(1 = turned on, 0 = turned off)

(gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices").enabledfss

Similarly, if you want to turn it off using powershell, try the following: (This will require a restart)

$temp = (gwmi win32_terminalservicesetting -N "root\cimv2\terminalservices")
$temp.enabledfss = 0

Changing the default shell of Windows Server 8 Core

March 30, 2012 5 comments

I have to admit, I’m a bit torn with Windows 8 in general. I’m absolutely in love with Windows Server 8’s new Powershell functions and management console, but despise the lack of a start menu. Luckily Powershell has gotten so powerful in Server 8, I hope to not spend much time in the Gui.

Back on topic: By default when you install Windows Server 8 Core and log into the console, you get presented with a CMD prompt… Weird eh?

Now most administrators will simply type powershell and perform their tasks, but I personally feel this is the wrong way around. Powershell should launch first, and if cmd is really needed you could call it inside of powershell!

Being the pedantic individual that I am, I set about changing Server Core to auto-load powershell on login. This was quite an easy task and I’ve documented it below for other users to follow if they wish:

The shell in Windows Server 8 is configured under the following key:

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Winlogon\AlternateShells\AvailableShells

Under this key, on Server 8 Core, you will see the following entry:

And that’s where our CMD is coming from! This is another one of these blasted TrustedInstaller Keys. So if you want to change it, you’ll need to take owership of the key, then assign full control to your user account.

So the first thing I did was create a value lower than 30000 and assign it to powershell, but this didnt work.

Unusually here the weighting system is highest wins, rather than lowest which is a little counter intuitive, but I digress.

I added a new key 90000 (i’ll explain this later) and entered the path to powershell as below:

Now Once I restarted, Powershell is the automatic shell of choice:

Bonus 1: Why 90000?

Well if you look at a Server 8 Gui server, you’ll notice that Explorer.exe wins the selection by being 60000:

So I added another 30000 and bob’s your uncle.

If you asked yourself, “hmmm, could i also do this on windows server 8 where the gui is installed?the answer is yes.

And if you asked yourself  “hmmm, could I also do this on Windows 8?the answer is no.

And if you also asked yourself “hmmm, could i assign these in a users key instead of local machine?the answer is no.


Get every new post delivered to your Inbox.

Join 2,587 other followers