Wednesday, October 29, 2008

Mac OS X alternative to SnagIt

I've been spoiled by an application for Windows called SnagIt.  Its a really nice screen capture tool that lets you take screen grabs of portions of the screen, annotate them with arrows and boxes and text, then save or copy the result to the clipboard.  

I wanted something similar for OS X.  While I knew about "ctrl + command + shift + 4" to do screen captures of specific portions of the screen (replace "4" with "3" for the whole screen), what I didn't know is that starting with 10.5, Preview actually includes all the annotation features I need.  Thanks LifeHacker for this article (excerpt below)
Mac OS X Leopard only: One of the built-in Mac utilities that got the most feature additions in Leopard—albeit pretty quietly—is Preview, the PDF and image viewer. We've already covered how you can do more with Preview in Leopard, but Mac OS X Hints points out another good one: image annotation. Add arrows and notes, or circle and outline areas of an image in Preview using the Annotation menu. (In Preview's View menu choose Customize Toolbar, then drag the Annotate menu onto the toolbar.) Then, when you're editing a non-PDF image in Preview, just select your annotation, and click and drag on the image itself. Handy, and no third-party software required.

So, now to get the same features for when I need to sent an annotated screenshot, I just:
  1. use the "CTRL+COMMAND+SHIFT+4" combination to bring up the screen grab crosshairs (use can press "space" after to get a camera icon to do a grab of a whole window)
  2. Select the portion I want to grab
  3. Open the Preview application
  4. Either do "File / New" or "COMMAND+N", which opens a new document with the contents of the clipboard
  5. Annotate away!

Friday, October 10, 2008

removing duplicate files with under bash using fdupes and accounting for spaces

Basically, I've been lazy.  I've been trying to organize a file structure, been unhappy with it, copied it, tried again, been unhappy, copied . . . and ended up with about six copies of this folder each with various additions made to it at various subfolder levels that I need to account for.

Now, I could simply do a recursive find and look for duplicate file names, but the other part of my being lazy is a lot of files in various subfolders are named simply with the very imaginative format of the date I wrote the file.  What I wanted was to compare md5 checksums to be sure they were truly identical.

While I use Windows at work and could whip of a powershell script to handle this on Windows, I run OS X for my personal machine.

I've tinkered with bash scripting before, enough to know that what I want to do should be doable in one line with the help of the great utility fdupes. (fdupes can be installed on OS X easily if you have MacPorts installed, simply call "sudo port install fdupes")

I whipped up the following and was proud of myself:
for i in $(fdupes -rf ./); do echo deleting: $i; rm $i; done
(of course the "rm" was done after making a backup ;-) )

What I noticed was this worked fine for all files except those with spaces in the name.  I apparently some files that were saved with the first sentence as the filename, which the output of this command confirmed as:
deleting: some
deleting: file
deleting: with
deleting: spaces.txt
After some head scratching thinking about piping through awk or escaping out the spaces, I found this on a google result:
If you set IFS to $'\n' then it will only split on newlines, not spaces.
Could it be that simple?  YES!  My completed commands:
IFS=$'\n'
for i in $(fdupes -rf ./); do echo deleting: $i; rm $i; done

Thursday, October 9, 2008

Manipulating remote services with Powershell 1.0

I know Powershell 2.0 CTP2 includes remote support for the get/set-service cmdlet, but I cannot use beta code in production and needed a way to use Powershell to accomplish the same functions we use the Resource Kit "sc.exe" tool for now (start, stop, enable/disable).

After much googling, this turned out to be insanely simple, yet hard to find.

First, get the remote service using WMI:
$Svc = Get-WmiObject -Computer $Server win32_service -filter "name='$Service'"
Second, issue the appropriate control command:
To start a service:
$Result = $Svc.StartService()
To stop a service:
$Result = $Svc.StopService()
To disable a service:
$Result = $Svc.ChangeStartMode("Disabled")
To enable a service for manual:
$Result = $Svc.ChangeStartMode("Manual")
To enable a service for auto start:
$Result = $Svc.ChangeStartMode("Auto")

Third, check if the command worked; just look for $Result.ReturnValue. It should be "0" if it succeeded.:
$Result.ReturnValue

For reference, "5" means you tried to stop an already stopped service and "10" means you tried to start and already started service.

You can also check the current state by:
$Svc.State
And the current StartMode by:
$Svc.StartMode

I would also add in a step after calling "Get-WmiObject" to verify you actually connected to a service. There is no response if the service didn't exist, but you can simply check if $Svc is null or not:
If (!($Svc)) { #perform action }

If this wasn't fully helpful for you (i.e. you want to manipulate lots of services or many machines) I found the best google search term to be "powershell win32_service" from http://google.com/microsoft