Saturday, October 11, 2008

I was working with a lot of images for a website today and I needed to quickly create thumbnails for each one. I did a quick Google search on PowerShell and creating thumbnails, but I gave up after about a minute… yeah, I probably got impatient, but oh well.

Anyway, here it is:

get-childitem *.jpg | foreach {
    $full = [System.Drawing.Image]::FromFile("$(resolve-path $_)");
    $thumb = $full.GetThumbnailImage(72, 72, $null, [intptr]::Zero);
    $thumb.Save("$(resolve-path $_).thumb.jpg" );
    $full.Dispose();
    $thumb.Dispose();
}

Obviously, you likely wouldn’t hardcode the height and width for the thumbnail, but would probably base it off of the original image (i.e. varying it off of whether the image was wide or tall). But, I didn’t need to. That’s up to you to figure out :-)

posted on Saturday, October 11, 2008 4:21:14 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Tuesday, September 30, 2008

I promised the slides, notes and links from my Memphis .NET User Group talk, so here they are… and wow, they haven’t really changed much from when I gave the PowerShell talk to the FSDNUG group. So, I’ll just link to the zip of the presentation from that talk.

The primary slide that I added to my presentation was entirely related to a StackOverflow question entitled, “how do you use PowerShell.”

I felt that the talk went fairly well, but I did have to rush towards the end because I added an overview of some real scripts that I use, but I didn’t remove enough of my prior content… thus, the rush. :-)  No big deal, though. I did get the feeling that there were a few people who didn’t really feel that PowerShell applied to them, but hey, that’s fine. At least there weren’t any tomatoes!

I’ll be presenting one more time (as far as I know) this year at Harding University. I’m looking forward to it, too. I’ll be presenting for the Computing Seminar on October 9. The last time I spoke before Seminar was in 2003 when I talked about “Smart Client Software.” That was when it was for college credit! I’m planning on changing the talk up a little to direct it more towards CS students instead of professional developers. I imagine it will be a slightly different audience than the typical .NET User Group, too. We’ll see.

Back on the MNUG talk, thanks to Randy for driving and thanks to Colin for inviting me to speak. It was fun!

posted on Tuesday, September 30, 2008 7:13:41 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, September 24, 2008

Colin is risking it I say. How is he risking it you might ask? By asking me to speak to the Memphis .NET User Group!

I think he’s crazy, but whatever.

Randy Walker and I will be traveling to Memphis, TN tomorrow night where I’ll be presenting on PowerShell. Randy is coming out to meet with the founding members of the Northeast Arkansas .NET User Group, which is very cool. Regarding my presentation, it will likely be a similar presentation to what I gave to the FSDNUG group, but I’m hoping to have more script examples. I think I gave the Fort Smith group a good picture of PowerShell, but I don’t think I showed them nearly as many practical uses of PowerShell as I would have liked. I’ve got a folder of scripts now, some that I’ve written for myself and a few that we’re using at work, that I’ll be showing and walking through during the presentation.

If you’re in the area, come on out!

posted on Wednesday, September 24, 2008 12:42:45 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, May 07, 2008

A coworker swung by a few days ago to ask some questions about using Reflection. I learn really well by example so I decided to use Powershell to show using Reflection. Below is the session I used and later emailed to him. You can see a few spots at the bottom of the example where I was unsure of the syntax on passing an empty parameter array, but I figured it out.

This is a good example of why I like Powershell :-)

  1 [1] » "haha".gettype()
  2
  3 IsPublic IsSerial Name                                     BaseType
  4 -------- -------- ----                                     --------
  5 True     True     String                                   System.Object
  6
  7
  8 [2] » $temp = "haha".gettype()
  9 [3] » $temp.GetProperties()
