Wednesday, March 16, 2016

PowerShell to the Philips Hue API

If you have been to HPE Discover London 2015, Aruba Atmosphere 2016, CeBIT 2016 or you are going to Citrix Synergy 2016 you will have an opportunity to experience the Collaborate Cube(d).

https://twitter.com/hpecollaborate

I have been working with the Cube (making it do its song and dance) and related technologies for nearly two years.

This is an IoT thing.  But what we are driving and the place we are operating is not what most folks thing of as IoT.
This is about taking context (a person, a physical place, the capabilities of a space, and what is relevant at this moment in time) and tying them all together into a set of context specific actions (capabilities, events, controls - call it what you will).

The actions are relevant to this time and place.

One of the actions in the Cube is setting lights around the glass enclosure to red (the room is busy) or green (the room is available).

This sounds pretty simple on the surface.  You hook up a Philips Hue then you link it in, then you send some commands.  Actually, it is rather simple.  Except one part that is not entirely obvious to most folks (that aren't makers nor developers), and that is getting that first connection in the first place.

In helping to set the Cube up at three venues now, the Hue connection still seems to be one of the more complex things.  Especially when you Hue is brand new (which of course it is at each show :-S  ).

So, I have a little PowerShell script that will give you what you need to:
  1. create a valid user in your local Hue bridge
  2. get the information you need to connect to that
Of course I am using Octoblu to control the Hue.  Why wouldn't I?  There are some decent instructions for getting things set up. (see Step 4, then instead of 3 come back here, then 5).
But they send you off to an API document to sort out the one critical getting started piece, getting connected.  And then Philips hides their API guide behind a registration gate.  Double whammy.  Too much effort.  Walk away.

Here is my script, with comments, to get you started.
And after you get hooked up, there is most likely enough guidance in this script for you to simply play with the Philips Hue API.  ;-)

You can copy, save, and run this script and it should do everything you need.

# Associate your Hue Bridge with Octoblu.
# These are the setup things you need to do.

# find the Hue on your local network - this assumes you have only one
$hueIp = Invoke-RestMethod -URI https://www.meethue.com/api/nupnp
$ip = $hueIp[0].internalipaddress

$gatebluName = Read-Host -Prompt "Enter the name of your Gateblu"

