• Create a temporary file with a custom extension in PowerShell

    Just a quick thing I wanted to record for posterity. The trick is using the -PassThru parameter with the Rename-Item cmdlet so that this ends up a one-liner thanks to PowerShell's pipeline:

    $tempNuspec = Get-ChildItem ([IO.Path]::GetTempFileName()) | Rename-Item -NewName { [IO.Path]::ChangeExtension($_, ".nuspec") } -PassThru
    

  • Microsoft LifeCam Studio stops working with Windows 10

    I have a Microsoft LiveCam Studio webcam that I bought a few years ago for the Adelaide .NET User Group for when we have remote presenters. It's been pretty good (although not long after I bought it, Scott Hanselman tweeted that actually the Logitech 930e was worth considering with possibly a wider shot).

    I went to use it the other day, and it just plain refused to work. My laptop has a builtin webcam and that was showing up, but using any app (eg. Microsoft Teams or the Windows Camera app) just wasn't showing the LifeCam. It was strange as it did show up as an audio device, but not video.

    I brought up Device Manager, and looked in the Cameras node, but it wasn't there. I tried unplugging it and re-plugging back in (and rebooting Windows) to no avail.

    Device Manager showing Cameras node

    I then tried the webcam with a different PC, and it worked, so at least I knew the device wasn't faulty. Firing up Device Manager on the second PC revealed something interesting though. The LifeCam wasn't under Cameras, it was listed under Imaging devices. Who would have guessed!

    Device Manager showing Imaging devices node

    Switching back to my laptop, in Device Manager, I went to the View menu and selected Show hidden devices. Looking under the Imaging devices revealed something unexpected. There were two device drivers listed for the LifeCam! I right-clicked on both devices and selected Uninstall device.

    I then plugged the webcam back into the laptop, and now Windows registered that a new device was attached and indicated it was installing the device drivers. After a short wait, it was now working correctly!

    Mystery solved 😁

  • Creating VSTS Service Hooks with PowerShell using the REST API

    Service Hooks are Visual Studio Team Services way of integrating with other web applications by automatically sending them events when specific things happen in VSTS, like a build completes or code is committed.

    These are what I used in my earlier post about integrating VSTS with TeamCity</a>. If you just have one service hook to set up then using the web UI is fine, but if you find yourself doing something again and again then finding a way to automate it can be really useful.

    Interacting with service hooks via VSTS REST API is documented here. Web Hooks are a particular service hook 'consumer' suitable for sending HTTP messages to any web endpoint.

    I'm going to create a PowerShell script which requires the following parameters

    Param(
       [string]$vstsAccount,
       [string]$projectName,
       [string]$repositoryName,
       [string]$token
    )
    

    Using the VSTS APIs requires authentication, so the first thing is to encode a Personal Access Token (PAT) so it can be set as a HTTP header. (You create PATs from the Web UI by clicking on your profile picture and selecting Security)

    $base64AuthInfo = [Convert]::ToBase64String([Text.Encoding]::ASCII.GetBytes(("{0}:{1}" -f "",$token)))
    

    There's a whole lot of VSTS events that you can choose as a trigger when creating a service hook. In this example, I'm interested in being notified when a Git pull request is created. In order to use this particular API, I need to also know the ids of the VSTS Project and Repository that I want this service hook associated with. I'll use API calls to find those out.

    $uri = "https://$($vstsAccount).visualstudio.com/_apis/projects?api-version=5.0-preview.1"
    $result = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}
    
    $projectId = $result.value | Where-Object { $_.name -eq $projectName } | Select-Object -ExpandProperty id
    
    $uri = "https://$($vstsAccount).visualstudio.com/_apis/git/repositories?api-version=5.0-preview.1"
    $result = Invoke-RestMethod -Uri $uri -Method Get -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)}
    
    $repositoryId = $result.value | Where-Object { $_.name -eq "$repositoryName" } | Select-Object -ExpandProperty id
    

    As far as the REST API is concerned, we're creating a new 'subscription'. Create operations use a POST and usually also require JSON data to be sent in the body. We'll use PowerShell to model the data and then convert it back to a JSON string:

    $body = @{
        "publisherId" = "tfs"
        "eventType" = "git.pullrequest.created"
        "resourceVersion" = "1.0"
        "consumerId" = "webHooks"
        "consumerActionId" = "httpRequest"
        "publisherInputs" = @{
            "projectId" = $projectId
            "repository" = $repositoryId
            "branch" = ""
            "pullrequestCreatedBy" = ""
            "pullrequestReviewersContains" = ""
        }
        "consumerInputs" = @{
            "url" = "https://servicetonotify"
            "basicAuthUsername" = ""
            "basicAuthPassword" = ""
            "resourceDetailsToSend" = "all"
            "messagesToSend" = "none"
            "detailedMessagesToSend" = "none"
        }
    }
    
    $bodyJson = $body | ConvertTo-Json
    

    Obviously you will need to customise the url value to point to your particular web service that should be notified. If that service requires authentication, you can supply a username and password in the basicAuthUsername and basicAuthPassword values. You can also control what detailed information VSTS will send to by setting the three *ToSend values. In my case I only needed resourceDetailsToSend but not the other two.

    $uri = "https://$($vstsAccount).visualstudio.com/_apis/hooks/subscriptions?api-version=5.0-preview.1"
    Invoke-RestMethod -Uri $uri -Method Post -ContentType "application/json" -Headers @{Authorization=("Basic {0}" -f $base64AuthInfo)} -Body $bodyJson
    

    Using the VSTS REST API is pretty straight forward, and gives you great access to query and modify your VSTS environment.