10
11
12 MemberType    : Property
13 Name          : Chars
14 DeclaringType : System.String
15 ReflectedType : System.String
16 MetadataToken : 385875994
17 Module        : CommonLanguageRuntimeLibrary
18 PropertyType  : System.Char
19 Attributes    : None
20 CanRead       : True
21 CanWrite      : False
22 IsSpecialName : False
23
24 MemberType    : Property
25 Name          : Length
26 DeclaringType : System.String
27 ReflectedType : System.String
28 MetadataToken : 385875995
29 Module        : CommonLanguageRuntimeLibrary
30 PropertyType  : System.Int32
31 Attributes    : None
32 CanRead       : True
33 CanWrite      : False
34 IsSpecialName : False
35
36
37
38 [4] » $temp.GetProperties()[0]
39
40
41 MemberType    : Property
42 Name          : Chars
43 DeclaringType : System.String
44 ReflectedType : System.String
45 MetadataToken : 385875994
46 Module        : CommonLanguageRuntimeLibrary
47 PropertyType  : System.Char
48 Attributes    : None
49 CanRead       : True
50 CanWrite      : False
51 IsSpecialName : False
52
53
54
55 [5] » $temp.GetProperties()[0].name
56 Chars
57 [6] » $temp.GetProperties()[1].name
58 Length
59 [7] » $temp.GetProperties()[1].GetGetMethod()
60
61
62 Name                       : get_Length
63 DeclaringType              : System.String
64 ReflectedType              : System.String
65 MemberType                 : Method
66 MetadataToken              : 100663629
67 Module                     : CommonLanguageRuntimeLibrary
68 MethodHandle               : System.RuntimeMethodHandle
69 Attributes                 : PrivateScope, Public, HideBySig, SpecialName
70 CallingConvention          : Standard, HasThis
71 ReturnType                 : System.Int32
72 ReturnTypeCustomAttributes : Int32
73 ReturnParameter            : Int32
74 IsGenericMethod            : False
75 IsGenericMethodDefinition  : False
76 ContainsGenericParameters  : False
77 IsPublic                   : True
78 IsPrivate                  : False
79 IsFamily                   : False
80 IsAssembly                 : False
81 IsFamilyAndAssembly        : False
82 IsFamilyOrAssembly         : False
83 IsStatic                   : False
84 IsFinal                    : False
85 IsVirtual                  : False
86 IsHideBySig                : True
87 IsAbstract                 : False
88 IsSpecialName              : True
89 IsConstructor              : False
90
91
92
93 [8] » $temp.GetProperties()[1].GetGetMethod().Invoke
94
95
96 MemberType          : Method
97 OverloadDefinitions : {System.Object Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo cu
98                       lture), System.Object Invoke(Object obj, Object[] parameters)}
99 TypeNameOfValue     : System.Management.Automation.PSMethod
100 Value               : System.Object Invoke(Object obj, BindingFlags invokeAttr, Binder binder, Object[] parameters, CultureInfo cul
101                       ture), System.Object Invoke(Object obj, Object[] parameters)
102 Name                : Invoke
103 IsInstance          : True
104
105
106
107 [9] » $temp.GetProperties()[1].GetGetMethod().Invoke("hello world", [])
108 Unable to find type []: make sure that the assembly containing this type is loaded.
109 At line:1 char:65
110 + $temp.GetProperties()[1].GetGetMethod().Invoke("hello world", []) <<<<
111 [10] » $temp.GetProperties()[1].GetGetMethod().Invoke("hello world")
112 Cannot find an overload for "Invoke" and the argument count: "1".
113 At line:1 char:47
114 + $temp.GetProperties()[1].GetGetMethod().Invoke( <<<< "hello world")
115 [11] » $temp.GetProperties()[1].GetGetMethod().Invoke("hello world", {})
116 Exception calling "Invoke" with "2" argument(s): "Parameter count mismatch."
117 At line:1 char:47
118 + $temp.GetProperties()[1].GetGetMethod().Invoke( <<<< "hello world", {})
119 [12] » $temp.GetProperties()[1].GetGetMethod().Invoke("hello world", $Null)
120 11
121 [13] »
122

Note - I used the :toHTML command from Vim along with Peter Provost's Powershell syntax file to get the color. Powershell doesn't support color at the console like this yet without explicitly passing color arguments to Write-Host.

