Showing posts with label How-To. Show all posts
Showing posts with label How-To. Show all posts

Tuesday, 15 May 2018

Compare the checksum (hash) of a download file

Ever needed to compute the checksum (i.e. the hash) of a file you’ve downloaded from the internet? If not, you probably should—when you can—to ensure the file you’ve downloaded wasn’t tampered with (e.g. to insert malware) or corrupted while it was being downloaded.

As two examples, there are the large files (OS, etc) we download from the trustworthy MSDN library, which may face interruptions during download, and then there are those really handy utilities like WinDirStat that may originate from unsavoury locations on the internet.

Microsoft provides a handy tool for the purpose of computing the cryptographic hash value of one or more files called the File Checksum Integrity Verifier utility. It’s simple to use and can be found here: https://support.microsoft.com/en-au/help/841290/availability-and-description-of-the-file-checksum-integrity-verifier-u

Once extracted, usage is as simple:

fciv myfile.exe

But it can also compute MD5 and/or SHA-1 hashes for a directory of files and store results in a database. Full details can be found at the download link, above.

Sunday, 8 April 2018

How to Save a Private Video from Facebook

Saving a video from your news feed or a group can be a little awkward because you’re operating within an authenticated environment (i.e. you log in to Facebook through your browser) but it’s actually pretty easy. Here are the steps:

  1. Browse to the video you want to download in Facebook and start it playing.
  2. Right-click the playing video and select Show video URL. Copy the URL and paste it into your browser’s address bar.
  3. Still in the address bar, change “www” to “m” to bring up the mobile version of the page; hit enter to load.
  4. In Chrome, hit F12 and click on the Network tab (ensure the network log is recording). I also like to check the Disable cache checkbox for convenience but if you don’t, click CTRL+F5 to forcefully reload the page and its resources from the server.
  5. Play the video (click play) and locate the the last request that pops up (it should be a .mp4 request).
  6. Right-click the request entry and click Copy > Copy link address
  7. Paste that address into your address bar and hit enter. The video will load.
  8. Right-click > Save As to save the .mp4 file

Tuesday, 13 March 2018

Saving videos from a web site with VLC

I recently wrote about how to download and save a Brightcove video using the m3u8 format. I’ve since found an even easier method for other sites using other video formats.

It’s as simple as this:

  1. Open VLC and select Open Network Stream from the Media menu.
  2. Paste in the URL of your youtube.com (or similar) URL
  3. Click Play
  4. From the Tools > Codec Information menu, copy the full Location link to your clipboard
  5. Paste the copied location into Chrome and right-click the video/Save As

Depending on video quality, some videos (especially longer ones) may be on the large for your mobile device without additional transcoding.

If you have any problems with VLC complaining about not being able to play the video, you probably need to update VLC or the .lua or .luac file in the VLC install directory. I was experiencing MRL / 403 Forbidden errors until I updated the youtube.lua file.