Do {
    if ( !$hueUser ) {
        Write-Host -ForegroundColor Black -BackgroundColor White "Press the button on the top of the Hue bridge."
    }
    elseif ( $hueUser.error.description ) {
        Write-Host -ForegroundColor Black -BackgroundColor White $hueUser[0].error.description
    }
   
    Read-Host -Prompt "Enter to continue"

    #Hue create account
    $body = @{ "devicetype" = "gateblu#$gatebluName" }
    $json_body = $body | ConvertTo-Json
    $hueUser = (Invoke-RestMethod -URI http://$ip/api -ContentType "application/json" -body $json_body -Method Post -ErrorAction SilentlyContinue)[0]

} until ( $hueUser.success )

$apiUsername = $hueUser.success.username

Write-Host "Open the Philis Hue Thing in Octoblu interface"
Write-Host "Select the Gateblu instance to connect to"
Write-Host "Enter: $ip as the ipAddress"
Write-Host "Enter: $apiUsername as the apiUsername"

# Return the full state
$hueState = Invoke-RestMethod -URI http://$ip/api/$apiUsername -ContentType "application/json" -Method Get -ErrorAction SilentlyContinue

"Configured Lights:"
$hueState.lights | Format-List

"Configured Groups:"
$hueState.groups

# Full configuration
# $hueState.config



Wednesday, March 2, 2016

How can my Checkpoints be consuming more storage than the root virtual disk?

I explain this in the forums every so often.

Folks Create a VM, then a few Checkpoints.  And before they know it they are in that horrific Paused-Critical state with their VMs.

All because they are running out of storage.

In the end, it comes down to many folks not really understanding how this happened in the first place.

It really goes back to the fact that Checkpoints use differencing disks.  And each differencing disk has the potential of consuming as much disk space as its parent.

First of all; the warnings:
Be sure to only delete checkpoints through the Hyper-V Manager.
Do not attempt to manually delete AVHD files on the local file system.

Also, dynamic disks do not matter.  Whether your VM began with a dynamic disk or a fixed disk makes no difference. 
A dynamic disk just gives the illusion of consuming less space as the full potential of the disk is not realized.
But all differencing disks are dynamic, regardless if the parent was fixed or dynamic.

The root concept here is:
Each Checkpoint disk has the potential of consuming the maximum amount of disk space that its parent did.

For example:  Say you make a VM with the default of a 127Gb dynamic virtual disk (you have the potential of consuming 127Gb of storage). 

You install an OS and only 14Gb of physical storage is used. 
You then take a Checkpoint.  Now, you have the root 14Gb, and the potential to consume another 127Gb of additional storage.
 
Time passes and this Checkpoint consumes 50Gb of storage.  14 + 50 = 64Gb consumed.
You now take another Checkpoint.  And all kinds of stuff happens in that VM OS. 
You install Visual Studio create a database application, who knows. 
And with all that the current state is now consuming 80Gb of Storage.

You have only increased the disk use by 30Gb. 
But, with the Checkpoint tree in place you have now consumed 14 + 50 + 80 = 144Gb. 
Beyond the 127Gb limit of the virtual disk. 

Because of the potential of each Checkpoint being able to consume 127Gb (of VM disk change) all by itself.

Side by side with this is folks that use Checkpoints or differencing disks with the false idea that they will save storage.  Over time, they save nothing and add complexity.
Unless you are doing test and are constantly tossing away VM disks and creating new ones, using differencing disks with the argument of reducing storage use is a very false assumption.

Tuesday, December 1, 2015

Error handling can make or break an experience

This post is a bit of an adventure in building a very small piece of a rather cool demo.
It is really an adventure in developing thorough unit tests.

Some of you have probably noticed that my blog has been kind of dead for a pretty long stretch.  Needless to say, I have been busy.

This week is HP Discover in London.  It is a really big show for HP.

There is a demo called Collaboration Cubed.  And I must say, it is pretty cool.
https://twitter.com/JordanTechPro/status/671698781965021188

This is all about building an experience more than it is about building software.

There is this big glass cube, with two monitors, a table, three Surface tablets, and more.
You walk in with a phone, you are recognized. 
You are welcomed by a synthetic voice. 
The room is tagged as occupied. 
Your cohorts come into the room.
A Lync meeting begins on the wall monitor.
A tweet is sent out.
You sit down at the table and your tablets are 'called' through Lync. 
You collaborate and save stuff. 
You exit the cube, the Lync meeting is exited and a follow-up email is sent.

Aruba handles the device detection.
Octoblu handles the automation of the actions.
Microsoft provides OneDrive and Lync.

Why describe all of this?  Well, for one thing I am kind of excepted about it.  But at the same time, there are lots of moving parts.  And each moving part must play its role.

I had a simple request around the tweet.  Since not everyone provides their twitter handle, can we substitute their first name instead?

Sure, sounds easy enough.
I observed some of the data I had captured.
I thought I was being rather cleaver with my solution and keyed off whether or not there was an '@' in the twittername field.
I tested it, it was great.
I deployed it.

Poo, a new case arose.  The app sending me data is suddenly sending me a twittername that is no more than '@'.  Now I am sending tweets with @ @ @ in them (and hoping that the Twitter spam bots don't kick in and suspend the account).

Suddenly I find myself focusing on my unit tests and the variations that I have seen as well as dreaming up ones that I have not seen but expect to.

In the end to handle this simple request I had 9 conditions to cover the cases of the expected data from the other application.
The golden case where everything is good, and eight cases of other stuff.

Since I use PowerShell to do everything, my JSON looks like this:

$TwitterHandles += @{ “firstname”=”Brian”; "twittername"="@testhandle" }
$TwitterHandles += @{ “firstname”=”Brian”; "twittername"="@" }
$TwitterHandles += @{ “firstname”=”Moheeb”; "twittername"="" }
$TwitterHandles += @{ “firstname”=””; "twittername"="@" }
$TwitterHandles += @{ “firstname”=”Thomas” }
$TwitterHandles += @{ “firstname”=”Joe”; "twittername"=$null }
$TwitterHandles += @{ “firstname”=$null; "twittername"=$null }
$TwitterHandles += @{ “firstname”=”Joe”; "twittername"="null" }
$TwitterHandles += @{ “firstname”="null"; "twittername"="null" }


I had two data fields to cover issues with; twittername always being my first key and the possibility of substituting the firstname.
Now, the resulting code I wrote in JavaScript.  And there is the possibility for 'null' and null.  This is null as a string vs. null as an object / value.  These go right along with missing or blank values.

Suddenly I have something with much better coverage of the possible cases and thus a much better product.
One hour to get the first version and three to work out all the error handling cases.

the end result is a solid product.  But the lesson is to not focus on getting it done, it is to make it solid.

In case anyone want sot see the javascript, here is it;

// Requirement: If there isn't a twitter handle provided, replace with the first name
if(typeof (msg.params.twittername) !== "undefined" && (msg.params.twittername) !== null) {
 if ( (msg.params.twittername).substring(0,1) === "@" && (msg.params.twittername).substring(1) && (msg.params.twittername) !== "null" ){
  return msg;
 } else {
  if ( (msg.params.firstname).substring(0) && (msg.params.firstname) !== "null" ) {
   return {
    params:{
     twittername: msg.params.firstname
    }
   };
  }
 }
} else {
 if(typeof (msg.params.firstname) !== "undefined" && (msg.params.firstname) !== null && (msg.params.firstname) !== "null") {
  return {
   params:{
    twittername: msg.params.firstname
   }
  };
 }
}

Thursday, September 24, 2015

PowerShell to manipulate Skype for Business and Lync converations

A recent project left me playing with the Lync SDK (Skype for Business).

The Skype for Business skin was clad onto the Lync 2013 client.  And thus the Lync 2013 SDK is the one I worked with.
Much of the SDK documentation is centered around writing your own application integration with Lync, event listeners, triggers, etc.  I am just wanting to drive Lync, not write a replacement for it.

Yes, I do know that Office 2016 released (yesterday) but I am not going there just yet.

Lets do some interesting things with Lync:

First - if you want to get started with Lync and PowerShell there are a few blog posts.  I find the automating Lync with PowerShell tutorial from Trevor Sullivan to be the most comprehensive / useful.  I am not going to re-hash what Trevor has already done pretty well.

He walks you though downloading the SDK, installing it, and invoking the 'model' DLL that you need to perform all of the actions.

If you are not a developer, then you still need to install the SDK, for one particular MSI - the redistributable.

In the install folder of the SDK ( C:\Program Files\Microsoft Office\Office15\LyncSDK\Redist ) is the lyncRuntime.msi.  This will give you only the bare minimum DLL that you need to make this all happen.  This would be the thing you package into your application.

Now, allow me to build upon Trevor's foundation.
I am going to launch a 'conversation', then call someone, then start open 'application sharing', then end the conversation.

The big assumption here is that you are logged in to Lync.  I am not going to test for that, MSFT has examples.

# import the Microsoft.Lync.Model.dll
Add-Type -Path 'C:\Program Files\Microsoft Office\Office15\LyncSDK\Assemblies\Desktop\Microsoft.Lync.Model.dll'

# Get the Lync Client SDK automation object
$Automation = [Microsoft.Lync.Model.LyncClient]::GetAutomation()


At this point in time I could go two directions.  I could use the 'Meet Now' feature, or I could build a conversation object the hard way.
What I have learned through experimentation is that the Meet Now sets up quite a few things for you and is thus pretty useful.  I have gone about it the other way and run into sharing problems that I don't run into when using Meet Now.  So I will take advantage of the fact that they have provided this.

# Launch a 'Meet Now' conversation
$meetNow = $Automation.BeginMeetNow({}, 0)
# Get the conversation window to manipulate the conversation.
$conversationWindow = $Automation.EndMeetNow( $meetNow )
# Get the conversation
$conversation = $conversationWindow.Conversation


The first thing that I noticed is that I have something that looks no more than an 'InstantMessage' modality conversation.   That is developer speak for I started a conversation and began a session of the type called instant message.
My experimentation shows that you always have IM in the background, it appears to be the base of the conversation.

Now, I want to create an empty 'Stage' just illustrate the rest.
So I will add the Application Sharing modality.

$Conversation.Modalities['ApplicationSharing'].BeginConnect({}, 0)

The Conversation Window object, there are a few things you can do to it.
Such as, make it full screen.

$conversationWindow.ShowFullScreen('0')

Now, I want to call someone.  And to do that, I add a participant.
To add a participant I do need one piece of information, their SIP URL.  For most organizations this is the email address of the individual, but it does not have to be (that is the caveat).

# add a person only knowing the SIP address (they do not need to be in your contacts list)
$conversation.AddParticipant( $LyncClient.ContactManager.GetContactByUri( "bogusUser@itproctology.com" ) )

# they will receive a Lync Call

You can keep adding folks.  If you forgot who you added, you can look:

$conversation.SelfParticipant # this is you
$conversation.Participants # this is everyone


Now, lets begin to close down this meeting example.

# exit full screen
$conversationWindow.ExitFullScreen() # note the application is left maximized.
# lets resize the window
$conversationWindow.Resize( 300, 300 )

# remove a participant (we only have their SIP address)
$removePeep = $conversation.Participants | where { $_.Contact.Uri -Match "bogusUser@itproctology.com" }


That was a sneaky one liner of me.  Note that I took all of the participants (which is always an array BTW) and I looked for the ContactUri that contained the email of my person to kick off the meeting.

$conversation.RemoveParticipant( $removePeep )
# note, the person you remove receives a notice that they were removed from the conversation.

# End the meeting

$conversation.End()

That is it.  The lifecycle of a Lync meeting from PowerShell

Those objects are powerful.

Say that you already have a meeting running and you want to use PowerShell to find it;
For this we need the Conversation Manager.

$LyncClient = [Microsoft.Lync.Model.LyncClient]::GetClient()
$conversation = $LyncClient.ConversationManager.Conversations


And then find the conversation (as we can have more than one IM conversation at a time).

Now, a few other shortcuts to get you working:

# add IM into IM Window
$Conversation.Modalities['InstantMessage'].BeginSendMessage("Welcome", {}, 0)

# what I can share
$resources = $Conversation.Modalities['ApplicationSharing'].ShareableResources

# share my desktop
$Conversation.Modalities['ApplicationSharing'].BeginShareDesktop( {}, 0)

# share a specific resource
$Conversation.Modalities['ApplicationSharing'].BeginShareResources( $resources[1], {}, 0)

# add voice
$Conversation.Modalities['AudioVideo'].BeginConnect({}, 0)

# remove contect sharing (stop sharing, stage stays present)
$Conversation.Modalities['ApplicationSharing'].BeginDisconnect([Microsoft.Lync.Model.Conversation.ModalityDisconnectReason]::None, {}, 0)

# stop the video call, keep the IM
$conversation.Modalities['AudioVideo'].BeginDisconnect([Microsoft.Lync.Model.Conversation.ModalityDisconnectReason]::None, {}, 0)

# send a thanks for attending IM
$Conversation.Modalities['InstantMessage'].BeginSendMessage("Thanks for attending. Tasks will follow.", {}, 0)

Thursday, August 20, 2015

Enabling Hyper-V causes continuous reboot

[updated 9/24/2015]

This is a post that I am getting out to pull together a symptom that I am seeing in the TechNet forums and is spread across multiple threads.

I will be updating this thread as I follow things unfolding.  If you have this issue, please follow this post or the thread I mention below.

The current take aways:
  • BIOS / chipset
  • NIC / drivers

A bit of background; Hyper-V takes advantage of hardware virtualization features.
As new releases come out it is not unusual for the platform to take advantage of some hardware feature that is not properly or fully implemented in hardware.  This has played in historic releases.

Now, I am not being critical by pointing that out.  What is am saying is this:
Step 1: check for BIOS updates from your system / motherboard manufacturer and update the BIOS.

As revealed in this thread:  Windows 10 x64 Pro infinite reboot loop with Hyper-V enabled this pattern has played out again.
This thread has been deleted for some reason.  Unknown as to why or by whom.
There is a new hardware feature that has been implemented with Windows 10: IOMMU
According to Wikipedia, iommu is a memory management feature that is present in both Northbridge and Southbridge Intel processors.
Quite honestly, I see folks with i7's reporting this problem.
 
That said, I have long mentioned that manufacturers release processors in families.  And within a family a feature may exist, but not across all processors in the family.  So you must always check your particular chipset with the manufacturer to ensure that your chipset actually implemented the feature that you think you have.
 
Manufacturers do this so that they can offer a range of prices for end products.  Be mindful of that.
 
I bring that up because I cannot tell you hoe many times I have helped folks wit an issue that turned out to be related to them thinking they have a feature (the motherboard implemented it) but the chipset actually lacked it (the particular processor they had didn't implement it, but the processor family did).
 
Now, here is the latest advice from MSFT folks:
 
There is a known issue where the machine will fail to boot when Hyper-V is installed but DEP/NX/XD is disabled in BIOS. You mentioned that you have enabled these options, but you are continuing to see the same problem.
One other thing we can try is disabling the IOMMU policy and see if that helps. (The hypervisor's usage of the IOMMU device by default is new in Windows 10, and might explain why you are seeing this only on Windows 10).
You can disable IOMMU usage by the hypervisor by running the following command from an elevated cmd window & rebooting your machine:
bcdedit /set {default} hypervisoriommupolicy disable
Can you try this and let me know if it helps?
If you can also share msinfo32 information with us, that will be helpful with the investigation.

  • One poster reported resolution when they simply disabled Data Execution Prevention and enabled it again (this requires a cold boot).

That said, iommu has (actually) been around for a long time.  And, most likely has not been taken advantage of, so I can understand the recommendation of disabling it in the bootloader.
That said, when do you set it?  Before or after enabling Hyper-V?
Did you update your BIOS?

As MSFT reports this issue to manufacturers, the BIOS update will become more relevant.
If you want to understand how important this is, search the Hyper-V forum for "Sony Viao" - Sony chose to release a system that reported chipset virtualization as being enabled, when in fact it was not.

Step 2: Check your network card drivers.

This one was a surprise.  Now, the networking stack has been undergoing an overhaul over time.  And in this release there are some big changes under the hood (that are pretty much hidden).

That said, recent reports are that rolling back to older versions of Network drivers can al alleviate this issue.

Here is the report from one recent poster in TechNet:

thanks for sharing your experience with Hyper-V on Windows 10 and the Broadcom wireless driver because it looks like you helped find a solution I could use in the meantime that does not crash/BSOD the Dell Precision M3800 laptop.
I used "Update Driver">"Browse My Computer">"Let me pick from a list of device drivers on my computer" to list the drivers on my machine and I happened to have a 6.x version of the driver already on my machine.
Specifically I changed drivers from/to:
-- Before -- "Dell Wireless 1560 802.11ac Version: 7.35.295.0 [7/30/2015]"
 -- After -- "Dell Wireless 1560 802.11ac Version: 6.30.223.259 [11/28/2014]"

After picking the 6.x driver I reinstalled the Hyper-V role, created a Virtual Switch(had to do it twice) and added it to the imported VM. I've been working with it all day and haven't had a BSOD/crash yet.

This is interesting, as most likely, you got new drivers through the upgrade process.  And MSFT most likely got them from Dell, or Broadcom, or Intel.

This said, Broadcom drivers do have a long and sordid history with Hyper-V and I generally stick with the in-box delivered drivers as those are usually the ones tested.  But this entire upgrade process is new, and if the virtual switch existed prior to the upgrade it would have one set of capabilities (copied form the physical NIC) and the new driver would give a different set of capabilities.  There is obviously some incompatibility here.