posted on Wednesday, May 07, 2008 7:51:00 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, April 24, 2008

Here is a simple script I wrote which was inspired by this post on terminal color highlighting and by ColorDiff that does essentially the same thing.

# Out-ColorDiff.ps1
Process {
    if ($_) {
        foreach ($line in $_) {
            if ($line -match '^[<|-]') {
                Write-Host -ForegroundColor red $line
            }
            elseif ($line -match '^[>|+]') {
                Write-Host -ForegroundColor green $line
            }
            else {
                Write-Host $line
            }
        }
    }
}

Here is a screenshot of sample output from the script:

image

You can use it by piping the diff output to the script, like 'svn diff somefile | out-colordiff' or if you're stuck using something like MKS, you can use 'si diff somefile | out-colordiff'.

Possible (and easy) additions would be to add direct parsing of a file instead of taking an argument off of the pipeline. This is all I need currently, but if you wish to add more features, feel free to leave them in the comments.

posted on Thursday, April 24, 2008 9:55:44 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Tuesday, November 06, 2007

image

I didn't expect to see this in the next version of PowerShell - very cool. It definitely still needs some work, but I like the start. The syntax highlighting for opened script files is nice. I'd like to see some intellisense in there, but it isn't a big deal. If intellisense would slow it down much, I think I'd rather not have it anyway. I think the biggest issues I've got with it so far is the lack of options to customize fonts and colors as well as tab expansion.

I've haven't had a chance to play with anything else, but it seems nice so far.

posted on Tuesday, November 06, 2007 8:40:44 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Friday, November 02, 2007

I'm finding myself wondering if I'm a beta junkie or a CTP junkie.

Why?

Because Jeffrey Snover announced that there will be a CTP release of PowerShell 2.0 next week. I'm not waiting for the beta either - I'm downloading the CTP bits as soon as the post announcing its release gets to Google Reader. Maybe I should change my "beta junkie" title to "pre-release junkie" or "I just like to install things junkie."*

PowerShell 1.0 single handedly turned me into a console user. I do 90+% of my file operations from PowerShell instead of Windows Explorer. I also do a large portion of my pseudo coding at the command prompt to see whether a basic algorithm will work the way I expect it to. I'm very excited to see what the team has come up with.

Update (per post from Jeffrey Snover):

The PowerShell V2 CTP is not for everyone. You should read this PowerShell Team blog entry ( http://blogs.msdn.com/powershell/archive/2007/11/02/ctp-watch-this-space.aspx ) to find out what it is and what it isn't and then make an informed decision before installing the CTP.

I may be an "I just like to install things junkie" but that doesn't mean that you should be to. Be responsible with pre-release software. If you've got production code that relies on PowerShell behavior, etc. you should consider holding off on installing it on your development machine.

 

* With all these installs I do, I actually do see UAC prompts a lot. And no, I haven't turned off the prompt.

posted on Friday, November 02, 2007 10:26:11 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 28, 2007

I was browsing around a few days ago and came across a link to a blog post on the SAPIEN website about searching live.com from PowerShell. Sounds cool, I think, so I download it to try it out only to be thwarted by the proxy at work.

There are a lot of scripts out there that use the System.Net.WebClient and the vast majority don't take proxies into account. To get around this issue, here's a simple script that I wrote to help out:

function Get-ProxyWebClient {
    $webclient = New-Object System.Net.WebClient
    $proxy = New-Object System.Net.WebProxy($global:ProxyUrl, $global:ProxyPort)
    $proxy.Credentials = (Get-Credential).GetNetworkCredential()
    $webclient.Proxy = $proxy
    return $webclient
}

This script makes the assumption that you've already predefined the $global.ProxyUrl and $global.ProxyPort variables in your profile. It is also nice for me because it prompts me for my credentials instead of having them hard-coded in the script or in my profile.

Now I can also check the weather from PowerShell using the Show-Weather script that the guys at SAPIEN provided in their über-prompt post.

posted on Thursday, June 28, 2007 11:39:11 AM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, June 21, 2007

/n software has a promotion going right now where you can get a free Powershell sticker from them. I haven't been so excited about stickers since elementary school!

Now to figure out where  to put it...

posted on Thursday, June 21, 2007 7:03:26 AM (Central Standard Time, UTC-06:00)  #    Comments [2]
 Wednesday, January 10, 2007

A recent post by Lee Holmes on breaking your writer's (blogger's?) block is prompting this post. I recently finished reading Steve McConnell's book, Code Complete*, over the Christmas holidays and the book was amazing. As I read it, I began taking lists of things I wanted to post on that were excellent advice... and ran into a block because there was just so much I wanted to say about. I still plan on writing more detailed posts on the issue but, as Lee suggests, I need to just get out here and post more.