To update:

  1. Save the text contents of this file as youtube.luac to a temporary location (note the .luac extension, not .lua): https://github.com/videolan/vlc/blob/master/share/lua/playlist/youtube.lua
  2. Replace the original youtube.luac in your VLC install directory (e.g. \VideoLAN\VLC\lua\playlist\ from c:\Program Files or c:\Program Files (x86)
  3. Restart VLC
  4. Update luac files for other sites if necessary

Sunday, 11 February 2018

How to Download and Save Videos from a Website

I recently watched a free video embedded in a website and wanted to save the video itself for future reference (imagine the nerve!). The video content was delivered via the Brightcove player and was not a Flash/.swf file which I could otherwise deal with using traditional video download tools or shonky websites. The video was in fact, I believe, an HLS m3u8 video… admittedly, I don’t know if those are the same thing, or for that matter, what they are, and I don’t particularly care.

Rather than download a suspicious installer and infect my computer with the latest crypto virus, TubeOffline provided a handy and relatively simple tutorial using the ever trusty (and trustworthy) VLC media player. I’m reproducing the steps here in simple terms for future reference.

  1. Firstly, find the URL to the .m3u8 file you want to save. In Chrome, hit F12 and go to the Network tab. Check the Disable Cache button. Make sure the Record Network Log button is red and type “m3u8” (without quotes) in the Filter box. Load (or reload the page containing the video you’re after) and have a look at the network log. I grabbed the URL to the master.m3u8 file (right-click, Copy > Copy link address).
  2. From the Media menu in VLC, select Open Network Stream. It should open to the Network tab
  3. Copy the URL of the .m3u8 file to be downloaded and paste it in to the Network URL box. Don’t click the Play button!
  4. Click on the arrow next to the Play button and select Stream
  5. Click Next on the Source screen
  6. At the Destination screen, ensure the destination is set to File and click the Add button. Browse to the location where you want to save your downloaded video and specify a file name. The Save as type box will be left as Containers.
  7. On the Transcoding Options screen, leave Profile set to the default (Video – H.264 + MP3 (MP4). You can disable transcoding if you like but file sizes will likely be larger.
  8. On the Option Setup screen, leave the Stream all elementary streams checkbox un-ticked. Click the Stream button.
  9. VLC will begin saving the video to the selected file. Don’t try and play the video and don’t touch anything until the blue progress bar in VLC has reached the end (the far right side). You can sometimes monitor the file itself by hovering over in the file system to keep an eye on its size.

In practice, I noticed the blue progress bar reached the end and the file size was showing as 132MB. I thought it was all finished at that stage but opening the .mp4 file to review in a new VLC instance opened a whole lot of nothing with a duration zero seconds. After another minute or so, the file size bumped up to 133MB and opening the file again revealed the downloaded video complete with audio. I’ve found closing the original VLC instance seems to finalise the download/flush the last few bits to file (note: don’t just close the video or open another file—completely close VLC so it can flush its buffers and clean up). Your mileage may vary.

Sunday, 16 April 2017

How to specify credentials to restart or shutdown a remote host with ‘net use’

I recently wanted to shutdown a server on my local network (notably a workgroup) using the Windows shutdown command but encountered an access denied error (or no feedback whatsoever).

I needed to use the administrator credentials of the remote server but shutdown.exe doesn’t accept credentials.

Using ‘net use’ to connect to the IPC$ share on remote host, you can set then call shutdown in that security context:

net use \\hostname\IPC$ mypassword /User:administrator
shutdown /r /t 60 /m \\hostname /f

In the net use command above, replace hostname with the name of your remote host (or maybe an IP address), replace mypassword with the password for the account you’re using, and replace administrator with the name of the local account on the remote host you wish to use (which presumably has the necessary rights to restart or shutdown the server).

In the shutdown command above, replace hostname with the name of your remote host, as per the net use command.

Note: Read the shutdown /? usage. The /r flag will restart the host; change /r to /s if you want to shutdown instead. Other parameters can also be specified. I also typically set the timeout (/t) flag to 0 (zero).

I call both commands back-to-back in a Windows Command Prompt, without running the console as Admin.

See below for a few more tips, links, and PowerShell alternatives.

If you’re used to operating as a domain user you may be asking why any of this is even necessary. It’s necessary in a workgroup context because the remote host has no idea who I am if I just tell it to shutdown from some other computer on the local IP network. It may be possible to an account on one host the necessary privileges on another host but I don’t know for certain and, in my limited experience, this can get hard and weird very quickly!

I used to run a domain controller on my small local network (just for fun) and all of my servers were members of a domain, which made security easy. I got rid of the DC as DHCP and other services were migrated to my internet router and to streamline things. In all regards, having one less server to manage, power, and so on is great. I’ll run a virtualised AD when I need to, e.g. for development purposes).

In addition to a media centre, I also still run a physical file server, primarily for backups. My basic process is to power on the file server once a week to backup the media centre, my laptop, etc and then shut it down again (so the kids don’t fiddle and to keep the noise down).

The backup process is otherwise seamless—the backup services on the file server and clients just pick up where they left off and run to completion without any human interaction (I use CrashPlan and would highly recommend it). I only need to power on the file server and then shut it down.

To shut down, I’d previously connect to the file server via Remote Desktop and then shut down. But that’s too hard. I can tell from the backup client on my laptop when a backup is complete so I just want to quickly shutdown the file server and go to bed.

In a domain environment, I could make sure my domain account was a member of the Administrators group on the file server and then call shutdown.exe from a command prompt on my laptop; without the DC, I need to explicitly provide shutdown.exe with the necessary credentials before actually calling shutdown.exe.

A few other notes: the file server is running Windows Server 2012 and my laptop is running Windows 8.1.

In recent versions of Windows (i.e. 2012+), I’ve read that UAC may interfere with things. You may want to turn it off but can simply add or configure this registry key (I didn’t have to):

HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows\CurrentVersion\Policies\System
Value: LocalAccountTokenFilterPolicy
Data: 1 (to disable) or 0 (to enables filtering)
Type: REG_DWORD (32-bit)

You may need to restart after making this change.

Thank to https://helgeklein.com/blog/2011/08/access-denied-trying-to-connect-to-administrative-shares-on-windows-7/ for this one. See also this Microsoft help article (ID 951016) “Description of User Account Control and remote restrictions in Windows Vista”

Others suggested File and Printer sharing must be allowed in the Windows Firewall.

I believe PowerShell offers similar restart (and stop) commands. I haven’t tried them and can’t say whether they work with the techniques described here but I believe both accept a –credential parameter.

See these references:

https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/restart-computer

https://msdn.microsoft.com/en-us/powershell/reference/5.1/microsoft.powershell.management/stop-computer

Tuesday, 5 April 2016

Disconnect or remove a website from Google Analytics

To clean up Google Analytics and remove web sites you’re no longer interacting with (e.g. client sites to which you’ve been granted access),  you can simply remove yourself in the User Management screen.

To get there, log in and click on the Admin tab at the top of the Google Analytics screen.

Select the Account you want to rid of from the drop down list in the left column. Then click on the User Management link below.

You should then see a big blue button that says Remove myself from this account. Click it, confirm, and you’re done.

No deletion or trashing of views or properties (but also no undo).

Remove myself from this account

Tuesday, 23 June 2015

How to increase the size of the shopping cart icon in WooCommerce

I found the default size of the WooCommerce shopping cart icon (in the Storefront theme) was a bit on the small size.

The icon is textual and comes from Font Awesome. Normally, this would be an easy change by adding fa-2x or something similar to the style declaration. Inspecting the CSS in Chrome didn’t offer me such an option (I’m new to Font Awesome) so I added this CSS to the custom CSS in my Storefront child theme:

/* Increase size of shopping cart icon */
    .site-header-cart .cart-contents:after
    {
        font-size: 1.25em !important;
    }
The 1.25em increased the size of the cart icon to better reflect the size of the menu text and stand out better.

Woocommerce Shopping Cart Icon

Sunday, 7 June 2015

How to set a product as a featured product in WooCommerce

If you want to mark a product as “featured” in WooCommerce (so it will display in the Featured Products widget, for example), you’ll soon find it’s nearly impossible to figure out how to do so.

There are two ways to set a product as a featured product in your WordPress admin screen:

  1. From the products list
  2. From the edit product page

Products List

Most forum posts, etc will suggest you can toggle a product as featured or not featured in the Products list by clicking the empty or filled star icon for each product. This is easy enough—especially for setting multiple products quickly—but requires you to drop out of the product edit page.

Featured Product Star

Edit Product Page

If you’re setting up a new product you may want to set it as a featured product from within the edit product page. To do so, expand (edit)  the Catalog visibility: section in the Publish widget. The last option is a checkbox to flag the product as a featured product.

Expand Catalog VisibilityFeaured Product Checkbox

You may also want to read the Adding and managing products documentation from WooThemes for more information.

Tuesday, 31 March 2015

How to recreate a windows folder and file structure with empty (zero byte) files

I have an external drive full content that I reference only periodically. I don’t connect the drive regularly to my laptop but I often want to know if a file is on that drive. I recently thought it would be helpful to have a zero-byte copy of the drive contents on my local machine.

Although I thought about writing a PowerShell script to accomplish this, robocopy includes a feature to do exactly what I want through the /Create command:

robocopy source dest /E /Create

Robocopy has been bundled with Windows since Vista.

Monday, 5 January 2015

Root redirect to www

Something changed in relation to the root redirect I previously had in place and I only just realised (my domain host, Planetdomain, is now owned by Netregistry so I attributed it that change initially but I suspect Google may actually be at fault here). In any case, mediawhole.com was not redirecting automatically to www.mediawhole.com and was coming up with a 404 or something equally boring instead.

I thought I’d need to mess around with DNS records at Netregistry to fix this but in actuality it was a simple as typing “www” into a text box in the Domains section of the Google Apps admin console. Google refers to this as redirecting the naked domain and provide suitable instructions on the process. In my case I didn’t need to configure A records as they were already in place.

The root mediawhole.com domain redirects efficiently, automatically, and as you might expect.

Update: this simple fix stopped working (or perhaps never worked in the first place) and I recently noticed my bare domain was no longer redirecting. Back to Google admin and I followed the instructions to add new A records to the DNS config in Netregistry (specifically, I added four new A records—one for each IP address noted by Google).

The Netregistry UI is awful for this task: Google suggests using @ for the name value but using @ or “.” or anything else in Netregistry didn’t work for me; I ended up leaving the Name field blank and setting only the Host field as the IP address. This created a new record with a “Record name” of mediawhole.com.

Thursday, 13 November 2014

Create a bootable USB drive

After so all these years I’ve never booted a machine from a USB drive—or, more specifically—had the need to create my own bootable USB drive. I’d just burn an ISO to DVD and call it done. Since I keep all of my ISOs for, like, ever, and tend to hang on to the DVDs “just in case” I’ve got a lot of crap lying around.

I’ve been on a mission to de-crap my life lately.

I also made two coasters today when a Windows Server 2012 ISO failed to burn successfully. Since I don’t like plastic, a better solution was required.

I opted to use Rufus to have a go at making my first bootable USB drive and it worked exactly as advertised. There’s no install required, which I like, and no extra Microsoft prerequisites to locate and install. I popped a big enough USB drive into a port, Rufus detected the insertion, I left the defaults as they were, selected the .iso file to use, and a few minutes later it was all finished.

On the target side (i.e. the computer I was booting with the USB drive), I did have to fiddle with the boot settings in the BIOS slightly to not only enable the machine to boot from USB but also make it extra aware of my intentions. You know what those BIOS developers can be like—your system will be specific so I won’t include the gory details.

If you found this post helpful, please support my advertisers.

Saturday, 8 March 2014

How to configure Hyper-V to use a wireless connection in Windows 8.1

I haven’t used Hyper-V for a while but when I recently built a Windows 8.1 test bed VM I needed a virtualisation platform  and Hyper-V was more or less ready to go within my Windows 8.1 host laptop.

The only hiccup I encountered along the way—and one I was familiar with from my days running Windows Server 2008 on my laptop simply so I could run Hyper-V—was configuring Hyper-V to make use of my laptop’s wireless connection. This time I followed Rick Gipson’s excellent post to get everything working  and I summarise/condense his steps here in the interest of preservation and to document a few notes relevant to my Win 8.1 environment. Check out Rick’s post for screenshots.

  1. Create a new Internal virtual network switch named Virtual WLAN from the Virtual Switch Manager in Hyper-V Manager. A new Unidentified Network connected to vEthernet (External WLAN) will now be visible within the host OS’ Network and Sharing Center. Note I renamed this connection to vEthernet (External WiFi) in Windows to reinforce its relationship to the wireless adapter and differentiated it from the Hyper-V object.
  2. In Hyper-V Manager, configure the target VM’s network adapter to use the newly-created virtual switch (i.e. Virtual WLAN). Note Rick suggested the need to add a new Legacy Network Adapter but I found this was unnecessary.
  3. In the host OS’ Network and Sharing Center, share the host’s physical WiFi adapter by checking the Allow other network users to connect through this computer’s internet connection box and specifying the Home networking connection as vEthernet (External WiFi). Note Rick’s screenshots show the Home networking connection field as a drop-down list but my current configuration displays as a text field. The WiFi adapter should now be listed as Shared in the host OS’ adapter settings.
  4. Start up your guest VM when you’re connected to a wireless and enjoy network connectivity including internet access.
If you found this post helpful, please support my advertisers.

Monday, 18 November 2013

Convert old .mdi files

I finally decided to bite the bullet and have a go at converting all of my old .mdi files ("printed" when the Microsoft Office suite included the .mdi virtual printer, before it was deprecated). Microsoft kindly supplies a command line utility to help out called MDI to TIFF Converter, which--as the name suggests--converts .mdi files to .tif files.

The tool only has a command line interface but the arguments it accepts are simple. The tool will also recurse through a directory hierarchy.

I did have trouble with one document and the tool just bombed while running but it was simply enough to track down the offending file and start afresh after deleting it (deletion was appropriate in my case).

You can download MDI to TIFF Converter here: http://www.microsoft.com/en-au/download/details.aspx?id=30328

Thursday, 3 March 2011

How to determine where an Active Directory object lives

Active Directory's Find… function is pretty handy: by searching from the directory root or any OU, you can search for specific objects by name, etc.

Unfortunately the search results display is a bit barebones and it's never obvious to a non-AD admin like me how to determine where the object actually lives in the hierarchy. Luckily you can drill into a search result item to view an object's properties but unless you're a real AD keener, you still might know how to find the object's location.

To rectify this situation, you'll need to turn on the Advanced Features setting from the Active Directory Users and Computers snap-in's View menu:

Active Directory Advanced Features

The object properties display will now include an Object tab which contains the Canonical name of object field (in other words, the path to the object within the directory):

Active Directory Object Sheet

If you found this post helpful, please support my advertisers.

Tuesday, 15 February 2011

How to reference a user control deployed to the GAC

Warning: I don't consider myself a control developer in the classic sense (although I frequently write web parts for deployment within a SharePoint environment, the scope of that deployment is fairly small by default).

A lot of the functionality I build these days runs client-side, powered by my all-time best friend jQuery. Because of this, I find I'm most productive when I first establish the HTML structure in a static HTML file before moving the mark-up to a control. In the bad old days of complete ignorance, I would have had refactor this HTML and build it programmatically within a custom control—an approach I despise (HTML belongs in mark-up).

To overcome many of the drawbacks to custom control development, I prefer migrating my prototype to a user control (which has a front-end .ascx file) and then loading that control in my web part code-behind or custom field control. Check out the LoadControl documentation for information about how load a user control programmatically.

This works beautifully when the control's code behind is compiled to an assembly destined for deployment to the private bin directory. The user control can be built in isolation with the ascx file and code behind remaining wired up for easy access to Intellisense, etc. At build time, the .ascx file is copied somewhere and deployed somewhere useful (the CONTROLTEMPLATES virtual directory, if you like).

Things get trickier when that assembly is to be deployed to the global assembly cache (aka the GAC). In my case I wanted to do this for a custom field control; although most of the code for that control was already being deployed to the GAC, it made sense to keep these artefacts together in the same project. For my non-SharePoint readers, any assembly going into the GAC has to be strong named and signed (via the project's properties sheet > Signing tab); to add the assembly to the GAC, call gacutil:

gacutil –i "MyAsemblyName.dll"

With that out of the way, assume we've got two projects: the first (MyControls) is a class library outputting a signed assembly intended for the GAC; the second is a simple web site (Web).

GAC_User_Control_sln

The MyControls project contains our user control (for information about how to set this up, refer to my post How to add a web project item to a class library). The MyControls assembly is deployed to the GAC.

The web site project contains a copy of the .ascx user control file from the MyControls project and a web page with a @ Register directive pointing to the project-local .ascx file. The Web project doesn't reference the MyControls project because we want it to load the assembly it depends on from the GAC. The .ascx copy can be done manually but you'll likely want to automate this as a pre-build task.

While the MyControls project will now compile, the Web site project will fail to compile with the error: Could not load type 'MyControls.MyUserControl'. If you're in a SharePoint environment, you'll likely see get this as a parser error when the page is dynamically compiled at first request.

To fix this, you need to add an @ Assembly directive to the top of the .ascx file to reference the MyControls assembly deployed to the GAC. You'll need the assembly name and public key token to flesh out this directive. The assembly name can be retrieved from the project properties sheet (normally it's the same as the project anyway). Then extract the public key token using the strong name application (it's the short value):

sn –Tp "MyControls.dll"

If your AssemblyInfo.cs specifies a version number of 1.0.0.0, your @ Assembly directive should look something like this:

<%@ Assembly Name="MyControls, Version=1.0.0.0, Culture=Neutral, PublicKeyToken=b3de351d91c5d4d2"%>

If you version numbers are automatically updated by some kind of policy or build event, beware you'll also need to update this directive as well, which may prove cumbersome.

This directive can be added to both copies of the .ascx file without impacting the MyControls build or edit-time experience.

Both projects will now compile and run, successfully loading the user control base type (i.e. the code behind) from the GAC.

You can download this solution here.

If you found this post helpful, please support my advertisers.

Wednesday, 9 February 2011

Cannot open a TFS query in Excel

After successfully upgrading from VS2008/TFS2008 to VS2010/TFS2010 in the last few months, I today realised my machine still had an outstanding issue opening TFS queries from Visual Studio in Excel . After running the query in VS and clicking Open in Microsoft Office –> Open Query in Microsoft Excel, I was the reluctant recipient of this error message and no Excel openage:

Team Foundation Error

TF80012: The document cannot be opened because there is a problem with the installation of the Microsoft Visual Studio v10.0 Team Foundation Office integration components.  Please see the Team Foundation Installation Guide for more information.

While a number of solutions were offered, what follows is the complete set of steps I followed to fix the problem in my workstation environment (Windows Server 2008 R2 x64 with Office 2010 x86 and VS2010 RTM + TFS bits):

1. I first repaired Microsoft Visual Studio 2010 Ultimate from Control Panel. This took a while and required a restart of my workstation. All of my extensions and settings were retained (I think). On its own, this didn't fix the problem but others have reported is did for them.

2. From a command prompt running as administrator (I'm in the local administrators on my machine but that's not good enough), I re-registered the TFSOfficeAdd-in.dll. I only ran the x86 command because VS2010 is a 32-bit app and I'm running the 32-bit version of Office on Windows x64; while the same assembly exists in the 64-bit Program Files directory, I'm assuming it's for the 64-bit version of Office 2010 (just guessing):

regsvr32 "C:\Program Files (x86)\Microsoft Visual Studio 10.0\Common7\IDE\PrivateAssemblies\TFSOfficeAdd-in.dll"

3. Starting Excel from that same command window to ensure Excel started as an admin, I removed the v9.0 Team Foundation Add-In since I noticed it was showing alongside the v10.0 add-in and I wasn't sure if it was wreaking havoc. At this point, the Team menu was visible in Excel when running as admin but not when running as myself. In Excel 2010, you can manage add-ins from the File –> Options menu; click the Add-Ins tab and then choose COM Add-Ins from the Manage drop down.

4. I finally opened Excel again as myself and enabled the Team Foundation Add-In (v10.0). The Team menu now appeared in Excel.

At this point I can now open a TFS query in Excel.

Note, others have suggested deleting their Windows profile solved the problem for them, at the cost of deleting all of their settings, My Documents, etc. If you go down that path, be careful!

If you found this post helpful, please support my advertisers.

Wednesday, 19 January 2011

Centralising global TFS alerts/notifications

TFS email alerts are critical to keeping your team informed about changes in the TFS projects they care about. At the very least, most users probably want to know when they've been assigned a work item.

Although Visual Studio 2010 includes the Alerts Explorer (Team –> Alerts Explorer) for signing yourself up for alerts, there's no obvious way to do the same thing for a group of users. Adding custom business logic into the mix really means you'll need to find a better alternative.

Behold! My latest Codeplex project is live, I call it TFS Global Alerts:

http://tfsalerts.codeplex.com/

When we last faced this problem with Visual Studio Team System 2008, we landed on a solution from vertigo.com--I'd link to the original blog post but it's been removed from the site. Moving forward a few years, it was recently time to upgrade our TFS 2008 install to TFS 2010 and the question naturally arose about what we do with alerts: continue using the Vertigo web service or not?

The custom logic originally added to the Vertigo solution was flailing a bit due to the kludge of time so we decided to refactor the current solution to better meet our needs and keep everything working with TFS 2010. I've uploaded a generalised version of the end result for your alerting enjoyment as an example of handling TFS events in a web service (you may want to follow the links below for alternatives based on Windows services and event listeners).

The Solution

TFS Global Alerts is, at its core, a web service containing a single public method:

[WebMethod]
public void Notify (string eventXml)

Notify() accepts a single parameter, a string containing XML detailing the change that occurred and some information about the work item itself. The Notify() method signature changed slightly from TFS 2008: it previously included a second string parameter, tfsIdentityXml. I removed this parameter to get things wired up successfully with TFS 2010.

Most elements in the eventXml look a bit like this—note the OldValue and NewValue child elements:

<Field>
<Name>State</Name>
<ReferenceName>System.State</ReferenceName>
<OldValue>Active</OldValue>
<NewValue>Resolved</NewValue>
</Field>

With the Notify() method called and most of the data you need at hand, sending an email to the relevant parties is then quite simple. TFS Global Alerts does some additional work to exclude the person who made the change from receiving a notification about that change (presumably they know what they've just done!) and avoid sending notifications about code check-ins linked to a work item.

The only real complexity in this code is retrieving an email address for each user from Active Directory. In our production environment I found TFS listed users by display name however in development, with TFS running as a service account in the dev domain, users were returned as domain\username. In production, if a user had multiple accounts (some of our admins), their name was returned as "First Last (domain\username)".

In terms of deployment, I simply deploy the web service to the web server hosting TFS itself and TFS web access.

The notification system hangs off TFS' own event subscription tool, bissubscribe.exe (you'll find it at C:\Program Files\Microsoft Team Foundation Server 2010\Tools\bissubscribe.exe). TFS raises events for all sorts of different happenings and bissubscribe.exe allows you to subscribe an email address or SOAP web service to handle those events.

Since I had some problems creating a server-level subscription, here's the command I use to create a project collection subscription (which captures all events in our case):

bissubscribe /eventType WorkItemChangedEvent /address http://localhost:8080/{vdir_path}/Alerts/WorkItemChanged.asmx /collection http://localhost:8080/tfs/{project_collection_name}

Result:

TF50001:  Created or found an existing subscription. The subscription ID is 36

Debugging

TFS 2010 only sends alerts every two minutes by default and events subscribed to via bissubscribe.exe adhere to the same policy. This can be a bit annoying when you're developing so you may want to dial down the batch wait time. I've included a Powershell script in the solution to configure this but otherwise, check out chrisid's post on the subject.

For additional help debugging bissubscribe, Grant Holliday has some useful tips.

Finally, don't forget to actually configure your TFS server to send email!

Resources

If you found this post helpful, please support my advertisers.

Wednesday, 12 January 2011

How to change the service accounts used by TFS 2010

As with many Microsoft products running with specific service accounts, TFS offers an easy way to change the service account it uses or update the account password.

You can do this manually by mucking with application pool identities and database permissions but there's a much easier way using the TFS Administration Console.

Assuming you have the right permissions, fire up the console and click into the Application Tier node; in the Application Tier Summary you'll find two links: Change Account and Reapply Account.

tfs_change_account

Change Account allows you to change the service account used by the system while Reapply Account allows you to change the password for the currently configured account. You can easily switch from Network Service to a local or domain account (or vice versa) but be sure to grant any local/domain account the Log on as service permission.

If you found this post helpful, please support my advertisers.

Tuesday, 11 January 2011

How to run the Visual Studio Remote Debugger as a Service

I've previously outlined a fairly clunky approach to getting the VS remote debugger installed and configured to start automatically (e.g. in a dev environment); since writing that post, I've since unearthed the remote debugger wizard and the joys (and ease) of running it as a service.

Firstly, the remote debug wizard is not shipped with VS2010 so you'll need to download the rdbgsetup file appropriate for your environment. Run the installer and you'll be prompted to configure the remote debugger once installation completes.

The wizard will present you with the option to Run the "Visual Studio 2010 Remote Debugger" service; check the box and supply an account with Log on as a service rights (the wizard will complain if the account isn't configured correctly).

To grant Log on as a service rights, do this in Windows Server 2008:

  1. Administrative Tools –> Local Security Policy;
  2. Security Settings\Local Policies\User Rights Assignment;
  3. Open Log on a service and add the user you want to configure.

The wizard will also configure the firewall on the machine to be debugged so you'll need to tell it what kind of users you want to allow in.

Once complete, you'll find the Visual Studio 10 Remote Debugger service listed in the Services applet and configured to start automatically. It runs as msvmon100 in the Services tab of Windows Task Manager.

Finally, launch visual studio and connect to the target server (Tools –> Attach to Process or CTRL+ALT+P and enter the name of your server in the Qualifier box.

If you found this post helpful, please support my advertisers.

Monday, 13 September 2010

How to pass JSON arrays and other data types to an ASMX web service

Ah interoperability… great fun, great fun.

So jQuery is your new best friend and, along with JSON, there's nuthin' you can't do. The server side stuff is still there in the background and you've got some old school ASP.NET (.asmx) web services hanging around but DOM elements are otherwise flying all over the place, postbacks are just so passé, and even the marketing girls are mildly impressed at your skillz. You're branching out, shifting code and complexity from the server to the browser, and it's time to do some heavier data shunting. Here a few things to know about passing JSON data to an ASMX web service that may help you on your way…

JSON.stringify

Know it, use it, love it. It's part of the JSON2 library and you need it if you don't have it already. Use it to prepare (aka properly encode) your JSON data before sending it off to the big mean ol' web server:

data: {"days": JSON.stringify(["Mon", "Tues"])}

That will encode as &days=["Monday","Tuesday"]

Yeah, I know, it's another file to download but the guy who wrote JSON also wrote this and it can be merged and minified. I've tried writing my own mini-version as a function and while this works for simple strings, save yourself some time when it comes to arrays and the like and just use this sucker.

Arrays

Arrays seem trickier than they should… maybe I'm just a dumb guy—probably. Anyway, you can pass a JSON array to an .asmx web service without much work at all.

The client-side call listed above is everything you need to do from that end. On the server side, create yourself a new web service method with a List<string> parameter:

[WebMethod]
[ScriptMethod (UseHttpGet = true, ResponseFormat = ResponseFormat.Json)]
public string ConsumeArray (List<string> days)
{…}

That's all there is to it. If you're not passing in strings, declare the List<> parameter with a type of object or something else. You can use .NET arrays in the web method signature as well if you really want (need) to.

Integers

When in doubt, stringify:

data: { "i": JSON.stringify(2) }

An int parameter on the web service end will handle this graciously.

Booleans

The good ol' boolean—a simple concept computer science has managed to bastardise like no other…

When in doubt, stringify:

data: { "b": jsonpEncode("true") }

Like the int parameter, a bool in your web method signature will take care of this.

A brief note: JSON, or rather jQuery's parseJSON function, is a particular beast and doesn't seem to know about anything other than the lower case true and false strings. If, for any reason, you ToString a bool in your .NET web service and try to pass it back, parseJSON will fail. If you forget to brush your teeth in the morning, parseJSON will fail.

Dates

Sorry, on my todo list ;-)

Tools

When working through this stuff, it pays to have Fiddler open to inspect the requests you're sending through and any error messages you're getting back. I find Fiddler sometimes breaks this stuff so try turning off the capture if you're getting weird errors; optionally, revert to Firebug (Firefox only, of course).

Fully decoding the data you sniff from a JSONP request passed along in the query string will require some additional tooling; in short, you'll want to decode the value using a free online tool like Opinionated Geek's URL decoder.

If you found this post helpful, please support my advertisers.