So anyway.

Recently, I posted an entry on calculating file hashes with PowerShell and promptly had to put an update because the PowerShell Community Extensions (PsCx) had provided a better file hash function. The good thing about PsCx is that it really provides a good example of PowerShell code and has a lot of cmdlets that drive home automating PowerShell for your needs.

One of my favorite functions is incredibly simple but it highlights how you can save just a few keystrokes for more productivity. The Edit-File function uses a predefined variable that points to an EXE path and runs the EXE with the specified parameter. There is also an alias for it (e) so you can type something like "e somefile.txt" and it will open. I like this method a little better than actually renaming notepad.exe to n.exe (*cough* Scott Hanselman *cough* :-) ). It actually prompted me to create multiple, similar functions so that I can open files in different editors (I use Ultra-Edit, Notepad2, Notepad++, or who knows what else) without having to respecify the editor variable. Now I type "u somefile.txt" to open a file in Ultra-Edit.

This also prompted me to set up the winmerge function below:

function winmerge ([string]$path1, [string]$path2) {

    $winmergePath = "c:\program files\winmerge\winmerge.exe"
    . $winmergePath $path1 $path2
}

It allows me to quickly see the comparisons between two different files without having to preselect them with the mouse. It is simple, but quite convenient. And I also don't have to go adding all sorts of random directories to my PATH just so I can get to them more quickly.

So there you go: my PowerShell automation.

I also promised some unrelated updates. On Monday, January 8, I had LASIK surgery on both of my eyes to correct my extreme nearsightedness. The whole operation took 15 minutes and the only discomfort I had was a headache and some stinging eyes on the day of the operation. Since that time, my left eye can already see with 20/15 vision. My right eye is still a little fuzzy, but that is supposed to clear up in another day or so - it took the laser twice as long to correct my right eye as it did my left eye!

If anyone is interested in more details on my experiences with LASIK, I'd be happy to provide a follow-up post on it.

* - Jeff Atwood really should get some sort of referral rewards for recommending Code Complete... I mean seriously...

posted on Wednesday, January 10, 2007 9:38:44 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, December 28, 2006

UPDATE NUMBER 2:

Kevin commented about a flaw in my script wherein it would keep files open until the PowerShell process was closed - a scenario I should've tested but, in all of the excitement (ha), I missed. You won't believe what the problem was, either. I forgot parentheses on my $inStream.Close() method (it looked like $inStream.Close instead of $inStream.Close() ). The reason the trap { } script block didn't catch it is because the statement was still valid... it would just display the MethodInfo like below:

MemberType          : Method
OverloadDefinitions : {System.Void Close()}
TypeNameOfValue     : System.Management.Automation.PSMethod
Value               : System.Void Close()
Name                : Close
IsInstance          : True

The [void] statement before it prevented the output from displaying, hence me not catching the bug. The script has now been fixed (hopefully). Thanks for the catch Kevin!

UPDATE:

Ignore my script. Go download the PowerShell Community Extensions instead. It has a great Get-Hash script that does everything that my script does and more. I wish I had downloaded it sooner :-)

 

Jeffrey Snover posted a suggestion on the PowerShell blog recently to post automation scripts people have written in PowerShell that they use. Well, here is a script I wrote that I also submitted for the PowerShell Scripting Contest a few weeks back. The script is quite basic and is based on other code I found, but I added a little bit to it to handle some of my own needs. It calculates file hashes based on a specified hash algorithm (i.e. SHA1, MD5, etc). I like to use it to determine if a large file I've downloaded (like an ISO from MSDN) is a good file or if it was corrupted during the download.

Here is Calc-Hash.ps1:

param (
	[string] $inFile = $(throw "Usage: Calc-Hash.ps1 file.txt [sha1|md5] "),
	[string] $hashType = "sha1"
)

function Main
{
	if ($hashType -eq "")
	{
		throw "Usage: Calc-Hash.ps1 file.txt [sha1|md5] "
	}
	
	if ($hashType -eq "sha1")
	{
		$provider = New-Object System.Security.Cryptography.SHA1CryptoServiceProvider
	}
	elseif ($hashType -eq "md5")
	{
		$provider = New-Object System.Security.Cryptography.MD5CryptoServiceProvider
	}
	else
	{
		throw "Unsupported hash type $hashType"
	}
		
	$inFileInfo = New-Object System.IO.FileInfo($inFile)
	if (-not $inFileInfo.Exists)
	{
		# If the file can't be found, try looking for it in the current directory.
		$inFileInfo = New-Object System.IO.FileInfo("$pwd\$inFile")
		if (-not $inFileInfo.Exists)
		{
			throw "Can't find $inFileInfo"
		}
	}

	$inStream = $inFileInfo.OpenRead()
	$hashBytes = $provider.ComputeHash($inStream)
	[void] $inStream.Close()
	
	trap
	{
		if ($inStream -ne $null)
		{
			[void] $inStream.Close()
		}
		break
	}
	
	foreach ($byte in $hashBytes)
	{
		Write-Host -NoNewLine $byte.ToString("X2")
	}
	
	Write-Host
}

. Main
posted on Thursday, December 28, 2006 7:55:57 AM (Central Standard Time, UTC-06:00)  #    Comments [4]
 Wednesday, November 29, 2006

A few weeks ago I posted a way to use PowerShell to find in files. This is just an extension of that post to show how you might open the results of your find in a program.

Try this out:

dir -include *.vb -recurse | select-string "text to search for" | % { notepad $_.Path }

If you've got a lot of Visual Basic files that contain "text to search for", you may end up with a lot of instances of notepad open. At work, I use UltraEdit, so I typically would open my files using uedit32 so that all of the results get opened in tabs. You could do the same with Notepad++ or any other program.

I haven't really used PowerShell for much production work, but it has already made me for more productive than I used to be.

While I'm at it, I'll share another nice one-liner that Kerry shared with me to ngen all assemblies in a directory:

dir *.dll | % { C:\WINDOWS\Microsoft.NET\Framework\v2.0.50727\ngen.exe $_.fullname}

posted on Wednesday, November 29, 2006 1:21:49 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Monday, November 06, 2006

I haven't posted anything on PowerShell in a while so here's something that's useful.

Get-ChildItem -Recurse -Include *.* | Select-String "text to search for"

Or, if you like things a little more abbreviated, try this:

dir -r -i *.* | Select-String "text to search for"

Select-String is a cmdlet that will search files or strings, sort of like grep in Unix or findstr in cmd.exe. If you use the Get-ChildItem cmdlet, you can specify the -Recurse switch to retrieve subdirectories and the -Include switch will only include the file types that you specify. Then you can pipe it over to Select-String.

Pretty nifty if you're wanting to do some quick file searches.

Check out this PowerShell in Action book excerpt. It gives a good overview on file manipulation from PowerShell and also introduced me to using the Get-ChildItem command and piping the output to Select-String.

Before I began using PowerShell, I had been using a small cmd file called ff.cmd that used the following:

findstr /p /s /i /c:%1 %2

Then I could type things like:

ff "text to search for" .\*.*

But PowerShell is so much cooler now :-)

posted on Monday, November 06, 2006 1:12:11 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, September 07, 2006

Having trouble changing your PowerShell Script Execution Policy in Vista because of access problems? This whole limited user thing will take some time to get used to, but it certainly is a good idea for security. What I did to fix this problem was I ran the command prompt as an admin. If you go under your start menu and accessories, you'll see a link to the command prompt. If you right click on it, you'll see an option to run as administrator. Here's a screenshot:

Once you do that, you'll be able to start up Powershell and then you'll have authority to change the execution policy. I've typically been setting mine to RemoteSigned (Set-ExecutionPolicy RemoteSigned).

Unrelated to Powershell, but wow will I need more memory if I want to run Vista! I barely have any programs open and my pagefile is getting hit like crazy! I'm probably averaging a gig of memory usage... with only one program open!

posted on Thursday, September 07, 2006 8:09:55 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Wednesday, July 26, 2006

Recently, I've been experimenting with different console colors in PowerShell, primarily because the light gray on black is sort of boring (lame excuse, I know). I've been using Console and I had set the foreground color to green in the options. The only problem with doing this is that programs that output other colors, such as the error messages from MSBuild, are not displayed. I like seeing the color difference because the red text really jumps out at me and says that I have an error.

This got me curious about whether or not I could set a different color in PowerShell, instead of in Console. I stumbled across this TechNet article from way back when PowerShell was still MSH. Basically, you use the -foregroundcolor or -backgroundcolor switch against Write-Host to alter the color of the text you're outputting. That's certainly userful information if you're writing cmdlets, but I wanted to change the default color for the entire session.

If you've worked with .NET console applications, you may have seen System.Console.ForegroundColor. Well, this is available from PowerShell as well! .NET shell integration is great! So now, my PowerShell profile has a brand new line in it:

[System.Console]::ForegroundColor = [System.ConsoleColor]::Green

By doing this, whenever an application, cmdlet, function or whatever changes the default output color, like MSBuild does, you'll be able to see it. As a side note, I really like the PowerShell profile idea. Though options dialogs tend to be more user friendly, the PowerShell profile (try 'notepad $profile') is far more powerful and customizable.

posted on Wednesday, July 26, 2006 12:00:28 PM (Central Standard Time, UTC-06:00)  #    Comments [0]
 Thursday, July 13, 2006

Yesterday, I downloaded the Developer Productivity Tools video from the Wrox website that Scott Hanselman did for one of his presentations with a user group. He had a lot of great resources in the video but the command prompt tips he had were new to me. I've done some work with the console, but I've only recently been using it more, particularly with PowerShell coming along.

Scott's tip about customizing your prompt (from c:\dir\> to whatever) was really cool (also posted here). I knew that the prompt could be customized, but at the time I saw someone do it, I didn't have a good grasp of environment variables so it didn't really make sense what was going on, but Scott's video and his post have helped out a lot. They also prompted me to want to do the same with my PowerShell prompt!

The PROMPT environment variable trick doesn't work for the PowerShell prompt, but after a little digging around with Google, I discovered this post from Lee Holmes about the prompt function. If you have a function named prompt declared, PowerShell will use the value returned by that function to alter the display of your prompt. Here's my prompt function, which I have saved in PowerShell profile so that it will load every time (mine is located here C:\Documents and Settings\David\My Documents\PSConfiguration\Microsoft.PowerShell_profile.ps1)

# Initialize custom prompt
function prompt
{
   "PS " + (get-location).Path + [System.Environment]::NewLine + ">".PadLeft((get-location -stack).Count + 1, "+")
}

The only thing I haven't figured out yet is how to get a visual indication of how far in the stack you are (by using pushd and popd). Once I figure that out, I'll have a PowerShell prompt customized just like my cmd prompt!

UPDATE: I did some more research and discovered get-location -stack which will return everything on the pushd/popd stack. I've updated my prompt function accordingly. Now it matches my cmd prompt in every way!

posted on Thursday, July 13, 2006 12:00:39 PM (Central Standard Time, UTC-06:00)  #    Comments [0]